clocksource: Refactor clocksource watchdog
Refactor clocksource watchdog code to make it more readable. Add clocksource_dequeue_watchdog to remove a clocksource from the watchdog list when it is unregistered. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Ingo Molnar <mingo@elte.hu> Acked-by: John Stultz <johnstul@us.ibm.com> Cc: Daniel Walker <dwalker@fifo99.com> LKML-Reference: <20090814134809.110881699@de.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
0f8e8ef7c2
commit
fb63a0ebe6
1 changed files with 69 additions and 28 deletions
|
@ -145,6 +145,7 @@ static struct clocksource *watchdog;
|
|||
static struct timer_list watchdog_timer;
|
||||
static DEFINE_SPINLOCK(watchdog_lock);
|
||||
static cycle_t watchdog_last;
|
||||
static int watchdog_running;
|
||||
|
||||
/*
|
||||
* Interval: 0.5sec Threshold: 0.0625s
|
||||
|
@ -168,6 +169,8 @@ static void clocksource_watchdog(unsigned long data)
|
|||
int64_t wd_nsec, cs_nsec;
|
||||
|
||||
spin_lock(&watchdog_lock);
|
||||
if (!watchdog_running)
|
||||
goto out;
|
||||
|
||||
wdnow = watchdog->read(watchdog);
|
||||
wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask);
|
||||
|
@ -217,9 +220,30 @@ static void clocksource_watchdog(unsigned long data)
|
|||
watchdog_timer.expires += WATCHDOG_INTERVAL;
|
||||
add_timer_on(&watchdog_timer, next_cpu);
|
||||
}
|
||||
out:
|
||||
spin_unlock(&watchdog_lock);
|
||||
}
|
||||
|
||||
static inline void clocksource_start_watchdog(void)
|
||||
{
|
||||
if (watchdog_running || !watchdog || list_empty(&watchdog_list))
|
||||
return;
|
||||
init_timer(&watchdog_timer);
|
||||
watchdog_timer.function = clocksource_watchdog;
|
||||
watchdog_last = watchdog->read(watchdog);
|
||||
watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;
|
||||
add_timer_on(&watchdog_timer, cpumask_first(cpu_online_mask));
|
||||
watchdog_running = 1;
|
||||
}
|
||||
|
||||
static inline void clocksource_stop_watchdog(void)
|
||||
{
|
||||
if (!watchdog_running || (watchdog && !list_empty(&watchdog_list)))
|
||||
return;
|
||||
del_timer(&watchdog_timer);
|
||||
watchdog_running = 0;
|
||||
}
|
||||
|
||||
static inline void clocksource_reset_watchdog(void)
|
||||
{
|
||||
struct clocksource *cs;
|
||||
|
@ -237,55 +261,70 @@ static void clocksource_resume_watchdog(void)
|
|||
spin_unlock_irqrestore(&watchdog_lock, flags);
|
||||
}
|
||||
|
||||
static void clocksource_check_watchdog(struct clocksource *cs)
|
||||
static void clocksource_enqueue_watchdog(struct clocksource *cs)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&watchdog_lock, flags);
|
||||
if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {
|
||||
int started = !list_empty(&watchdog_list);
|
||||
|
||||
/* cs is a clocksource to be watched. */
|
||||
list_add(&cs->wd_list, &watchdog_list);
|
||||
if (!started && watchdog) {
|
||||
watchdog_last = watchdog->read(watchdog);
|
||||
watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;
|
||||
add_timer_on(&watchdog_timer,
|
||||
cpumask_first(cpu_online_mask));
|
||||
}
|
||||
cs->flags &= ~CLOCK_SOURCE_WATCHDOG;
|
||||
} else {
|
||||
/* cs is a watchdog. */
|
||||
if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
|
||||
cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
|
||||
|
||||
/* Pick the best watchdog. */
|
||||
if (!watchdog || cs->rating > watchdog->rating) {
|
||||
if (watchdog)
|
||||
del_timer(&watchdog_timer);
|
||||
watchdog = cs;
|
||||
init_timer(&watchdog_timer);
|
||||
watchdog_timer.function = clocksource_watchdog;
|
||||
|
||||
/* Reset watchdog cycles */
|
||||
clocksource_reset_watchdog();
|
||||
/* Start if list is not empty */
|
||||
if (!list_empty(&watchdog_list)) {
|
||||
watchdog_last = watchdog->read(watchdog);
|
||||
watchdog_timer.expires =
|
||||
jiffies + WATCHDOG_INTERVAL;
|
||||
add_timer_on(&watchdog_timer,
|
||||
cpumask_first(cpu_online_mask));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Check if the watchdog timer needs to be started. */
|
||||
clocksource_start_watchdog();
|
||||
spin_unlock_irqrestore(&watchdog_lock, flags);
|
||||
}
|
||||
#else
|
||||
static void clocksource_check_watchdog(struct clocksource *cs)
|
||||
|
||||
static void clocksource_dequeue_watchdog(struct clocksource *cs)
|
||||
{
|
||||
struct clocksource *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&watchdog_lock, flags);
|
||||
if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {
|
||||
/* cs is a watched clocksource. */
|
||||
list_del_init(&cs->wd_list);
|
||||
} else if (cs == watchdog) {
|
||||
/* Reset watchdog cycles */
|
||||
clocksource_reset_watchdog();
|
||||
/* Current watchdog is removed. Find an alternative. */
|
||||
watchdog = NULL;
|
||||
list_for_each_entry(tmp, &clocksource_list, list) {
|
||||
if (tmp == cs || tmp->flags & CLOCK_SOURCE_MUST_VERIFY)
|
||||
continue;
|
||||
if (!watchdog || tmp->rating > watchdog->rating)
|
||||
watchdog = tmp;
|
||||
}
|
||||
}
|
||||
cs->flags &= ~CLOCK_SOURCE_WATCHDOG;
|
||||
/* Check if the watchdog timer needs to be stopped. */
|
||||
clocksource_stop_watchdog();
|
||||
spin_unlock_irqrestore(&watchdog_lock, flags);
|
||||
}
|
||||
|
||||
#else /* CONFIG_CLOCKSOURCE_WATCHDOG */
|
||||
|
||||
static void clocksource_enqueue_watchdog(struct clocksource *cs)
|
||||
{
|
||||
if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
|
||||
cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
|
||||
}
|
||||
|
||||
static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }
|
||||
static inline void clocksource_resume_watchdog(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
|
||||
|
||||
/**
|
||||
* clocksource_resume - resume the clocksource(s)
|
||||
|
@ -414,14 +453,13 @@ int clocksource_register(struct clocksource *cs)
|
|||
clocksource_enqueue(cs);
|
||||
clocksource_select();
|
||||
spin_unlock_irqrestore(&clocksource_lock, flags);
|
||||
clocksource_check_watchdog(cs);
|
||||
clocksource_enqueue_watchdog(cs);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clocksource_register);
|
||||
|
||||
/**
|
||||
* clocksource_change_rating - Change the rating of a registered clocksource
|
||||
*
|
||||
*/
|
||||
void clocksource_change_rating(struct clocksource *cs, int rating)
|
||||
{
|
||||
|
@ -434,6 +472,7 @@ void clocksource_change_rating(struct clocksource *cs, int rating)
|
|||
clocksource_select();
|
||||
spin_unlock_irqrestore(&clocksource_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(clocksource_change_rating);
|
||||
|
||||
/**
|
||||
* clocksource_unregister - remove a registered clocksource
|
||||
|
@ -442,11 +481,13 @@ void clocksource_unregister(struct clocksource *cs)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
clocksource_dequeue_watchdog(cs);
|
||||
spin_lock_irqsave(&clocksource_lock, flags);
|
||||
list_del(&cs->list);
|
||||
clocksource_select();
|
||||
spin_unlock_irqrestore(&clocksource_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(clocksource_unregister);
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue