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; |
