diff options
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/clocksource.c | 57 |
1 files changed, 42 insertions, 15 deletions
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index e713ef7d19a7..50a8736757f3 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
@@ -181,6 +181,7 @@ static int finished_booting; | |||
181 | 181 | ||
182 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG | 182 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG |
183 | static void clocksource_watchdog_work(struct work_struct *work); | 183 | static void clocksource_watchdog_work(struct work_struct *work); |
184 | static void clocksource_select(void); | ||
184 | 185 | ||
185 | static LIST_HEAD(watchdog_list); | 186 | static LIST_HEAD(watchdog_list); |
186 | static struct clocksource *watchdog; | 187 | static struct clocksource *watchdog; |
@@ -301,13 +302,30 @@ static void clocksource_watchdog(unsigned long data) | |||
301 | if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && | 302 | if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && |
302 | (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && | 303 | (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && |
303 | (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) { | 304 | (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) { |
305 | /* Mark it valid for high-res. */ | ||
304 | cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; | 306 | cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; |
307 | |||
308 | /* | ||
309 | * clocksource_done_booting() will sort it if | ||
310 | * finished_booting is not set yet. | ||
311 | */ | ||
312 | if (!finished_booting) | ||
313 | continue; | ||
314 | |||
305 | /* | 315 | /* |
306 | * We just marked the clocksource as highres-capable, | 316 | * If this is not the current clocksource let |
307 | * notify the rest of the system as well so that we | 317 | * the watchdog thread reselect it. Due to the |
308 | * transition into high-res mode: | 318 | * change to high res this clocksource might |
319 | * be preferred now. If it is the current | ||
320 | * clocksource let the tick code know about | ||
321 | * that change. | ||
309 | */ | 322 | */ |
310 | tick_clock_notify(); | 323 | if (cs != curr_clocksource) { |
324 | cs->flags |= CLOCK_SOURCE_RESELECT; | ||
325 | schedule_work(&watchdog_work); | ||
326 | } else { | ||
327 | tick_clock_notify(); | ||
328 | } | ||
311 | } | 329 | } |
312 | } | 330 | } |
313 | 331 | ||
@@ -404,19 +422,25 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs) | |||
404 | spin_unlock_irqrestore(&watchdog_lock, flags); | 422 | spin_unlock_irqrestore(&watchdog_lock, flags); |
405 | } | 423 | } |
406 | 424 | ||
407 | static int clocksource_watchdog_kthread(void *data) | 425 | static int __clocksource_watchdog_kthread(void) |
408 | { | 426 | { |
409 | struct clocksource *cs, *tmp; | 427 | struct clocksource *cs, *tmp; |
410 | unsigned long flags; | 428 | unsigned long flags; |
411 | LIST_HEAD(unstable); | 429 | LIST_HEAD(unstable); |
430 | int select = 0; | ||
412 | 431 | ||
413 | mutex_lock(&clocksource_mutex); | ||
414 | spin_lock_irqsave(&watchdog_lock, flags); | 432 | spin_lock_irqsave(&watchdog_lock, flags); |
415 | list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) | 433 | list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) { |
416 | if (cs->flags & CLOCK_SOURCE_UNSTABLE) { | 434 | if (cs->flags & CLOCK_SOURCE_UNSTABLE) { |
417 | list_del_init(&cs->wd_list); | 435 | list_del_init(&cs->wd_list); |
418 | list_add(&cs->wd_list, &unstable); | 436 | list_add(&cs->wd_list, &unstable); |
437 | select = 1; | ||
438 | } | ||
439 | if (cs->flags & CLOCK_SOURCE_RESELECT) { | ||
440 | cs->flags &= ~CLOCK_SOURCE_RESELECT; | ||
441 | select = 1; | ||
419 | } | 442 | } |
443 | } | ||
420 | /* Check if the watchdog timer needs to be stopped. */ | 444 | /* Check if the watchdog timer needs to be stopped. */ |
421 | clocksource_stop_watchdog(); | 445 | clocksource_stop_watchdog(); |
422 | spin_unlock_irqrestore(&watchdog_lock, flags); | 446 | spin_unlock_irqrestore(&watchdog_lock, flags); |
@@ -426,6 +450,14 @@ static int clocksource_watchdog_kthread(void *data) | |||
426 | list_del_init(&cs->wd_list); | 450 | list_del_init(&cs->wd_list); |
427 | __clocksource_change_rating(cs, 0); | 451 | __clocksource_change_rating(cs, 0); |
428 | } | 452 | } |
453 | return select; | ||
454 | } | ||
455 | |||
456 | static int clocksource_watchdog_kthread(void *data) | ||
457 | { | ||
458 | mutex_lock(&clocksource_mutex); | ||
459 | if (__clocksource_watchdog_kthread()) | ||
460 | clocksource_select(); | ||
429 | mutex_unlock(&clocksource_mutex); | 461 | mutex_unlock(&clocksource_mutex); |
430 | return 0; | 462 | return 0; |
431 | } | 463 | } |
@@ -445,7 +477,7 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs) | |||
445 | 477 | ||
446 | static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { } | 478 | static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { } |
447 | static inline void clocksource_resume_watchdog(void) { } | 479 | static inline void clocksource_resume_watchdog(void) { } |
448 | static inline int clocksource_watchdog_kthread(void *data) { return 0; } | 480 | static inline int __clocksource_watchdog_kthread(void) { return 0; } |
449 | static bool clocksource_is_watchdog(struct clocksource *cs) { return false; } | 481 | static bool clocksource_is_watchdog(struct clocksource *cs) { return false; } |
450 | 482 | ||
451 | #endif /* CONFIG_CLOCKSOURCE_WATCHDOG */ | 483 | #endif /* CONFIG_CLOCKSOURCE_WATCHDOG */ |
@@ -647,16 +679,11 @@ static int __init clocksource_done_booting(void) | |||
647 | { | 679 | { |
648 | mutex_lock(&clocksource_mutex); | 680 | mutex_lock(&clocksource_mutex); |
649 | curr_clocksource = clocksource_default_clock(); | 681 | curr_clocksource = clocksource_default_clock(); |
650 | mutex_unlock(&clocksource_mutex); | ||
651 | |||
652 | finished_booting = 1; | 682 | finished_booting = 1; |
653 | |||
654 | /* | 683 | /* |
655 | * Run the watchdog first to eliminate unstable clock sources | 684 | * Run the watchdog first to eliminate unstable clock sources |
656 | */ | 685 | */ |
657 | clocksource_watchdog_kthread(NULL); | 686 | __clocksource_watchdog_kthread(); |
658 | |||
659 | mutex_lock(&clocksource_mutex); | ||
660 | clocksource_select(); | 687 | clocksource_select(); |
661 | mutex_unlock(&clocksource_mutex); | 688 | mutex_unlock(&clocksource_mutex); |
662 | return 0; | 689 | return 0; |
@@ -789,7 +816,6 @@ static void __clocksource_change_rating(struct clocksource *cs, int rating) | |||
789 | list_del(&cs->list); | 816 | list_del(&cs->list); |
790 | cs->rating = rating; | 817 | cs->rating = rating; |
791 | clocksource_enqueue(cs); | 818 | clocksource_enqueue(cs); |
792 | clocksource_select(); | ||
793 | } | 819 | } |
794 | 820 | ||
795 | /** | 821 | /** |
@@ -801,6 +827,7 @@ void clocksource_change_rating(struct clocksource *cs, int rating) | |||
801 | { | 827 | { |
802 | mutex_lock(&clocksource_mutex); | 828 | mutex_lock(&clocksource_mutex); |
803 | __clocksource_change_rating(cs, rating); | 829 | __clocksource_change_rating(cs, rating); |
830 | clocksource_select(); | ||
804 | mutex_unlock(&clocksource_mutex); | 831 | mutex_unlock(&clocksource_mutex); |
805 | } | 832 | } |
806 | EXPORT_SYMBOL(clocksource_change_rating); | 833 | EXPORT_SYMBOL(clocksource_change_rating); |