Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: add ability to push out an existing wakealarm using sysfs

This adds the ability for the rtc sysfs code to handle += characters at
the beginning of a wakealarm setting string. This will allow the user
to attempt to push out an existing wakealarm by a provided amount.

In the case that the += characters are provided but the alarm is not
active -EINVAL is returned.

his is useful, at least for my purposes in suspend/resume testing. The
basic test goes something like:

1. Set a wake alarm from userspace 5 seconds in the future

2. Start the suspend process (echo mem > /sys/power/state)

3. After ~2.5 seconds if userspace is still running (using another
thread to check this), move the wake alarm 5 more seconds

If the "move" involves an unset of the wakealarm then there's a period
of time where the system is midway through suspending but has no wake
alarm. It will get stuck.

We'd rather not remove the "move" since the idea is to avoid a cancelled
suspend when the alarm fires _during_ suspend. It is difficult for the
test to tell the difference between a suspend that was cancelled because
the alarm fired too early and a suspend that was

Signed-off-by: Bernie Thompson <bhthompson@chromium.org>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Doug Anderson <dianders@chromium.org>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Bernie Thompson and committed by
Linus Torvalds
1df0a471 c67d96e3

+19 -8
+4 -3
Documentation/rtc.txt
··· 153 153 time: RTC-provided time 154 154 wakealarm: The time at which the clock will generate a system wakeup 155 155 event. This is a one shot wakeup event, so must be reset 156 - after wake if a daily wakeup is required. Format is either 157 - seconds since the epoch or, if there's a leading +, seconds 158 - in the future. 156 + after wake if a daily wakeup is required. Format is seconds since 157 + the epoch by default, or if there's a leading +, seconds in the 158 + future, or if there is a leading +=, seconds ahead of the current 159 + alarm. 159 160 160 161 IOCTL INTERFACE 161 162 ---------------
+15 -5
drivers/rtc/rtc-sysfs.c
··· 164 164 { 165 165 ssize_t retval; 166 166 unsigned long now, alarm; 167 + unsigned long push = 0; 167 168 struct rtc_wkalrm alm; 168 169 struct rtc_device *rtc = to_rtc_device(dev); 169 170 char *buf_ptr; ··· 181 180 buf_ptr = (char *)buf; 182 181 if (*buf_ptr == '+') { 183 182 buf_ptr++; 184 - adjust = 1; 183 + if (*buf_ptr == '=') { 184 + buf_ptr++; 185 + push = 1; 186 + } else 187 + adjust = 1; 185 188 } 186 189 alarm = simple_strtoul(buf_ptr, NULL, 0); 187 190 if (adjust) { 188 191 alarm += now; 189 192 } 190 - if (alarm > now) { 193 + if (alarm > now || push) { 191 194 /* Avoid accidentally clobbering active alarms; we can't 192 195 * entirely prevent that here, without even the minimal 193 196 * locking from the /dev/rtcN api. ··· 199 194 retval = rtc_read_alarm(rtc, &alm); 200 195 if (retval < 0) 201 196 return retval; 202 - if (alm.enabled) 203 - return -EBUSY; 204 - 197 + if (alm.enabled) { 198 + if (push) { 199 + rtc_tm_to_time(&alm.time, &push); 200 + alarm += push; 201 + } else 202 + return -EBUSY; 203 + } else if (push) 204 + return -EINVAL; 205 205 alm.enabled = 1; 206 206 } else { 207 207 alm.enabled = 0;