aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-11-09 09:17:59 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2017-11-10 04:49:48 -0500
commit4f8413a3a799c958f7a10a6310a451e6b8aef5ad (patch)
treeafefcfa5b445e3cbd33d7511c603c5e6c02cf000
parent666740fde412567aa0a8ea251ffee3004a6fa3a6 (diff)
genirq: Track whether the trigger type has been set
When requesting a shared interrupt, we assume that the firmware support code (DT or ACPI) has called irqd_set_trigger_type already, so that we can retrieve it and check that the requester is being reasonnable. Unfortunately, we still have non-DT, non-ACPI systems around, and these guys won't call irqd_set_trigger_type before requesting the interrupt. The consequence is that we fail the request that would have worked before. We can either chase all these use cases (boring), or address it in core code (easier). Let's have a per-irq_desc flag that indicates whether irqd_set_trigger_type has been called, and let's just check it when checking for a shared interrupt. If it hasn't been set, just take whatever the interrupt requester asks. Fixes: 382bd4de6182 ("genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs") Cc: stable@vger.kernel.org Reported-and-tested-by: Petr Cvek <petrcvekcz@gmail.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--include/linux/irq.h11
-rw-r--r--kernel/irq/manage.c13
2 files changed, 22 insertions, 2 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h
index fda8da7c45e7..73f61eeb152e 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -210,6 +210,7 @@ struct irq_data {
210 * IRQD_MANAGED_SHUTDOWN - Interrupt was shutdown due to empty affinity 210 * IRQD_MANAGED_SHUTDOWN - Interrupt was shutdown due to empty affinity
211 * mask. Applies only to affinity managed irqs. 211 * mask. Applies only to affinity managed irqs.
212 * IRQD_SINGLE_TARGET - IRQ allows only a single affinity target 212 * IRQD_SINGLE_TARGET - IRQ allows only a single affinity target
213 * IRQD_DEFAULT_TRIGGER_SET - Expected trigger already been set
213 */ 214 */
214enum { 215enum {
215 IRQD_TRIGGER_MASK = 0xf, 216 IRQD_TRIGGER_MASK = 0xf,
@@ -230,6 +231,7 @@ enum {
230 IRQD_IRQ_STARTED = (1 << 22), 231 IRQD_IRQ_STARTED = (1 << 22),
231 IRQD_MANAGED_SHUTDOWN = (1 << 23), 232 IRQD_MANAGED_SHUTDOWN = (1 << 23),
232 IRQD_SINGLE_TARGET = (1 << 24), 233 IRQD_SINGLE_TARGET = (1 << 24),
234 IRQD_DEFAULT_TRIGGER_SET = (1 << 25),
233}; 235};
234 236
235#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors) 237#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -259,18 +261,25 @@ static inline void irqd_mark_affinity_was_set(struct irq_data *d)
259 __irqd_to_state(d) |= IRQD_AFFINITY_SET; 261 __irqd_to_state(d) |= IRQD_AFFINITY_SET;
260} 262}
261 263
264static inline bool irqd_trigger_type_was_set(struct irq_data *d)
265{
266 return __irqd_to_state(d) & IRQD_DEFAULT_TRIGGER_SET;
267}
268
262static inline u32 irqd_get_trigger_type(struct irq_data *d) 269static inline u32 irqd_get_trigger_type(struct irq_data *d)
263{ 270{
264 return __irqd_to_state(d) & IRQD_TRIGGER_MASK; 271 return __irqd_to_state(d) & IRQD_TRIGGER_MASK;
265} 272}
266 273
267/* 274/*
268 * Must only be called inside irq_chip.irq_set_type() functions. 275 * Must only be called inside irq_chip.irq_set_type() functions or
276 * from the DT/ACPI setup code.
269 */ 277 */
270static inline void irqd_set_trigger_type(struct irq_data *d, u32 type) 278static inline void irqd_set_trigger_type(struct irq_data *d, u32 type)
271{ 279{
272 __irqd_to_state(d) &= ~IRQD_TRIGGER_MASK; 280 __irqd_to_state(d) &= ~IRQD_TRIGGER_MASK;
273 __irqd_to_state(d) |= type & IRQD_TRIGGER_MASK; 281 __irqd_to_state(d) |= type & IRQD_TRIGGER_MASK;
282 __irqd_to_state(d) |= IRQD_DEFAULT_TRIGGER_SET;
274} 283}
275 284
276static inline bool irqd_is_level_type(struct irq_data *d) 285static inline bool irqd_is_level_type(struct irq_data *d)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index e667912d0e9c..21e04e780be4 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1228,7 +1228,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
1228 * set the trigger type must match. Also all must 1228 * set the trigger type must match. Also all must
1229 * agree on ONESHOT. 1229 * agree on ONESHOT.
1230 */ 1230 */
1231 unsigned int oldtype = irqd_get_trigger_type(&desc->irq_data); 1231 unsigned int oldtype;
1232
1233 /*
1234 * If nobody did set the configuration before, inherit
1235 * the one provided by the requester.
1236 */
1237 if (irqd_trigger_type_was_set(&desc->irq_data)) {
1238 oldtype = irqd_get_trigger_type(&desc->irq_data);
1239 } else {
1240 oldtype = new->flags & IRQF_TRIGGER_MASK;
1241 irqd_set_trigger_type(&desc->irq_data, oldtype);
1242 }
1232 1243
1233 if (!((old->flags & new->flags) & IRQF_SHARED) || 1244 if (!((old->flags & new->flags) & IRQF_SHARED) ||
1234 (oldtype != (new->flags & IRQF_TRIGGER_MASK)) || 1245 (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||