diff options
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r-- | kernel/time/timekeeping.c | 297 |
1 files changed, 262 insertions, 35 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 49010d822f72..342408cf68dd 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/sysdev.h> | 17 | #include <linux/syscore_ops.h> |
18 | #include <linux/clocksource.h> | 18 | #include <linux/clocksource.h> |
19 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
@@ -32,6 +32,8 @@ struct timekeeper { | |||
32 | cycle_t cycle_interval; | 32 | cycle_t cycle_interval; |
33 | /* Number of clock shifted nano seconds in one NTP interval. */ | 33 | /* Number of clock shifted nano seconds in one NTP interval. */ |
34 | u64 xtime_interval; | 34 | u64 xtime_interval; |
35 | /* shifted nano seconds left over when rounding cycle_interval */ | ||
36 | s64 xtime_remainder; | ||
35 | /* Raw nano seconds accumulated per NTP interval. */ | 37 | /* Raw nano seconds accumulated per NTP interval. */ |
36 | u32 raw_interval; | 38 | u32 raw_interval; |
37 | 39 | ||
@@ -47,7 +49,7 @@ struct timekeeper { | |||
47 | u32 mult; | 49 | u32 mult; |
48 | }; | 50 | }; |
49 | 51 | ||
50 | struct timekeeper timekeeper; | 52 | static struct timekeeper timekeeper; |
51 | 53 | ||
52 | /** | 54 | /** |
53 | * timekeeper_setup_internals - Set up internals to use clocksource clock. | 55 | * timekeeper_setup_internals - Set up internals to use clocksource clock. |
@@ -62,7 +64,7 @@ struct timekeeper timekeeper; | |||
62 | static void timekeeper_setup_internals(struct clocksource *clock) | 64 | static void timekeeper_setup_internals(struct clocksource *clock) |
63 | { | 65 | { |
64 | cycle_t interval; | 66 | cycle_t interval; |
65 | u64 tmp; | 67 | u64 tmp, ntpinterval; |
66 | 68 | ||
67 | timekeeper.clock = clock; | 69 | timekeeper.clock = clock; |
68 | clock->cycle_last = clock->read(clock); | 70 | clock->cycle_last = clock->read(clock); |
@@ -70,6 +72,7 @@ static void timekeeper_setup_internals(struct clocksource *clock) | |||
70 | /* Do the ns -> cycle conversion first, using original mult */ | 72 | /* Do the ns -> cycle conversion first, using original mult */ |
71 | tmp = NTP_INTERVAL_LENGTH; | 73 | tmp = NTP_INTERVAL_LENGTH; |
72 | tmp <<= clock->shift; | 74 | tmp <<= clock->shift; |
75 | ntpinterval = tmp; | ||
73 | tmp += clock->mult/2; | 76 | tmp += clock->mult/2; |
74 | do_div(tmp, clock->mult); | 77 | do_div(tmp, clock->mult); |
75 | if (tmp == 0) | 78 | if (tmp == 0) |
@@ -80,6 +83,7 @@ static void timekeeper_setup_internals(struct clocksource *clock) | |||
80 | 83 | ||
81 | /* Go back from cycles -> shifted ns */ | 84 | /* Go back from cycles -> shifted ns */ |
82 | timekeeper.xtime_interval = (u64) interval * clock->mult; | 85 | timekeeper.xtime_interval = (u64) interval * clock->mult; |
86 | timekeeper.xtime_remainder = ntpinterval - timekeeper.xtime_interval; | ||
83 | timekeeper.raw_interval = | 87 | timekeeper.raw_interval = |
84 | ((u64) interval * clock->mult) >> clock->shift; | 88 | ((u64) interval * clock->mult) >> clock->shift; |
85 | 89 | ||
@@ -160,7 +164,7 @@ static struct timespec total_sleep_time; | |||
160 | /* | 164 | /* |
161 | * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. | 165 | * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. |
162 | */ | 166 | */ |
163 | struct timespec raw_time; | 167 | static struct timespec raw_time; |
164 | 168 | ||
165 | /* flag for if timekeeping is suspended */ | 169 | /* flag for if timekeeping is suspended */ |
166 | int __read_mostly timekeeping_suspended; | 170 | int __read_mostly timekeeping_suspended; |
@@ -284,6 +288,49 @@ void ktime_get_ts(struct timespec *ts) | |||
284 | } | 288 | } |
285 | EXPORT_SYMBOL_GPL(ktime_get_ts); | 289 | EXPORT_SYMBOL_GPL(ktime_get_ts); |
286 | 290 | ||
291 | #ifdef CONFIG_NTP_PPS | ||
292 | |||
293 | /** | ||
294 | * getnstime_raw_and_real - get day and raw monotonic time in timespec format | ||
295 | * @ts_raw: pointer to the timespec to be set to raw monotonic time | ||
296 | * @ts_real: pointer to the timespec to be set to the time of day | ||
297 | * | ||
298 | * This function reads both the time of day and raw monotonic time at the | ||
299 | * same time atomically and stores the resulting timestamps in timespec | ||
300 | * format. | ||
301 | */ | ||
302 | void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real) | ||
303 | { | ||
304 | unsigned long seq; | ||
305 | s64 nsecs_raw, nsecs_real; | ||
306 | |||
307 | WARN_ON_ONCE(timekeeping_suspended); | ||
308 | |||
309 | do { | ||
310 | u32 arch_offset; | ||
311 | |||
312 | seq = read_seqbegin(&xtime_lock); | ||
313 | |||
314 | *ts_raw = raw_time; | ||
315 | *ts_real = xtime; | ||
316 | |||
317 | nsecs_raw = timekeeping_get_ns_raw(); | ||
318 | nsecs_real = timekeeping_get_ns(); | ||
319 | |||
320 | /* If arch requires, add in gettimeoffset() */ | ||
321 | arch_offset = arch_gettimeoffset(); | ||
322 | nsecs_raw += arch_offset; | ||
323 | nsecs_real += arch_offset; | ||
324 | |||
325 | } while (read_seqretry(&xtime_lock, seq)); | ||
326 | |||
327 | timespec_add_ns(ts_raw, nsecs_raw); | ||
328 | timespec_add_ns(ts_real, nsecs_real); | ||
329 | } | ||
330 | EXPORT_SYMBOL(getnstime_raw_and_real); | ||
331 | |||
332 | #endif /* CONFIG_NTP_PPS */ | ||
333 | |||
287 | /** | 334 | /** |
288 | * do_gettimeofday - Returns the time of day in a timeval | 335 | * do_gettimeofday - Returns the time of day in a timeval |
289 | * @tv: pointer to the timeval to be set | 336 | * @tv: pointer to the timeval to be set |
@@ -306,7 +353,7 @@ EXPORT_SYMBOL(do_gettimeofday); | |||
306 | * | 353 | * |
307 | * Sets the time of day to the new time and update NTP and notify hrtimers | 354 | * Sets the time of day to the new time and update NTP and notify hrtimers |
308 | */ | 355 | */ |
309 | int do_settimeofday(struct timespec *tv) | 356 | int do_settimeofday(const struct timespec *tv) |
310 | { | 357 | { |
311 | struct timespec ts_delta; | 358 | struct timespec ts_delta; |
312 | unsigned long flags; | 359 | unsigned long flags; |
@@ -340,6 +387,42 @@ int do_settimeofday(struct timespec *tv) | |||
340 | 387 | ||
341 | EXPORT_SYMBOL(do_settimeofday); | 388 | EXPORT_SYMBOL(do_settimeofday); |
342 | 389 | ||
390 | |||
391 | /** | ||
392 | * timekeeping_inject_offset - Adds or subtracts from the current time. | ||
393 | * @tv: pointer to the timespec variable containing the offset | ||
394 | * | ||
395 | * Adds or subtracts an offset value from the current time. | ||
396 | */ | ||
397 | int timekeeping_inject_offset(struct timespec *ts) | ||
398 | { | ||
399 | unsigned long flags; | ||
400 | |||
401 | if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) | ||
402 | return -EINVAL; | ||
403 | |||
404 | write_seqlock_irqsave(&xtime_lock, flags); | ||
405 | |||
406 | timekeeping_forward_now(); | ||
407 | |||
408 | xtime = timespec_add(xtime, *ts); | ||
409 | wall_to_monotonic = timespec_sub(wall_to_monotonic, *ts); | ||
410 | |||
411 | timekeeper.ntp_error = 0; | ||
412 | ntp_clear(); | ||
413 | |||
414 | update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock, | ||
415 | timekeeper.mult); | ||
416 | |||
417 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
418 | |||
419 | /* signal hrtimers about time change */ | ||
420 | clock_was_set(); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | EXPORT_SYMBOL(timekeeping_inject_offset); | ||
425 | |||
343 | /** | 426 | /** |
344 | * change_clocksource - Swaps clocksources if a new one is available | 427 | * change_clocksource - Swaps clocksources if a new one is available |
345 | * | 428 | * |
@@ -513,14 +596,65 @@ void __init timekeeping_init(void) | |||
513 | static struct timespec timekeeping_suspend_time; | 596 | static struct timespec timekeeping_suspend_time; |
514 | 597 | ||
515 | /** | 598 | /** |
599 | * __timekeeping_inject_sleeptime - Internal function to add sleep interval | ||
600 | * @delta: pointer to a timespec delta value | ||
601 | * | ||
602 | * Takes a timespec offset measuring a suspend interval and properly | ||
603 | * adds the sleep offset to the timekeeping variables. | ||
604 | */ | ||
605 | static void __timekeeping_inject_sleeptime(struct timespec *delta) | ||
606 | { | ||
607 | xtime = timespec_add(xtime, *delta); | ||
608 | wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta); | ||
609 | total_sleep_time = timespec_add(total_sleep_time, *delta); | ||
610 | } | ||
611 | |||
612 | |||
613 | /** | ||
614 | * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values | ||
615 | * @delta: pointer to a timespec delta value | ||
616 | * | ||
617 | * This hook is for architectures that cannot support read_persistent_clock | ||
618 | * because their RTC/persistent clock is only accessible when irqs are enabled. | ||
619 | * | ||
620 | * This function should only be called by rtc_resume(), and allows | ||
621 | * a suspend offset to be injected into the timekeeping values. | ||
622 | */ | ||
623 | void timekeeping_inject_sleeptime(struct timespec *delta) | ||
624 | { | ||
625 | unsigned long flags; | ||
626 | struct timespec ts; | ||
627 | |||
628 | /* Make sure we don't set the clock twice */ | ||
629 | read_persistent_clock(&ts); | ||
630 | if (!(ts.tv_sec == 0 && ts.tv_nsec == 0)) | ||
631 | return; | ||
632 | |||
633 | write_seqlock_irqsave(&xtime_lock, flags); | ||
634 | timekeeping_forward_now(); | ||
635 | |||
636 | __timekeeping_inject_sleeptime(delta); | ||
637 | |||
638 | timekeeper.ntp_error = 0; | ||
639 | ntp_clear(); | ||
640 | update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock, | ||
641 | timekeeper.mult); | ||
642 | |||
643 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
644 | |||
645 | /* signal hrtimers about time change */ | ||
646 | clock_was_set(); | ||
647 | } | ||
648 | |||
649 | |||
650 | /** | ||
516 | * timekeeping_resume - Resumes the generic timekeeping subsystem. | 651 | * timekeeping_resume - Resumes the generic timekeeping subsystem. |
517 | * @dev: unused | ||
518 | * | 652 | * |
519 | * This is for the generic clocksource timekeeping. | 653 | * This is for the generic clocksource timekeeping. |
520 | * xtime/wall_to_monotonic/jiffies/etc are | 654 | * xtime/wall_to_monotonic/jiffies/etc are |
521 | * still managed by arch specific suspend/resume code. | 655 | * still managed by arch specific suspend/resume code. |
522 | */ | 656 | */ |
523 | static int timekeeping_resume(struct sys_device *dev) | 657 | static void timekeeping_resume(void) |
524 | { | 658 | { |
525 | unsigned long flags; | 659 | unsigned long flags; |
526 | struct timespec ts; | 660 | struct timespec ts; |
@@ -533,9 +667,7 @@ static int timekeeping_resume(struct sys_device *dev) | |||
533 | 667 | ||
534 | if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) { | 668 | if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) { |
535 | ts = timespec_sub(ts, timekeeping_suspend_time); | 669 | ts = timespec_sub(ts, timekeeping_suspend_time); |
536 | xtime = timespec_add(xtime, ts); | 670 | __timekeeping_inject_sleeptime(&ts); |
537 | wall_to_monotonic = timespec_sub(wall_to_monotonic, ts); | ||
538 | total_sleep_time = timespec_add(total_sleep_time, ts); | ||
539 | } | 671 | } |
540 | /* re-base the last cycle value */ | 672 | /* re-base the last cycle value */ |
541 | timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock); | 673 | timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock); |
@@ -548,12 +680,10 @@ static int timekeeping_resume(struct sys_device *dev) | |||
548 | clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL); | 680 | clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL); |
549 | 681 | ||
550 | /* Resume hrtimers */ | 682 | /* Resume hrtimers */ |
551 | hres_timers_resume(); | 683 | hrtimers_resume(); |
552 | |||
553 | return 0; | ||
554 | } | 684 | } |
555 | 685 | ||
556 | static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | 686 | static int timekeeping_suspend(void) |
557 | { | 687 | { |
558 | unsigned long flags; | 688 | unsigned long flags; |
559 | 689 | ||
@@ -571,26 +701,18 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | |||
571 | } | 701 | } |
572 | 702 | ||
573 | /* sysfs resume/suspend bits for timekeeping */ | 703 | /* sysfs resume/suspend bits for timekeeping */ |
574 | static struct sysdev_class timekeeping_sysclass = { | 704 | static struct syscore_ops timekeeping_syscore_ops = { |
575 | .name = "timekeeping", | ||
576 | .resume = timekeeping_resume, | 705 | .resume = timekeeping_resume, |
577 | .suspend = timekeeping_suspend, | 706 | .suspend = timekeeping_suspend, |
578 | }; | 707 | }; |
579 | 708 | ||
580 | static struct sys_device device_timer = { | 709 | static int __init timekeeping_init_ops(void) |
581 | .id = 0, | ||
582 | .cls = &timekeeping_sysclass, | ||
583 | }; | ||
584 | |||
585 | static int __init timekeeping_init_device(void) | ||
586 | { | 710 | { |
587 | int error = sysdev_class_register(&timekeeping_sysclass); | 711 | register_syscore_ops(&timekeeping_syscore_ops); |
588 | if (!error) | 712 | return 0; |
589 | error = sysdev_register(&device_timer); | ||
590 | return error; | ||
591 | } | 713 | } |
592 | 714 | ||
593 | device_initcall(timekeeping_init_device); | 715 | device_initcall(timekeeping_init_ops); |
594 | 716 | ||
595 | /* | 717 | /* |
596 | * If the error is already larger, we look ahead even further | 718 | * If the error is already larger, we look ahead even further |
@@ -719,7 +841,8 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) | |||
719 | 841 | ||
720 | /* Accumulate error between NTP and clock interval */ | 842 | /* Accumulate error between NTP and clock interval */ |
721 | timekeeper.ntp_error += tick_length << shift; | 843 | timekeeper.ntp_error += tick_length << shift; |
722 | timekeeper.ntp_error -= timekeeper.xtime_interval << | 844 | timekeeper.ntp_error -= |
845 | (timekeeper.xtime_interval + timekeeper.xtime_remainder) << | ||
723 | (timekeeper.ntp_error_shift + shift); | 846 | (timekeeper.ntp_error_shift + shift); |
724 | 847 | ||
725 | return offset; | 848 | return offset; |
@@ -731,7 +854,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) | |||
731 | * | 854 | * |
732 | * Called from the timer interrupt, must hold a write on xtime_lock. | 855 | * Called from the timer interrupt, must hold a write on xtime_lock. |
733 | */ | 856 | */ |
734 | void update_wall_time(void) | 857 | static void update_wall_time(void) |
735 | { | 858 | { |
736 | struct clocksource *clock; | 859 | struct clocksource *clock; |
737 | cycle_t offset; | 860 | cycle_t offset; |
@@ -823,7 +946,7 @@ void update_wall_time(void) | |||
823 | * getboottime - Return the real time of system boot. | 946 | * getboottime - Return the real time of system boot. |
824 | * @ts: pointer to the timespec to be set | 947 | * @ts: pointer to the timespec to be set |
825 | * | 948 | * |
826 | * Returns the time of day in a timespec. | 949 | * Returns the wall-time of boot in a timespec. |
827 | * | 950 | * |
828 | * This is based on the wall_to_monotonic offset and the total suspend | 951 | * This is based on the wall_to_monotonic offset and the total suspend |
829 | * time. Calls to settimeofday will affect the value returned (which | 952 | * time. Calls to settimeofday will affect the value returned (which |
@@ -841,6 +964,55 @@ void getboottime(struct timespec *ts) | |||
841 | } | 964 | } |
842 | EXPORT_SYMBOL_GPL(getboottime); | 965 | EXPORT_SYMBOL_GPL(getboottime); |
843 | 966 | ||
967 | |||
968 | /** | ||
969 | * get_monotonic_boottime - Returns monotonic time since boot | ||
970 | * @ts: pointer to the timespec to be set | ||
971 | * | ||
972 | * Returns the monotonic time since boot in a timespec. | ||
973 | * | ||
974 | * This is similar to CLOCK_MONTONIC/ktime_get_ts, but also | ||
975 | * includes the time spent in suspend. | ||
976 | */ | ||
977 | void get_monotonic_boottime(struct timespec *ts) | ||
978 | { | ||
979 | struct timespec tomono, sleep; | ||
980 | unsigned int seq; | ||
981 | s64 nsecs; | ||
982 | |||
983 | WARN_ON(timekeeping_suspended); | ||
984 | |||
985 | do { | ||
986 | seq = read_seqbegin(&xtime_lock); | ||
987 | *ts = xtime; | ||
988 | tomono = wall_to_monotonic; | ||
989 | sleep = total_sleep_time; | ||
990 | nsecs = timekeeping_get_ns(); | ||
991 | |||
992 | } while (read_seqretry(&xtime_lock, seq)); | ||
993 | |||
994 | set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec, | ||
995 | ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs); | ||
996 | } | ||
997 | EXPORT_SYMBOL_GPL(get_monotonic_boottime); | ||
998 | |||
999 | /** | ||
1000 | * ktime_get_boottime - Returns monotonic time since boot in a ktime | ||
1001 | * | ||
1002 | * Returns the monotonic time since boot in a ktime | ||
1003 | * | ||
1004 | * This is similar to CLOCK_MONTONIC/ktime_get, but also | ||
1005 | * includes the time spent in suspend. | ||
1006 | */ | ||
1007 | ktime_t ktime_get_boottime(void) | ||
1008 | { | ||
1009 | struct timespec ts; | ||
1010 | |||
1011 | get_monotonic_boottime(&ts); | ||
1012 | return timespec_to_ktime(ts); | ||
1013 | } | ||
1014 | EXPORT_SYMBOL_GPL(ktime_get_boottime); | ||
1015 | |||
844 | /** | 1016 | /** |
845 | * monotonic_to_bootbased - Convert the monotonic time to boot based. | 1017 | * monotonic_to_bootbased - Convert the monotonic time to boot based. |
846 | * @ts: pointer to the timespec to be converted | 1018 | * @ts: pointer to the timespec to be converted |
@@ -862,11 +1034,6 @@ struct timespec __current_kernel_time(void) | |||
862 | return xtime; | 1034 | return xtime; |
863 | } | 1035 | } |
864 | 1036 | ||
865 | struct timespec __get_wall_to_monotonic(void) | ||
866 | { | ||
867 | return wall_to_monotonic; | ||
868 | } | ||
869 | |||
870 | struct timespec current_kernel_time(void) | 1037 | struct timespec current_kernel_time(void) |
871 | { | 1038 | { |
872 | struct timespec now; | 1039 | struct timespec now; |
@@ -898,3 +1065,63 @@ struct timespec get_monotonic_coarse(void) | |||
898 | now.tv_nsec + mono.tv_nsec); | 1065 | now.tv_nsec + mono.tv_nsec); |
899 | return now; | 1066 | return now; |
900 | } | 1067 | } |
1068 | |||
1069 | /* | ||
1070 | * The 64-bit jiffies value is not atomic - you MUST NOT read it | ||
1071 | * without sampling the sequence number in xtime_lock. | ||
1072 | * jiffies is defined in the linker script... | ||
1073 | */ | ||
1074 | void do_timer(unsigned long ticks) | ||
1075 | { | ||
1076 | jiffies_64 += ticks; | ||
1077 | update_wall_time(); | ||
1078 | calc_global_load(ticks); | ||
1079 | } | ||
1080 | |||
1081 | /** | ||
1082 | * get_xtime_and_monotonic_and_sleep_offset() - get xtime, wall_to_monotonic, | ||
1083 | * and sleep offsets. | ||
1084 | * @xtim: pointer to timespec to be set with xtime | ||
1085 | * @wtom: pointer to timespec to be set with wall_to_monotonic | ||
1086 | * @sleep: pointer to timespec to be set with time in suspend | ||
1087 | */ | ||
1088 | void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, | ||
1089 | struct timespec *wtom, struct timespec *sleep) | ||
1090 | { | ||
1091 | unsigned long seq; | ||
1092 | |||
1093 | do { | ||
1094 | seq = read_seqbegin(&xtime_lock); | ||
1095 | *xtim = xtime; | ||
1096 | *wtom = wall_to_monotonic; | ||
1097 | *sleep = total_sleep_time; | ||
1098 | } while (read_seqretry(&xtime_lock, seq)); | ||
1099 | } | ||
1100 | |||
1101 | /** | ||
1102 | * ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format | ||
1103 | */ | ||
1104 | ktime_t ktime_get_monotonic_offset(void) | ||
1105 | { | ||
1106 | unsigned long seq; | ||
1107 | struct timespec wtom; | ||
1108 | |||
1109 | do { | ||
1110 | seq = read_seqbegin(&xtime_lock); | ||
1111 | wtom = wall_to_monotonic; | ||
1112 | } while (read_seqretry(&xtime_lock, seq)); | ||
1113 | return timespec_to_ktime(wtom); | ||
1114 | } | ||
1115 | |||
1116 | /** | ||
1117 | * xtime_update() - advances the timekeeping infrastructure | ||
1118 | * @ticks: number of ticks, that have elapsed since the last call. | ||
1119 | * | ||
1120 | * Must be called with interrupts disabled. | ||
1121 | */ | ||
1122 | void xtime_update(unsigned long ticks) | ||
1123 | { | ||
1124 | write_seqlock(&xtime_lock); | ||
1125 | do_timer(ticks); | ||
1126 | write_sequnlock(&xtime_lock); | ||
1127 | } | ||