diff options
author | Marc Zyngier <maz@kernel.org> | 2020-06-21 14:43:15 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-07-22 09:10:54 +0200 |
commit | c50b30f39de86f65ad95de855c155f0ea054131e (patch) | |
tree | 849513cc36deff0b3c91433ee9df13a10c0a5e25 | |
parent | 8b72b56ba1811e3db07a27cd6a01c060448f4e2f (diff) | |
download | linux-stable-c50b30f39de86f65ad95de855c155f0ea054131e.tar.gz linux-stable-c50b30f39de86f65ad95de855c155f0ea054131e.tar.bz2 linux-stable-c50b30f39de86f65ad95de855c155f0ea054131e.zip |
irqchip/gic: Atomically update affinity
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>
-rw-r--r-- | drivers/irqchip/irq-gic.c | 13 |
1 files changed, 3 insertions, 10 deletions
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index d6c404b3584d..006b17593c12 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -324,10 +324,8 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) 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_data *d, const struct cpumask *mask_val, 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; } |