irqchip/gic-v3-its: Remove cpumask_var_t allocation
authorPierre Gondois <pierre.gondois@arm.com>
Mon, 12 Sep 2022 14:18:57 +0000 (16:18 +0200)
committerMarc Zyngier <maz@kernel.org>
Mon, 12 Sep 2022 15:37:43 +0000 (16:37 +0100)
Running a PREEMPT_RT kernel based on v5.19-rc3-rt4 on an Ampere Altra
triggers:

[   22.616229] BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:46
[   22.616239] in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 1884, name: kworker/80:1
[   22.616243] preempt_count: 3, expected: 0
[   22.616244] RCU nest depth: 0, expected: 0
[...]
[   22.616250] hardirqs last enabled at (33): _raw_spin_unlock_irq (/home/piegon01/linux/./arch/arm64/include/asm/irqflags.h:35)
[   22.616273] hardirqs last disabled at (34): __schedule (/home/piegon01/linux/kernel/sched/core.c:6432 (discriminator 1))
[   22.616283] softirqs last enabled at (0): copy_process (/home/piegon01/linux/./include/linux/lockdep.h:191)
[   22.616297] softirqs last disabled at (0): 0x0
[   22.616305] Preemption disabled at:
[   22.616307] __setup_irq (/home/piegon01/linux/kernel/irq/manage.c:1612)
[   22.616322] CPU: 80 PID: 1884 Comm: kworker/80:1 Tainted: G        W        [...]
[   22.616328] Hardware name: WIWYNN Mt.Jade Server System B81.03001.0005/Mt.Jade Motherboard, BIOS 1.08.20220218 (SCP: 1.08.20220218) 2022/02/18
[   22.616333] Workqueue: events work_for_cpu_fn
[   22.616344] Call trace:
[...]
[   22.616403] alloc_cpumask_var_node (/home/piegon01/linux/lib/cpumask.c:115)
[   22.616414] alloc_cpumask_var (/home/piegon01/linux/lib/cpumask.c:147)
[   22.616417] its_select_cpu (/home/piegon01/linux/drivers/irqchip/irq-gic-v3-its.c:1580)
[   22.616428] its_set_affinity (/home/piegon01/linux/drivers/irqchip/irq-gic-v3-its.c:1659)
[   22.616431] msi_domain_set_affinity (/home/piegon01/linux/kernel/irq/msi.c:501)
[   22.616440] irq_do_set_affinity (/home/piegon01/linux/kernel/irq/manage.c:276)
[   22.616443] irq_setup_affinity (/home/piegon01/linux/kernel/irq/manage.c:633)
[   22.616447] irq_startup (/home/piegon01/linux/kernel/irq/chip.c:280)
[   22.616453] __setup_irq (/home/piegon01/linux/kernel/irq/manage.c:1777)

Follow the pattern established in commit cba4235e6031e ("genirq: Remove
mask argument from setup_affinity()") and co to overcome this issue by
defining a static struct cpumask and protecting it by a raw spinlock.

Since its_select_cpu() can be executed with IRQs enabled or disabled,
enforce that the cpumask computation is done with interrupts disabled.

Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220912141857.1391343-1-pierre.gondois@arm.com
drivers/irqchip/irq-gic-v3-its.c

index 5ff09de6c48fcbec5a9b954fa284c02617204de4..beead1a0191c11b2daa1925f0730bba49a1c8f9d 100644 (file)
@@ -1574,13 +1574,15 @@ static int its_select_cpu(struct irq_data *d,
                          const struct cpumask *aff_mask)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
-       cpumask_var_t tmpmask;
+       static DEFINE_RAW_SPINLOCK(tmpmask_lock);
+       static struct cpumask __tmpmask;
+       struct cpumask *tmpmask;
+       unsigned long flags;
        int cpu, node;
-
-       if (!alloc_cpumask_var(&tmpmask, GFP_ATOMIC))
-               return -ENOMEM;
-
        node = its_dev->its->numa_node;
+       tmpmask = &__tmpmask;
+
+       raw_spin_lock_irqsave(&tmpmask_lock, flags);
 
        if (!irqd_affinity_is_managed(d)) {
                /* First try the NUMA node */
@@ -1634,7 +1636,7 @@ static int its_select_cpu(struct irq_data *d,
                cpu = cpumask_pick_least_loaded(d, tmpmask);
        }
 out:
-       free_cpumask_var(tmpmask);
+       raw_spin_unlock_irqrestore(&tmpmask_lock, flags);
 
        pr_debug("IRQ%d -> %*pbl CPU%d\n", d->irq, cpumask_pr_args(aff_mask), cpu);
        return cpu;