[PATCH] irqchip/sifive-plic: Fix plic_set_affinity() only enables 1 cpu

Anup Patel anup at brainfault.org
Wed Jul 3 04:58:23 PDT 2024


On Wed, Jul 3, 2024 at 12:57 PM Nam Cao <namcao at linutronix.de> wrote:
>
> 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).

Well, you are assuming that multiple CPUs are always idle or available
to process interrupts. In other words, if the system is loaded running
some workload on each CPU then performance on multiple CPUs
will degrade since multiple CPUs will wastefully try to claim interrupt.

In reality, we can't make such assumptions and it is better to target a
particular CPU for processing interrupts (just like various other interrupt
controllers). For balancing interrupt processing load, we have software
irq balancers running in user-space (or kernel space) which do a
reasonably fine job of picking appropriate CPU for interrupt processing.

> 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.

Randomly attempting to take an interrupt on multiple CPUs affects the
workload running all such CPUs (see above comment).

It's better to have a more predictable and targeted interrupt affinity
so that software irq balancers work effectively.

>
> Rewrite plic_set_affinity() to enable interrupt for all possible CPUs in
> the mask.

At least from my side, it is a NO to this approach.

Regards,
Anup

>
> 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