Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/gic: Take lock when updating irq type

Most MMIO GIC register accesses use a 1-hot bit scheme that
avoids requiring any form of locking. This isn't true for the
GICD_ICFGRn registers, which require a RMW sequence.

Unfortunately, we seem to be missing a lock for these particular
accesses, which could result in a race condition if changing the
trigger type on any two interrupts within the same set of 16
interrupts (and thus controlled by the same CFGR register).

Introduce a private lock in the GIC common comde for this
particular case, making it cover both GIC implementations
in one go.

Cc: stable@vger.kernel.org
Signed-off-by: Aniruddha Banerjee <aniruddhab@nvidia.com>
[maz: updated changelog]
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Aniruddha Banerjee and committed by
Marc Zyngier
aa08192a d01d3274

+8 -1
+8 -1
drivers/irqchip/irq-gic-common.c
··· 21 21 22 22 #include "irq-gic-common.h" 23 23 24 + static DEFINE_RAW_SPINLOCK(irq_controller_lock); 25 + 24 26 static const struct gic_kvm_info *gic_kvm_info; 25 27 26 28 const struct gic_kvm_info *gic_get_kvm_info(void) ··· 55 53 u32 confoff = (irq / 16) * 4; 56 54 u32 val, oldval; 57 55 int ret = 0; 56 + unsigned long flags; 58 57 59 58 /* 60 59 * Read current configuration register, and insert the config 61 60 * for "irq", depending on "type". 62 61 */ 62 + raw_spin_lock_irqsave(&irq_controller_lock, flags); 63 63 val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); 64 64 if (type & IRQ_TYPE_LEVEL_MASK) 65 65 val &= ~confmask; ··· 69 65 val |= confmask; 70 66 71 67 /* If the current configuration is the same, then we are done */ 72 - if (val == oldval) 68 + if (val == oldval) { 69 + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); 73 70 return 0; 71 + } 74 72 75 73 /* 76 74 * Write back the new configuration, and possibly re-enable ··· 90 84 pr_warn("GIC: PPI%d is secure or misconfigured\n", 91 85 irq - 16); 92 86 } 87 + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); 93 88 94 89 if (sync_access) 95 90 sync_access();