diff mbox

pinctrl: rockchip: don't disable clk when irq mask is already set

Message ID 1474655197-26919-1-git-send-email-jacob-chen@iotwrt.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jacob Chen Sept. 23, 2016, 6:26 p.m. UTC
From: Jacob Chen <jacob2.chen@rock-chips.com>

In some drivers, disable_irq() call don't be symmetric with enable_irq()
, disable_irq() will be called before call free_irq().

But both disable_irq() and free_irq() will call rockchip_irq_gc_mask_set_bit,
 and clk_disable() will be called more times than clk_enable(), which will
cause bugs.

I think we can correct that by checking of mask.If mask is already set, do nothing.

Change-Id: If19912c7658253e15531c04db6c70fdbffd5960a
Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 4 ++++
 1 file changed, 4 insertions(+)

--
2.7.4

Comments

Shawn Lin Sept. 24, 2016, 10:24 a.m. UTC | #1
On 2016/9/24 2:26, Jacob Chen wrote:
> From: Jacob Chen <jacob2.chen@rock-chips.com>
>
> In some drivers, disable_irq() call don't be symmetric with enable_irq()
> , disable_irq() will be called before call free_irq().

Which upstream drivers you refer to?

Shouldn't it be the unbalanced call for these drivers?

>
> But both disable_irq() and free_irq() will call rockchip_irq_gc_mask_set_bit,
>  and clk_disable() will be called more times than clk_enable(), which will
> cause bugs.
>
> I think we can correct that by checking of mask.If mask is already set, do nothing.
>

Looks like a little hacky to me.

> Change-Id: If19912c7658253e15531c04db6c70fdbffd5960a

remove this.

> Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
> ---
>  drivers/pinctrl/pinctrl-rockchip.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
> index c6c04ac..9a8804a 100644
> --- a/drivers/pinctrl/pinctrl-rockchip.c
> +++ b/drivers/pinctrl/pinctrl-rockchip.c
> @@ -2334,8 +2334,12 @@ static void rockchip_irq_gc_mask_clr_bit(struct irq_data *d)
>  void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
>  {
>  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> +	struct irq_chip_type *ct = irq_data_get_chip_type(d);
>  	struct rockchip_pin_bank *bank = gc->private;
>
> +	if (*ct->mask_cache & d->mask)
> +		return;
> +
>  	irq_gc_mask_set_bit(d);
>  	clk_disable(bank->clk);
>  }
> --
> 2.7.4
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
Jacob Chen Sept. 24, 2016, 2:42 p.m. UTC | #2
2016-09-24 18:24 GMT+08:00 Shawn Lin <shawn.lin@rock-chips.com>:
> On 2016/9/24 2:26, Jacob Chen wrote:
>>
>> From: Jacob Chen <jacob2.chen@rock-chips.com>
>>
>> In some drivers, disable_irq() call don't be symmetric with enable_irq()
>> , disable_irq() will be called before call free_irq().
>
>
> Which upstream drivers you refer to?
>
> Shouldn't it be the unbalanced call for these drivers?
>


I met this in bcmdhd driver, it seems upstream brcmfmac driver don't
have this problem.

======================================================================
void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
{
    int err = 0;
    bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;

    SDLX_MSG(("%s: Enter\n", __FUNCTION__));
    if (!bcmsdh_osinfo->oob_irq_registered) {
        SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__));
    return;
}
    if (bcmsdh_osinfo->oob_irq_wake_enabled) {
    err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
    if (!err)
        bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
    }
    if (bcmsdh_osinfo->oob_irq_enabled) {
        disable_irq(bcmsdh_osinfo->oob_irq_num);
        bcmsdh_osinfo->oob_irq_enabled = FALSE;
    }
    free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
    bcmsdh_osinfo->oob_irq_registered = FALSE;
}
======================================================================
In this funciton, it will disable irq before free_irq.
At first, i think that commenting the line
"disable_irq(bcmsdh_osinfo->oob_irq_num);" can slove this problem,
but actually this driver have many hidden calls to disable_irq and
hardlly to correct....

Besides, I think that umask() and mask() aren't supposed to be strict symmetric.

>>
>> But both disable_irq() and free_irq() will call
>> rockchip_irq_gc_mask_set_bit,
>>  and clk_disable() will be called more times than clk_enable(), which will
>> cause bugs.
>>
>> I think we can correct that by checking of mask.If mask is already set, do
>> nothing.
>>
>
> Looks like a little hacky to me.
>

Yes, it's pretty hacky, but i think it can work stable since this
condition only take effect when disbale_irq + free_irq was called.
Heiko Stuebner Sept. 26, 2016, 10:35 p.m. UTC | #3
Am Samstag, 24. September 2016, 18:24:11 CEST schrieb Shawn Lin:
> On 2016/9/24 2:26, Jacob Chen wrote:
> > From: Jacob Chen <jacob2.chen@rock-chips.com>
> > 
> > In some drivers, disable_irq() call don't be symmetric with enable_irq()
> > , disable_irq() will be called before call free_irq().
> 
> Which upstream drivers you refer to?
> 
> Shouldn't it be the unbalanced call for these drivers?
> 
> > But both disable_irq() and free_irq() will call
> > rockchip_irq_gc_mask_set_bit,> 
> >  and clk_disable() will be called more times than clk_enable(), which will
> > 
> > cause bugs.
> > 
> > I think we can correct that by checking of mask.If mask is already set, do
> > nothing.
> Looks like a little hacky to me.

that may be true, but on first glance I tend to agree with Jacob.
Look for example at (a driver using disable_irq I picked at random) drivertc/
rtcrs/-tps6586x.c .

In its probe function it does devm_request_irq directly followed by 
disable_irq on its alarm interrupt. The interrupt only gets enabled again if 
the rtc alarm gets enabled. So you can easily run into the disable + free case 
there as well. Similar probably in a lot of other drivers.


Heiko

> 
> > Change-Id: If19912c7658253e15531c04db6c70fdbffd5960a
> 
> remove this.
> 
> > Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
> > ---
> > 
> >  drivers/pinctrl/pinctrl-rockchip.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/pinctrl/pinctrl-rockchip.c
> > b/drivers/pinctrl/pinctrl-rockchip.c index c6c04ac..9a8804a 100644
> > --- a/drivers/pinctrl/pinctrl-rockchip.c
> > +++ b/drivers/pinctrl/pinctrl-rockchip.c
> > @@ -2334,8 +2334,12 @@ static void rockchip_irq_gc_mask_clr_bit(struct
> > irq_data *d)> 
> >  void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
> >  {
> >  
> >  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> > 
> > +	struct irq_chip_type *ct = irq_data_get_chip_type(d);
> > 
> >  	struct rockchip_pin_bank *bank = gc->private;
> > 
> > +	if (*ct->mask_cache & d->mask)
> > +		return;
> > +
> > 
> >  	irq_gc_mask_set_bit(d);
> >  	clk_disable(bank->clk);
> >  
> >  }
> > 
> > --
> > 2.7.4
> > 
> > 
> > _______________________________________________
> > Linux-rockchip mailing list
> > Linux-rockchip@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-rockchip
Shawn Lin Sept. 29, 2016, 7:29 a.m. UTC | #4
在 2016/9/27 6:35, Heiko Stuebner 写道:
> Am Samstag, 24. September 2016, 18:24:11 CEST schrieb Shawn Lin:
>> On 2016/9/24 2:26, Jacob Chen wrote:
>>> From: Jacob Chen <jacob2.chen@rock-chips.com>
>>>
>>> In some drivers, disable_irq() call don't be symmetric with enable_irq()
>>> , disable_irq() will be called before call free_irq().
>>
>> Which upstream drivers you refer to?
>>
>> Shouldn't it be the unbalanced call for these drivers?
>>
>>> But both disable_irq() and free_irq() will call
>>> rockchip_irq_gc_mask_set_bit,>
>>>  and clk_disable() will be called more times than clk_enable(), which will
>>>
>>> cause bugs.
>>>
>>> I think we can correct that by checking of mask.If mask is already set, do
>>> nothing.
>> Looks like a little hacky to me.
>
> that may be true, but on first glance I tend to agree with Jacob.
> Look for example at (a driver using disable_irq I picked at random) drivertc/
> rtcrs/-tps6586x.c .

yep, I took a quick look at the files you pointed to, and it seems
there should be the problems for what this patch to deal with. Probably
I didn't see this error since the drivers we was using happened to
handle it properly but maybe not for other drivers. I am okay if this
could solve problems for Jacob.

>
> In its probe function it does devm_request_irq directly followed by
> disable_irq on its alarm interrupt. The interrupt only gets enabled again if
> the rtc alarm gets enabled. So you can easily run into the disable + free case
> there as well. Similar probably in a lot of other drivers.
>
>
> Heiko
>
>>
>>> Change-Id: If19912c7658253e15531c04db6c70fdbffd5960a
>>
>> remove this.
>>
>>> Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
>>> ---
>>>
>>>  drivers/pinctrl/pinctrl-rockchip.c | 4 ++++
>>>  1 file changed, 4 insertions(+)
>>>
>>> diff --git a/drivers/pinctrl/pinctrl-rockchip.c
>>> b/drivers/pinctrl/pinctrl-rockchip.c index c6c04ac..9a8804a 100644
>>> --- a/drivers/pinctrl/pinctrl-rockchip.c
>>> +++ b/drivers/pinctrl/pinctrl-rockchip.c
>>> @@ -2334,8 +2334,12 @@ static void rockchip_irq_gc_mask_clr_bit(struct
>>> irq_data *d)>
>>>  void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
>>>  {
>>>
>>>  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
>>>
>>> +	struct irq_chip_type *ct = irq_data_get_chip_type(d);
>>>
>>>  	struct rockchip_pin_bank *bank = gc->private;
>>>
>>> +	if (*ct->mask_cache & d->mask)
>>> +		return;
>>> +
>>>
>>>  	irq_gc_mask_set_bit(d);
>>>  	clk_disable(bank->clk);
>>>
>>>  }
>>>
>>> --
>>> 2.7.4
>>>
>>>
>>> _______________________________________________
>>> Linux-rockchip mailing list
>>> Linux-rockchip@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
diff mbox

Patch

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index c6c04ac..9a8804a 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -2334,8 +2334,12 @@  static void rockchip_irq_gc_mask_clr_bit(struct irq_data *d)
 void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct irq_chip_type *ct = irq_data_get_chip_type(d);
 	struct rockchip_pin_bank *bank = gc->private;

+	if (*ct->mask_cache & d->mask)
+		return;
+
 	irq_gc_mask_set_bit(d);
 	clk_disable(bank->clk);
 }