Merge branch 'linus' into timers/nohz
[sfrench/cifs-2.6.git] / kernel / time / tick-sched.c
index b854a895591efe4f1d40f522d079fe1de0cf256e..a5c26d2b132307bd7199e0f56e3a07b3578c2dcb 100644 (file)
@@ -48,6 +48,13 @@ static void tick_do_update_jiffies64(ktime_t now)
        unsigned long ticks = 0;
        ktime_t delta;
 
+       /*
+        * Do a quick check without holding xtime_lock:
+        */
+       delta = ktime_sub(now, last_jiffies_update);
+       if (delta.tv64 < tick_period.tv64)
+               return;
+
        /* Reevalute with xtime_lock held */
        write_seqlock(&xtime_lock);
 
@@ -188,7 +195,7 @@ u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
  * Called either from the idle loop or from irq_exit() when an idle period was
  * just interrupted by an interrupt which did not cause a reschedule.
  */
-void tick_nohz_stop_sched_tick(void)
+void tick_nohz_stop_sched_tick(int inidle)
 {
        unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
        struct tick_sched *ts;
@@ -217,6 +224,11 @@ void tick_nohz_stop_sched_tick(void)
        if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
                goto end;
 
+       if (!inidle && !ts->inidle)
+               goto end;
+
+       ts->inidle = 1;
+
        if (need_resched())
                goto end;
 
@@ -228,6 +240,7 @@ void tick_nohz_stop_sched_tick(void)
                               local_softirq_pending());
                        ratelimit++;
                }
+               goto end;
        }
 
        ts->idle_calls++;
@@ -276,6 +289,7 @@ void tick_nohz_stop_sched_tick(void)
                        ts->tick_stopped = 1;
                        ts->idle_jiffies = last_jiffies;
                        rcu_enter_nohz();
+                       sched_clock_tick_stop(cpu);
                }
 
                /*
@@ -364,17 +378,21 @@ void tick_nohz_restart_sched_tick(void)
        local_irq_disable();
        tick_nohz_stop_idle(cpu);
 
-       if (!ts->tick_stopped) {
+       if (!ts->inidle || !ts->tick_stopped) {
+               ts->inidle = 0;
                local_irq_enable();
                return;
        }
 
+       ts->inidle = 0;
+
        rcu_exit_nohz();
 
        /* Update jiffies first */
        select_nohz_load_balancer(0);
        now = ktime_get();
        tick_do_update_jiffies64(now);
+       sched_clock_tick_start(cpu);
        cpu_clear(cpu, nohz_cpu_mask);
 
        /*