Hi,Yes
On Mon, Nov 30, 2020 at 2:33 AM Maulik Shah <mkshah@xxxxxxxxxxxxxx> wrote:
Oh, oops. Somehow I thought your reply was in response to patch #3 in[1] https://lore.kernel.org/r/603c691f-3614-d87b-075a-0889e9ffc453@xxxxxxxxxxxxxxPlease wait to land [1] before i confirm with HW team if this is indeed
valid case.
the series, not #1. I responded to patch #1 in the series now to make
it clear to wait for you.
Have you tested this experimentally?@@ -187,15 +217,26 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,The phantom irq can come when switching to GPIO irq mode. so may be only
if (WARN_ON(i == g->nfuncs))
return -EINVAL;
- raw_spin_lock_irqsave(&pctrl->lock, flags);
+ disable_irq(irq);
- val = msm_readl_ctl(pctrl, g);
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ oldval = val = msm_readl_ctl(pctrl, g);
val &= ~mask;
val |= i << g->mux_bit;
msm_writel_ctl(val, pctrl, g);
-
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ /*
+ * Clear IRQs if switching to/from GPIO mode since muxing to/from
+ * the GPIO path can cause phantom edges.
+ */
+ old_i = (oldval & mask) >> g->mux_bit;
+ if (old_i != i &&
+ (i == pctrl->soc->gpio_func || old_i == pctrl->soc->gpio_func))
+ msm_pinctrl_clear_pending_irq(pctrl, group, irq);
+
check if (i == pctrl->soc->gpio_func) {
I have experimentally tested this and I can actually see an interrupt
generated when I _leave_ GPIO as well as when I enter GPIO mode. If
you can't see this I can re-setup my test, but this was one of those
things that convinced me that the _transition_ is what was causing the
fake interrupt.
I think my test CL <https://crrev.com/c/2556012/> can help you with
testing if you wish.
even better if you can clear this unconditionally.Why? It should only matter if we're going to/from GPIO mode.
Any reason why? If we didn't change anything then there's no reason@@ -456,32 +497,49 @@ static const struct pinconf_ops msm_pinconf_ops = {same as above, can you clear this unconditionally.
static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
const struct msm_pingroup *g;
+ unsigned int irq = irq_find_mapping(chip->irq.domain, offset);
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
+ u32 oldval;
u32 val;
g = &pctrl->soc->groups[offset];
+ disable_irq(irq);
+
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = msm_readl_ctl(pctrl, g);
+ oldval = val = msm_readl_ctl(pctrl, g);
val &= ~BIT(g->oe_bit);
msm_writel_ctl(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ /*
+ * Clear IRQs if switching to/from input mode since that can use
+ * a phantom edge.
+ */
+ if (oldval != val)
+ msm_pinctrl_clear_pending_irq(pctrl, offset, irq);
to go through all this extra code?
Whoa! Good catch. How did I miss that and how did it not fail? Istatic int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)should be, oldval = val = msm_readl_ctl(pctrl, g);
{
const struct msm_pingroup *g;
+ unsigned int irq = irq_find_mapping(chip->irq.domain, offset);
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
+ u32 oldval;
u32 val;
g = &pctrl->soc->groups[offset];
+ disable_irq(irq);
+
raw_spin_lock_irqsave(&pctrl->lock, flags);
val = msm_readl_io(pctrl, g);
@@ -491,12 +549,21 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
val &= ~BIT(g->out_bit);
msm_writel_io(val, pctrl, g);
- val = msm_readl_ctl(pctrl, g);
+ oldval = msm_readl_ctl(pctrl, g);
otherwise val will carry invalid value.
will fix in a v3 but will wait until other questions are resolved
before sending.
I haven't confirmed that this can glitch, however I did confirm that Ival |= BIT(g->oe_bit);i don't see a reason to clear the edges when switching to output mode.
msm_writel_ctl(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ /*
+ * Clear IRQs if switching to/from input mode since that can use
+ * a phantom edge.
+ */
+ if (oldval != val)
+ msm_pinctrl_clear_pending_irq(pctrl, offset, irq);
can you remove the changes from .direction_output callback?
could glitch when muxing _away_ from GPIO mode. This makes me believe
that I could also glitch when muxing to an output.
I can try to concoct a test for this if necessary.
Ugh, so we need a clear in yet another place. Joy. OK, I will wait@@ -792,17 +859,6 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)Above change was clearing irq in .irq_enable callback which will do
raw_spin_lock_irqsave(&pctrl->lock, flags);
- if (status_clear) {
- /*
- * clear the interrupt status bit before unmask to avoid
- * any erroneous interrupts that would have got latched
- * when the interrupt is not in use.
- */
- val = msm_readl_intr_status(pctrl, g);
- val &= ~BIT(g->intr_status_bit);
- msm_writel_intr_status(val, pctrl, g);
- }
-
clear + unmask from irq_startup() at the very end.
With your change, The problem is we have cleared the phantom irq much
earlier in __setup_irq() phase and in below case its still latched as
pending.
1. The client driver calls request_irq() => __setup_irq()
2. __setup_irq() then first invokes irq_request_resources() =>
msm_gpio_irq_reqres() => msm_pinmux_set_mux() =>
msm_pinctrl_clear_pending_irq()
3. __setup_irq() goes ahead and invokes __irq_set_trigger() =>
msm_gpio_irq_set_type()
4. __setup_irq() then invokes irq_startup() => gpiochip_irq_enable() =>
msm_gpio_irq_enable()
The phantom irq gets cleared in step (2) here, but with step (3) it gets
latched again and at the end of step (4) still get phantom irq.
This seems because as per below comment in driver, pasting the part
which has info,
/*
* The edge detection logic seems to have a problem where toggling the
RAW_STATUS_EN bit may
* cause the status bit to latch spuriously when there isn't any edge
*/
In step (3) msm_gpio_irq_set_type() touches the RAW_STATUS_EN making the
phantom irq pending again.
To resolve this, you will need to invoke msm_pinctrl_clear_pending_irq()
at the end of the msm_gpio_irq_set_type().
I would like Rajendra's (already in cc) review as well on above part.
for Rajendra's comment but I can add similar code in
msm_gpio_irq_enable().
Right. I'll fix it when I send the v3. Thanks!val = msm_readl_intr_cfg(pctrl, g);Still need the above if condition, the previous call
val |= BIT(g->intr_raw_status_bit);
val |= BIT(g->intr_enable_bit);
@@ -815,14 +871,10 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
static void msm_gpio_irq_enable(struct irq_data *d)
{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
-
if (d->parent_data)
irq_chip_enable_parent(d);
- if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
- msm_gpio_irq_clear_unmask(d, true);
+ msm_gpio_irq_unmask(d);
irq_chip_enable_parent() already enabled the IRQ at PDC and GIC, so only
go ahead to enable it at TLMM if there wasn't any parent.
if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
msm_gpio_irq_unmask(d);
-Doug