diff options
-rw-r--r-- | arch/x86/kernel/tsc.c | 8 | ||||
-rw-r--r-- | include/linux/clocksource.h | 1 | ||||
-rw-r--r-- | kernel/time/clocksource.c | 33 |
3 files changed, 36 insertions, 6 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 968425422c46..fc3672a303d6 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
@@ -767,12 +767,14 @@ void mark_tsc_unstable(char *reason) | |||
767 | { | 767 | { |
768 | if (!tsc_unstable) { | 768 | if (!tsc_unstable) { |
769 | tsc_unstable = 1; | 769 | tsc_unstable = 1; |
770 | printk("Marking TSC unstable due to %s\n", reason); | 770 | printk(KERN_INFO "Marking TSC unstable due to %s\n", reason); |
771 | /* Change only the rating, when not registered */ | 771 | /* Change only the rating, when not registered */ |
772 | if (clocksource_tsc.mult) | 772 | if (clocksource_tsc.mult) |
773 | clocksource_change_rating(&clocksource_tsc, 0); | 773 | clocksource_mark_unstable(&clocksource_tsc); |
774 | else | 774 | else { |
775 | clocksource_tsc.flags |= CLOCK_SOURCE_UNSTABLE; | ||
775 | clocksource_tsc.rating = 0; | 776 | clocksource_tsc.rating = 0; |
777 | } | ||
776 | } | 778 | } |
777 | } | 779 | } |
778 | 780 | ||
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 9ea40ff26f0e..83d2fbd81b93 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
@@ -277,6 +277,7 @@ extern struct clocksource* clocksource_get_next(void); | |||
277 | extern void clocksource_change_rating(struct clocksource *cs, int rating); | 277 | extern void clocksource_change_rating(struct clocksource *cs, int rating); |
278 | extern void clocksource_resume(void); | 278 | extern void clocksource_resume(void); |
279 | extern struct clocksource * __init __weak clocksource_default_clock(void); | 279 | extern struct clocksource * __init __weak clocksource_default_clock(void); |
280 | extern void clocksource_mark_unstable(struct clocksource *cs); | ||
280 | 281 | ||
281 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL | 282 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL |
282 | extern void update_vsyscall(struct timespec *ts, struct clocksource *c); | 283 | extern void update_vsyscall(struct timespec *ts, struct clocksource *c); |
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index e0c86ad6e9fb..a0af4ffcb6e5 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
@@ -149,15 +149,42 @@ static void clocksource_watchdog_work(struct work_struct *work) | |||
149 | kthread_run(clocksource_watchdog_kthread, NULL, "kwatchdog"); | 149 | kthread_run(clocksource_watchdog_kthread, NULL, "kwatchdog"); |
150 | } | 150 | } |
151 | 151 | ||
152 | static void clocksource_unstable(struct clocksource *cs, int64_t delta) | 152 | static void __clocksource_unstable(struct clocksource *cs) |
153 | { | 153 | { |
154 | printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", | ||
155 | cs->name, delta); | ||
156 | cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); | 154 | cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); |
157 | cs->flags |= CLOCK_SOURCE_UNSTABLE; | 155 | cs->flags |= CLOCK_SOURCE_UNSTABLE; |
158 | schedule_work(&watchdog_work); | 156 | schedule_work(&watchdog_work); |
159 | } | 157 | } |
160 | 158 | ||
159 | static void clocksource_unstable(struct clocksource *cs, int64_t delta) | ||
160 | { | ||
161 | printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", | ||
162 | cs->name, delta); | ||
163 | __clocksource_unstable(cs); | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * clocksource_mark_unstable - mark clocksource unstable via watchdog | ||
168 | * @cs: clocksource to be marked unstable | ||
169 | * | ||
170 | * This function is called instead of clocksource_change_rating from | ||
171 | * cpu hotplug code to avoid a deadlock between the clocksource mutex | ||
172 | * and the cpu hotplug mutex. It defers the update of the clocksource | ||
173 | * to the watchdog thread. | ||
174 | */ | ||
175 | void clocksource_mark_unstable(struct clocksource *cs) | ||
176 | { | ||
177 | unsigned long flags; | ||
178 | |||
179 | spin_lock_irqsave(&watchdog_lock, flags); | ||
180 | if (!(cs->flags & CLOCK_SOURCE_UNSTABLE)) { | ||
181 | if (list_empty(&cs->wd_list)) | ||
182 | list_add(&cs->wd_list, &watchdog_list); | ||
183 | __clocksource_unstable(cs); | ||
184 | } | ||
185 | spin_unlock_irqrestore(&watchdog_lock, flags); | ||
186 | } | ||
187 | |||
161 | static void clocksource_watchdog(unsigned long data) | 188 | static void clocksource_watchdog(unsigned long data) |
162 | { | 189 | { |
163 | struct clocksource *cs; | 190 | struct clocksource *cs; |