diff options
author | Aniruddha Banerjee <aniruddhab@nvidia.com> | 2018-03-28 09:42:00 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2018-03-29 06:47:50 -0400 |
commit | aa08192a254d362a4d5317647a81de6996961aef (patch) | |
tree | 4078cc6883332ae0fda2dca708cd5ace43a4a354 | |
parent | d01d327406d9c36e066181240ac078b636871de8 (diff) |
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>
-rw-r--r-- | drivers/irqchip/irq-gic-common.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 30017df5b54c..01e673c680cd 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c | |||
@@ -21,6 +21,8 @@ | |||
21 | 21 | ||
22 | #include "irq-gic-common.h" | 22 | #include "irq-gic-common.h" |
23 | 23 | ||
24 | static DEFINE_RAW_SPINLOCK(irq_controller_lock); | ||
25 | |||
24 | static const struct gic_kvm_info *gic_kvm_info; | 26 | static const struct gic_kvm_info *gic_kvm_info; |
25 | 27 | ||
26 | const struct gic_kvm_info *gic_get_kvm_info(void) | 28 | const struct gic_kvm_info *gic_get_kvm_info(void) |
@@ -53,11 +55,13 @@ int gic_configure_irq(unsigned int irq, unsigned int type, | |||
53 | u32 confoff = (irq / 16) * 4; | 55 | u32 confoff = (irq / 16) * 4; |
54 | u32 val, oldval; | 56 | u32 val, oldval; |
55 | int ret = 0; | 57 | int ret = 0; |
58 | unsigned long flags; | ||
56 | 59 | ||
57 | /* | 60 | /* |
58 | * Read current configuration register, and insert the config | 61 | * Read current configuration register, and insert the config |
59 | * for "irq", depending on "type". | 62 | * for "irq", depending on "type". |
60 | */ | 63 | */ |
64 | raw_spin_lock_irqsave(&irq_controller_lock, flags); | ||
61 | val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); | 65 | val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); |
62 | if (type & IRQ_TYPE_LEVEL_MASK) | 66 | if (type & IRQ_TYPE_LEVEL_MASK) |
63 | val &= ~confmask; | 67 | val &= ~confmask; |
@@ -65,8 +69,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, | |||
65 | val |= confmask; | 69 | val |= confmask; |
66 | 70 | ||
67 | /* If the current configuration is the same, then we are done */ | 71 | /* If the current configuration is the same, then we are done */ |
68 | if (val == oldval) | 72 | if (val == oldval) { |
73 | raw_spin_unlock_irqrestore(&irq_controller_lock, flags); | ||
69 | return 0; | 74 | return 0; |
75 | } | ||
70 | 76 | ||
71 | /* | 77 | /* |
72 | * Write back the new configuration, and possibly re-enable | 78 | * Write back the new configuration, and possibly re-enable |
@@ -84,6 +90,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, | |||
84 | pr_warn("GIC: PPI%d is secure or misconfigured\n", | 90 | pr_warn("GIC: PPI%d is secure or misconfigured\n", |
85 | irq - 16); | 91 | irq - 16); |
86 | } | 92 | } |
93 | raw_spin_unlock_irqrestore(&irq_controller_lock, flags); | ||
87 | 94 | ||
88 | if (sync_access) | 95 | if (sync_access) |
89 | sync_access(); | 96 | sync_access(); |