Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1470237 > unrolled thread

Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume

Started byGabriele Mazzotta <gabriele.mzt@gmail.com>
First post2016-08-25 17:50 +0200
Last post2016-08-31 18:10 +0200
Articles 4 — 2 participants

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Gabriele Mazzotta <gabriele.mzt@gmail.com> - 2016-08-25 17:50 +0200
    Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Alexandre Belloni <alexandre.belloni@free-electrons.com> - 2016-08-31 01:30 +0200
      Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Gabriele Mazzotta <gabriele.mzt@gmail.com> - 2016-08-31 17:10 +0200
        Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume Alexandre Belloni <alexandre.belloni@free-electrons.com> - 2016-08-31 18:10 +0200

#1470237 — Re: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume

FromGabriele Mazzotta <gabriele.mzt@gmail.com>
Date2016-08-25 17:50 +0200
SubjectRe: [PATCH 1/2] rtc-cmos: Clear expired alarm after resume
Message-ID<sa54J-2ST-3@gated-at.bofh.it>
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

[toc] | [next] | [standalone]


#1472944

FromAlexandre Belloni <alexandre.belloni@free-electrons.com>
Date2016-08-31 01:30 +0200
Message-ID<sc0DE-30k-19@gated-at.bofh.it>
In reply to#1470237
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

[toc] | [prev] | [next] | [standalone]


#1473594

FromGabriele Mazzotta <gabriele.mzt@gmail.com>
Date2016-08-31 17:10 +0200
Message-ID<scfjk-40K-33@gated-at.bofh.it>
In reply to#1472944
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,
> 

[toc] | [prev] | [next] | [standalone]


#1473633

FromAlexandre Belloni <alexandre.belloni@free-electrons.com>
Date2016-08-31 18:10 +0200
Message-ID<scgfn-4zJ-1@gated-at.bofh.it>
In reply to#1473594
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

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web