diff options
Diffstat (limited to 'kernel/time/timekeeping.c')
| -rw-r--r-- | kernel/time/timekeeping.c | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 6a931852082f..91db94136c10 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -230,9 +230,7 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) | |||
| 230 | 230 | ||
| 231 | /** | 231 | /** |
| 232 | * update_fast_timekeeper - Update the fast and NMI safe monotonic timekeeper. | 232 | * update_fast_timekeeper - Update the fast and NMI safe monotonic timekeeper. |
| 233 | * @tk: The timekeeper from which we take the update | 233 | * @tkr: Timekeeping readout base from which we take the update |
| 234 | * @tkf: The fast timekeeper to update | ||
| 235 | * @tbase: The time base for the fast timekeeper (mono/raw) | ||
| 236 | * | 234 | * |
| 237 | * We want to use this from any context including NMI and tracing / | 235 | * We want to use this from any context including NMI and tracing / |
| 238 | * instrumenting the timekeeping code itself. | 236 | * instrumenting the timekeeping code itself. |
| @@ -244,11 +242,11 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) | |||
| 244 | * smp_wmb(); <- Ensure that the last base[1] update is visible | 242 | * smp_wmb(); <- Ensure that the last base[1] update is visible |
| 245 | * tkf->seq++; | 243 | * tkf->seq++; |
| 246 | * smp_wmb(); <- Ensure that the seqcount update is visible | 244 | * smp_wmb(); <- Ensure that the seqcount update is visible |
| 247 | * update(tkf->base[0], tk); | 245 | * update(tkf->base[0], tkr); |
| 248 | * smp_wmb(); <- Ensure that the base[0] update is visible | 246 | * smp_wmb(); <- Ensure that the base[0] update is visible |
| 249 | * tkf->seq++; | 247 | * tkf->seq++; |
| 250 | * smp_wmb(); <- Ensure that the seqcount update is visible | 248 | * smp_wmb(); <- Ensure that the seqcount update is visible |
| 251 | * update(tkf->base[1], tk); | 249 | * update(tkf->base[1], tkr); |
| 252 | * | 250 | * |
| 253 | * The reader side does: | 251 | * The reader side does: |
| 254 | * | 252 | * |
| @@ -269,7 +267,7 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) | |||
| 269 | * slightly wrong timestamp (a few nanoseconds). See | 267 | * slightly wrong timestamp (a few nanoseconds). See |
| 270 | * @ktime_get_mono_fast_ns. | 268 | * @ktime_get_mono_fast_ns. |
| 271 | */ | 269 | */ |
| 272 | static void update_fast_timekeeper(struct timekeeper *tk) | 270 | static void update_fast_timekeeper(struct tk_read_base *tkr) |
| 273 | { | 271 | { |
| 274 | struct tk_read_base *base = tk_fast_mono.base; | 272 | struct tk_read_base *base = tk_fast_mono.base; |
| 275 | 273 | ||
| @@ -277,7 +275,7 @@ static void update_fast_timekeeper(struct timekeeper *tk) | |||
| 277 | raw_write_seqcount_latch(&tk_fast_mono.seq); | 275 | raw_write_seqcount_latch(&tk_fast_mono.seq); |
| 278 | 276 | ||
| 279 | /* Update base[0] */ | 277 | /* Update base[0] */ |
| 280 | memcpy(base, &tk->tkr, sizeof(*base)); | 278 | memcpy(base, tkr, sizeof(*base)); |
| 281 | 279 | ||
| 282 | /* Force readers back to base[0] */ | 280 | /* Force readers back to base[0] */ |
| 283 | raw_write_seqcount_latch(&tk_fast_mono.seq); | 281 | raw_write_seqcount_latch(&tk_fast_mono.seq); |
| @@ -334,6 +332,35 @@ u64 notrace ktime_get_mono_fast_ns(void) | |||
| 334 | } | 332 | } |
| 335 | EXPORT_SYMBOL_GPL(ktime_get_mono_fast_ns); | 333 | EXPORT_SYMBOL_GPL(ktime_get_mono_fast_ns); |
| 336 | 334 | ||
| 335 | /* Suspend-time cycles value for halted fast timekeeper. */ | ||
| 336 | static cycle_t cycles_at_suspend; | ||
| 337 | |||
| 338 | static cycle_t dummy_clock_read(struct clocksource *cs) | ||
| 339 | { | ||
| 340 | return cycles_at_suspend; | ||
| 341 | } | ||
| 342 | |||
| 343 | /** | ||
| 344 | * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource. | ||
| 345 | * @tk: Timekeeper to snapshot. | ||
| 346 | * | ||
| 347 | * It generally is unsafe to access the clocksource after timekeeping has been | ||
| 348 | * suspended, so take a snapshot of the readout base of @tk and use it as the | ||
| 349 | * fast timekeeper's readout base while suspended. It will return the same | ||
| 350 | * number of cycles every time until timekeeping is resumed at which time the | ||
| 351 | * proper readout base for the fast timekeeper will be restored automatically. | ||
| 352 | */ | ||
| 353 | static void halt_fast_timekeeper(struct timekeeper *tk) | ||
| 354 | { | ||
| 355 | static struct tk_read_base tkr_dummy; | ||
| 356 | struct tk_read_base *tkr = &tk->tkr; | ||
| 357 | |||
| 358 | memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy)); | ||
| 359 | cycles_at_suspend = tkr->read(tkr->clock); | ||
| 360 | tkr_dummy.read = dummy_clock_read; | ||
| 361 | update_fast_timekeeper(&tkr_dummy); | ||
| 362 | } | ||
| 363 | |||
| 337 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD | 364 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD |
| 338 | 365 | ||
| 339 | static inline void update_vsyscall(struct timekeeper *tk) | 366 | static inline void update_vsyscall(struct timekeeper *tk) |
| @@ -462,7 +489,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) | |||
| 462 | memcpy(&shadow_timekeeper, &tk_core.timekeeper, | 489 | memcpy(&shadow_timekeeper, &tk_core.timekeeper, |
| 463 | sizeof(tk_core.timekeeper)); | 490 | sizeof(tk_core.timekeeper)); |
| 464 | 491 | ||
| 465 | update_fast_timekeeper(tk); | 492 | update_fast_timekeeper(&tk->tkr); |
| 466 | } | 493 | } |
| 467 | 494 | ||
| 468 | /** | 495 | /** |
| @@ -1170,7 +1197,7 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta) | |||
| 1170 | * xtime/wall_to_monotonic/jiffies/etc are | 1197 | * xtime/wall_to_monotonic/jiffies/etc are |
| 1171 | * still managed by arch specific suspend/resume code. | 1198 | * still managed by arch specific suspend/resume code. |
| 1172 | */ | 1199 | */ |
| 1173 | static void timekeeping_resume(void) | 1200 | void timekeeping_resume(void) |
| 1174 | { | 1201 | { |
| 1175 | struct timekeeper *tk = &tk_core.timekeeper; | 1202 | struct timekeeper *tk = &tk_core.timekeeper; |
| 1176 | struct clocksource *clock = tk->tkr.clock; | 1203 | struct clocksource *clock = tk->tkr.clock; |
| @@ -1251,7 +1278,7 @@ static void timekeeping_resume(void) | |||
| 1251 | hrtimers_resume(); | 1278 | hrtimers_resume(); |
| 1252 | } | 1279 | } |
| 1253 | 1280 | ||
| 1254 | static int timekeeping_suspend(void) | 1281 | int timekeeping_suspend(void) |
| 1255 | { | 1282 | { |
| 1256 | struct timekeeper *tk = &tk_core.timekeeper; | 1283 | struct timekeeper *tk = &tk_core.timekeeper; |
| 1257 | unsigned long flags; | 1284 | unsigned long flags; |
| @@ -1296,6 +1323,7 @@ static int timekeeping_suspend(void) | |||
| 1296 | } | 1323 | } |
| 1297 | 1324 | ||
| 1298 | timekeeping_update(tk, TK_MIRROR); | 1325 | timekeeping_update(tk, TK_MIRROR); |
| 1326 | halt_fast_timekeeper(tk); | ||
| 1299 | write_seqcount_end(&tk_core.seq); | 1327 | write_seqcount_end(&tk_core.seq); |
| 1300 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 1328 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| 1301 | 1329 | ||
| @@ -1659,24 +1687,24 @@ out: | |||
| 1659 | } | 1687 | } |
| 1660 | 1688 | ||
| 1661 | /** | 1689 | /** |
| 1662 | * getboottime - Return the real time of system boot. | 1690 | * getboottime64 - Return the real time of system boot. |
| 1663 | * @ts: pointer to the timespec to be set | 1691 | * @ts: pointer to the timespec64 to be set |
| 1664 | * | 1692 | * |
| 1665 | * Returns the wall-time of boot in a timespec. | 1693 | * Returns the wall-time of boot in a timespec64. |
| 1666 | * | 1694 | * |
| 1667 | * This is based on the wall_to_monotonic offset and the total suspend | 1695 | * This is based on the wall_to_monotonic offset and the total suspend |
| 1668 | * time. Calls to settimeofday will affect the value returned (which | 1696 | * time. Calls to settimeofday will affect the value returned (which |
| 1669 | * basically means that however wrong your real time clock is at boot time, | 1697 | * basically means that however wrong your real time clock is at boot time, |
| 1670 | * you get the right time here). | 1698 | * you get the right time here). |
| 1671 | */ | 1699 | */ |
| 1672 | void getboottime(struct timespec *ts) | 1700 | void getboottime64(struct timespec64 *ts) |
| 1673 | { | 1701 | { |
| 1674 | struct timekeeper *tk = &tk_core.timekeeper; | 1702 | struct timekeeper *tk = &tk_core.timekeeper; |
| 1675 | ktime_t t = ktime_sub(tk->offs_real, tk->offs_boot); | 1703 | ktime_t t = ktime_sub(tk->offs_real, tk->offs_boot); |
| 1676 | 1704 | ||
| 1677 | *ts = ktime_to_timespec(t); | 1705 | *ts = ktime_to_timespec64(t); |
| 1678 | } | 1706 | } |
| 1679 | EXPORT_SYMBOL_GPL(getboottime); | 1707 | EXPORT_SYMBOL_GPL(getboottime64); |
| 1680 | 1708 | ||
| 1681 | unsigned long get_seconds(void) | 1709 | unsigned long get_seconds(void) |
| 1682 | { | 1710 | { |
