rtc: cmos: Cancel alarm timer if alarm time is equal to now+1 seconds
authorAdrian Huang <adrianhuang0701@gmail.com>
Mon, 6 Jul 2015 04:19:12 +0000 (12:19 +0800)
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>
Sat, 5 Sep 2015 11:19:08 +0000 (13:19 +0200)
commit88b8d33b1c6aadba553c998db91c4b36be0fac52
treea9bdfe0d2391f4d279b72b9a72935526ff602551
parent80ca3277bc7f398e3315af996443464dac5d4b88
rtc: cmos: Cancel alarm timer if alarm time is equal to now+1 seconds

Steps to reproduce the problem:
1) Enable RTC wake-up option in BIOS Setup
2) Issue one of these commands in the OS: "poweroff"
   or "shutdown -h now"
3) System will shut down and then reboot automatically

Root-cause of the issue:
1) During the shutdown process, the hwclock utility is used
   to save the system clock to hardware clock (RTC).
2) The hwclock utility invokes ioctl() with RTC_UIE_ON. The
   kernel configures the RTC alarm for the periodic interrupt
   (every 1 second).
3) The hwclock uitlity closes the /dev/rtc0 device, and the
   kernel disables the RTC alarm irq (AIE bit of Register B)
   via ioctl() with RTC_UIE_OFF. But, the configured alarm
   time is the current_time + 1.
4) After the next 1 second is elapsed, the AF (alarm
   interrupt flag) of Register C is set.
5) The S5 handler in BIOS is invoked to configure alarm
   registers (enable AIE bit and configure alarm date/time).
   But, BIOS does not clear the previous interrupt status
   during alarm configuration. Therefore, "AF=AIE=1" causes
   the rtc device to trigger an interrupt.
6) So, the machine reboots automatically right after shutdown.

This patch cancels the alarm timer if the following condictions are
met (suggested by Alexandre):
1) The configured alarm time is equal to current_time + 1
   seconds.
2) The AIE timer is not in use.

The member 'alarm_expires' is introduced in struct cmos_rtc because
of the following reasons:
1) The configured alarm time can be retrieved from
   cmos_read_alarm(), but we need to take the 'wrapped
   timestamp' and 'time rollover' into consideration. The
   function __rtc_read_alarm() eliminates the concerns. To
   avoid the duplicated code in the lower level RTC driver,
   invoking __rtc_read_alarm from the lower level RTC driver
   is not encouraged. Moreover, the compilation error 'the
   undefined __rtc_read_alarm" is observed if the lower level
   RTC driver is compiled as a kernel module.
2) The uie_rtctimer.node.expires and aie_timer.node.expires can
   be retrieved for the configured alarm time. But, the problem
   is that either of them might configure the CMOS alarm time.
   We cannot make sure UIE timer or AIE tiemr configured the
   CMOS alarm time before. (uie_rtctimer or aie_timer is enabled
   and then is disabled).
3) The patch introduces the member 'alarm_expires' to keep the
   newly configured alarm time, so the above-mentioned concerns
   can be eliminated.

The issue goes away after 20-time shutdown tests.

Signed-off-by: Adrian Huang <ahuang12@lenovo.com>
Tested-by: Egbert Eich <eich@suse.de>
Tested-by: Diego Ercolani <diego.ercolani@gmail.com>
Cc: Borislav Petkov <bp@suse.de>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
drivers/rtc/rtc-cmos.c