]>
Commit | Line | Data |
---|---|---|
1dabdb6f GKH |
1 | From 325aa19598e410672175ed50982f902d4e3f31c5 Mon Sep 17 00:00:00 2001 |
2 | From: Stephen Boyd <swboyd@chromium.org> | |
3 | Date: Mon, 25 Mar 2019 11:10:26 -0700 | |
4 | Subject: genirq: Respect IRQCHIP_SKIP_SET_WAKE in irq_chip_set_wake_parent() | |
5 | ||
6 | From: Stephen Boyd <swboyd@chromium.org> | |
7 | ||
8 | commit 325aa19598e410672175ed50982f902d4e3f31c5 upstream. | |
9 | ||
10 | If a child irqchip calls irq_chip_set_wake_parent() but its parent irqchip | |
11 | has the IRQCHIP_SKIP_SET_WAKE flag set an error is returned. | |
12 | ||
13 | This is inconsistent behaviour vs. set_irq_wake_real() which returns 0 when | |
14 | the irqchip has the IRQCHIP_SKIP_SET_WAKE flag set. It doesn't attempt to | |
15 | walk the chain of parents and set irq wake on any chips that don't have the | |
16 | flag set either. If the intent is to call the .irq_set_wake() callback of | |
17 | the parent irqchip, then we expect irqchip implementations to omit the | |
18 | IRQCHIP_SKIP_SET_WAKE flag and implement an .irq_set_wake() function that | |
19 | calls irq_chip_set_wake_parent(). | |
20 | ||
21 | The problem has been observed on a Qualcomm sdm845 device where set wake | |
22 | fails on any GPIO interrupts after applying work in progress wakeup irq | |
23 | patches to the GPIO driver. The chain of chips looks like this: | |
24 | ||
25 | QCOM GPIO -> QCOM PDC (SKIP) -> ARM GIC (SKIP) | |
26 | ||
27 | The GPIO controllers parent is the QCOM PDC irqchip which in turn has ARM | |
28 | GIC as parent. The QCOM PDC irqchip has the IRQCHIP_SKIP_SET_WAKE flag | |
29 | set, and so does the grandparent ARM GIC. | |
30 | ||
31 | The GPIO driver doesn't know if the parent needs to set wake or not, so it | |
32 | unconditionally calls irq_chip_set_wake_parent() causing this function to | |
33 | return a failure because the parent irqchip (PDC) doesn't have the | |
34 | .irq_set_wake() callback set. Returning 0 instead makes everything work and | |
35 | irqs from the GPIO controller can be configured for wakeup. | |
36 | ||
37 | Make it consistent by returning 0 (success) from irq_chip_set_wake_parent() | |
38 | when a parent chip has IRQCHIP_SKIP_SET_WAKE set. | |
39 | ||
40 | [ tglx: Massaged changelog ] | |
41 | ||
42 | Fixes: 08b55e2a9208e ("genirq: Add irqchip_set_wake_parent") | |
43 | Signed-off-by: Stephen Boyd <swboyd@chromium.org> | |
44 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
45 | Acked-by: Marc Zyngier <marc.zyngier@arm.com> | |
46 | Cc: linux-arm-kernel@lists.infradead.org | |
47 | Cc: linux-gpio@vger.kernel.org | |
48 | Cc: Lina Iyer <ilina@codeaurora.org> | |
49 | Cc: stable@vger.kernel.org | |
50 | Link: https://lkml.kernel.org/r/20190325181026.247796-1-swboyd@chromium.org | |
51 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
52 | ||
53 | --- | |
54 | kernel/irq/chip.c | 4 ++++ | |
55 | 1 file changed, 4 insertions(+) | |
56 | ||
57 | --- a/kernel/irq/chip.c | |
58 | +++ b/kernel/irq/chip.c | |
59 | @@ -1384,6 +1384,10 @@ int irq_chip_set_vcpu_affinity_parent(st | |
60 | int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on) | |
61 | { | |
62 | data = data->parent_data; | |
63 | + | |
64 | + if (data->chip->flags & IRQCHIP_SKIP_SET_WAKE) | |
65 | + return 0; | |
66 | + | |
67 | if (data->chip->irq_set_wake) | |
68 | return data->chip->irq_set_wake(data, on); | |
69 |