[PATCH] irqchip/sifive-plic: Fix plic_set_affinity() only enables 1 cpu
Nam Cao
namcao at linutronix.de
Wed Jul 3 00:26:59 PDT 2024
plic_set_affinity() only enables interrupt for the first possible CPU in
the mask. The point is to prevent all CPUs trying to claim an interrupt,
but only one CPU succeeds and the other CPUs wasted some clock cycles for
nothing.
However, there are two problems with that:
1. Users cannot enable interrupt on multiple CPUs (for example, to minimize
interrupt latency).
2. Even if users do not touch SMP interrupt affinity, plic_set_affinity()
is still invoked once (in plic_irqdomain_map()). Thus, by default, only
CPU0 handles interrupts from PLIC. That may overload CPU0.
Considering this optimization is not strictly the best (it is tradeoff
between CPU cycles and interrupt latency), it should not be forced on
users.
Rewrite plic_set_affinity() to enable interrupt for all possible CPUs in
the mask.
Before:
$ cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
10: 2538 2695 3080 2309 RISC-V INTC 5 Edge riscv-timer
12: 3 0 0 0 SiFive PLIC 111 Edge 17030000.power-controller
13: 1163 0 0 0 SiFive PLIC 25 Edge 13010000.spi
14: 60 0 0 0 SiFive PLIC 7 Edge end0
15: 0 0 0 0 SiFive PLIC 6 Edge end0
16: 0 0 0 0 SiFive PLIC 5 Edge end0
17: 0 0 0 0 SiFive PLIC 78 Edge end1
18: 0 0 0 0 SiFive PLIC 77 Edge end1
19: 0 0 0 0 SiFive PLIC 76 Edge end1
22: 796 0 0 0 SiFive PLIC 32 Edge ttyS0
23: 0 0 0 0 SiFive PLIC 38 Edge pl022
24: 9062 0 0 0 SiFive PLIC 75 Edge dw-mci
25: 0 0 0 0 SiFive PLIC 35 Edge 10030000.i2c
26: 0 0 0 0 SiFive PLIC 37 Edge 10050000.i2c
27: 1 0 0 0 SiFive PLIC 50 Edge 12050000.i2c
28: 0 0 0 0 SiFive PLIC 51 Edge 12060000.i2c
IPI0: 118 98 88 138 Rescheduling interrupts
IPI1: 2272 1910 3758 3200 Function call interrupts
IPI2: 0 0 0 0 CPU stop interrupts
IPI3: 0 0 0 0 CPU stop (for crash dump) interrupts
IPI4: 0 0 0 0 IRQ work interrupts
IPI5: 0 0 0 0 Timer broadcast interrupts
After:
$ cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
10: 2539 2734 2295 2552 RISC-V INTC 5 Edge riscv-timer
12: 2 1 0 0 SiFive PLIC 111 Edge 17030000.power-controller
13: 643 194 368 75 SiFive PLIC 25 Edge 13010000.spi
14: 6 22 19 27 SiFive PLIC 7 Edge end0
15: 0 0 0 0 SiFive PLIC 6 Edge end0
16: 0 0 0 0 SiFive PLIC 5 Edge end0
17: 0 0 0 0 SiFive PLIC 78 Edge end1
18: 0 0 0 0 SiFive PLIC 77 Edge end1
19: 0 0 0 0 SiFive PLIC 76 Edge end1
22: 158 254 226 207 SiFive PLIC 32 Edge ttyS0
23: 0 0 0 0 SiFive PLIC 38 Edge pl022
24: 2265 2250 1452 2024 SiFive PLIC 75 Edge dw-mci
25: 0 0 0 0 SiFive PLIC 35 Edge 10030000.i2c
26: 0 0 0 0 SiFive PLIC 37 Edge 10050000.i2c
27: 0 0 0 1 SiFive PLIC 50 Edge 12050000.i2c
28: 0 0 0 0 SiFive PLIC 51 Edge 12060000.i2c
IPI0: 92 118 116 120 Rescheduling interrupts
IPI1: 4135 2653 2170 3160 Function call interrupts
IPI2: 0 0 0 0 CPU stop interrupts
IPI3: 0 0 0 0 CPU stop (for crash dump) interrupts
IPI4: 0 0 0 0 IRQ work interrupts
IPI5: 0 0 0 0 Timer broadcast interrupts
Signed-off-by: Nam Cao <namcao at linutronix.de>
Cc: Anup Patel <anup at brainfault.org>
Cc: Christoph Hellwig <hch at lst.de>
Cc: Marc Zyngier <marc.zyngier at arm.com>
---
drivers/irqchip/irq-sifive-plic.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 9e22f7e378f5..f30bdb94ceeb 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -163,20 +163,19 @@ static void plic_irq_eoi(struct irq_data *d)
static int plic_set_affinity(struct irq_data *d,
const struct cpumask *mask_val, bool force)
{
- unsigned int cpu;
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
+ struct cpumask new_mask;
- if (force)
- cpu = cpumask_first_and(&priv->lmask, mask_val);
- else
- cpu = cpumask_first_and_and(&priv->lmask, mask_val, cpu_online_mask);
+ cpumask_and(&new_mask, mask_val, &priv->lmask);
+ if (!force)
+ cpumask_and(&new_mask, &new_mask, cpu_online_mask);
- if (cpu >= nr_cpu_ids)
+ if (cpumask_empty(&new_mask))
return -EINVAL;
plic_irq_disable(d);
- irq_data_update_effective_affinity(d, cpumask_of(cpu));
+ irq_data_update_effective_affinity(d, &new_mask);
if (!irqd_irq_disabled(d))
plic_irq_enable(d);
--
2.39.2
More information about the linux-riscv
mailing list