irqchip/gic-v3-its: Make vlpi_lock a spinlock
authorMarc Zyngier <maz@kernel.org>
Fri, 8 Nov 2019 16:58:05 +0000 (16:58 +0000)
committerMarc Zyngier <maz@kernel.org>
Sun, 10 Nov 2019 18:48:35 +0000 (18:48 +0000)
The VLPI map is currently a mutex, and that's a bad idea as
this lock can be taken in non-preemptible contexts. Convert
it to a raw spinlock, and turn the memory allocation of the
VLPI map to be atomic.

Reported-by: Heyi Guo <guoheyi@huawei.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20191108165805.3071-12-maz@kernel.org
drivers/irqchip/irq-gic-v3-its.c

index 9c4f35ed134cbcde61b7a5fb977e97fa926028c7..e05673bcd52bdad6adff75c48140baaeea1a79c1 100644 (file)
@@ -132,7 +132,7 @@ struct event_lpi_map {
        u16                     *col_map;
        irq_hw_number_t         lpi_base;
        int                     nr_lpis;
-       struct mutex            vlpi_lock;
+       raw_spinlock_t          vlpi_lock;
        struct its_vm           *vm;
        struct its_vlpi_map     *vlpi_maps;
        int                     nr_vlpis;
@@ -1436,13 +1436,13 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
        if (!info->map)
                return -EINVAL;
 
-       mutex_lock(&its_dev->event_map.vlpi_lock);
+       raw_spin_lock(&its_dev->event_map.vlpi_lock);
 
        if (!its_dev->event_map.vm) {
                struct its_vlpi_map *maps;
 
                maps = kcalloc(its_dev->event_map.nr_lpis, sizeof(*maps),
-                              GFP_KERNEL);
+                              GFP_ATOMIC);
                if (!maps) {
                        ret = -ENOMEM;
                        goto out;
@@ -1485,7 +1485,7 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
        }
 
 out:
-       mutex_unlock(&its_dev->event_map.vlpi_lock);
+       raw_spin_unlock(&its_dev->event_map.vlpi_lock);
        return ret;
 }
 
@@ -1495,7 +1495,7 @@ static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info)
        struct its_vlpi_map *map;
        int ret = 0;
 
-       mutex_lock(&its_dev->event_map.vlpi_lock);
+       raw_spin_lock(&its_dev->event_map.vlpi_lock);
 
        map = get_vlpi_map(d);
 
@@ -1508,7 +1508,7 @@ static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info)
        *info->map = *map;
 
 out:
-       mutex_unlock(&its_dev->event_map.vlpi_lock);
+       raw_spin_unlock(&its_dev->event_map.vlpi_lock);
        return ret;
 }
 
@@ -1518,7 +1518,7 @@ static int its_vlpi_unmap(struct irq_data *d)
        u32 event = its_get_event_id(d);
        int ret = 0;
 
-       mutex_lock(&its_dev->event_map.vlpi_lock);
+       raw_spin_lock(&its_dev->event_map.vlpi_lock);
 
        if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d)) {
                ret = -EINVAL;
@@ -1548,7 +1548,7 @@ static int its_vlpi_unmap(struct irq_data *d)
        }
 
 out:
-       mutex_unlock(&its_dev->event_map.vlpi_lock);
+       raw_spin_unlock(&its_dev->event_map.vlpi_lock);
        return ret;
 }
 
@@ -2608,7 +2608,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        dev->event_map.col_map = col_map;
        dev->event_map.lpi_base = lpi_base;
        dev->event_map.nr_lpis = nr_lpis;
-       mutex_init(&dev->event_map.vlpi_lock);
+       raw_spin_lock_init(&dev->event_map.vlpi_lock);
        dev->device_id = dev_id;
        INIT_LIST_HEAD(&dev->entry);