diff options
| author | Xunlei Pang <pang.xunlei@linaro.org> | 2015-04-01 23:34:38 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-04-03 02:18:34 -0400 |
| commit | 0fa88cb4b82b5cf7429bc1cef9db006ca035754e (patch) | |
| tree | b3800f619ee137e6914e56bf803968642bd389af /kernel/time | |
| parent | 264bb3f79f2a465477cdcd2f0554e21aedc443a3 (diff) | |
time, drivers/rtc: Don't bother with rtc_resume() for the nonstop clocksource
If a system does not provide a persistent_clock(), the time
will be updated on resume by rtc_resume(). With the addition
of the non-stop clocksources for suspend timing, those systems
set the time on resume in timekeeping_resume(), but may not
provide a valid persistent_clock().
This results in the rtc_resume() logic thinking no one has set
the time and it then will over-write the suspend time again,
which is not necessary and only increases clock error.
So, fix this for rtc_resume().
This patch also improves the name of persistent_clock_exist to
make it more grammatical.
Signed-off-by: Xunlei Pang <pang.xunlei@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1427945681-29972-19-git-send-email-john.stultz@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/time')
| -rw-r--r-- | kernel/time/timekeeping.c | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index b7db4916415b..79b9bc6e7876 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -64,9 +64,6 @@ static struct tk_fast tk_fast_raw ____cacheline_aligned; | |||
| 64 | /* flag for if timekeeping is suspended */ | 64 | /* flag for if timekeeping is suspended */ |
| 65 | int __read_mostly timekeeping_suspended; | 65 | int __read_mostly timekeeping_suspended; |
| 66 | 66 | ||
| 67 | /* Flag for if there is a persistent clock on this platform */ | ||
| 68 | bool __read_mostly persistent_clock_exist = false; | ||
| 69 | |||
| 70 | static inline void tk_normalize_xtime(struct timekeeper *tk) | 67 | static inline void tk_normalize_xtime(struct timekeeper *tk) |
| 71 | { | 68 | { |
| 72 | while (tk->tkr_mono.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_mono.shift)) { | 69 | while (tk->tkr_mono.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_mono.shift)) { |
| @@ -1204,6 +1201,12 @@ void __weak read_boot_clock64(struct timespec64 *ts64) | |||
| 1204 | *ts64 = timespec_to_timespec64(ts); | 1201 | *ts64 = timespec_to_timespec64(ts); |
| 1205 | } | 1202 | } |
| 1206 | 1203 | ||
| 1204 | /* Flag for if timekeeping_resume() has injected sleeptime */ | ||
| 1205 | static bool sleeptime_injected; | ||
| 1206 | |||
| 1207 | /* Flag for if there is a persistent clock on this platform */ | ||
| 1208 | static bool persistent_clock_exists; | ||
| 1209 | |||
| 1207 | /* | 1210 | /* |
| 1208 | * timekeeping_init - Initializes the clocksource and common timekeeping values | 1211 | * timekeeping_init - Initializes the clocksource and common timekeeping values |
| 1209 | */ | 1212 | */ |
| @@ -1221,7 +1224,7 @@ void __init timekeeping_init(void) | |||
| 1221 | now.tv_sec = 0; | 1224 | now.tv_sec = 0; |
| 1222 | now.tv_nsec = 0; | 1225 | now.tv_nsec = 0; |
| 1223 | } else if (now.tv_sec || now.tv_nsec) | 1226 | } else if (now.tv_sec || now.tv_nsec) |
| 1224 | persistent_clock_exist = true; | 1227 | persistent_clock_exists = true; |
| 1225 | 1228 | ||
| 1226 | read_boot_clock64(&boot); | 1229 | read_boot_clock64(&boot); |
| 1227 | if (!timespec64_valid_strict(&boot)) { | 1230 | if (!timespec64_valid_strict(&boot)) { |
| @@ -1282,11 +1285,47 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, | |||
| 1282 | 1285 | ||
| 1283 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE) | 1286 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE) |
| 1284 | /** | 1287 | /** |
| 1288 | * We have three kinds of time sources to use for sleep time | ||
| 1289 | * injection, the preference order is: | ||
| 1290 | * 1) non-stop clocksource | ||
| 1291 | * 2) persistent clock (ie: RTC accessible when irqs are off) | ||
| 1292 | * 3) RTC | ||
| 1293 | * | ||
| 1294 | * 1) and 2) are used by timekeeping, 3) by RTC subsystem. | ||
| 1295 | * If system has neither 1) nor 2), 3) will be used finally. | ||
| 1296 | * | ||
| 1297 | * | ||
| 1298 | * If timekeeping has injected sleeptime via either 1) or 2), | ||
| 1299 | * 3) becomes needless, so in this case we don't need to call | ||
| 1300 | * rtc_resume(), and this is what timekeeping_rtc_skipresume() | ||
| 1301 | * means. | ||
| 1302 | */ | ||
| 1303 | bool timekeeping_rtc_skipresume(void) | ||
| 1304 | { | ||
| 1305 | return sleeptime_injected; | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | /** | ||
| 1309 | * 1) can be determined whether to use or not only when doing | ||
| 1310 | * timekeeping_resume() which is invoked after rtc_suspend(), | ||
| 1311 | * so we can't skip rtc_suspend() surely if system has 1). | ||
| 1312 | * | ||
| 1313 | * But if system has 2), 2) will definitely be used, so in this | ||
| 1314 | * case we don't need to call rtc_suspend(), and this is what | ||
| 1315 | * timekeeping_rtc_skipsuspend() means. | ||
| 1316 | */ | ||
| 1317 | bool timekeeping_rtc_skipsuspend(void) | ||
| 1318 | { | ||
| 1319 | return persistent_clock_exists; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | /** | ||
| 1285 | * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values | 1323 | * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values |
| 1286 | * @delta: pointer to a timespec64 delta value | 1324 | * @delta: pointer to a timespec64 delta value |
| 1287 | * | 1325 | * |
| 1288 | * This hook is for architectures that cannot support read_persistent_clock64 | 1326 | * This hook is for architectures that cannot support read_persistent_clock64 |
| 1289 | * because their RTC/persistent clock is only accessible when irqs are enabled. | 1327 | * because their RTC/persistent clock is only accessible when irqs are enabled. |
| 1328 | * and also don't have an effective nonstop clocksource. | ||
| 1290 | * | 1329 | * |
| 1291 | * This function should only be called by rtc_resume(), and allows | 1330 | * This function should only be called by rtc_resume(), and allows |
| 1292 | * a suspend offset to be injected into the timekeeping values. | 1331 | * a suspend offset to be injected into the timekeeping values. |
| @@ -1296,13 +1335,6 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta) | |||
| 1296 | struct timekeeper *tk = &tk_core.timekeeper; | 1335 | struct timekeeper *tk = &tk_core.timekeeper; |
| 1297 | unsigned long flags; | 1336 | unsigned long flags; |
| 1298 | 1337 | ||
| 1299 | /* | ||
| 1300 | * Make sure we don't set the clock twice, as timekeeping_resume() | ||
| 1301 | * already did it | ||
| 1302 | */ | ||
| 1303 | if (has_persistent_clock()) | ||
| 1304 | return; | ||
| 1305 | |||
| 1306 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 1338 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
| 1307 | write_seqcount_begin(&tk_core.seq); | 1339 | write_seqcount_begin(&tk_core.seq); |
| 1308 | 1340 | ||
| @@ -1334,8 +1366,8 @@ void timekeeping_resume(void) | |||
| 1334 | unsigned long flags; | 1366 | unsigned long flags; |
| 1335 | struct timespec64 ts_new, ts_delta; | 1367 | struct timespec64 ts_new, ts_delta; |
| 1336 | cycle_t cycle_now, cycle_delta; | 1368 | cycle_t cycle_now, cycle_delta; |
| 1337 | bool suspendtime_found = false; | ||
| 1338 | 1369 | ||
| 1370 | sleeptime_injected = false; | ||
| 1339 | read_persistent_clock64(&ts_new); | 1371 | read_persistent_clock64(&ts_new); |
| 1340 | 1372 | ||
| 1341 | clockevents_resume(); | 1373 | clockevents_resume(); |
| @@ -1381,13 +1413,13 @@ void timekeeping_resume(void) | |||
| 1381 | nsec += ((u64) cycle_delta * mult) >> shift; | 1413 | nsec += ((u64) cycle_delta * mult) >> shift; |
| 1382 | 1414 | ||
| 1383 | ts_delta = ns_to_timespec64(nsec); | 1415 | ts_delta = ns_to_timespec64(nsec); |
| 1384 | suspendtime_found = true; | 1416 | sleeptime_injected = true; |
| 1385 | } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { | 1417 | } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { |
| 1386 | ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time); | 1418 | ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time); |
| 1387 | suspendtime_found = true; | 1419 | sleeptime_injected = true; |
| 1388 | } | 1420 | } |
| 1389 | 1421 | ||
| 1390 | if (suspendtime_found) | 1422 | if (sleeptime_injected) |
| 1391 | __timekeeping_inject_sleeptime(tk, &ts_delta); | 1423 | __timekeeping_inject_sleeptime(tk, &ts_delta); |
| 1392 | 1424 | ||
| 1393 | /* Re-base the last cycle value */ | 1425 | /* Re-base the last cycle value */ |
| @@ -1421,14 +1453,14 @@ int timekeeping_suspend(void) | |||
| 1421 | * value returned, update the persistent_clock_exists flag. | 1453 | * value returned, update the persistent_clock_exists flag. |
| 1422 | */ | 1454 | */ |
| 1423 | if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec) | 1455 | if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec) |
| 1424 | persistent_clock_exist = true; | 1456 | persistent_clock_exists = true; |
| 1425 | 1457 | ||
| 1426 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 1458 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
| 1427 | write_seqcount_begin(&tk_core.seq); | 1459 | write_seqcount_begin(&tk_core.seq); |
| 1428 | timekeeping_forward_now(tk); | 1460 | timekeeping_forward_now(tk); |
| 1429 | timekeeping_suspended = 1; | 1461 | timekeeping_suspended = 1; |
| 1430 | 1462 | ||
| 1431 | if (has_persistent_clock()) { | 1463 | if (persistent_clock_exists) { |
| 1432 | /* | 1464 | /* |
| 1433 | * To avoid drift caused by repeated suspend/resumes, | 1465 | * To avoid drift caused by repeated suspend/resumes, |
| 1434 | * which each can add ~1 second drift error, | 1466 | * which each can add ~1 second drift error, |
