diff options
| -rw-r--r-- | drivers/rtc/class.c | 4 | ||||
| -rw-r--r-- | include/linux/timekeeping.h | 9 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 66 |
3 files changed, 54 insertions, 25 deletions
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index d40760aa4553..c29ba7e14304 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
| @@ -55,7 +55,7 @@ static int rtc_suspend(struct device *dev) | |||
| 55 | struct timespec64 delta, delta_delta; | 55 | struct timespec64 delta, delta_delta; |
| 56 | int err; | 56 | int err; |
| 57 | 57 | ||
| 58 | if (has_persistent_clock()) | 58 | if (timekeeping_rtc_skipsuspend()) |
| 59 | return 0; | 59 | return 0; |
| 60 | 60 | ||
| 61 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) | 61 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
| @@ -102,7 +102,7 @@ static int rtc_resume(struct device *dev) | |||
| 102 | struct timespec64 sleep_time; | 102 | struct timespec64 sleep_time; |
| 103 | int err; | 103 | int err; |
| 104 | 104 | ||
| 105 | if (has_persistent_clock()) | 105 | if (timekeeping_rtc_skipresume()) |
| 106 | return 0; | 106 | return 0; |
| 107 | 107 | ||
| 108 | rtc_hctosys_ret = -ENODEV; | 108 | rtc_hctosys_ret = -ENODEV; |
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 7a2369d5b3f4..99176af216af 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h | |||
| @@ -248,6 +248,9 @@ static inline void timekeeping_clocktai(struct timespec *ts) | |||
| 248 | /* | 248 | /* |
| 249 | * RTC specific | 249 | * RTC specific |
| 250 | */ | 250 | */ |
| 251 | extern bool timekeeping_rtc_skipsuspend(void); | ||
| 252 | extern bool timekeeping_rtc_skipresume(void); | ||
| 253 | |||
| 251 | extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); | 254 | extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); |
| 252 | 255 | ||
| 253 | /* | 256 | /* |
| @@ -259,14 +262,8 @@ extern void getnstime_raw_and_real(struct timespec *ts_raw, | |||
| 259 | /* | 262 | /* |
| 260 | * Persistent clock related interfaces | 263 | * Persistent clock related interfaces |
| 261 | */ | 264 | */ |
| 262 | extern bool persistent_clock_exist; | ||
| 263 | extern int persistent_clock_is_local; | 265 | extern int persistent_clock_is_local; |
| 264 | 266 | ||
| 265 | static inline bool has_persistent_clock(void) | ||
| 266 | { | ||
| 267 | return persistent_clock_exist; | ||
| 268 | } | ||
| 269 | |||
| 270 | extern void read_persistent_clock(struct timespec *ts); | 267 | extern void read_persistent_clock(struct timespec *ts); |
| 271 | extern void read_persistent_clock64(struct timespec64 *ts); | 268 | extern void read_persistent_clock64(struct timespec64 *ts); |
| 272 | extern void read_boot_clock(struct timespec *ts); | 269 | extern void read_boot_clock(struct timespec *ts); |
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, |
