Browse Source

Merge branch 'fortglx/4.14/time' of https://git.linaro.org/people/john.stultz/linux into timers/core

Pull timekeepig updates from John Stultz

 - kselftest improvements

 - Use the proper timekeeper in the debug code

 - Prevent accessing an unavailable wakeup source in the alarmtimer sysfs
   interface.
Thomas Gleixner 8 years ago
parent
commit
4e2a809703

+ 9 - 2
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:

+ 1 - 1
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

+ 6 - 2
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;
@@ -262,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();
 }

+ 90 - 13
tools/testing/selftests/timers/set-timer-lat.c

@@ -20,6 +20,7 @@
  */
 
 
+#include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <time.h>
@@ -63,6 +64,7 @@ int alarmcount;
 int clock_id;
 struct timespec start_time;
 long long max_latency_ns;
+int timer_fired_early;
 
 char *clockstring(int clockid)
 {
@@ -115,16 +117,23 @@ 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;
 }
 
-int do_timer(int clock_id, int flags)
+void describe_timer(int flags, int interval)
+{
+	printf("%-22s %s %s ",
+			clockstring(clock_id),
+			flags ? "ABSTIME":"RELTIME",
+			interval ? "PERIODIC":"ONE-SHOT");
+}
+
+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;
 
@@ -136,8 +145,9 @@ 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);
+	err = timer_create(clock_id, &se, tm1);
 	if (err) {
 		if ((clock_id == CLOCK_REALTIME_ALARM) ||
 		    (clock_id == CLOCK_BOOTTIME_ALARM)) {
@@ -158,32 +168,97 @@ 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;
+}
 
-	printf("%-22s %s max latency: %10lld ns : ",
-			clockstring(clock_id),
-			flags ? "ABSTIME":"RELTIME",
-			max_latency_ns);
+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");
+	} else {
+		printf("[FAILED]\n");
+		err = -1;
+	}
+
+	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 {
+		printf("[FAILED]\n");
+		err = -1;
+	}
+	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;
@@ -209,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();