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.c131
1 files changed, 93 insertions, 38 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index cb02324bdb88..342fc9ccab46 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -20,6 +20,7 @@
20#include <linux/profile.h> 20#include <linux/profile.h>
21#include <linux/sched.h> 21#include <linux/sched.h>
22#include <linux/tick.h> 22#include <linux/tick.h>
23#include <linux/module.h>
23 24
24#include <asm/irq_regs.h> 25#include <asm/irq_regs.h>
25 26
@@ -154,7 +155,7 @@ void tick_nohz_update_jiffies(void)
154 touch_softlockup_watchdog(); 155 touch_softlockup_watchdog();
155} 156}
156 157
157void tick_nohz_stop_idle(int cpu) 158static void tick_nohz_stop_idle(int cpu)
158{ 159{
159 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); 160 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
160 161
@@ -190,9 +191,17 @@ u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
190{ 191{
191 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); 192 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
192 193
193 *last_update_time = ktime_to_us(ts->idle_lastupdate); 194 if (!tick_nohz_enabled)
195 return -1;
196
197 if (ts->idle_active)
198 *last_update_time = ktime_to_us(ts->idle_lastupdate);
199 else
200 *last_update_time = ktime_to_us(ktime_get());
201
194 return ktime_to_us(ts->idle_sleeptime); 202 return ktime_to_us(ts->idle_sleeptime);
195} 203}
204EXPORT_SYMBOL_GPL(get_cpu_idle_time_us);
196 205
197/** 206/**
198 * tick_nohz_stop_sched_tick - stop the idle tick from the idle task 207 * tick_nohz_stop_sched_tick - stop the idle tick from the idle task
@@ -261,7 +270,7 @@ void tick_nohz_stop_sched_tick(int inidle)
261 next_jiffies = get_next_timer_interrupt(last_jiffies); 270 next_jiffies = get_next_timer_interrupt(last_jiffies);
262 delta_jiffies = next_jiffies - last_jiffies; 271 delta_jiffies = next_jiffies - last_jiffies;
263 272
264 if (rcu_needs_cpu(cpu)) 273 if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu))
265 delta_jiffies = 1; 274 delta_jiffies = 1;
266 /* 275 /*
267 * Do not stop the tick, if we are only one off 276 * Do not stop the tick, if we are only one off
@@ -291,7 +300,7 @@ void tick_nohz_stop_sched_tick(int inidle)
291 goto out; 300 goto out;
292 } 301 }
293 302
294 ts->idle_tick = ts->sched_timer.expires; 303 ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
295 ts->tick_stopped = 1; 304 ts->tick_stopped = 1;
296 ts->idle_jiffies = last_jiffies; 305 ts->idle_jiffies = last_jiffies;
297 rcu_enter_nohz(); 306 rcu_enter_nohz();
@@ -368,6 +377,32 @@ ktime_t tick_nohz_get_sleep_length(void)
368 return ts->sleep_length; 377 return ts->sleep_length;
369} 378}
370 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
371/** 406/**
372 * 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
373 * 408 *
@@ -421,35 +456,16 @@ void tick_nohz_restart_sched_tick(void)
421 */ 456 */
422 ts->tick_stopped = 0; 457 ts->tick_stopped = 0;
423 ts->idle_exittime = now; 458 ts->idle_exittime = now;
424 hrtimer_cancel(&ts->sched_timer);
425 ts->sched_timer.expires = ts->idle_tick;
426 459
427 while (1) { 460 tick_nohz_restart(ts, now);
428 /* Forward the time to expire in the future */
429 hrtimer_forward(&ts->sched_timer, now, tick_period);
430 461
431 if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
432 hrtimer_start(&ts->sched_timer,
433 ts->sched_timer.expires,
434 HRTIMER_MODE_ABS);
435 /* Check, if the timer was already in the past */
436 if (hrtimer_active(&ts->sched_timer))
437 break;
438 } else {
439 if (!tick_program_event(ts->sched_timer.expires, 0))
440 break;
441 }
442 /* Update jiffies and reread time */
443 tick_do_update_jiffies64(now);
444 now = ktime_get();
445 }
446 local_irq_enable(); 462 local_irq_enable();
447} 463}
448 464
449static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now) 465static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now)
450{ 466{
451 hrtimer_forward(&ts->sched_timer, now, tick_period); 467 hrtimer_forward(&ts->sched_timer, now, tick_period);
452 return tick_program_event(ts->sched_timer.expires, 0); 468 return tick_program_event(hrtimer_get_expires(&ts->sched_timer), 0);
453} 469}
454 470
455/* 471/*
@@ -494,10 +510,6 @@ static void tick_nohz_handler(struct clock_event_device *dev)
494 update_process_times(user_mode(regs)); 510 update_process_times(user_mode(regs));
495 profile_tick(CPU_PROFILING); 511 profile_tick(CPU_PROFILING);
496 512
497 /* Do not restart, when we are in the idle loop */
498 if (ts->tick_stopped)
499 return;
500
501 while (tick_nohz_reprogram(ts, now)) { 513 while (tick_nohz_reprogram(ts, now)) {
502 now = ktime_get(); 514 now = ktime_get();
503 tick_do_update_jiffies64(now); 515 tick_do_update_jiffies64(now);
@@ -532,7 +544,7 @@ static void tick_nohz_switch_to_nohz(void)
532 next = tick_init_jiffy_update(); 544 next = tick_init_jiffy_update();
533 545
534 for (;;) { 546 for (;;) {
535 ts->sched_timer.expires = next; 547 hrtimer_set_expires(&ts->sched_timer, next);
536 if (!tick_program_event(next, 0)) 548 if (!tick_program_event(next, 0))
537 break; 549 break;
538 next = ktime_add(next, tick_period); 550 next = ktime_add(next, tick_period);
@@ -543,6 +555,41 @@ static void tick_nohz_switch_to_nohz(void)
543 smp_processor_id()); 555 smp_processor_id());
544} 556}
545 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#if 0
572 /* Switch back to 2.6.27 behaviour */
573
574 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
575 ktime_t delta, now;
576
577 if (!ts->tick_stopped)
578 return;
579
580 /*
581 * Do not touch the tick device, when the next expiry is either
582 * already reached or less/equal than the tick period.
583 */
584 now = ktime_get();
585 delta = ktime_sub(hrtimer_get_expires(&ts->sched_timer), now);
586 if (delta.tv64 <= tick_period.tv64)
587 return;
588
589 tick_nohz_restart(ts, now);
590#endif
591}
592
546#else 593#else
547 594
548static inline void tick_nohz_switch_to_nohz(void) { } 595static inline void tick_nohz_switch_to_nohz(void) { }
@@ -550,6 +597,19 @@ static inline void tick_nohz_switch_to_nohz(void) { }
550#endif /* NO_HZ */ 597#endif /* NO_HZ */
551 598
552/* 599/*
600 * Called from irq_enter to notify about the possible interruption of idle()
601 */
602void tick_check_idle(int cpu)
603{
604 tick_check_oneshot_broadcast(cpu);
605#ifdef CONFIG_NO_HZ
606 tick_nohz_stop_idle(cpu);
607 tick_nohz_update_jiffies();
608 tick_nohz_kick_tick(cpu);
609#endif
610}
611
612/*
553 * High resolution timer specific code 613 * High resolution timer specific code
554 */ 614 */
555#ifdef CONFIG_HIGH_RES_TIMERS 615#ifdef CONFIG_HIGH_RES_TIMERS
@@ -602,10 +662,6 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
602 profile_tick(CPU_PROFILING); 662 profile_tick(CPU_PROFILING);
603 } 663 }
604 664
605 /* Do not restart, when we are in the idle loop */
606 if (ts->tick_stopped)
607 return HRTIMER_NORESTART;
608
609 hrtimer_forward(timer, now, tick_period); 665 hrtimer_forward(timer, now, tick_period);
610 666
611 return HRTIMER_RESTART; 667 return HRTIMER_RESTART;
@@ -628,16 +684,15 @@ void tick_setup_sched_timer(void)
628 ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_PERCPU; 684 ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_PERCPU;
629 685
630 /* Get the next period (per cpu) */ 686 /* Get the next period (per cpu) */
631 ts->sched_timer.expires = tick_init_jiffy_update(); 687 hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
632 offset = ktime_to_ns(tick_period) >> 1; 688 offset = ktime_to_ns(tick_period) >> 1;
633 do_div(offset, num_possible_cpus()); 689 do_div(offset, num_possible_cpus());
634 offset *= smp_processor_id(); 690 offset *= smp_processor_id();
635 ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset); 691 hrtimer_add_expires_ns(&ts->sched_timer, offset);
636 692
637 for (;;) { 693 for (;;) {
638 hrtimer_forward(&ts->sched_timer, now, tick_period); 694 hrtimer_forward(&ts->sched_timer, now, tick_period);
639 hrtimer_start(&ts->sched_timer, ts->sched_timer.expires, 695 hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS);
640 HRTIMER_MODE_ABS);
641 /* Check, if the timer was already in the past */ 696 /* Check, if the timer was already in the past */
642 if (hrtimer_active(&ts->sched_timer)) 697 if (hrtimer_active(&ts->sched_timer))
643 break; 698 break;