Message ID | 20201209163818.v3.1.I2702919afc253e2a451bebc3b701b462b2d22344@changeid |
---|---|
State | New |
Headers | show |
Series | [v3,1/3] irqchip: qcom-pdc: Fix phantom irq when changing between rising/falling | expand |
Quoting Douglas Anderson (2020-12-09 16:41:01) > We have a problem if we use gpio-keys and configure wakeups such that > we only want one edge to wake us up. AKA: > wakeup-event-action = <EV_ACT_DEASSERTED>; > wakeup-source; > > Specifically we end up with a phantom interrupt that blocks suspend if > the line was already high and we want wakeups on rising edges (AKA we > want the GPIO to go low and then high again before we wake up). The > opposite is also problematic. > > Specifically, here's what's happening today: > 1. Normally, gpio-keys configures to look for both edges. Due to the > current workaround introduced in commit c3c0c2e18d94 ("pinctrl: > qcom: Handle broken/missing PDC dual edge IRQs on sc7180"), if the > line was high we'd configure for falling edges. > 2. At suspend time, we change to look for rising edges. > 3. After qcom_pdc_gic_set_type() runs, we get a phantom interrupt. > > We can solve this by just clearing the phantom interrupt. > > NOTE: it is possible that this could cause problems for a client with > very specific needs, but there's not much we can do with this > hardware. As an example, let's say the interrupt signal is currently > high and the client is looking for falling edges. The client now > changes to look for rising edges. The client could possibly expect > that if the line has a short pulse low (and back high) that it would > always be detected. Specifically no matter when the pulse happened, > it should either have tripped the (old) falling edge trigger or the > (new) rising edge trigger. We will simply not trip it. We could > narrow down the race a bit by polling our parent before changing > types, but no matter what we do there will still be a period of time > where we can't tell the difference between a real transition (or more > than one transition) and the phantom. > > Fixes: f55c73aef890 ("irqchip/pdc: Add PDC interrupt controller for QCOM SoCs") > Signed-off-by: Douglas Anderson <dianders@chromium.org> > Reviewed-by: Maulik Shah <mkshah@codeaurora.org> > Tested-by: Maulik Shah <mkshah@codeaurora.org> > --- Reviewed-by: Stephen Boyd <swboyd@chromium.org>
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index bd39e9de6ecf..5dc63c20b67e 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -159,6 +159,8 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) { int pin_out = d->hwirq; enum pdc_irq_config_bits pdc_type; + enum pdc_irq_config_bits old_pdc_type; + int ret; if (pin_out == GPIO_NO_WAKE_IRQ) return 0; @@ -187,9 +189,26 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } + old_pdc_type = pdc_reg_read(IRQ_i_CFG, pin_out); pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type); - return irq_chip_set_type_parent(d, type); + ret = irq_chip_set_type_parent(d, type); + if (ret) + return ret; + + /* + * When we change types the PDC can give a phantom interrupt. + * Clear it. Specifically the phantom shows up when reconfiguring + * polarity of interrupt without changing the state of the signal + * but let's be consistent and clear it always. + * + * Doing this works because we have IRQCHIP_SET_TYPE_MASKED so the + * interrupt will be cleared before the rest of the system sees it. + */ + if (old_pdc_type != pdc_type) + irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false); + + return 0; } static struct irq_chip qcom_pdc_gic_chip = {