diff mbox

[2/3] pinctrl:Intel: clear interrupt status for every IRQ setup

Message ID 1457715962-108484-2-git-send-email-qipeng.zha@intel.com
State New
Headers show

Commit Message

qipeng.zha March 11, 2016, 5:06 p.m. UTC
There is one unexpected GPIO interrupt coming in below scenario.
1. GPIO X is going to be used as falling edge interrupt.
2. Before request_irq call, this GPIO X interrupt was masked.
3. But the IRQ mode may be set for some mode in default (by BIOS).
4. Toggle GPIO X from high to low.
5. The GPIO X interrupt status will be set even if it was masked.
6. Register the interrupt for GPIO X, the interrupt will be unmasked.
7. Even if no change on GPIO X afterwards, but one GPIO X interrupt
will be triggered because the interrupt status was set.

To avoid above issue, the interrupt status need clear before request_irq.

Signed-off-by: Qi Zheng <qi.zheng@intel.com>
Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
---
 drivers/pinctrl/intel/pinctrl-intel.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Mika Westerberg March 11, 2016, 9:45 a.m. UTC | #1
On Sat, Mar 12, 2016 at 01:06:01AM +0800, Qipeng Zha wrote:
> There is one unexpected GPIO interrupt coming in below scenario.
> 1. GPIO X is going to be used as falling edge interrupt.
> 2. Before request_irq call, this GPIO X interrupt was masked.
> 3. But the IRQ mode may be set for some mode in default (by BIOS).
> 4. Toggle GPIO X from high to low.
> 5. The GPIO X interrupt status will be set even if it was masked.
> 6. Register the interrupt for GPIO X, the interrupt will be unmasked.
> 7. Even if no change on GPIO X afterwards, but one GPIO X interrupt
> will be triggered because the interrupt status was set.
> 
> To avoid above issue, the interrupt status need clear before request_irq.
> 
> Signed-off-by: Qi Zheng <qi.zheng@intel.com>
> Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
> ---
>  drivers/pinctrl/intel/pinctrl-intel.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
> index ded5378..d6fe659 100644
> --- a/drivers/pinctrl/intel/pinctrl-intel.c
> +++ b/drivers/pinctrl/intel/pinctrl-intel.c
> @@ -773,6 +773,8 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
>  		return -EPERM;
>  	}
>  
> +	intel_gpio_irq_ack(d);

If the pin toggles right here, we still have the same issue, no?

We should check in the interrupt handler whether the interrupt is
actually enabled which I think we do already. Maybe that code has bug
somewhere?

> +
>  	spin_lock_irqsave(&pctrl->lock, flags);
>  
>  	value = readl(reg);
> -- 
> 1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zheng, Qi March 14, 2016, 1:24 a.m. UTC | #2
On Sat, Mar 12, 2016 at 01:06:01AM +0800, Qipeng Zha wrote:
> There is one unexpected GPIO interrupt coming in below scenario.
> 1. GPIO X is going to be used as falling edge interrupt.
> 2. Before request_irq call, this GPIO X interrupt was masked.
> 3. But the IRQ mode may be set for some mode in default (by BIOS).
> 4. Toggle GPIO X from high to low.
> 5. The GPIO X interrupt status will be set even if it was masked.
> 6. Register the interrupt for GPIO X, the interrupt will be unmasked.
> 7. Even if no change on GPIO X afterwards, but one GPIO X interrupt 
> will be triggered because the interrupt status was set.
> 
> To avoid above issue, the interrupt status need clear before request_irq.
> 
> Signed-off-by: Qi Zheng <qi.zheng@intel.com>
> Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
> ---
>  drivers/pinctrl/intel/pinctrl-intel.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/pinctrl/intel/pinctrl-intel.c 
> b/drivers/pinctrl/intel/pinctrl-intel.c
> index ded5378..d6fe659 100644
> --- a/drivers/pinctrl/intel/pinctrl-intel.c
> +++ b/drivers/pinctrl/intel/pinctrl-intel.c
> @@ -773,6 +773,8 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
>  		return -EPERM;
>  	}
>  
> +	intel_gpio_irq_ack(d);

> If the pin toggles right here, we still have the same issue, no?

Yes. But it is very short time from here to the place IRQ got enabled.
To me, it is the only available platform dependent interface to do the "ACK" in the flow of request_irq.
Maybe you have other better option here?

> We should check in the interrupt handler whether the interrupt is actually enabled which I think we do already. Maybe that code has bug somewhere?

The check in the interrupt handler can't distinguish if the interrupt status was set before or after the request_irq.
On the Broxton RVP, one unexpected GPIO interrupt was captured during our GPIO unit test program.
This issue can be fixed by this patch.

> +
>  	spin_lock_irqsave(&pctrl->lock, flags);
>  
>  	value = readl(reg);
> --
> 1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg March 14, 2016, 8:44 a.m. UTC | #3
On Mon, Mar 14, 2016 at 03:24:06AM +0200, Zheng, Qi wrote:
> 
> On Sat, Mar 12, 2016 at 01:06:01AM +0800, Qipeng Zha wrote:
> > There is one unexpected GPIO interrupt coming in below scenario.
> > 1. GPIO X is going to be used as falling edge interrupt.
> > 2. Before request_irq call, this GPIO X interrupt was masked.
> > 3. But the IRQ mode may be set for some mode in default (by BIOS).
> > 4. Toggle GPIO X from high to low.
> > 5. The GPIO X interrupt status will be set even if it was masked.
> > 6. Register the interrupt for GPIO X, the interrupt will be unmasked.
> > 7. Even if no change on GPIO X afterwards, but one GPIO X interrupt 
> > will be triggered because the interrupt status was set.
> > 
> > To avoid above issue, the interrupt status need clear before request_irq.
> > 
> > Signed-off-by: Qi Zheng <qi.zheng@intel.com>
> > Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
> > ---
> >  drivers/pinctrl/intel/pinctrl-intel.c | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/drivers/pinctrl/intel/pinctrl-intel.c 
> > b/drivers/pinctrl/intel/pinctrl-intel.c
> > index ded5378..d6fe659 100644
> > --- a/drivers/pinctrl/intel/pinctrl-intel.c
> > +++ b/drivers/pinctrl/intel/pinctrl-intel.c
> > @@ -773,6 +773,8 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
> >  		return -EPERM;
> >  	}
> >  
> > +	intel_gpio_irq_ack(d);
> 
> > If the pin toggles right here, we still have the same issue, no?
> 
> Yes. But it is very short time from here to the place IRQ got enabled.

That is still a race.

> To me, it is the only available platform dependent interface to do the "ACK" in the flow of request_irq.
> Maybe you have other better option here?
> 
> > We should check in the interrupt handler whether the interrupt is actually enabled which I think we do already. Maybe that code has bug somewhere?
> 
> The check in the interrupt handler can't distinguish if the interrupt status was set before or after the request_irq.
> On the Broxton RVP, one unexpected GPIO interrupt was captured during our GPIO unit test program.
> This issue can be fixed by this patch.

Drivers need to deal with the fact that they might get spurious
interrupts from time to time. You need to check in the interrupt handler
if the interrupt was from the device you are driving or not.

request_irq() enables the interrupt line and if the pin is already in
a state that triggers an interrupt, the driver interrupt handler will
be called.
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zheng, Qi March 14, 2016, 9:02 a.m. UTC | #4
On Mon, Mar 14, 2016 at 03:24:06AM +0200, Zheng, Qi wrote:
> 
> On Sat, Mar 12, 2016 at 01:06:01AM +0800, Qipeng Zha wrote:
> > There is one unexpected GPIO interrupt coming in below scenario.
> > 1. GPIO X is going to be used as falling edge interrupt.
> > 2. Before request_irq call, this GPIO X interrupt was masked.
> > 3. But the IRQ mode may be set for some mode in default (by BIOS).
> > 4. Toggle GPIO X from high to low.
> > 5. The GPIO X interrupt status will be set even if it was masked.
> > 6. Register the interrupt for GPIO X, the interrupt will be unmasked.
> > 7. Even if no change on GPIO X afterwards, but one GPIO X interrupt 
> > will be triggered because the interrupt status was set.
> > 
> > To avoid above issue, the interrupt status need clear before request_irq.
> > 
> > Signed-off-by: Qi Zheng <qi.zheng@intel.com>
> > Signed-off-by: Qipeng Zha <qipeng.zha@intel.com>
> > ---
> >  drivers/pinctrl/intel/pinctrl-intel.c | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/drivers/pinctrl/intel/pinctrl-intel.c
> > b/drivers/pinctrl/intel/pinctrl-intel.c
> > index ded5378..d6fe659 100644
> > --- a/drivers/pinctrl/intel/pinctrl-intel.c
> > +++ b/drivers/pinctrl/intel/pinctrl-intel.c
> > @@ -773,6 +773,8 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
> >  		return -EPERM;
> >  	}
> >  
> > +	intel_gpio_irq_ack(d);
> 
> > If the pin toggles right here, we still have the same issue, no?
> 
> Yes. But it is very short time from here to the place IRQ got enabled.

>That is still a race.

> To me, it is the only available platform dependent interface to do the "ACK" in the flow of request_irq.
> Maybe you have other better option here?
> 
> > We should check in the interrupt handler whether the interrupt is actually enabled which I think we do already. Maybe that code has bug somewhere?
> 
> The check in the interrupt handler can't distinguish if the interrupt status was set before or after the request_irq.
> On the Broxton RVP, one unexpected GPIO interrupt was captured during our GPIO unit test program.
> This issue can be fixed by this patch.

> Drivers need to deal with the fact that they might get spurious interrupts from time to time. You need to check in the interrupt handler if the interrupt was from the device you are driving or not.

> request_irq() enables the interrupt line and if the pin is already in a state that triggers an interrupt, the driver interrupt handler will be called.

I agree with you that the driver need deal with spurious interrupts, but it is expected that the GPIO driver eliminate this spurious interrupts as well which the patch can help.
And IMHO, adding ACK in the irq_set_type makes sense since a clean interrupt status is expected behavior before enabling the interrupt.


--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg March 14, 2016, 9:20 a.m. UTC | #5
On Mon, Mar 14, 2016 at 11:02:04AM +0200, Zheng, Qi wrote:
> I agree with you that the driver need deal with spurious interrupts,
> but it is expected that the GPIO driver eliminate this spurious
> interrupts as well which the patch can help.  And IMHO, adding ACK in
> the irq_set_type makes sense since a clean interrupt status is
> expected behavior before enabling the interrupt.

But it does not solve anything if the pin status changes right after you
call ack.
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij March 14, 2016, 12:40 p.m. UTC | #6
On Mon, Mar 14, 2016 at 9:44 AM, Westerberg, Mika
<mika.westerberg@intel.com> wrote:
> On Mon, Mar 14, 2016 at 03:24:06AM +0200, Zheng, Qi wrote:

>> > +   intel_gpio_irq_ack(d);
>>
>> > If the pin toggles right here, we still have the same issue, no?
>>
>> Yes. But it is very short time from here to the place IRQ got enabled.
>
> That is still a race.
>
>> To me, it is the only available platform dependent interface to do
> the "ACK" in the flow of request_irq. Maybe you have other better
> option here?
(...)
> Drivers need to deal with the fact that they might get spurious
> interrupts from time to time. You need to check in the interrupt handler
> if the interrupt was from the device you are driving or not.
>
> request_irq() enables the interrupt line and if the pin is already in
> a state that triggers an interrupt, the driver interrupt handler will
> be called.

This looks like something is wrong in the irqchip.

Your set_type() is supporting edges but have all IRQs
handled by handle_simple_irq() rather than handle_edge_irq()
for the edges, which gives a more robust control flow
from IRQ to ACK to calling the handler.

Zheng/Mika: please look at how the level/edge
IRQs are handled in drivers/gpio/gpio-pl061.c
where I *tried* to do things right, switching handler
in .set_type() using irq_set_handler_locked(). I think
you may need to use handle_edge_irq() for the edge IRQs
and handle_level_irq() for the level IRQs just like I do
in the PL061 driver.

(I might be wrong.)

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg March 14, 2016, 12:54 p.m. UTC | #7
On Mon, Mar 14, 2016 at 01:40:39PM +0100, Linus Walleij wrote:
> On Mon, Mar 14, 2016 at 9:44 AM, Westerberg, Mika
> <mika.westerberg@intel.com> wrote:
> > On Mon, Mar 14, 2016 at 03:24:06AM +0200, Zheng, Qi wrote:
> 
> >> > +   intel_gpio_irq_ack(d);
> >>
> >> > If the pin toggles right here, we still have the same issue, no?
> >>
> >> Yes. But it is very short time from here to the place IRQ got enabled.
> >
> > That is still a race.
> >
> >> To me, it is the only available platform dependent interface to do
> > the "ACK" in the flow of request_irq. Maybe you have other better
> > option here?
> (...)
> > Drivers need to deal with the fact that they might get spurious
> > interrupts from time to time. You need to check in the interrupt handler
> > if the interrupt was from the device you are driving or not.
> >
> > request_irq() enables the interrupt line and if the pin is already in
> > a state that triggers an interrupt, the driver interrupt handler will
> > be called.
> 
> This looks like something is wrong in the irqchip.

If request_irq() is called so that the interrupt is level triggered,
let's say active low, and the pin is already in that state I would
expect interrupt to trigger immediately when enabled, no?

If I understand correctly this is precisely what Zheng is describing
they are trying to solve.

> Your set_type() is supporting edges but have all IRQs
> handled by handle_simple_irq() rather than handle_edge_irq()
> for the edges, which gives a more robust control flow
> from IRQ to ACK to calling the handler.
> 
> Zheng/Mika: please look at how the level/edge
> IRQs are handled in drivers/gpio/gpio-pl061.c
> where I *tried* to do things right, switching handler
> in .set_type() using irq_set_handler_locked(). I think
> you may need to use handle_edge_irq() for the edge IRQs
> and handle_level_irq() for the level IRQs just like I do
> in the PL061 driver.

The driver is already doing that as far as I can tell (see
intel_gpio_irq_type()).
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg March 14, 2016, 1 p.m. UTC | #8
On Mon, Mar 14, 2016 at 02:54:36PM +0200, Westerberg, Mika wrote:
> On Mon, Mar 14, 2016 at 01:40:39PM +0100, Linus Walleij wrote:
> > On Mon, Mar 14, 2016 at 9:44 AM, Westerberg, Mika
> > <mika.westerberg@intel.com> wrote:
> > > On Mon, Mar 14, 2016 at 03:24:06AM +0200, Zheng, Qi wrote:
> > 
> > >> > +   intel_gpio_irq_ack(d);
> > >>
> > >> > If the pin toggles right here, we still have the same issue, no?
> > >>
> > >> Yes. But it is very short time from here to the place IRQ got enabled.
> > >
> > > That is still a race.
> > >
> > >> To me, it is the only available platform dependent interface to do
> > > the "ACK" in the flow of request_irq. Maybe you have other better
> > > option here?
> > (...)
> > > Drivers need to deal with the fact that they might get spurious
> > > interrupts from time to time. You need to check in the interrupt handler
> > > if the interrupt was from the device you are driving or not.
> > >
> > > request_irq() enables the interrupt line and if the pin is already in
> > > a state that triggers an interrupt, the driver interrupt handler will
> > > be called.
> > 
> > This looks like something is wrong in the irqchip.
> 
> If request_irq() is called so that the interrupt is level triggered,
> let's say active low, and the pin is already in that state I would
> expect interrupt to trigger immediately when enabled, no?
> 
> If I understand correctly this is precisely what Zheng is describing
> they are trying to solve.

Scratch that. I just re-read the patch changelog and they are
configuring the pin as edge triggered.

> > Your set_type() is supporting edges but have all IRQs
> > handled by handle_simple_irq() rather than handle_edge_irq()
> > for the edges, which gives a more robust control flow
> > from IRQ to ACK to calling the handler.
> > 
> > Zheng/Mika: please look at how the level/edge
> > IRQs are handled in drivers/gpio/gpio-pl061.c
> > where I *tried* to do things right, switching handler
> > in .set_type() using irq_set_handler_locked(). I think
> > you may need to use handle_edge_irq() for the edge IRQs
> > and handle_level_irq() for the level IRQs just like I do
> > in the PL061 driver.
> 
> The driver is already doing that as far as I can tell (see
> intel_gpio_irq_type()).

I will check again if we are still missing something there.
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index ded5378..d6fe659 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -773,6 +773,8 @@  static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
 		return -EPERM;
 	}
 
+	intel_gpio_irq_ack(d);
+
 	spin_lock_irqsave(&pctrl->lock, flags);
 
 	value = readl(reg);