Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
[firefly-linux-kernel-4.4.55.git] / drivers / cpuidle / cpuidle.c
index becd6d99203be3d1fffc84a6980f32d4fbed31ce..06ce2680d00d4ff33582d04cc9cb67eabf0bc442 100644 (file)
@@ -62,8 +62,9 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
 int cpuidle_idle_call(void)
 {
        struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+       struct cpuidle_driver *drv = cpuidle_get_driver();
        struct cpuidle_state *target_state;
-       int next_state;
+       int next_state, entered_state;
 
        if (off)
                return -ENODEV;
@@ -84,45 +85,36 @@ int cpuidle_idle_call(void)
        hrtimer_peek_ahead_timers();
 #endif
 
-       /*
-        * Call the device's prepare function before calling the
-        * governor's select function.  ->prepare gives the device's
-        * cpuidle driver a chance to update any dynamic information
-        * of its cpuidle states for the current idle period, e.g.
-        * state availability, latencies, residencies, etc.
-        */
-       if (dev->prepare)
-               dev->prepare(dev);
-
        /* ask the governor for the next state */
-       next_state = cpuidle_curr_governor->select(dev);
+       next_state = cpuidle_curr_governor->select(drv, dev);
        if (need_resched()) {
                local_irq_enable();
                return 0;
        }
 
-       target_state = &dev->states[next_state];
-
-       /* enter the state and update stats */
-       dev->last_state = target_state;
+       target_state = &drv->states[next_state];
 
        trace_power_start(POWER_CSTATE, next_state, dev->cpu);
        trace_cpu_idle(next_state, dev->cpu);
 
-       dev->last_residency = target_state->enter(dev, target_state);
+       entered_state = target_state->enter(dev, drv, next_state);
 
        trace_power_end(dev->cpu);
        trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
 
-       if (dev->last_state)
-               target_state = dev->last_state;
-
-       target_state->time += (unsigned long long)dev->last_residency;
-       target_state->usage++;
+       if (entered_state >= 0) {
+               /* Update cpuidle counters */
+               /* This can be moved to within driver enter routine
+                * but that results in multiple copies of same code.
+                */
+               dev->states_usage[entered_state].time +=
+                               (unsigned long long)dev->last_residency;
+               dev->states_usage[entered_state].usage++;
+       }
 
        /* give the governor an opportunity to reflect on the outcome */
        if (cpuidle_curr_governor->reflect)
-               cpuidle_curr_governor->reflect(dev);
+               cpuidle_curr_governor->reflect(dev, entered_state);
 
        return 0;
 }
@@ -173,11 +165,11 @@ void cpuidle_resume_and_unlock(void)
 EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
 
 #ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+static int poll_idle(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
 {
        ktime_t t1, t2;
        s64 diff;
-       int ret;
 
        t1 = ktime_get();
        local_irq_enable();
@@ -189,15 +181,14 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
        if (diff > INT_MAX)
                diff = INT_MAX;
 
-       ret = (int) diff;
-       return ret;
+       dev->last_residency = (int) diff;
+
+       return index;
 }
 
-static void poll_idle_init(struct cpuidle_device *dev)
+static void poll_idle_init(struct cpuidle_driver *drv)
 {
-       struct cpuidle_state *state = &dev->states[0];
-
-       cpuidle_set_statedata(state, NULL);
+       struct cpuidle_state *state = &drv->states[0];
 
        snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
        snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
@@ -208,7 +199,7 @@ static void poll_idle_init(struct cpuidle_device *dev)
        state->enter = poll_idle;
 }
 #else
-static void poll_idle_init(struct cpuidle_device *dev) {}
+static void poll_idle_init(struct cpuidle_driver *drv) {}
 #endif /* CONFIG_ARCH_HAS_CPU_RELAX */
 
 /**
@@ -235,21 +226,20 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
                        return ret;
        }
 
-       poll_idle_init(dev);
+       poll_idle_init(cpuidle_get_driver());
 
        if ((ret = cpuidle_add_state_sysfs(dev)))
                return ret;
 
        if (cpuidle_curr_governor->enable &&
-           (ret = cpuidle_curr_governor->enable(dev)))
+           (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev)))
                goto fail_sysfs;
 
        for (i = 0; i < dev->state_count; i++) {
-               dev->states[i].usage = 0;
-               dev->states[i].time = 0;
+               dev->states_usage[i].usage = 0;
+               dev->states_usage[i].time = 0;
        }
        dev->last_residency = 0;
-       dev->last_state = NULL;
 
        smp_wmb();
 
@@ -283,7 +273,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
        dev->enabled = 0;
 
        if (cpuidle_curr_governor->disable)
-               cpuidle_curr_governor->disable(dev);
+               cpuidle_curr_governor->disable(cpuidle_get_driver(), dev);
 
        cpuidle_remove_state_sysfs(dev);
        enabled_devices--;
@@ -311,26 +301,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 
        init_completion(&dev->kobj_unregister);
 
-       /*
-        * cpuidle driver should set the dev->power_specified bit
-        * before registering the device if the driver provides
-        * power_usage numbers.
-        *
-        * For those devices whose ->power_specified is not set,
-        * we fill in power_usage with decreasing values as the
-        * cpuidle code has an implicit assumption that state Cn
-        * uses less power than C(n-1).
-        *
-        * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
-        * an power value of -1.  So we use -2, -3, etc, for other
-        * c-states.
-        */
-       if (!dev->power_specified) {
-               int i;
-               for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++)
-                       dev->states[i].power_usage = -1 - i;
-       }
-
        per_cpu(cpuidle_devices, dev->cpu) = dev;
        list_add(&dev->device_list, &cpuidle_detected_devices);
        if ((ret = cpuidle_add_sysfs(sys_dev))) {