diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/time/clocksource.c | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 56aaa749645d..f1508019bfb4 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
@@ -143,10 +143,13 @@ fs_initcall(clocksource_done_booting); | |||
143 | static LIST_HEAD(watchdog_list); | 143 | static LIST_HEAD(watchdog_list); |
144 | static struct clocksource *watchdog; | 144 | static struct clocksource *watchdog; |
145 | static struct timer_list watchdog_timer; | 145 | static struct timer_list watchdog_timer; |
146 | static struct work_struct watchdog_work; | ||
146 | static DEFINE_SPINLOCK(watchdog_lock); | 147 | static DEFINE_SPINLOCK(watchdog_lock); |
147 | static cycle_t watchdog_last; | 148 | static cycle_t watchdog_last; |
148 | static int watchdog_running; | 149 | static int watchdog_running; |
149 | 150 | ||
151 | static void clocksource_watchdog_work(struct work_struct *work); | ||
152 | |||
150 | /* | 153 | /* |
151 | * Interval: 0.5sec Threshold: 0.0625s | 154 | * Interval: 0.5sec Threshold: 0.0625s |
152 | */ | 155 | */ |
@@ -158,15 +161,16 @@ static void clocksource_unstable(struct clocksource *cs, int64_t delta) | |||
158 | printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", | 161 | printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", |
159 | cs->name, delta); | 162 | cs->name, delta); |
160 | cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); | 163 | cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); |
161 | clocksource_change_rating(cs, 0); | 164 | cs->flags |= CLOCK_SOURCE_UNSTABLE; |
162 | list_del(&cs->wd_list); | 165 | schedule_work(&watchdog_work); |
163 | } | 166 | } |
164 | 167 | ||
165 | static void clocksource_watchdog(unsigned long data) | 168 | static void clocksource_watchdog(unsigned long data) |
166 | { | 169 | { |
167 | struct clocksource *cs, *tmp; | 170 | struct clocksource *cs; |
168 | cycle_t csnow, wdnow; | 171 | cycle_t csnow, wdnow; |
169 | int64_t wd_nsec, cs_nsec; | 172 | int64_t wd_nsec, cs_nsec; |
173 | int next_cpu; | ||
170 | 174 | ||
171 | spin_lock(&watchdog_lock); | 175 | spin_lock(&watchdog_lock); |
172 | if (!watchdog_running) | 176 | if (!watchdog_running) |
@@ -176,7 +180,12 @@ static void clocksource_watchdog(unsigned long data) | |||
176 | wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask); | 180 | wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask); |
177 | watchdog_last = wdnow; | 181 | watchdog_last = wdnow; |
178 | 182 | ||
179 | list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) { | 183 | list_for_each_entry(cs, &watchdog_list, wd_list) { |
184 | |||
185 | /* Clocksource already marked unstable? */ | ||
186 | if (cs->flags & CLOCK_SOURCE_UNSTABLE) | ||
187 | continue; | ||
188 | |||
180 | csnow = cs->read(cs); | 189 | csnow = cs->read(cs); |
181 | 190 | ||
182 | /* Clocksource initialized ? */ | 191 | /* Clocksource initialized ? */ |
@@ -207,19 +216,15 @@ static void clocksource_watchdog(unsigned long data) | |||
207 | } | 216 | } |
208 | } | 217 | } |
209 | 218 | ||
210 | if (!list_empty(&watchdog_list)) { | 219 | /* |
211 | /* | 220 | * Cycle through CPUs to check if the CPUs stay synchronized |
212 | * Cycle through CPUs to check if the CPUs stay | 221 | * to each other. |
213 | * synchronized to each other. | 222 | */ |
214 | */ | 223 | next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask); |
215 | int next_cpu = cpumask_next(raw_smp_processor_id(), | 224 | if (next_cpu >= nr_cpu_ids) |
216 | cpu_online_mask); | 225 | next_cpu = cpumask_first(cpu_online_mask); |
217 | 226 | watchdog_timer.expires += WATCHDOG_INTERVAL; | |
218 | if (next_cpu >= nr_cpu_ids) | 227 | add_timer_on(&watchdog_timer, next_cpu); |
219 | next_cpu = cpumask_first(cpu_online_mask); | ||
220 | watchdog_timer.expires += WATCHDOG_INTERVAL; | ||
221 | add_timer_on(&watchdog_timer, next_cpu); | ||
222 | } | ||
223 | out: | 228 | out: |
224 | spin_unlock(&watchdog_lock); | 229 | spin_unlock(&watchdog_lock); |
225 | } | 230 | } |
@@ -228,6 +233,7 @@ static inline void clocksource_start_watchdog(void) | |||
228 | { | 233 | { |
229 | if (watchdog_running || !watchdog || list_empty(&watchdog_list)) | 234 | if (watchdog_running || !watchdog || list_empty(&watchdog_list)) |
230 | return; | 235 | return; |
236 | INIT_WORK(&watchdog_work, clocksource_watchdog_work); | ||
231 | init_timer(&watchdog_timer); | 237 | init_timer(&watchdog_timer); |
232 | watchdog_timer.function = clocksource_watchdog; | 238 | watchdog_timer.function = clocksource_watchdog; |
233 | watchdog_last = watchdog->read(watchdog); | 239 | watchdog_last = watchdog->read(watchdog); |
@@ -313,6 +319,22 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs) | |||
313 | spin_unlock_irqrestore(&watchdog_lock, flags); | 319 | spin_unlock_irqrestore(&watchdog_lock, flags); |
314 | } | 320 | } |
315 | 321 | ||
322 | static void clocksource_watchdog_work(struct work_struct *work) | ||
323 | { | ||
324 | struct clocksource *cs, *tmp; | ||
325 | unsigned long flags; | ||
326 | |||
327 | spin_lock_irqsave(&watchdog_lock, flags); | ||
328 | list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) | ||
329 | if (cs->flags & CLOCK_SOURCE_UNSTABLE) { | ||
330 | list_del_init(&cs->wd_list); | ||
331 | clocksource_change_rating(cs, 0); | ||
332 | } | ||
333 | /* Check if the watchdog timer needs to be stopped. */ | ||
334 | clocksource_stop_watchdog(); | ||
335 | spin_unlock(&watchdog_lock); | ||
336 | } | ||
337 | |||
316 | #else /* CONFIG_CLOCKSOURCE_WATCHDOG */ | 338 | #else /* CONFIG_CLOCKSOURCE_WATCHDOG */ |
317 | 339 | ||
318 | static void clocksource_enqueue_watchdog(struct clocksource *cs) | 340 | static void clocksource_enqueue_watchdog(struct clocksource *cs) |