| From 325aa19598e410672175ed50982f902d4e3f31c5 Mon Sep 17 00:00:00 2001 |
| From: Stephen Boyd <swboyd@chromium.org> |
| Date: Mon, 25 Mar 2019 11:10:26 -0700 |
| Subject: genirq: Respect IRQCHIP_SKIP_SET_WAKE in irq_chip_set_wake_parent() |
| |
| From: Stephen Boyd <swboyd@chromium.org> |
| |
| commit 325aa19598e410672175ed50982f902d4e3f31c5 upstream. |
| |
| If a child irqchip calls irq_chip_set_wake_parent() but its parent irqchip |
| has the IRQCHIP_SKIP_SET_WAKE flag set an error is returned. |
| |
| This is inconsistent behaviour vs. set_irq_wake_real() which returns 0 when |
| the irqchip has the IRQCHIP_SKIP_SET_WAKE flag set. It doesn't attempt to |
| walk the chain of parents and set irq wake on any chips that don't have the |
| flag set either. If the intent is to call the .irq_set_wake() callback of |
| the parent irqchip, then we expect irqchip implementations to omit the |
| IRQCHIP_SKIP_SET_WAKE flag and implement an .irq_set_wake() function that |
| calls irq_chip_set_wake_parent(). |
| |
| The problem has been observed on a Qualcomm sdm845 device where set wake |
| fails on any GPIO interrupts after applying work in progress wakeup irq |
| patches to the GPIO driver. The chain of chips looks like this: |
| |
| QCOM GPIO -> QCOM PDC (SKIP) -> ARM GIC (SKIP) |
| |
| The GPIO controllers parent is the QCOM PDC irqchip which in turn has ARM |
| GIC as parent. The QCOM PDC irqchip has the IRQCHIP_SKIP_SET_WAKE flag |
| set, and so does the grandparent ARM GIC. |
| |
| The GPIO driver doesn't know if the parent needs to set wake or not, so it |
| unconditionally calls irq_chip_set_wake_parent() causing this function to |
| return a failure because the parent irqchip (PDC) doesn't have the |
| .irq_set_wake() callback set. Returning 0 instead makes everything work and |
| irqs from the GPIO controller can be configured for wakeup. |
| |
| Make it consistent by returning 0 (success) from irq_chip_set_wake_parent() |
| when a parent chip has IRQCHIP_SKIP_SET_WAKE set. |
| |
| [ tglx: Massaged changelog ] |
| |
| Fixes: 08b55e2a9208e ("genirq: Add irqchip_set_wake_parent") |
| Signed-off-by: Stephen Boyd <swboyd@chromium.org> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Acked-by: Marc Zyngier <marc.zyngier@arm.com> |
| Cc: linux-arm-kernel@lists.infradead.org |
| Cc: linux-gpio@vger.kernel.org |
| Cc: Lina Iyer <ilina@codeaurora.org> |
| Cc: stable@vger.kernel.org |
| Link: https://lkml.kernel.org/r/20190325181026.247796-1-swboyd@chromium.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/irq/chip.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/kernel/irq/chip.c |
| +++ b/kernel/irq/chip.c |
| @@ -1384,6 +1384,10 @@ int irq_chip_set_vcpu_affinity_parent(st |
| int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on) |
| { |
| data = data->parent_data; |
| + |
| + if (data->chip->flags & IRQCHIP_SKIP_SET_WAKE) |
| + return 0; |
| + |
| if (data->chip->irq_set_wake) |
| return data->chip->irq_set_wake(data, on); |
| |