aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/tick-sched.c')
-rw-r--r--kernel/time/tick-sched.c101
1 files changed, 72 insertions, 29 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index a547be11cf97..5bbb1044f847 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -155,7 +155,7 @@ void tick_nohz_update_jiffies(void)
155 touch_softlockup_watchdog(); 155 touch_softlockup_watchdog();
156} 156}
157 157
158void tick_nohz_stop_idle(int cpu) 158static void tick_nohz_stop_idle(int cpu)
159{ 159{
160 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); 160 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
161 161
@@ -377,6 +377,32 @@ ktime_t tick_nohz_get_sleep_length(void)
377 return ts->sleep_length; 377 return ts->sleep_length;
378} 378}
379 379
380static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
381{
382 hrtimer_cancel(&ts->sched_timer);
383 hrtimer_set_expires(&ts->sched_timer, ts->idle_tick);
384
385 while (1) {
386 /* Forward the time to expire in the future */
387 hrtimer_forward(&ts->sched_timer, now, tick_period);
388
389 if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
390 hrtimer_start_expires(&ts->sched_timer,
391 HRTIMER_MODE_ABS);
392 /* Check, if the timer was already in the past */
393 if (hrtimer_active(&ts->sched_timer))
394 break;
395 } else {
396 if (!tick_program_event(
397 hrtimer_get_expires(&ts->sched_timer), 0))
398 break;
399 }
400 /* Update jiffies and reread time */
401 tick_do_update_jiffies64(now);
402 now = ktime_get();
403 }
404}
405
380/** 406/**
381 * tick_nohz_restart_sched_tick - restart the idle tick from the idle task 407 * tick_nohz_restart_sched_tick - restart the idle tick from the idle task
382 * 408 *
@@ -430,28 +456,9 @@ void tick_nohz_restart_sched_tick(void)
430 */ 456 */
431 ts->tick_stopped = 0; 457 ts->tick_stopped = 0;
432 ts->idle_exittime = now; 458 ts->idle_exittime = now;
433 hrtimer_cancel(&ts->sched_timer);
434 hrtimer_set_expires(&ts->sched_timer, ts->idle_tick);
435 459
436 while (1) { 460 tick_nohz_restart(ts, now);
437 /* Forward the time to expire in the future */
438 hrtimer_forward(&ts->sched_timer, now, tick_period);
439 461
440 if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
441 hrtimer_start_expires(&ts->sched_timer,
442 HRTIMER_MODE_ABS);
443 /* Check, if the timer was already in the past */
444 if (hrtimer_active(&ts->sched_timer))
445 break;
446 } else {
447 if (!tick_program_event(
448 hrtimer_get_expires(&ts->sched_timer), 0))
449 break;
450 }
451 /* Update jiffies and reread time */
452 tick_do_update_jiffies64(now);
453 now = ktime_get();
454 }
455 local_irq_enable(); 462 local_irq_enable();
456} 463}
457 464
@@ -503,10 +510,6 @@ static void tick_nohz_handler(struct clock_event_device *dev)
503 update_process_times(user_mode(regs)); 510 update_process_times(user_mode(regs));
504 profile_tick(CPU_PROFILING); 511 profile_tick(CPU_PROFILING);
505 512
506 /* Do not restart, when we are in the idle loop */
507 if (ts->tick_stopped)
508 return;
509
510 while (tick_nohz_reprogram(ts, now)) { 513 while (tick_nohz_reprogram(ts, now)) {
511 now = ktime_get(); 514 now = ktime_get();
512 tick_do_update_jiffies64(now); 515 tick_do_update_jiffies64(now);
@@ -552,6 +555,37 @@ static void tick_nohz_switch_to_nohz(void)
552 smp_processor_id()); 555 smp_processor_id());
553} 556}
554 557
558/*
559 * When NOHZ is enabled and the tick is stopped, we need to kick the
560 * tick timer from irq_enter() so that the jiffies update is kept
561 * alive during long running softirqs. That's ugly as hell, but
562 * correctness is key even if we need to fix the offending softirq in
563 * the first place.
564 *
565 * Note, this is different to tick_nohz_restart. We just kick the
566 * timer and do not touch the other magic bits which need to be done
567 * when idle is left.
568 */
569static void tick_nohz_kick_tick(int cpu)
570{
571 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
572 ktime_t delta, now;
573
574 if (!ts->tick_stopped)
575 return;
576
577 /*
578 * Do not touch the tick device, when the next expiry is either
579 * already reached or less/equal than the tick period.
580 */
581 now = ktime_get();
582 delta = ktime_sub(hrtimer_get_expires(&ts->sched_timer), now);
583 if (delta.tv64 <= tick_period.tv64)
584 return;
585
586 tick_nohz_restart(ts, now);
587}
588
555#else 589#else
556 590
557static inline void tick_nohz_switch_to_nohz(void) { } 591static inline void tick_nohz_switch_to_nohz(void) { }
@@ -559,6 +593,19 @@ static inline void tick_nohz_switch_to_nohz(void) { }
559#endif /* NO_HZ */ 593#endif /* NO_HZ */
560 594
561/* 595/*
596 * Called from irq_enter to notify about the possible interruption of idle()
597 */
598void tick_check_idle(int cpu)
599{
600 tick_check_oneshot_broadcast(cpu);
601#ifdef CONFIG_NO_HZ
602 tick_nohz_stop_idle(cpu);
603 tick_nohz_update_jiffies();
604 tick_nohz_kick_tick(cpu);
605#endif
606}
607
608/*
562 * High resolution timer specific code 609 * High resolution timer specific code
563 */ 610 */
564#ifdef CONFIG_HIGH_RES_TIMERS 611#ifdef CONFIG_HIGH_RES_TIMERS
@@ -611,10 +658,6 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
611 profile_tick(CPU_PROFILING); 658 profile_tick(CPU_PROFILING);
612 } 659 }
613 660
614 /* Do not restart, when we are in the idle loop */
615 if (ts->tick_stopped)
616 return HRTIMER_NORESTART;
617
618 hrtimer_forward(timer, now, tick_period); 661 hrtimer_forward(timer, now, tick_period);
619 662
620 return HRTIMER_RESTART; 663 return HRTIMER_RESTART;