| From 005c34ae4b44f085120d7f371121ec7ded677761 Mon Sep 17 00:00:00 2001 |
| From: Marc Zyngier <maz@kernel.org> |
| Date: Sun, 21 Jun 2020 14:43:15 +0100 |
| Subject: irqchip/gic: Atomically update affinity |
| |
| From: Marc Zyngier <maz@kernel.org> |
| |
| commit 005c34ae4b44f085120d7f371121ec7ded677761 upstream. |
| |
| The GIC driver uses a RMW sequence to update the affinity, and |
| relies on the gic_lock_irqsave/gic_unlock_irqrestore sequences |
| to update it atomically. |
| |
| But these sequences only expand into anything meaningful if |
| the BL_SWITCHER option is selected, which almost never happens. |
| |
| It also turns out that using a RMW and locks is just as silly, |
| as the GIC distributor supports byte accesses for the GICD_TARGETRn |
| registers, which when used make the update atomic by definition. |
| |
| Drop the terminally broken code and replace it by a byte write. |
| |
| Fixes: 04c8b0f82c7d ("irqchip/gic: Make locking a BL_SWITCHER only feature") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Marc Zyngier <maz@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| |
| --- |
| drivers/irqchip/irq-gic.c | 13 +++---------- |
| 1 file changed, 3 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/irqchip/irq-gic.c |
| +++ b/drivers/irqchip/irq-gic.c |
| @@ -324,10 +324,8 @@ static int gic_irq_set_vcpu_affinity(str |
| static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, |
| bool force) |
| { |
| - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); |
| - unsigned int cpu, shift = (gic_irq(d) % 4) * 8; |
| - u32 val, mask, bit; |
| - unsigned long flags; |
| + void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d); |
| + unsigned int cpu; |
| |
| if (!force) |
| cpu = cpumask_any_and(mask_val, cpu_online_mask); |
| @@ -337,12 +335,7 @@ static int gic_set_affinity(struct irq_d |
| if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) |
| return -EINVAL; |
| |
| - gic_lock_irqsave(flags); |
| - mask = 0xff << shift; |
| - bit = gic_cpu_map[cpu] << shift; |
| - val = readl_relaxed(reg) & ~mask; |
| - writel_relaxed(val | bit, reg); |
| - gic_unlock_irqrestore(flags); |
| + writeb_relaxed(gic_cpu_map[cpu], reg); |
| |
| return IRQ_SET_MASK_OK_DONE; |
| } |