summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2017-04-15 12:08:31 +0200
committerThomas Gleixner <tglx@linutronix.de>2017-04-15 15:42:43 +0200
commit382bd4de61827dbaaf5fb4fb7b1f4be4a86505e7 (patch)
treec009717481f1691701c7b970e8d3cbfd9f67a139 /kernel
parentd1b25279c1a3fe99a14b3afc6d590e218f854b10 (diff)
downloadlinux-382bd4de61827dbaaf5fb4fb7b1f4be4a86505e7.tar.bz2
genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs
When requesting a shared irq with IRQF_TRIGGER_NONE then the irqaction flags get filled with the trigger type from the irq_data: if (!(new->flags & IRQF_TRIGGER_MASK)) new->flags |= irqd_get_trigger_type(&desc->irq_data); On the first setup_irq() the trigger type in irq_data is NONE when the above code executes, then the irq is started up for the first time and then the actual trigger type gets established, but that's too late to fix up new->flags. When then a second user of the irq requests the irq with IRQF_TRIGGER_NONE its irqaction's triggertype gets set to the actual trigger type and the following check fails: if (!((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) Resulting in the request_irq failing with -EBUSY even though both users requested the irq with IRQF_SHARED | IRQF_TRIGGER_NONE Fix this by comparing the new irqaction's trigger type to the trigger type stored in the irq_data which correctly reflects the actual trigger type being used for the irq. Suggested-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Link: http://lkml.kernel.org/r/20170415100831.17073-1-hdegoede@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/manage.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 155e3c3357a1..ae1c90f20381 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1212,8 +1212,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
* set the trigger type must match. Also all must
* agree on ONESHOT.
*/
+ unsigned int oldtype = irqd_get_trigger_type(&desc->irq_data);
+
if (!((old->flags & new->flags) & IRQF_SHARED) ||
- ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) ||
+ (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||
((old->flags ^ new->flags) & IRQF_ONESHOT))
goto mismatch;