summaryrefslogtreecommitdiff
path: root/kernel/irq
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-11-09 14:17:59 +0000
committerMarc Zyngier <marc.zyngier@arm.com>2017-11-10 09:49:48 +0000
commit4f8413a3a799c958f7a10a6310a451e6b8aef5ad (patch)
treeafefcfa5b445e3cbd33d7511c603c5e6c02cf000 /kernel/irq
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>
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/manage.c13
1 files changed, 12 insertions, 1 deletions
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)
* set the trigger type must match. Also all must
* agree on ONESHOT.
*/
- unsigned int oldtype = irqd_get_trigger_type(&desc->irq_data);
+ unsigned int oldtype;
+
+ /*
+ * If nobody did set the configuration before, inherit
+ * the one provided by the requester.
+ */
+ if (irqd_trigger_type_was_set(&desc->irq_data)) {
+ oldtype = irqd_get_trigger_type(&desc->irq_data);
+ } else {
+ oldtype = new->flags & IRQF_TRIGGER_MASK;
+ irqd_set_trigger_type(&desc->irq_data, oldtype);
+ }
if (!((old->flags & new->flags) & IRQF_SHARED) ||
(oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||