diff options
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/tick-sched.c | 86 |
1 files changed, 47 insertions, 39 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 73cc4901336..430e1b6901c 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -271,47 +271,15 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time) | |||
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us); | 272 | EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us); |
273 | 273 | ||
274 | static void tick_nohz_stop_sched_tick(struct tick_sched *ts, ktime_t now) | 274 | static void tick_nohz_stop_sched_tick(struct tick_sched *ts, |
275 | ktime_t now, int cpu) | ||
275 | { | 276 | { |
276 | unsigned long seq, last_jiffies, next_jiffies, delta_jiffies; | 277 | unsigned long seq, last_jiffies, next_jiffies, delta_jiffies; |
277 | ktime_t last_update, expires; | 278 | ktime_t last_update, expires; |
278 | struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; | 279 | struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; |
279 | u64 time_delta; | 280 | u64 time_delta; |
280 | int cpu; | ||
281 | |||
282 | cpu = smp_processor_id(); | ||
283 | ts = &per_cpu(tick_cpu_sched, cpu); | ||
284 | |||
285 | /* | ||
286 | * If this cpu is offline and it is the one which updates | ||
287 | * jiffies, then give up the assignment and let it be taken by | ||
288 | * the cpu which runs the tick timer next. If we don't drop | ||
289 | * this here the jiffies might be stale and do_timer() never | ||
290 | * invoked. | ||
291 | */ | ||
292 | if (unlikely(!cpu_online(cpu))) { | ||
293 | if (cpu == tick_do_timer_cpu) | ||
294 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; | ||
295 | } | ||
296 | |||
297 | if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) | ||
298 | return; | ||
299 | |||
300 | if (need_resched()) | ||
301 | return; | ||
302 | 281 | ||
303 | if (unlikely(local_softirq_pending() && cpu_online(cpu))) { | ||
304 | static int ratelimit; | ||
305 | |||
306 | if (ratelimit < 10) { | ||
307 | printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n", | ||
308 | (unsigned int) local_softirq_pending()); | ||
309 | ratelimit++; | ||
310 | } | ||
311 | return; | ||
312 | } | ||
313 | 282 | ||
314 | ts->idle_calls++; | ||
315 | /* Read jiffies and the time when jiffies were updated last */ | 283 | /* Read jiffies and the time when jiffies were updated last */ |
316 | do { | 284 | do { |
317 | seq = read_seqbegin(&xtime_lock); | 285 | seq = read_seqbegin(&xtime_lock); |
@@ -441,16 +409,56 @@ out: | |||
441 | ts->sleep_length = ktime_sub(dev->next_event, now); | 409 | ts->sleep_length = ktime_sub(dev->next_event, now); |
442 | } | 410 | } |
443 | 411 | ||
412 | static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) | ||
413 | { | ||
414 | /* | ||
415 | * If this cpu is offline and it is the one which updates | ||
416 | * jiffies, then give up the assignment and let it be taken by | ||
417 | * the cpu which runs the tick timer next. If we don't drop | ||
418 | * this here the jiffies might be stale and do_timer() never | ||
419 | * invoked. | ||
420 | */ | ||
421 | if (unlikely(!cpu_online(cpu))) { | ||
422 | if (cpu == tick_do_timer_cpu) | ||
423 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; | ||
424 | } | ||
425 | |||
426 | if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) | ||
427 | return false; | ||
428 | |||
429 | if (need_resched()) | ||
430 | return false; | ||
431 | |||
432 | if (unlikely(local_softirq_pending() && cpu_online(cpu))) { | ||
433 | static int ratelimit; | ||
434 | |||
435 | if (ratelimit < 10) { | ||
436 | printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n", | ||
437 | (unsigned int) local_softirq_pending()); | ||
438 | ratelimit++; | ||
439 | } | ||
440 | return false; | ||
441 | } | ||
442 | |||
443 | return true; | ||
444 | } | ||
445 | |||
444 | static void __tick_nohz_idle_enter(struct tick_sched *ts) | 446 | static void __tick_nohz_idle_enter(struct tick_sched *ts) |
445 | { | 447 | { |
446 | ktime_t now; | 448 | ktime_t now; |
447 | int was_stopped = ts->tick_stopped; | 449 | int cpu = smp_processor_id(); |
448 | 450 | ||
449 | now = tick_nohz_start_idle(smp_processor_id(), ts); | 451 | now = tick_nohz_start_idle(cpu, ts); |
450 | tick_nohz_stop_sched_tick(ts, now); | ||
451 | 452 | ||
452 | if (!was_stopped && ts->tick_stopped) | 453 | if (can_stop_idle_tick(cpu, ts)) { |
453 | ts->idle_jiffies = ts->last_jiffies; | 454 | int was_stopped = ts->tick_stopped; |
455 | |||
456 | ts->idle_calls++; | ||
457 | tick_nohz_stop_sched_tick(ts, now, cpu); | ||
458 | |||
459 | if (!was_stopped && ts->tick_stopped) | ||
460 | ts->idle_jiffies = ts->last_jiffies; | ||
461 | } | ||
454 | } | 462 | } |
455 | 463 | ||
456 | /** | 464 | /** |