From 0aeab46ed8bde9e5850b2558b99307633093d0a2 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 14 Aug 2017 13:46:32 -0700 Subject: [PATCH 1/6] kselftests: timers: freq-step: Define ADJ_SETOFFSET if device has older kernel headers On some systems, the kernel headers haven't been updated to include ADJ_SETOFFSET, so define it in the test if needed. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Miroslav Lichvar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Stephen Boyd Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: John Stultz --- tools/testing/selftests/timers/freq-step.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/timers/freq-step.c b/tools/testing/selftests/timers/freq-step.c index e8c61830825a..934a308ee686 100644 --- a/tools/testing/selftests/timers/freq-step.c +++ b/tools/testing/selftests/timers/freq-step.c @@ -33,6 +33,10 @@ #define MAX_FREQ_ERROR 10e-6 #define MAX_STDDEV 1000e-9 +#ifndef ADJ_SETOFFSET + #define ADJ_SETOFFSET 0x0100 +#endif + struct sample { double offset; double time; From 6cc636614e144b7cb4c6578bce5cc9b76b7c11e7 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 14 Aug 2017 13:57:34 -0700 Subject: [PATCH 2/6] kselftests: timers: freq-step: Fix build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following build warning: freq-step.c: In function ‘main’: freq-step.c:271:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ By returning the return values from ksft_success/fail. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Miroslav Lichvar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Stephen Boyd Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: John Stultz --- tools/testing/selftests/timers/freq-step.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/timers/freq-step.c b/tools/testing/selftests/timers/freq-step.c index 934a308ee686..926828ea84d1 100644 --- a/tools/testing/selftests/timers/freq-step.c +++ b/tools/testing/selftests/timers/freq-step.c @@ -266,7 +266,7 @@ int main(int argc, char **argv) set_frequency(0.0); if (fails) - ksft_exit_fail(); + return ksft_exit_fail(); - ksft_exit_pass(); + return ksft_exit_pass(); } From a524b1184b8e86141d689fa78ad150fbf2db9b4c Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 25 Jul 2017 14:36:25 -0700 Subject: [PATCH 3/6] kselftests: timers: set-timer-lat: Tweak reporting when timer fires early Rather than printing an error inside the alarm signal handler, set a flag that we check later. This keeps the test from spamming the console every time the alarm fires early. It also fixes the test exiting with error code 0 if this was the only test failure. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Miroslav Lichvar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Stephen Boyd Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: Greg Hackmann Signed-off-by: John Stultz --- .../testing/selftests/timers/set-timer-lat.c | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/timers/set-timer-lat.c b/tools/testing/selftests/timers/set-timer-lat.c index 4fc98c5b0899..10c2e18737c0 100644 --- a/tools/testing/selftests/timers/set-timer-lat.c +++ b/tools/testing/selftests/timers/set-timer-lat.c @@ -63,6 +63,7 @@ int alarmcount; int clock_id; struct timespec start_time; long long max_latency_ns; +int timer_fired_early; char *clockstring(int clockid) { @@ -115,12 +116,19 @@ void sigalarm(int signo) delta_ns -= NSEC_PER_SEC * TIMER_SECS * alarmcount; if (delta_ns < 0) - printf("%s timer fired early: FAIL\n", clockstring(clock_id)); + timer_fired_early = 1; if (delta_ns > max_latency_ns) max_latency_ns = delta_ns; } +void describe_timer(int flags) +{ + printf("%-22s %s ", + clockstring(clock_id), + flags ? "ABSTIME":"RELTIME"); +} + int do_timer(int clock_id, int flags) { struct sigevent se; @@ -136,6 +144,7 @@ int do_timer(int clock_id, int flags) max_latency_ns = 0; alarmcount = 0; + timer_fired_early = 0; err = timer_create(clock_id, &se, &tm1); if (err) { @@ -170,18 +179,26 @@ int do_timer(int clock_id, int flags) while (alarmcount < 5) sleep(1); - printf("%-22s %s max latency: %10lld ns : ", - clockstring(clock_id), - flags ? "ABSTIME":"RELTIME", - max_latency_ns); + describe_timer(flags); + printf("timer fired early: %7d : ", timer_fired_early); + if (!timer_fired_early) { + printf("[OK]\n"); + } else { + printf("[FAILED]\n"); + err = -1; + } + + describe_timer(flags); + printf("max latency: %10lld ns : ", max_latency_ns); timer_delete(tm1); if (max_latency_ns < UNRESONABLE_LATENCY) { printf("[OK]\n"); - return 0; + } else { + printf("[FAILED]\n"); + err = -1; } - printf("[FAILED]\n"); - return -1; + return err; } int main(void) From 28be3f8f48cfb3cf024860f042d424cd4824f5f7 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 25 Jul 2017 14:36:26 -0700 Subject: [PATCH 4/6] kselftests: timers: set-timer-lat: Add one-shot timer test cases These testcases are motivated by a recent alarmtimer regression, which caused one-shot CLOCK_{BOOTTIME,REALTIME}_ALARM timers to become periodic timers. The new testcases are very similar to the existing testcases for repeating timers. But rather than waiting for 5 alarms, they wait for 5 seconds and verify that the alarm fired exactly once. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Miroslav Lichvar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Stephen Boyd Cc: Shuah Khan Cc: linux-kselftest@vger.kernel.org Signed-off-by: Greg Hackmann Signed-off-by: John Stultz --- .../testing/selftests/timers/set-timer-lat.c | 86 ++++++++++++++++--- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/timers/set-timer-lat.c b/tools/testing/selftests/timers/set-timer-lat.c index 10c2e18737c0..15434da23b04 100644 --- a/tools/testing/selftests/timers/set-timer-lat.c +++ b/tools/testing/selftests/timers/set-timer-lat.c @@ -20,6 +20,7 @@ */ +#include #include #include #include @@ -122,17 +123,17 @@ void sigalarm(int signo) max_latency_ns = delta_ns; } -void describe_timer(int flags) +void describe_timer(int flags, int interval) { - printf("%-22s %s ", + printf("%-22s %s %s ", clockstring(clock_id), - flags ? "ABSTIME":"RELTIME"); + flags ? "ABSTIME":"RELTIME", + interval ? "PERIODIC":"ONE-SHOT"); } -int do_timer(int clock_id, int flags) +int setup_timer(int clock_id, int flags, int interval, timer_t *tm1) { struct sigevent se; - timer_t tm1; struct itimerspec its1, its2; int err; @@ -146,7 +147,7 @@ int do_timer(int clock_id, int flags) alarmcount = 0; timer_fired_early = 0; - err = timer_create(clock_id, &se, &tm1); + err = timer_create(clock_id, &se, tm1); if (err) { if ((clock_id == CLOCK_REALTIME_ALARM) || (clock_id == CLOCK_BOOTTIME_ALARM)) { @@ -167,19 +168,23 @@ int do_timer(int clock_id, int flags) its1.it_value.tv_sec = TIMER_SECS; its1.it_value.tv_nsec = 0; } - its1.it_interval.tv_sec = TIMER_SECS; + its1.it_interval.tv_sec = interval; its1.it_interval.tv_nsec = 0; - err = timer_settime(tm1, flags, &its1, &its2); + err = timer_settime(*tm1, flags, &its1, &its2); if (err) { printf("%s - timer_settime() failed\n", clockstring(clock_id)); return -1; } - while (alarmcount < 5) - sleep(1); + return 0; +} - describe_timer(flags); +int check_timer_latency(int flags, int interval) +{ + int err = 0; + + describe_timer(flags, interval); printf("timer fired early: %7d : ", timer_fired_early); if (!timer_fired_early) { printf("[OK]\n"); @@ -188,10 +193,9 @@ int do_timer(int clock_id, int flags) err = -1; } - describe_timer(flags); + describe_timer(flags, interval); printf("max latency: %10lld ns : ", max_latency_ns); - timer_delete(tm1); if (max_latency_ns < UNRESONABLE_LATENCY) { printf("[OK]\n"); } else { @@ -201,6 +205,60 @@ int do_timer(int clock_id, int flags) return err; } +int check_alarmcount(int flags, int interval) +{ + describe_timer(flags, interval); + printf("count: %19d : ", alarmcount); + if (alarmcount == 1) { + printf("[OK]\n"); + return 0; + } + printf("[FAILED]\n"); + return -1; +} + +int do_timer(int clock_id, int flags) +{ + timer_t tm1; + const int interval = TIMER_SECS; + int err; + + err = setup_timer(clock_id, flags, interval, &tm1); + if (err) + return err; + + while (alarmcount < 5) + sleep(1); + + timer_delete(tm1); + return check_timer_latency(flags, interval); +} + +int do_timer_oneshot(int clock_id, int flags) +{ + timer_t tm1; + const int interval = 0; + struct timeval timeout; + fd_set fds; + int err; + + err = setup_timer(clock_id, flags, interval, &tm1); + if (err) + return err; + + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = 5; + FD_ZERO(&fds); + do { + err = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + } while (err == -1 && errno == EINTR); + + timer_delete(tm1); + err = check_timer_latency(flags, interval); + err |= check_alarmcount(flags, interval); + return err; +} + int main(void) { struct sigaction act; @@ -226,6 +284,8 @@ int main(void) ret |= do_timer(clock_id, TIMER_ABSTIME); ret |= do_timer(clock_id, 0); + ret |= do_timer_oneshot(clock_id, TIMER_ABSTIME); + ret |= do_timer_oneshot(clock_id, 0); } if (ret) return ksft_exit_fail(); From a529bea8fa6b6dded6179c72d3385e0f7d0a4fde Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Wed, 28 Jun 2017 22:21:35 +0900 Subject: [PATCH 5/6] timekeeping: Use proper timekeeper for debug code When CONFIG_DEBUG_TIMEKEEPING is enabled the timekeeping_check_update() function will update status like last_warning and underflow_seen on the timekeeper. If there are issues found this state is used to rate limit the warnings that get printed. This rate limiting doesn't really really work if stored in real_tk as the shadow timekeeper is overwritten onto real_tk at the end of every update_wall_time() call, resetting last_warning and other statuses. Fix rate limiting by using the shadow_timekeeper for timekeeping_check_update(). Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Miroslav Lichvar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Stephen Boyd Fixes: commit 57d05a93ada7 ("time: Rework debugging variables so they aren't global") Signed-off-by: Stafford Horne Signed-off-by: John Stultz --- kernel/time/timekeeping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index cedafa008de5..8f5866981883 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2066,7 +2066,7 @@ void update_wall_time(void) goto out; /* Do some additional sanity checking */ - timekeeping_check_update(real_tk, offset); + timekeeping_check_update(tk, offset); /* * With NO_HZ we may have to accumulate many cycle_intervals From 47b4a457e4cc816b3fdd2ee55c65fda8ea6de051 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 5 Jul 2017 14:08:35 +0200 Subject: [PATCH 6/6] alarmtimer: Fix unavailable wake-up source in sysfs Currently the alarmtimer registers a wake-up source unconditionally, regardless of the system having a (wake-up capable) RTC or not. Hence the alarmtimer will always show up in /sys/kernel/debug/wakeup_sources, even if it is not available, and thus cannot be a wake-up source. To fix this, postpone registration until a wake-up capable RTC device is added. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Miroslav Lichvar Cc: Richard Cochran Cc: Prarit Bhargava Cc: Stephen Boyd Signed-off-by: Geert Uytterhoeven Signed-off-by: John Stultz --- kernel/time/alarmtimer.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 0b8ff7d257ea..73a2b476e59f 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -56,9 +56,9 @@ static ktime_t freezer_delta; static DEFINE_SPINLOCK(freezer_delta_lock); #endif +#ifdef CONFIG_RTC_CLASS static struct wakeup_source *ws; -#ifdef CONFIG_RTC_CLASS /* rtc timer and device for setting alarm wakeups at suspend */ static struct rtc_timer rtctimer; static struct rtc_device *rtcdev; @@ -89,6 +89,7 @@ static int alarmtimer_rtc_add_device(struct device *dev, { unsigned long flags; struct rtc_device *rtc = to_rtc_device(dev); + struct wakeup_source *__ws; if (rtcdev) return -EBUSY; @@ -98,13 +99,20 @@ static int alarmtimer_rtc_add_device(struct device *dev, if (!device_may_wakeup(rtc->dev.parent)) return -1; + __ws = wakeup_source_register("alarmtimer"); + spin_lock_irqsave(&rtcdev_lock, flags); if (!rtcdev) { rtcdev = rtc; /* hold a reference so it doesn't go away */ get_device(dev); + ws = __ws; + __ws = NULL; } spin_unlock_irqrestore(&rtcdev_lock, flags); + + wakeup_source_unregister(__ws); + return 0; } @@ -860,7 +868,6 @@ static int __init alarmtimer_init(void) error = PTR_ERR(pdev); goto out_drv; } - ws = wakeup_source_register("alarmtimer"); return 0; out_drv: