| From 20e360f9bad105a89b3030fb1ba21b3b928b5d45 Mon Sep 17 00:00:00 2001 |
| From: Marc Zyngier <maz@kernel.org> |
| Date: Sun, 21 Jun 2020 14:43:15 +0100 |
| Subject: [PATCH] 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c |
| index e45f45e68720..50b9ca69e6a2 100644 |
| --- a/drivers/irqchip/irq-gic.c |
| +++ b/drivers/irqchip/irq-gic.c |
| @@ -321,10 +321,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); |
| @@ -334,13 +332,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); |
| irq_data_update_effective_affinity(d, cpumask_of(cpu)); |
| |
| return IRQ_SET_MASK_OK_DONE; |
| -- |
| 2.27.0 |
| |