diff options
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/clocksource.c | 23 | ||||
-rw-r--r-- | kernel/time/tick-common.c | 12 | ||||
-rw-r--r-- | kernel/time/tick-oneshot.c | 17 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 9 |
4 files changed, 55 insertions, 6 deletions
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index ecfd7b5187e0..592bf584d1d2 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
@@ -402,9 +402,6 @@ int clocksource_register(struct clocksource *c) | |||
402 | unsigned long flags; | 402 | unsigned long flags; |
403 | int ret; | 403 | int ret; |
404 | 404 | ||
405 | /* save mult_orig on registration */ | ||
406 | c->mult_orig = c->mult; | ||
407 | |||
408 | spin_lock_irqsave(&clocksource_lock, flags); | 405 | spin_lock_irqsave(&clocksource_lock, flags); |
409 | ret = clocksource_enqueue(c); | 406 | ret = clocksource_enqueue(c); |
410 | if (!ret) | 407 | if (!ret) |
@@ -512,6 +509,18 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, | |||
512 | } | 509 | } |
513 | } | 510 | } |
514 | 511 | ||
512 | /* | ||
513 | * Check to make sure we don't switch to a non-highres capable | ||
514 | * clocksource if the tick code is in oneshot mode (highres or nohz) | ||
515 | */ | ||
516 | if (tick_oneshot_mode_active() && | ||
517 | !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) { | ||
518 | printk(KERN_WARNING "%s clocksource is not HRT compatible. " | ||
519 | "Cannot switch while in HRT/NOHZ mode\n", ovr->name); | ||
520 | ovr = NULL; | ||
521 | override_name[0] = 0; | ||
522 | } | ||
523 | |||
515 | /* Reselect, when the override name has changed */ | 524 | /* Reselect, when the override name has changed */ |
516 | if (ovr != clocksource_override) { | 525 | if (ovr != clocksource_override) { |
517 | clocksource_override = ovr; | 526 | clocksource_override = ovr; |
@@ -540,7 +549,13 @@ sysfs_show_available_clocksources(struct sys_device *dev, | |||
540 | 549 | ||
541 | spin_lock_irq(&clocksource_lock); | 550 | spin_lock_irq(&clocksource_lock); |
542 | list_for_each_entry(src, &clocksource_list, list) { | 551 | list_for_each_entry(src, &clocksource_list, list) { |
543 | count += snprintf(buf + count, | 552 | /* |
553 | * Don't show non-HRES clocksource if the tick code is | ||
554 | * in one shot mode (highres=on or nohz=on) | ||
555 | */ | ||
556 | if (!tick_oneshot_mode_active() || | ||
557 | (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) | ||
558 | count += snprintf(buf + count, | ||
544 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), | 559 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), |
545 | "%s ", src->name); | 560 | "%s ", src->name); |
546 | } | 561 | } |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 21a5ca849514..83c4417b6a3c 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
@@ -93,7 +93,17 @@ void tick_handle_periodic(struct clock_event_device *dev) | |||
93 | for (;;) { | 93 | for (;;) { |
94 | if (!clockevents_program_event(dev, next, ktime_get())) | 94 | if (!clockevents_program_event(dev, next, ktime_get())) |
95 | return; | 95 | return; |
96 | tick_periodic(cpu); | 96 | /* |
97 | * Have to be careful here. If we're in oneshot mode, | ||
98 | * before we call tick_periodic() in a loop, we need | ||
99 | * to be sure we're using a real hardware clocksource. | ||
100 | * Otherwise we could get trapped in an infinite | ||
101 | * loop, as the tick_periodic() increments jiffies, | ||
102 | * when then will increment time, posibly causing | ||
103 | * the loop to trigger again and again. | ||
104 | */ | ||
105 | if (timekeeping_valid_for_hres()) | ||
106 | tick_periodic(cpu); | ||
97 | next = ktime_add(next, tick_period); | 107 | next = ktime_add(next, tick_period); |
98 | } | 108 | } |
99 | } | 109 | } |
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 2e8de678e767..a96c0e2b89cf 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c | |||
@@ -128,6 +128,23 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) | |||
128 | return 0; | 128 | return 0; |
129 | } | 129 | } |
130 | 130 | ||
131 | /** | ||
132 | * tick_check_oneshot_mode - check whether the system is in oneshot mode | ||
133 | * | ||
134 | * returns 1 when either nohz or highres are enabled. otherwise 0. | ||
135 | */ | ||
136 | int tick_oneshot_mode_active(void) | ||
137 | { | ||
138 | unsigned long flags; | ||
139 | int ret; | ||
140 | |||
141 | local_irq_save(flags); | ||
142 | ret = __get_cpu_var(tick_cpu_device).mode == TICKDEV_MODE_ONESHOT; | ||
143 | local_irq_restore(flags); | ||
144 | |||
145 | return ret; | ||
146 | } | ||
147 | |||
131 | #ifdef CONFIG_HIGH_RES_TIMERS | 148 | #ifdef CONFIG_HIGH_RES_TIMERS |
132 | /** | 149 | /** |
133 | * tick_init_highres - switch to high resolution mode | 150 | * tick_init_highres - switch to high resolution mode |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 687dff49f6e7..e8c77d9c633a 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -22,7 +22,7 @@ | |||
22 | 22 | ||
23 | /* | 23 | /* |
24 | * This read-write spinlock protects us from races in SMP while | 24 | * This read-write spinlock protects us from races in SMP while |
25 | * playing with xtime and avenrun. | 25 | * playing with xtime. |
26 | */ | 26 | */ |
27 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); | 27 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); |
28 | 28 | ||
@@ -77,6 +77,10 @@ static void clocksource_forward_now(void) | |||
77 | clock->cycle_last = cycle_now; | 77 | clock->cycle_last = cycle_now; |
78 | 78 | ||
79 | nsec = cyc2ns(clock, cycle_delta); | 79 | nsec = cyc2ns(clock, cycle_delta); |
80 | |||
81 | /* If arch requires, add in gettimeoffset() */ | ||
82 | nsec += arch_gettimeoffset(); | ||
83 | |||
80 | timespec_add_ns(&xtime, nsec); | 84 | timespec_add_ns(&xtime, nsec); |
81 | 85 | ||
82 | nsec = ((s64)cycle_delta * clock->mult_orig) >> clock->shift; | 86 | nsec = ((s64)cycle_delta * clock->mult_orig) >> clock->shift; |
@@ -111,6 +115,9 @@ void getnstimeofday(struct timespec *ts) | |||
111 | /* convert to nanoseconds: */ | 115 | /* convert to nanoseconds: */ |
112 | nsecs = cyc2ns(clock, cycle_delta); | 116 | nsecs = cyc2ns(clock, cycle_delta); |
113 | 117 | ||
118 | /* If arch requires, add in gettimeoffset() */ | ||
119 | nsecs += arch_gettimeoffset(); | ||
120 | |||
114 | } while (read_seqretry(&xtime_lock, seq)); | 121 | } while (read_seqretry(&xtime_lock, seq)); |
115 | 122 | ||
116 | timespec_add_ns(ts, nsecs); | 123 | timespec_add_ns(ts, nsecs); |