diff mbox

[v3,7/8] rtc: ds3232-core: fix issue when irq is shared several devices

Message ID 1456758832-10590-7-git-send-email-akinobu.mita@gmail.com
State Superseded
Headers show

Commit Message

Akinobu Mita Feb. 29, 2016, 3:13 p.m. UTC
ds3232-core requests irq with IRQF_SHARED, so irq can be shared by
several devices.  But the irq handler for ds3232 unconditionally
disables the irq at first and the irq is re-enabled only when the
interrupt source was the ds3232's alarm.  This behaviour breaks the
devices sharing the same irq in the various scenarios.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Dennis Aberilla <denzzzhome@yahoo.com>
---
* New patch from this version

 drivers/rtc/rtc-ds3232-core.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

Comments

Akinobu Mita March 3, 2016, 2:10 p.m. UTC | #1
2016-03-01 0:13 GMT+09:00 Akinobu Mita <akinobu.mita@gmail.com>:
> ds3232-core requests irq with IRQF_SHARED, so irq can be shared by
> several devices.  But the irq handler for ds3232 unconditionally
> disables the irq at first and the irq is re-enabled only when the
> interrupt source was the ds3232's alarm.  This behaviour breaks the
> devices sharing the same irq in the various scenarios.
>
> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> Cc: Alessandro Zummo <a.zummo@towertech.it>
> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Dennis Aberilla <denzzzhome@yahoo.com>
> ---
> * New patch from this version
>
>  drivers/rtc/rtc-ds3232-core.c | 14 ++------------
>  1 file changed, 2 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/rtc/rtc-ds3232-core.c b/drivers/rtc/rtc-ds3232-core.c
> index be8dfe0..6489380 100644
> --- a/drivers/rtc/rtc-ds3232-core.c
> +++ b/drivers/rtc/rtc-ds3232-core.c
> @@ -59,7 +59,6 @@ struct ds3232 {
>          */
>         struct mutex mutex;
>         bool suspended;
> -       int exiting;
>  };
>
>  static int ds3232_check_rtc_status(struct device *dev)
> @@ -314,8 +313,6 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
>         struct device *dev = dev_id;
>         struct ds3232 *ds3232 = dev_get_drvdata(dev);
>
> -       disable_irq_nosync(irq);
> -
>         /*
>          * If rtc as a wakeup source, can't schedule the work
>          * at system resume flow, because at this time the i2c bus

I found that this patch is not correct because interrupt is re-enabled
after this hardirq handler finished without clearing Alarm Flag or
Alarm Interrupt Enable in RTC register.

Maybe we should drop IRQF_SHARED flag.
Alexandre Belloni March 3, 2016, 10:57 p.m. UTC | #2
On 03/03/2016 at 23:10:35 +0900, Akinobu Mita wrote :
> 2016-03-01 0:13 GMT+09:00 Akinobu Mita <akinobu.mita@gmail.com>:
> > ds3232-core requests irq with IRQF_SHARED, so irq can be shared by
> > several devices.  But the irq handler for ds3232 unconditionally
> > disables the irq at first and the irq is re-enabled only when the
> > interrupt source was the ds3232's alarm.  This behaviour breaks the
> > devices sharing the same irq in the various scenarios.
> >
> > Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> > Cc: Alessandro Zummo <a.zummo@towertech.it>
> > Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> > Cc: Dennis Aberilla <denzzzhome@yahoo.com>
> > ---
> > * New patch from this version
> >
> >  drivers/rtc/rtc-ds3232-core.c | 14 ++------------
> >  1 file changed, 2 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/rtc/rtc-ds3232-core.c b/drivers/rtc/rtc-ds3232-core.c
> > index be8dfe0..6489380 100644
> > --- a/drivers/rtc/rtc-ds3232-core.c
> > +++ b/drivers/rtc/rtc-ds3232-core.c
> > @@ -59,7 +59,6 @@ struct ds3232 {
> >          */
> >         struct mutex mutex;
> >         bool suspended;
> > -       int exiting;
> >  };
> >
> >  static int ds3232_check_rtc_status(struct device *dev)
> > @@ -314,8 +313,6 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
> >         struct device *dev = dev_id;
> >         struct ds3232 *ds3232 = dev_get_drvdata(dev);
> >
> > -       disable_irq_nosync(irq);
> > -
> >         /*
> >          * If rtc as a wakeup source, can't schedule the work
> >          * at system resume flow, because at this time the i2c bus
> 
> I found that this patch is not correct because interrupt is re-enabled
> after this hardirq handler finished without clearing Alarm Flag or
> Alarm Interrupt Enable in RTC register.
> 
> Maybe we should drop IRQF_SHARED flag.

I think the best is to completely reworke the irq handling. It dates
from many many year ago and can be replace by a simple threaded irq.
This will solve your issue.
Akinobu Mita March 4, 2016, 1:56 p.m. UTC | #3
2016-03-04 7:57 GMT+09:00 Alexandre Belloni
<alexandre.belloni@free-electrons.com>:
> On 03/03/2016 at 23:10:35 +0900, Akinobu Mita wrote :
>> 2016-03-01 0:13 GMT+09:00 Akinobu Mita <akinobu.mita@gmail.com>:
>> > ds3232-core requests irq with IRQF_SHARED, so irq can be shared by
>> > several devices.  But the irq handler for ds3232 unconditionally
>> > disables the irq at first and the irq is re-enabled only when the
>> > interrupt source was the ds3232's alarm.  This behaviour breaks the
>> > devices sharing the same irq in the various scenarios.
>> >
>> > Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
>> > Cc: Alessandro Zummo <a.zummo@towertech.it>
>> > Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
>> > Cc: Dennis Aberilla <denzzzhome@yahoo.com>
>> > ---
>> > * New patch from this version
>> >
>> >  drivers/rtc/rtc-ds3232-core.c | 14 ++------------
>> >  1 file changed, 2 insertions(+), 12 deletions(-)
>> >
>> > diff --git a/drivers/rtc/rtc-ds3232-core.c b/drivers/rtc/rtc-ds3232-core.c
>> > index be8dfe0..6489380 100644
>> > --- a/drivers/rtc/rtc-ds3232-core.c
>> > +++ b/drivers/rtc/rtc-ds3232-core.c
>> > @@ -59,7 +59,6 @@ struct ds3232 {
>> >          */
>> >         struct mutex mutex;
>> >         bool suspended;
>> > -       int exiting;
>> >  };
>> >
>> >  static int ds3232_check_rtc_status(struct device *dev)
>> > @@ -314,8 +313,6 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
>> >         struct device *dev = dev_id;
>> >         struct ds3232 *ds3232 = dev_get_drvdata(dev);
>> >
>> > -       disable_irq_nosync(irq);
>> > -
>> >         /*
>> >          * If rtc as a wakeup source, can't schedule the work
>> >          * at system resume flow, because at this time the i2c bus
>>
>> I found that this patch is not correct because interrupt is re-enabled
>> after this hardirq handler finished without clearing Alarm Flag or
>> Alarm Interrupt Enable in RTC register.
>>
>> Maybe we should drop IRQF_SHARED flag.
>
> I think the best is to completely reworke the irq handling. It dates
> from many many year ago and can be replace by a simple threaded irq.
> This will solve your issue.

I tried converting to threaded irq.  But it needs to deal with suspend
resume paths. (i.e. the following comment in ds3232_irq)

        /*
         * If rtc as a wakeup source, can't schedule the work
         * at system resume flow, because at this time the i2c bus
         * has not been resumed.
         */

Unfortunately, I don't have the computer that can use RTC on i2c-bus
as wake up source.  So I think dropping IRQF_SHARED is safe for now.
Alexandre Belloni March 4, 2016, 2:16 p.m. UTC | #4
On 04/03/2016 at 22:56:01 +0900, Akinobu Mita wrote :
> 2016-03-04 7:57 GMT+09:00 Alexandre Belloni
> <alexandre.belloni@free-electrons.com>:
> > On 03/03/2016 at 23:10:35 +0900, Akinobu Mita wrote :
> >> 2016-03-01 0:13 GMT+09:00 Akinobu Mita <akinobu.mita@gmail.com>:
> >> > ds3232-core requests irq with IRQF_SHARED, so irq can be shared by
> >> > several devices.  But the irq handler for ds3232 unconditionally
> >> > disables the irq at first and the irq is re-enabled only when the
> >> > interrupt source was the ds3232's alarm.  This behaviour breaks the
> >> > devices sharing the same irq in the various scenarios.
> >> >
> >> > Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> >> > Cc: Alessandro Zummo <a.zummo@towertech.it>
> >> > Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> >> > Cc: Dennis Aberilla <denzzzhome@yahoo.com>
> >> > ---
> >> > * New patch from this version
> >> >
> >> >  drivers/rtc/rtc-ds3232-core.c | 14 ++------------
> >> >  1 file changed, 2 insertions(+), 12 deletions(-)
> >> >
> >> > diff --git a/drivers/rtc/rtc-ds3232-core.c b/drivers/rtc/rtc-ds3232-core.c
> >> > index be8dfe0..6489380 100644
> >> > --- a/drivers/rtc/rtc-ds3232-core.c
> >> > +++ b/drivers/rtc/rtc-ds3232-core.c
> >> > @@ -59,7 +59,6 @@ struct ds3232 {
> >> >          */
> >> >         struct mutex mutex;
> >> >         bool suspended;
> >> > -       int exiting;
> >> >  };
> >> >
> >> >  static int ds3232_check_rtc_status(struct device *dev)
> >> > @@ -314,8 +313,6 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
> >> >         struct device *dev = dev_id;
> >> >         struct ds3232 *ds3232 = dev_get_drvdata(dev);
> >> >
> >> > -       disable_irq_nosync(irq);
> >> > -
> >> >         /*
> >> >          * If rtc as a wakeup source, can't schedule the work
> >> >          * at system resume flow, because at this time the i2c bus
> >>
> >> I found that this patch is not correct because interrupt is re-enabled
> >> after this hardirq handler finished without clearing Alarm Flag or
> >> Alarm Interrupt Enable in RTC register.
> >>
> >> Maybe we should drop IRQF_SHARED flag.
> >
> > I think the best is to completely reworke the irq handling. It dates
> > from many many year ago and can be replace by a simple threaded irq.
> > This will solve your issue.
> 
> I tried converting to threaded irq.  But it needs to deal with suspend
> resume paths. (i.e. the following comment in ds3232_irq)
> 
>         /*
>          * If rtc as a wakeup source, can't schedule the work
>          * at system resume flow, because at this time the i2c bus
>          * has not been resumed.
>          */
> 
> Unfortunately, I don't have the computer that can use RTC on i2c-bus
> as wake up source.  So I think dropping IRQF_SHARED is safe for now.

That comment is bogus, you can drop it as well. It may have been the
case a few years ago but that is not true anymore (else a lot of other
RTC would fail).
diff mbox

Patch

diff --git a/drivers/rtc/rtc-ds3232-core.c b/drivers/rtc/rtc-ds3232-core.c
index be8dfe0..6489380 100644
--- a/drivers/rtc/rtc-ds3232-core.c
+++ b/drivers/rtc/rtc-ds3232-core.c
@@ -59,7 +59,6 @@  struct ds3232 {
 	 */
 	struct mutex mutex;
 	bool suspended;
-	int exiting;
 };
 
 static int ds3232_check_rtc_status(struct device *dev)
@@ -314,8 +313,6 @@  static irqreturn_t ds3232_irq(int irq, void *dev_id)
 	struct device *dev = dev_id;
 	struct ds3232 *ds3232 = dev_get_drvdata(dev);
 
-	disable_irq_nosync(irq);
-
 	/*
 	 * If rtc as a wakeup source, can't schedule the work
 	 * at system resume flow, because at this time the i2c bus
@@ -342,8 +339,8 @@  static void ds3232_work(struct work_struct *work)
 	if (stat & DS3232_REG_SR_A1F) {
 		ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
 		if (ret) {
-			pr_warn("Read Control Register error - Disable IRQ%d\n",
-				ds3232->irq);
+			dev_warn(ds3232->dev,
+				"Read Control Register error %d\n", ret);
 		} else {
 			/* disable alarm1 interrupt */
 			control &= ~(DS3232_REG_CR_A1IE);
@@ -367,9 +364,6 @@  static void ds3232_work(struct work_struct *work)
 			}
 
 			rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
-
-			if (!ds3232->exiting)
-				enable_irq(ds3232->irq);
 		}
 	}
 
@@ -428,10 +422,6 @@  int ds3232_remove(struct device *dev)
 	struct ds3232 *ds3232 = dev_get_drvdata(dev);
 
 	if (ds3232->irq > 0) {
-		mutex_lock(&ds3232->mutex);
-		ds3232->exiting = 1;
-		mutex_unlock(&ds3232->mutex);
-
 		devm_free_irq(dev, ds3232->irq, dev);
 		cancel_work_sync(&ds3232->work);
 	}