|
@@ -181,6 +181,7 @@ static int finished_booting;
|
|
|
|
|
|
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
|
|
|
static void clocksource_watchdog_work(struct work_struct *work);
|
|
|
+static void clocksource_select(void);
|
|
|
|
|
|
static LIST_HEAD(watchdog_list);
|
|
|
static struct clocksource *watchdog;
|
|
@@ -301,13 +302,30 @@ static void clocksource_watchdog(unsigned long data)
|
|
|
if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) &&
|
|
|
(cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) &&
|
|
|
(watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) {
|
|
|
+ /* Mark it valid for high-res. */
|
|
|
cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * clocksource_done_booting() will sort it if
|
|
|
+ * finished_booting is not set yet.
|
|
|
+ */
|
|
|
+ if (!finished_booting)
|
|
|
+ continue;
|
|
|
+
|
|
|
/*
|
|
|
- * We just marked the clocksource as highres-capable,
|
|
|
- * notify the rest of the system as well so that we
|
|
|
- * transition into high-res mode:
|
|
|
+ * If this is not the current clocksource let
|
|
|
+ * the watchdog thread reselect it. Due to the
|
|
|
+ * change to high res this clocksource might
|
|
|
+ * be preferred now. If it is the current
|
|
|
+ * clocksource let the tick code know about
|
|
|
+ * that change.
|
|
|
*/
|
|
|
- tick_clock_notify();
|
|
|
+ if (cs != curr_clocksource) {
|
|
|
+ cs->flags |= CLOCK_SOURCE_RESELECT;
|
|
|
+ schedule_work(&watchdog_work);
|
|
|
+ } else {
|
|
|
+ tick_clock_notify();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -404,19 +422,25 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs)
|
|
|
spin_unlock_irqrestore(&watchdog_lock, flags);
|
|
|
}
|
|
|
|
|
|
-static int clocksource_watchdog_kthread(void *data)
|
|
|
+static int __clocksource_watchdog_kthread(void)
|
|
|
{
|
|
|
struct clocksource *cs, *tmp;
|
|
|
unsigned long flags;
|
|
|
LIST_HEAD(unstable);
|
|
|
+ int select = 0;
|
|
|
|
|
|
- mutex_lock(&clocksource_mutex);
|
|
|
spin_lock_irqsave(&watchdog_lock, flags);
|
|
|
- list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list)
|
|
|
+ list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
|
|
|
if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
|
|
|
list_del_init(&cs->wd_list);
|
|
|
list_add(&cs->wd_list, &unstable);
|
|
|
+ select = 1;
|
|
|
+ }
|
|
|
+ if (cs->flags & CLOCK_SOURCE_RESELECT) {
|
|
|
+ cs->flags &= ~CLOCK_SOURCE_RESELECT;
|
|
|
+ select = 1;
|
|
|
}
|
|
|
+ }
|
|
|
/* Check if the watchdog timer needs to be stopped. */
|
|
|
clocksource_stop_watchdog();
|
|
|
spin_unlock_irqrestore(&watchdog_lock, flags);
|
|
@@ -426,6 +450,14 @@ static int clocksource_watchdog_kthread(void *data)
|
|
|
list_del_init(&cs->wd_list);
|
|
|
__clocksource_change_rating(cs, 0);
|
|
|
}
|
|
|
+ return select;
|
|
|
+}
|
|
|
+
|
|
|
+static int clocksource_watchdog_kthread(void *data)
|
|
|
+{
|
|
|
+ mutex_lock(&clocksource_mutex);
|
|
|
+ if (__clocksource_watchdog_kthread())
|
|
|
+ clocksource_select();
|
|
|
mutex_unlock(&clocksource_mutex);
|
|
|
return 0;
|
|
|
}
|
|
@@ -445,7 +477,7 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs)
|
|
|
|
|
|
static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }
|
|
|
static inline void clocksource_resume_watchdog(void) { }
|
|
|
-static inline int clocksource_watchdog_kthread(void *data) { return 0; }
|
|
|
+static inline int __clocksource_watchdog_kthread(void) { return 0; }
|
|
|
static bool clocksource_is_watchdog(struct clocksource *cs) { return false; }
|
|
|
|
|
|
#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
|
|
@@ -647,16 +679,11 @@ static int __init clocksource_done_booting(void)
|
|
|
{
|
|
|
mutex_lock(&clocksource_mutex);
|
|
|
curr_clocksource = clocksource_default_clock();
|
|
|
- mutex_unlock(&clocksource_mutex);
|
|
|
-
|
|
|
finished_booting = 1;
|
|
|
-
|
|
|
/*
|
|
|
* Run the watchdog first to eliminate unstable clock sources
|
|
|
*/
|
|
|
- clocksource_watchdog_kthread(NULL);
|
|
|
-
|
|
|
- mutex_lock(&clocksource_mutex);
|
|
|
+ __clocksource_watchdog_kthread();
|
|
|
clocksource_select();
|
|
|
mutex_unlock(&clocksource_mutex);
|
|
|
return 0;
|
|
@@ -789,7 +816,6 @@ static void __clocksource_change_rating(struct clocksource *cs, int rating)
|
|
|
list_del(&cs->list);
|
|
|
cs->rating = rating;
|
|
|
clocksource_enqueue(cs);
|
|
|
- clocksource_select();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -801,6 +827,7 @@ void clocksource_change_rating(struct clocksource *cs, int rating)
|
|
|
{
|
|
|
mutex_lock(&clocksource_mutex);
|
|
|
__clocksource_change_rating(cs, rating);
|
|
|
+ clocksource_select();
|
|
|
mutex_unlock(&clocksource_mutex);
|
|
|
}
|
|
|
EXPORT_SYMBOL(clocksource_change_rating);
|