time: more timer related cleanups
[safe/jmp/linux-2.6] / kernel / time / tick-sched.c
index 8c3fef1..49e12f6 100644 (file)
@@ -9,7 +9,7 @@
  *
  *  Started by: Thomas Gleixner and Ingo Molnar
  *
- *  For licencing details see kernel-base/COPYING
+ *  Distribute under GPLv2.
  */
 #include <linux/cpu.h>
 #include <linux/err.h>
@@ -133,6 +133,8 @@ void tick_nohz_update_jiffies(void)
        if (!ts->tick_stopped)
                return;
 
+       touch_softlockup_watchdog();
+
        cpu_clear(cpu, nohz_cpu_mask);
        now = ktime_get();
 
@@ -151,8 +153,10 @@ void tick_nohz_update_jiffies(void)
 void tick_nohz_stop_sched_tick(void)
 {
        unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
+       unsigned long rt_jiffies;
        struct tick_sched *ts;
        ktime_t last_update, expires, now, delta;
+       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
        int cpu;
 
        local_irq_save(flags);
@@ -213,6 +217,10 @@ void tick_nohz_stop_sched_tick(void)
        next_jiffies = get_next_timer_interrupt(last_jiffies);
        delta_jiffies = next_jiffies - last_jiffies;
 
+       rt_jiffies = rt_needs_cpu(cpu);
+       if (rt_jiffies && rt_jiffies < delta_jiffies)
+               delta_jiffies = rt_jiffies;
+
        if (rcu_needs_cpu(cpu))
                delta_jiffies = 1;
        /*
@@ -288,7 +296,7 @@ void tick_nohz_stop_sched_tick(void)
                        /* Check, if the timer was already in the past */
                        if (hrtimer_active(&ts->sched_timer))
                                goto out;
-               } else if(!tick_program_event(expires, 0))
+               } else if (!tick_program_event(expires, 0))
                                goto out;
                /*
                 * We are past the event already. So we crossed a
@@ -302,12 +310,25 @@ void tick_nohz_stop_sched_tick(void)
 out:
        ts->next_jiffies = next_jiffies;
        ts->last_jiffies = last_jiffies;
+       ts->sleep_length = ktime_sub(dev->next_event, now);
 end:
        local_irq_restore(flags);
 }
 
 /**
- * nohz_restart_sched_tick - restart the idle tick from the idle task
+ * tick_nohz_get_sleep_length - return the length of the current sleep
+ *
+ * Called from power state control code with interrupts disabled
+ */
+ktime_t tick_nohz_get_sleep_length(void)
+{
+       struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+
+       return ts->sleep_length;
+}
+
+/**
+ * tick_nohz_restart_sched_tick - restart the idle tick from the idle task
  *
  * Restart the idle tick when the CPU is woken up from idle
  */
@@ -486,14 +507,13 @@ static inline void tick_nohz_switch_to_nohz(void) { }
  */
 #ifdef CONFIG_HIGH_RES_TIMERS
 /*
- * We rearm the timer until we get disabled by the idle code
+ * We rearm the timer until we get disabled by the idle code.
  * Called with interrupts disabled and timer->base->cpu_base->lock held.
  */
 static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
 {
        struct tick_sched *ts =
                container_of(timer, struct tick_sched, sched_timer);
-       struct hrtimer_cpu_base *base = timer->base->cpu_base;
        struct pt_regs *regs = get_irq_regs();
        ktime_t now = ktime_get();
        int cpu = smp_processor_id();
@@ -531,15 +551,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
                        touch_softlockup_watchdog();
                        ts->idle_jiffies++;
                }
-               /*
-                * update_process_times() might take tasklist_lock, hence
-                * drop the base lock. sched-tick hrtimers are per-CPU and
-                * never accessible by userspace APIs, so this is safe to do.
-                */
-               spin_unlock(&base->lock);
                update_process_times(user_mode(regs));
                profile_tick(CPU_PROFILING);
-               spin_lock(&base->lock);
        }
 
        /* Do not restart, when we are in the idle loop */
@@ -570,7 +583,7 @@ void tick_setup_sched_timer(void)
        /* Get the next period (per cpu) */
        ts->sched_timer.expires = tick_init_jiffy_update();
        offset = ktime_to_ns(tick_period) >> 1;
-       do_div(offset, NR_CPUS);
+       do_div(offset, num_possible_cpus());
        offset *= smp_processor_id();
        ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);