linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
@ 2016-06-01 15:40 Gabriele Mazzotta
  2016-06-01 15:40 ` [PATCH 2/2] rtc-cmos: Restore " Gabriele Mazzotta
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Gabriele Mazzotta @ 2016-06-01 15:40 UTC (permalink / raw)
  To: a.zummo, alexandre.belloni
  Cc: rtc-linux, linux-kernel, matthew.garrett, Gabriele Mazzotta

If the system wakes up because of a wake alarm, the internal state
of the alarm is not updated. As consequence, the state no longer
reflects the actual state of the hardware and setting a new alarm
is not possible until the expired alarm is cleared.

Signed-off-by: Gabriele Mazzotta <gabriele.mzt@gmail.com>
---
 drivers/rtc/rtc-cmos.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index fbe9c72..fd121e3 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -900,11 +900,33 @@ static inline int cmos_poweroff(struct device *dev)
 
 #ifdef	CONFIG_PM_SLEEP
 
+static void cmos_check_alarm(struct device *dev)
+{
+	struct cmos_rtc *cmos = dev_get_drvdata(dev);
+	struct rtc_wkalrm alarm;
+	struct rtc_time now;
+	time64_t t_now;
+	time64_t t_expires;
+
+	cmos_read_time(dev, &now);
+	rtc_read_alarm(cmos->rtc, &alarm);
+	t_now = rtc_tm_to_time64(&now);
+	t_expires = rtc_tm_to_time64(&alarm.time);
+
+	if (t_expires <= t_now && alarm.enabled) {
+		alarm.enabled = 0;
+		cmos->suspend_ctrl &= ~RTC_AIE;
+		rtc_set_alarm(cmos->rtc, &alarm);
+	}
+}
+
 static int cmos_resume(struct device *dev)
 {
 	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
 	unsigned char tmp;
 
+	cmos_check_alarm(dev);
+
 	if (cmos->enabled_wake) {
 		if (cmos->wake_off)
 			cmos->wake_off(dev);
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] rtc-cmos: Restore alarm after resume
  2016-06-01 15:40 [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Gabriele Mazzotta
@ 2016-06-01 15:40 ` Gabriele Mazzotta
  2016-06-01 16:11 ` [PATCH 1/2] rtc-cmos: Clear expired " Gabriele Mazzotta
  2016-06-04 14:46 ` Alexandre Belloni
  2 siblings, 0 replies; 10+ messages in thread
From: Gabriele Mazzotta @ 2016-06-01 15:40 UTC (permalink / raw)
  To: a.zummo, alexandre.belloni
  Cc: rtc-linux, linux-kernel, matthew.garrett, Gabriele Mazzotta

Some platform firmware may interfere with the RTC alarm over suspend,
resulting in the kernel and hardware having different ideas about system
state but also potentially causing problems with firmware that assumes the
OS will clean this case up.  This patch restores the RTC alarm on resume
to ensure that kernel and hardware are in sync.

The case we've seen is Intel Rapid Start, which is a firmware-mediated
feature that automatically transitions systems from suspend-to-RAM to
suspend-to-disk without OS involvement.  It does this by setting the RTC
alarm and a flag that indicates that on wake it should perform the
transition rather than re-starting the OS.  However, if the OS has set a
wakeup alarm that would wake the machine earlier, it refuses to overwrite
it and allows the system to wake instead.

This fails in the following situation:

1) User configures Intel Rapid Start to transition after (say) 15
minutes
2) User suspends to RAM. Firmware sets the wakeup alarm for 15 minutes
in the future
3) User resumes after 5 minutes. Firmware does not reset the alarm, and
as such it is still set for 10 minutes in the future
4) User suspends after 5 minutes. Firmware notices that the alarm is set
for 5 minutes in the future, which is less than the 15 minute transition
threshold. It therefore assumes that the user wants the machine to wake
in 5 minutes
5) System resumes after 5 minutes

The worst case scenario here is that the user may have put the system in a
bag between (4) and (5), resulting in it running in a confined space and
potentially overheating.  This seems reasonably important.  The Rapid
Start support code got added in 3.11, but it can be configured in the
firmware regardless of kernel support.

Signed-off-by: Gabriele Mazzotta <gabriele.mzt@gmail.com>
---
This a rework of http://patchwork.ozlabs.org/patch/423494/.

I think rtc-cmos is the only timer that needs to be protected from unwated
firmware changes, but I'm not sure of this. This is enough to fix the
problem on my laptop.

 drivers/rtc/rtc-cmos.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index fd121e3..83fd4df 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -918,6 +918,9 @@ static void cmos_check_alarm(struct device *dev)
 		cmos->suspend_ctrl &= ~RTC_AIE;
 		rtc_set_alarm(cmos->rtc, &alarm);
 	}
+
+	/* The BIOS might have changed the alarm, restore it */
+	cmos_set_alarm(dev, &alarm);
 }
 
 static int cmos_resume(struct device *dev)
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-06-01 15:40 [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Gabriele Mazzotta
  2016-06-01 15:40 ` [PATCH 2/2] rtc-cmos: Restore " Gabriele Mazzotta
@ 2016-06-01 16:11 ` Gabriele Mazzotta
  2016-06-04 14:46 ` Alexandre Belloni
  2 siblings, 0 replies; 10+ messages in thread
From: Gabriele Mazzotta @ 2016-06-01 16:11 UTC (permalink / raw)
  To: a.zummo, alexandre.belloni; +Cc: rtc-linux, linux-kernel, matthew.garrett

On 01/06/2016 17:40, Gabriele Mazzotta wrote:
> If the system wakes up because of a wake alarm, the internal state
> of the alarm is not updated. As consequence, the state no longer
> reflects the actual state of the hardware and setting a new alarm
> is not possible until the expired alarm is cleared.
> 
> Signed-off-by: Gabriele Mazzotta <gabriele.mzt@gmail.com>
> ---
>  drivers/rtc/rtc-cmos.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
> index fbe9c72..fd121e3 100644
> --- a/drivers/rtc/rtc-cmos.c
> +++ b/drivers/rtc/rtc-cmos.c
> @@ -900,11 +900,33 @@ static inline int cmos_poweroff(struct device *dev)
>  
>  #ifdef	CONFIG_PM_SLEEP
>  
> +static void cmos_check_alarm(struct device *dev)
> +{
> +	struct cmos_rtc *cmos = dev_get_drvdata(dev);
> +	struct rtc_wkalrm alarm;
> +	struct rtc_time now;
> +	time64_t t_now;
> +	time64_t t_expires;
> +
> +	cmos_read_time(dev, &now);
> +	rtc_read_alarm(cmos->rtc, &alarm);

Here it should probably check the return value and exit in case of error.

> +	t_now = rtc_tm_to_time64(&now);
> +	t_expires = rtc_tm_to_time64(&alarm.time);
> +
> +	if (t_expires <= t_now && alarm.enabled) {
> +		alarm.enabled = 0;
> +		cmos->suspend_ctrl &= ~RTC_AIE;
> +		rtc_set_alarm(cmos->rtc, &alarm);

Same here.

> +	}
> +}
> +
>  static int cmos_resume(struct device *dev)
>  {
>  	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
>  	unsigned char tmp;
>  
> +	cmos_check_alarm(dev);
> +
>  	if (cmos->enabled_wake) {
>  		if (cmos->wake_off)
>  			cmos->wake_off(dev);
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-06-01 15:40 [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Gabriele Mazzotta
  2016-06-01 15:40 ` [PATCH 2/2] rtc-cmos: Restore " Gabriele Mazzotta
  2016-06-01 16:11 ` [PATCH 1/2] rtc-cmos: Clear expired " Gabriele Mazzotta
@ 2016-06-04 14:46 ` Alexandre Belloni
  2016-06-04 16:58   ` Gabriele Mazzotta
  2 siblings, 1 reply; 10+ messages in thread
From: Alexandre Belloni @ 2016-06-04 14:46 UTC (permalink / raw)
  To: Gabriele Mazzotta; +Cc: a.zummo, rtc-linux, linux-kernel, matthew.garrett

Hi,

On 01/06/2016 at 17:40:14 +0200, Gabriele Mazzotta wrote :
> If the system wakes up because of a wake alarm, the internal state
> of the alarm is not updated. As consequence, the state no longer
> reflects the actual state of the hardware and setting a new alarm
> is not possible until the expired alarm is cleared.
> 

I'm not completely sure to understand what is happening but could you
check whether that one is solved by
2b2f5ff00f63847d95adad6289bd8b05f5983dd5 in my tree (rtc-next).


-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-06-04 14:46 ` Alexandre Belloni
@ 2016-06-04 16:58   ` Gabriele Mazzotta
  2016-06-04 17:48     ` Alexandre Belloni
  0 siblings, 1 reply; 10+ messages in thread
From: Gabriele Mazzotta @ 2016-06-04 16:58 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, matthew.garrett

2016-06-04 16:46 GMT+02:00 Alexandre Belloni
<alexandre.belloni@free-electrons.com>:
> Hi,
>
> On 01/06/2016 at 17:40:14 +0200, Gabriele Mazzotta wrote :
>> If the system wakes up because of a wake alarm, the internal state
>> of the alarm is not updated. As consequence, the state no longer
>> reflects the actual state of the hardware and setting a new alarm
>> is not possible until the expired alarm is cleared.
>>
>
> I'm not completely sure to understand what is happening but could you
> check whether that one is solved by
> 2b2f5ff00f63847d95adad6289bd8b05f5983dd5 in my tree (rtc-next).
>

I picked 2b2f5ff00f63847d95adad6289bd8b05f5983dd5 and applied it
on top of 4.7-rc1, but that didn't fix the problem.

Let me explain the problem by showing you how I reproduce it:

root@localhost:~# cat /proc/driver/rtc | grep alarm_IRQ
alarm_IRQ       : no
root@localhost:~# echo +10 > /sys/class/rtc/rtc0/wakealarm
root@localhost:~# echo mem > /sys/power/state  # wait for auto-resume
root@localhost:~# echo +10 > /sys/class/rtc/rtc0/wakealarm
bash: echo: write error: Device or resource busy
root@localhost:~# cat /proc/driver/rtc | grep alarm_IRQ
alarm_IRQ       : yes

To set another alarm, I have to first write 0 to wakealarm. After that
I can set what I want. This doesn't happen if the alarm fires while
the system is awake, it happens only if the system is suspended and
the alarm wakes it.

I actually forgot to say that maybe this problem is not limited
to rtc-cmos and that maybe a general solution could be used.

I've just looked better into what is causing this and the problem
seems to be caused by the fact that rtc_timer_do_work() is not
executed if the timer expires while the system is suspended.

The following solves this particular problem:

diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 74fd974..80d6a12 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -102,6 +102,9 @@ static int rtc_resume(struct device *dev)
     struct timespec64    sleep_time;
     int err;

+    /* A timer might have expired while suspended */
+    schedule_work(&rtc->irqwork);
+
     if (timekeeping_rtc_skipresume())
         return 0;


> --
> Alexandre Belloni, Free Electrons
> Embedded Linux, Kernel and Android engineering
> http://free-electrons.com

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-06-04 16:58   ` Gabriele Mazzotta
@ 2016-06-04 17:48     ` Alexandre Belloni
  2016-08-25 14:54       ` Gabriele Mazzotta
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Belloni @ 2016-06-04 17:48 UTC (permalink / raw)
  To: Gabriele Mazzotta
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, matthew.garrett

On 04/06/2016 at 18:58:59 +0200, Gabriele Mazzotta wrote :
> 2016-06-04 16:46 GMT+02:00 Alexandre Belloni
> <alexandre.belloni@free-electrons.com>:
> > On 01/06/2016 at 17:40:14 +0200, Gabriele Mazzotta wrote :
> >> If the system wakes up because of a wake alarm, the internal state
> >> of the alarm is not updated. As consequence, the state no longer
> >> reflects the actual state of the hardware and setting a new alarm
> >> is not possible until the expired alarm is cleared.
> >>
> >
> > I'm not completely sure to understand what is happening but could you
> > check whether that one is solved by
> > 2b2f5ff00f63847d95adad6289bd8b05f5983dd5 in my tree (rtc-next).
> >
> 
> I picked 2b2f5ff00f63847d95adad6289bd8b05f5983dd5 and applied it
> on top of 4.7-rc1, but that didn't fix the problem.
> 
> Let me explain the problem by showing you how I reproduce it:
> 
> root@localhost:~# cat /proc/driver/rtc | grep alarm_IRQ
> alarm_IRQ       : no
> root@localhost:~# echo +10 > /sys/class/rtc/rtc0/wakealarm
> root@localhost:~# echo mem > /sys/power/state  # wait for auto-resume
> root@localhost:~# echo +10 > /sys/class/rtc/rtc0/wakealarm
> bash: echo: write error: Device or resource busy
> root@localhost:~# cat /proc/driver/rtc | grep alarm_IRQ
> alarm_IRQ       : yes
> 
> To set another alarm, I have to first write 0 to wakealarm. After that
> I can set what I want. This doesn't happen if the alarm fires while
> the system is awake, it happens only if the system is suspended and
> the alarm wakes it.
> 
> I actually forgot to say that maybe this problem is not limited
> to rtc-cmos and that maybe a general solution could be used.
> 
> I've just looked better into what is causing this and the problem
> seems to be caused by the fact that rtc_timer_do_work() is not
> executed if the timer expires while the system is suspended.
> 

I doubt this is a driver independent issues as I don't get that
behaviour on many other RTCs. I'll have a look.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-06-04 17:48     ` Alexandre Belloni
@ 2016-08-25 14:54       ` Gabriele Mazzotta
  2016-08-30 23:28         ` Alexandre Belloni
  0 siblings, 1 reply; 10+ messages in thread
From: Gabriele Mazzotta @ 2016-08-25 14:54 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, matthew.garrett

On 04/06/2016 19:48, Alexandre Belloni wrote:
> On 04/06/2016 at 18:58:59 +0200, Gabriele Mazzotta wrote :
>> 2016-06-04 16:46 GMT+02:00 Alexandre Belloni
>> <alexandre.belloni@free-electrons.com>:
>>> On 01/06/2016 at 17:40:14 +0200, Gabriele Mazzotta wrote :
>>>> If the system wakes up because of a wake alarm, the internal state
>>>> of the alarm is not updated. As consequence, the state no longer
>>>> reflects the actual state of the hardware and setting a new alarm
>>>> is not possible until the expired alarm is cleared.
>>>>
>>>
>>> I'm not completely sure to understand what is happening but could you
>>> check whether that one is solved by
>>> 2b2f5ff00f63847d95adad6289bd8b05f5983dd5 in my tree (rtc-next).
>>>
>>
>> I picked 2b2f5ff00f63847d95adad6289bd8b05f5983dd5 and applied it
>> on top of 4.7-rc1, but that didn't fix the problem.
>>
>> Let me explain the problem by showing you how I reproduce it:
>>
>> root@localhost:~# cat /proc/driver/rtc | grep alarm_IRQ
>> alarm_IRQ       : no
>> root@localhost:~# echo +10 > /sys/class/rtc/rtc0/wakealarm
>> root@localhost:~# echo mem > /sys/power/state  # wait for auto-resume
>> root@localhost:~# echo +10 > /sys/class/rtc/rtc0/wakealarm
>> bash: echo: write error: Device or resource busy
>> root@localhost:~# cat /proc/driver/rtc | grep alarm_IRQ
>> alarm_IRQ       : yes
>>
>> To set another alarm, I have to first write 0 to wakealarm. After that
>> I can set what I want. This doesn't happen if the alarm fires while
>> the system is awake, it happens only if the system is suspended and
>> the alarm wakes it.
>>
>> I actually forgot to say that maybe this problem is not limited
>> to rtc-cmos and that maybe a general solution could be used.
>>
>> I've just looked better into what is causing this and the problem
>> seems to be caused by the fact that rtc_timer_do_work() is not
>> executed if the timer expires while the system is suspended.
>>
> 
> I doubt this is a driver independent issues as I don't get that
> behaviour on many other RTCs. I'll have a look.

Hi,

were you able to verify that no other driver is affect?

Gabriele

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-08-25 14:54       ` Gabriele Mazzotta
@ 2016-08-30 23:28         ` Alexandre Belloni
  2016-08-31 15:05           ` Gabriele Mazzotta
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Belloni @ 2016-08-30 23:28 UTC (permalink / raw)
  To: Gabriele Mazzotta
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, matthew.garrett

Hi,

On 25/08/2016 at 16:54:18 +0200, Gabriele Mazzotta wrote :
> Hi,
> 
> were you able to verify that no other driver is affect?
> 

I had a closer look at the issue. I think what is happening is that you
don't enter the do/while loop in cmos_resume twice. That is supposed to
handle then clear the RTC_AIE bit and that is why the alarm still seems
enabled.

Can you add some tracing there to understand why? It is probably also
useful to know the value of cmos->suspend_ctrl in cmos_suspend.

My guess is that is_intr(mask) is false and you break out of the loop at
the first pass, meaning that the RTC_AIE bit is never cleared from
RTC_CONTROL. That would also mean that your RTC is not setting RTC_AF
after waking your PC. Am I right?

Regards,

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-08-30 23:28         ` Alexandre Belloni
@ 2016-08-31 15:05           ` Gabriele Mazzotta
  2016-08-31 16:08             ` Alexandre Belloni
  0 siblings, 1 reply; 10+ messages in thread
From: Gabriele Mazzotta @ 2016-08-31 15:05 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, matthew.garrett

On 31/08/2016 01:28, Alexandre Belloni wrote:
> Hi,
> 
> On 25/08/2016 at 16:54:18 +0200, Gabriele Mazzotta wrote :
>> Hi,
>>
>> were you able to verify that no other driver is affect?
>>
> 
> I had a closer look at the issue. I think what is happening is that you
> don't enter the do/while loop in cmos_resume twice. That is supposed to
> handle then clear the RTC_AIE bit and that is why the alarm still seems
> enabled.
> 
> Can you add some tracing there to understand why? It is probably also
> useful to know the value of cmos->suspend_ctrl in cmos_suspend.

cmos->suspend_ctrl is 0x2 when no alarm is set, 0x22 otherwise.
The only way to clear RTC_AIE is to set an alarm and wait for it to
expire while the system is awake.

> My guess is that is_intr(mask) is false and you break out of the loop at
> the first pass, meaning that the RTC_AIE bit is never cleared from
> RTC_CONTROL. That would also mean that your RTC is not setting RTC_AF
> after waking your PC. Am I right?

You are right, is_intr(mask) is false and now I see where the problem is.

I thought cmos_interrupt() was taking care of everything, but I've just
noticed that it's executed only when the system is awake. That's because
cmos->wake_on is not NULL, so enable_irq_wake() is not called.

However, not even rtc_handler() is called, so I guess the BIOS silently
wakes the system when an alarm expires while suspended. This means that
we can't update RTC_CONTROL from rtc_handler() and that we have to do it
from cmos_resume().

There's a problem with this. We don't know whether the system is waking up
because of an alarm or because the user resumed it. In both cases RTC_AIE
is set.

One way to solve this problem is to manually check from cmos_resume() if
any alarm expired while suspended. If we find such an alarm, we don't
break early out of the loop and let it clear the flags.

Is this reasonable?

> Regards,
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
  2016-08-31 15:05           ` Gabriele Mazzotta
@ 2016-08-31 16:08             ` Alexandre Belloni
  0 siblings, 0 replies; 10+ messages in thread
From: Alexandre Belloni @ 2016-08-31 16:08 UTC (permalink / raw)
  To: Gabriele Mazzotta
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, matthew.garrett

On 31/08/2016 at 17:05:58 +0200, Gabriele Mazzotta wrote :
> On 31/08/2016 01:28, Alexandre Belloni wrote:
> > Hi,
> > 
> > On 25/08/2016 at 16:54:18 +0200, Gabriele Mazzotta wrote :
> >> Hi,
> >>
> >> were you able to verify that no other driver is affect?
> >>
> > 
> > I had a closer look at the issue. I think what is happening is that you
> > don't enter the do/while loop in cmos_resume twice. That is supposed to
> > handle then clear the RTC_AIE bit and that is why the alarm still seems
> > enabled.
> > 
> > Can you add some tracing there to understand why? It is probably also
> > useful to know the value of cmos->suspend_ctrl in cmos_suspend.
> 
> cmos->suspend_ctrl is 0x2 when no alarm is set, 0x22 otherwise.
> The only way to clear RTC_AIE is to set an alarm and wait for it to
> expire while the system is awake.
> 
> > My guess is that is_intr(mask) is false and you break out of the loop at
> > the first pass, meaning that the RTC_AIE bit is never cleared from
> > RTC_CONTROL. That would also mean that your RTC is not setting RTC_AF
> > after waking your PC. Am I right?
> 
> You are right, is_intr(mask) is false and now I see where the problem is.
> 
> I thought cmos_interrupt() was taking care of everything, but I've just
> noticed that it's executed only when the system is awake. That's because
> cmos->wake_on is not NULL, so enable_irq_wake() is not called.
> 
> However, not even rtc_handler() is called, so I guess the BIOS silently
> wakes the system when an alarm expires while suspended. This means that
> we can't update RTC_CONTROL from rtc_handler() and that we have to do it
> from cmos_resume().
> 
> There's a problem with this. We don't know whether the system is waking up
> because of an alarm or because the user resumed it. In both cases RTC_AIE
> is set.
> 
> One way to solve this problem is to manually check from cmos_resume() if
> any alarm expired while suspended. If we find such an alarm, we don't
> break early out of the loop and let it clear the flags.
> 
> Is this reasonable?
> 

Yeah, I think the fix is to clear RTC_AIE in cmos_resume when now >
alarm (same check as in your original patch) after the do/while loop.
Also, you will need to properly handle the "missed" interrupt and call
rtc_update_irq

To be clear, something like:

if (mask & RTC_AIE) {
	...
	if (now > alarm) {
			rtc_update_irq(cmos->rtc, 1, mask);
			tmp &= ~RTC_AIE;
			CMOS_WRITE(tmp, RTC_CONTROL);
	}
}

This limits the impact of the patch as (mask & RTC_AIE) will be false in
the case of a properly functioning RTC.

Don't forget to comment that it is a quirk, possibly mentioning the
maker of the PC and the BIOS.

The other quirk is a bit more complicated than your second fix. You
actually have to read the alarm in cmos_suspend and then compare it with what
you have in cmos_resume. If it has changed and is not expired then you
have to set it back.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-08-31 16:08 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-01 15:40 [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Gabriele Mazzotta
2016-06-01 15:40 ` [PATCH 2/2] rtc-cmos: Restore " Gabriele Mazzotta
2016-06-01 16:11 ` [PATCH 1/2] rtc-cmos: Clear expired " Gabriele Mazzotta
2016-06-04 14:46 ` Alexandre Belloni
2016-06-04 16:58   ` Gabriele Mazzotta
2016-06-04 17:48     ` Alexandre Belloni
2016-08-25 14:54       ` Gabriele Mazzotta
2016-08-30 23:28         ` Alexandre Belloni
2016-08-31 15:05           ` Gabriele Mazzotta
2016-08-31 16:08             ` Alexandre Belloni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).