aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/rtc/class.c4
-rw-r--r--include/linux/timekeeping.h9
-rw-r--r--kernel/time/timekeeping.c66
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 */
251extern bool timekeeping_rtc_skipsuspend(void);
252extern bool timekeeping_rtc_skipresume(void);
253
251extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); 254extern 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 */
262extern bool persistent_clock_exist;
263extern int persistent_clock_is_local; 265extern int persistent_clock_is_local;
264 266
265static inline bool has_persistent_clock(void)
266{
267 return persistent_clock_exist;
268}
269
270extern void read_persistent_clock(struct timespec *ts); 267extern void read_persistent_clock(struct timespec *ts);
271extern void read_persistent_clock64(struct timespec64 *ts); 268extern void read_persistent_clock64(struct timespec64 *ts);
272extern void read_boot_clock(struct timespec *ts); 269extern 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 */
65int __read_mostly timekeeping_suspended; 65int __read_mostly timekeeping_suspended;
66 66
67/* Flag for if there is a persistent clock on this platform */
68bool __read_mostly persistent_clock_exist = false;
69
70static inline void tk_normalize_xtime(struct timekeeper *tk) 67static 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 */
1205static bool sleeptime_injected;
1206
1207/* Flag for if there is a persistent clock on this platform */
1208static 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 */
1303bool 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 */
1317bool 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,