Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 7 Nov 2011 18:13:52 +0000 (10:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 7 Nov 2011 18:13:52 +0000 (10:13 -0800)
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux:
  cpuidle: Single/Global registration of idle states
  cpuidle: Split cpuidle_state structure and move per-cpu statistics fields
  cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare()
  cpuidle: Move dev->last_residency update to driver enter routine; remove dev->last_state
  ACPI: Fix CONFIG_ACPI_DOCK=n compiler warning
  ACPI: Export FADT pm_profile integer value to userspace
  thermal: Prevent polling from happening during system suspend
  ACPI: Drop ACPI_NO_HARDWARE_INIT
  ACPI atomicio: Convert width in bits to bytes in __acpi_ioremap_fast()
  PNPACPI: Simplify disabled resource registration
  ACPI: Fix possible recursive locking in hwregs.c
  ACPI: use kstrdup()
  mrst pmu: update comment
  tools/power turbostat: less verbose debugging

12 files changed:
1  2 
arch/arm/mach-at91/cpuidle.c
arch/arm/mach-davinci/cpuidle.c
arch/arm/mach-exynos/cpuidle.c
arch/arm/mach-kirkwood/cpuidle.c
arch/sh/kernel/cpu/shmobile/cpuidle.c
drivers/acpi/atomicio.c
drivers/acpi/processor_idle.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governors/ladder.c
drivers/cpuidle/governors/menu.c
drivers/idle/intel_idle.c
include/linux/cpuidle.h

@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/cpuidle.h>
  #include <asm/proc-fns.h>
  #include <linux/io.h>
 +#include <linux/export.h>
  
  #include "pm.h"
  
@@@ -34,7 -33,8 +34,8 @@@ static struct cpuidle_driver at91_idle_
  
  /* Actual code that puts the SoC in different idle states */
  static int at91_enter_idle(struct cpuidle_device *dev,
-                              struct cpuidle_state *state)
+                       struct cpuidle_driver *drv,
+                              int index)
  {
        struct timeval before, after;
        int idle_time;
  
        local_irq_disable();
        do_gettimeofday(&before);
-       if (state == &dev->states[0])
+       if (index == 0)
                /* Wait for interrupt state */
                cpu_do_idle();
-       else if (state == &dev->states[1]) {
+       else if (index == 1) {
                asm("b 1f; .align 5; 1:");
                asm("mcr p15, 0, r0, c7, c10, 4");      /* drain write buffer */
                saved_lpr = sdram_selfrefresh_enable();
        local_irq_enable();
        idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
                        (after.tv_usec - before.tv_usec);
-       return idle_time;
+       dev->last_residency = idle_time;
+       return index;
  }
  
  /* Initialize CPU idle by registering the idle states */
  static int at91_init_cpuidle(void)
  {
        struct cpuidle_device *device;
-       cpuidle_register_driver(&at91_idle_driver);
+       struct cpuidle_driver *driver = &at91_idle_driver;
  
        device = &per_cpu(at91_cpuidle_device, smp_processor_id());
        device->state_count = AT91_MAX_STATES;
+       driver->state_count = AT91_MAX_STATES;
  
        /* Wait for interrupt state */
-       device->states[0].enter = at91_enter_idle;
-       device->states[0].exit_latency = 1;
-       device->states[0].target_residency = 10000;
-       device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-       strcpy(device->states[0].name, "WFI");
-       strcpy(device->states[0].desc, "Wait for interrupt");
+       driver->states[0].enter = at91_enter_idle;
+       driver->states[0].exit_latency = 1;
+       driver->states[0].target_residency = 10000;
+       driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(driver->states[0].name, "WFI");
+       strcpy(driver->states[0].desc, "Wait for interrupt");
  
        /* Wait for interrupt and RAM self refresh state */
-       device->states[1].enter = at91_enter_idle;
-       device->states[1].exit_latency = 10;
-       device->states[1].target_residency = 10000;
-       device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-       strcpy(device->states[1].name, "RAM_SR");
-       strcpy(device->states[1].desc, "WFI and RAM Self Refresh");
+       driver->states[1].enter = at91_enter_idle;
+       driver->states[1].exit_latency = 10;
+       driver->states[1].target_residency = 10000;
+       driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(driver->states[1].name, "RAM_SR");
+       strcpy(driver->states[1].desc, "WFI and RAM Self Refresh");
+       cpuidle_register_driver(&at91_idle_driver);
  
        if (cpuidle_register_device(device)) {
                printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
  #include <linux/platform_device.h>
  #include <linux/cpuidle.h>
  #include <linux/io.h>
 +#include <linux/export.h>
  #include <asm/proc-fns.h>
  
  #include <mach/cpuidle.h>
 -#include <mach/memory.h>
 +#include <mach/ddr2.h>
  
  #define DAVINCI_CPUIDLE_MAX_STATES    2
  
@@@ -79,9 -78,11 +79,11 @@@ static struct davinci_ops davinci_state
  
  /* Actual code that puts the SoC in different idle states */
  static int davinci_enter_idle(struct cpuidle_device *dev,
-                                               struct cpuidle_state *state)
+                               struct cpuidle_driver *drv,
+                                               int index)
  {
-       struct davinci_ops *ops = cpuidle_get_statedata(state);
+       struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+       struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
        struct timeval before, after;
        int idle_time;
  
        local_irq_enable();
        idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
                        (after.tv_usec - before.tv_usec);
-       return idle_time;
+       dev->last_residency = idle_time;
+       return index;
  }
  
  static int __init davinci_cpuidle_probe(struct platform_device *pdev)
  {
        int ret;
        struct cpuidle_device *device;
+       struct cpuidle_driver *driver = &davinci_idle_driver;
        struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
  
        device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
  
        ddr2_reg_base = pdata->ddr2_ctlr_base;
  
-       ret = cpuidle_register_driver(&davinci_idle_driver);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register driver\n");
-               return ret;
-       }
        /* Wait for interrupt state */
-       device->states[0].enter = davinci_enter_idle;
-       device->states[0].exit_latency = 1;
-       device->states[0].target_residency = 10000;
-       device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-       strcpy(device->states[0].name, "WFI");
-       strcpy(device->states[0].desc, "Wait for interrupt");
+       driver->states[0].enter = davinci_enter_idle;
+       driver->states[0].exit_latency = 1;
+       driver->states[0].target_residency = 10000;
+       driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(driver->states[0].name, "WFI");
+       strcpy(driver->states[0].desc, "Wait for interrupt");
  
        /* Wait for interrupt and DDR self refresh state */
-       device->states[1].enter = davinci_enter_idle;
-       device->states[1].exit_latency = 10;
-       device->states[1].target_residency = 10000;
-       device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-       strcpy(device->states[1].name, "DDR SR");
-       strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+       driver->states[1].enter = davinci_enter_idle;
+       driver->states[1].exit_latency = 10;
+       driver->states[1].target_residency = 10000;
+       driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(driver->states[1].name, "DDR SR");
+       strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
        if (pdata->ddr2_pdown)
                davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
-       cpuidle_set_statedata(&device->states[1], &davinci_states[1]);
+       cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
  
        device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+       driver->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+       ret = cpuidle_register_driver(&davinci_idle_driver);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register driver\n");
+               return ret;
+       }
  
        ret = cpuidle_register_device(device);
        if (ret) {
@@@ -16,7 -16,8 +16,8 @@@
  #include <asm/proc-fns.h>
  
  static int exynos4_enter_idle(struct cpuidle_device *dev,
-                             struct cpuidle_state *state);
+                       struct cpuidle_driver *drv,
+                             int index);
  
  static struct cpuidle_state exynos4_cpuidle_set[] = {
        [0] = {
@@@ -37,7 -38,8 +38,8 @@@ static struct cpuidle_driver exynos4_id
  };
  
  static int exynos4_enter_idle(struct cpuidle_device *dev,
-                             struct cpuidle_state *state)
+                               struct cpuidle_driver *drv,
+                             int index)
  {
        struct timeval before, after;
        int idle_time;
        idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
                    (after.tv_usec - before.tv_usec);
  
-       return idle_time;
+       dev->last_residency = idle_time;
+       return index;
  }
  
  static int __init exynos4_init_cpuidle(void)
  {
        int i, max_cpuidle_state, cpu_id;
        struct cpuidle_device *device;
+       struct cpuidle_driver *drv = &exynos4_idle_driver;
+       /* Setup cpuidle driver */
+       drv->state_count = (sizeof(exynos4_cpuidle_set) /
+                                      sizeof(struct cpuidle_state));
+       max_cpuidle_state = drv->state_count;
+       for (i = 0; i < max_cpuidle_state; i++) {
+               memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
+                               sizeof(struct cpuidle_state));
+       }
        cpuidle_register_driver(&exynos4_idle_driver);
  
        for_each_cpu(cpu_id, cpu_online_mask) {
                device = &per_cpu(exynos4_cpuidle_device, cpu_id);
                device->cpu = cpu_id;
  
-               device->state_count = (sizeof(exynos4_cpuidle_set) /
-                                              sizeof(struct cpuidle_state));
-               max_cpuidle_state = device->state_count;
-               for (i = 0; i < max_cpuidle_state; i++) {
-                       memcpy(&device->states[i], &exynos4_cpuidle_set[i],
-                                       sizeof(struct cpuidle_state));
-               }
+               device->state_count = drv->state_count;
  
                if (cpuidle_register_device(device)) {
                        printk(KERN_ERR "CPUidle register device failed\n,");
@@@ -18,7 -18,6 +18,7 @@@
  #include <linux/platform_device.h>
  #include <linux/cpuidle.h>
  #include <linux/io.h>
 +#include <linux/export.h>
  #include <asm/proc-fns.h>
  #include <mach/kirkwood.h>
  
@@@ -33,17 -32,18 +33,18 @@@ static DEFINE_PER_CPU(struct cpuidle_de
  
  /* Actual code that puts the SoC in different idle states */
  static int kirkwood_enter_idle(struct cpuidle_device *dev,
-                              struct cpuidle_state *state)
+                               struct cpuidle_driver *drv,
+                              int index)
  {
        struct timeval before, after;
        int idle_time;
  
        local_irq_disable();
        do_gettimeofday(&before);
-       if (state == &dev->states[0])
+       if (index == 0)
                /* Wait for interrupt state */
                cpu_do_idle();
-       else if (state == &dev->states[1]) {
+       else if (index == 1) {
                /*
                 * Following write will put DDR in self refresh.
                 * Note that we have 256 cycles before DDR puts it
        local_irq_enable();
        idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
                        (after.tv_usec - before.tv_usec);
-       return idle_time;
+       /* Update last residency */
+       dev->last_residency = idle_time;
+       return index;
  }
  
  /* Initialize CPU idle by registering the idle states */
  static int kirkwood_init_cpuidle(void)
  {
        struct cpuidle_device *device;
-       cpuidle_register_driver(&kirkwood_idle_driver);
+       struct cpuidle_driver *driver = &kirkwood_idle_driver;
  
        device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
        device->state_count = KIRKWOOD_MAX_STATES;
+       driver->state_count = KIRKWOOD_MAX_STATES;
  
        /* Wait for interrupt state */
-       device->states[0].enter = kirkwood_enter_idle;
-       device->states[0].exit_latency = 1;
-       device->states[0].target_residency = 10000;
-       device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-       strcpy(device->states[0].name, "WFI");
-       strcpy(device->states[0].desc, "Wait for interrupt");
+       driver->states[0].enter = kirkwood_enter_idle;
+       driver->states[0].exit_latency = 1;
+       driver->states[0].target_residency = 10000;
+       driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(driver->states[0].name, "WFI");
+       strcpy(driver->states[0].desc, "Wait for interrupt");
  
        /* Wait for interrupt and DDR self refresh state */
-       device->states[1].enter = kirkwood_enter_idle;
-       device->states[1].exit_latency = 10;
-       device->states[1].target_residency = 10000;
-       device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-       strcpy(device->states[1].name, "DDR SR");
-       strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+       driver->states[1].enter = kirkwood_enter_idle;
+       driver->states[1].exit_latency = 10;
+       driver->states[1].target_residency = 10000;
+       driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+       strcpy(driver->states[1].name, "DDR SR");
+       strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
  
+       cpuidle_register_driver(&kirkwood_idle_driver);
        if (cpuidle_register_device(device)) {
                printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
                return -EIO;
@@@ -14,7 -14,6 +14,7 @@@
  #include <linux/io.h>
  #include <linux/suspend.h>
  #include <linux/cpuidle.h>
 +#include <linux/export.h>
  #include <asm/suspend.h>
  #include <asm/uaccess.h>
  #include <asm/hwblk.h>
@@@ -26,11 -25,12 +26,12 @@@ static unsigned long cpuidle_mode[] = 
  };
  
  static int cpuidle_sleep_enter(struct cpuidle_device *dev,
-                              struct cpuidle_state *state)
+                               struct cpuidle_driver *drv,
+                               int index)
  {
        unsigned long allowed_mode = arch_hwblk_sleep_mode();
        ktime_t before, after;
-       int requested_state = state - &dev->states[0];
+       int requested_state = index;
        int allowed_state;
        int k;
  
         */
        k = min_t(int, allowed_state, requested_state);
  
-       dev->last_state = &dev->states[k];
        before = ktime_get();
        sh_mobile_call_standby(cpuidle_mode[k]);
        after = ktime_get();
-       return ktime_to_ns(ktime_sub(after, before)) >> 10;
+       dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10;
+       return k;
  }
  
  static struct cpuidle_device cpuidle_dev;
@@@ -63,19 -65,19 +66,19 @@@ static struct cpuidle_driver cpuidle_dr
  void sh_mobile_setup_cpuidle(void)
  {
        struct cpuidle_device *dev = &cpuidle_dev;
+       struct cpuidle_driver *drv = &cpuidle_driver;
        struct cpuidle_state *state;
        int i;
  
-       cpuidle_register_driver(&cpuidle_driver);
  
        for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
-               dev->states[i].name[0] = '\0';
-               dev->states[i].desc[0] = '\0';
+               drv->states[i].name[0] = '\0';
+               drv->states[i].desc[0] = '\0';
        }
  
        i = CPUIDLE_DRIVER_STATE_START;
  
-       state = &dev->states[i++];
+       state = &drv->states[i++];
        snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
        strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
        state->exit_latency = 1;
        state->flags |= CPUIDLE_FLAG_TIME_VALID;
        state->enter = cpuidle_sleep_enter;
  
-       dev->safe_state = state;
+       drv->safe_state_index = i-1;
  
        if (sh_mobile_sleep_supported & SUSP_SH_SF) {
-               state = &dev->states[i++];
+               state = &drv->states[i++];
                snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
                strncpy(state->desc, "SuperH Sleep Mode [SF]",
                        CPUIDLE_DESC_LEN);
        }
  
        if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
-               state = &dev->states[i++];
+               state = &drv->states[i++];
                snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
                strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
                        CPUIDLE_DESC_LEN);
                state->enter = cpuidle_sleep_enter;
        }
  
+       drv->state_count = i;
        dev->state_count = i;
  
+       cpuidle_register_driver(&cpuidle_driver);
        cpuidle_register_device(dev);
  }
diff --combined drivers/acpi/atomicio.c
@@@ -24,7 -24,7 +24,7 @@@
   */
  
  #include <linux/kernel.h>
 -#include <linux/module.h>
 +#include <linux/export.h>
  #include <linux/init.h>
  #include <linux/acpi.h>
  #include <linux/io.h>
@@@ -76,7 -76,7 +76,7 @@@ static void __iomem *__acpi_ioremap_fas
  {
        struct acpi_iomap *map;
  
-       map = __acpi_find_iomap(paddr, size);
+       map = __acpi_find_iomap(paddr, size/8);
        if (map)
                return map->vaddr + (paddr - map->paddr);
        else
@@@ -37,7 -37,7 +37,7 @@@
  #include <linux/dmi.h>
  #include <linux/moduleparam.h>
  #include <linux/sched.h>      /* need_resched() */
 -#include <linux/pm_qos_params.h>
 +#include <linux/pm_qos.h>
  #include <linux/clockchips.h>
  #include <linux/cpuidle.h>
  #include <linux/irqflags.h>
@@@ -741,22 -741,25 +741,25 @@@ static inline void acpi_idle_do_entry(s
  /**
   * acpi_idle_enter_c1 - enters an ACPI C1 state-type
   * @dev: the target CPU
-  * @state: the state data
+  * @drv: cpuidle driver containing cpuidle state info
+  * @index: index of target state
   *
   * This is equivalent to the HALT instruction.
   */
  static int acpi_idle_enter_c1(struct cpuidle_device *dev,
-                             struct cpuidle_state *state)
+               struct cpuidle_driver *drv, int index)
  {
        ktime_t  kt1, kt2;
        s64 idle_time;
        struct acpi_processor *pr;
-       struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+       struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+       struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
  
        pr = __this_cpu_read(processors);
+       dev->last_residency = 0;
  
        if (unlikely(!pr))
-               return 0;
+               return -EINVAL;
  
        local_irq_disable();
  
        if (acpi_idle_suspend) {
                local_irq_enable();
                cpu_relax();
-               return 0;
+               return -EINVAL;
        }
  
        lapic_timer_state_broadcast(pr, cx, 1);
        kt2 = ktime_get_real();
        idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
  
+       /* Update device last_residency*/
+       dev->last_residency = (int)idle_time;
        local_irq_enable();
        cx->usage++;
        lapic_timer_state_broadcast(pr, cx, 0);
  
-       return idle_time;
+       return index;
  }
  
  /**
   * acpi_idle_enter_simple - enters an ACPI state without BM handling
   * @dev: the target CPU
-  * @state: the state data
+  * @drv: cpuidle driver with cpuidle state information
+  * @index: the index of suggested state
   */
  static int acpi_idle_enter_simple(struct cpuidle_device *dev,
-                                 struct cpuidle_state *state)
+               struct cpuidle_driver *drv, int index)
  {
        struct acpi_processor *pr;
-       struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+       struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+       struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
        ktime_t  kt1, kt2;
        s64 idle_time_ns;
        s64 idle_time;
  
        pr = __this_cpu_read(processors);
+       dev->last_residency = 0;
  
        if (unlikely(!pr))
-               return 0;
-       if (acpi_idle_suspend)
-               return(acpi_idle_enter_c1(dev, state));
+               return -EINVAL;
  
        local_irq_disable();
  
+       if (acpi_idle_suspend) {
+               local_irq_enable();
+               cpu_relax();
+               return -EINVAL;
+       }
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
                /*
                if (unlikely(need_resched())) {
                        current_thread_info()->status |= TS_POLLING;
                        local_irq_enable();
-                       return 0;
+                       return -EINVAL;
                }
        }
  
        idle_time = idle_time_ns;
        do_div(idle_time, NSEC_PER_USEC);
  
+       /* Update device last_residency*/
+       dev->last_residency = (int)idle_time;
        /* Tell the scheduler how much we idled: */
        sched_clock_idle_wakeup_event(idle_time_ns);
  
  
        lapic_timer_state_broadcast(pr, cx, 0);
        cx->time += idle_time;
-       return idle_time;
+       return index;
  }
  
  static int c3_cpu_count;
 -static DEFINE_SPINLOCK(c3_lock);
 +static DEFINE_RAW_SPINLOCK(c3_lock);
  
  /**
   * acpi_idle_enter_bm - enters C3 with proper BM handling
   * @dev: the target CPU
-  * @state: the state data
+  * @drv: cpuidle driver containing state data
+  * @index: the index of suggested state
   *
   * If BM is detected, the deepest non-C3 idle state is entered instead.
   */
  static int acpi_idle_enter_bm(struct cpuidle_device *dev,
-                             struct cpuidle_state *state)
+               struct cpuidle_driver *drv, int index)
  {
        struct acpi_processor *pr;
-       struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+       struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+       struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
        ktime_t  kt1, kt2;
        s64 idle_time_ns;
        s64 idle_time;
  
  
        pr = __this_cpu_read(processors);
+       dev->last_residency = 0;
  
        if (unlikely(!pr))
-               return 0;
+               return -EINVAL;
  
-       if (acpi_idle_suspend)
-               return(acpi_idle_enter_c1(dev, state));
+       if (acpi_idle_suspend) {
+               cpu_relax();
+               return -EINVAL;
+       }
  
        if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
-               if (dev->safe_state) {
-                       dev->last_state = dev->safe_state;
-                       return dev->safe_state->enter(dev, dev->safe_state);
+               if (drv->safe_state_index >= 0) {
+                       return drv->states[drv->safe_state_index].enter(dev,
+                                               drv, drv->safe_state_index);
                } else {
                        local_irq_disable();
                        acpi_safe_halt();
                        local_irq_enable();
-                       return 0;
+                       return -EINVAL;
                }
        }
  
                if (unlikely(need_resched())) {
                        current_thread_info()->status |= TS_POLLING;
                        local_irq_enable();
-                       return 0;
+                       return -EINVAL;
                }
        }
  
         * without doing anything.
         */
        if (pr->flags.bm_check && pr->flags.bm_control) {
 -              spin_lock(&c3_lock);
 +              raw_spin_lock(&c3_lock);
                c3_cpu_count++;
                /* Disable bus master arbitration when all CPUs are in C3 */
                if (c3_cpu_count == num_online_cpus())
                        acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
 -              spin_unlock(&c3_lock);
 +              raw_spin_unlock(&c3_lock);
        } else if (!pr->flags.bm_check) {
                ACPI_FLUSH_CPU_CACHE();
        }
  
        /* Re-enable bus master arbitration */
        if (pr->flags.bm_check && pr->flags.bm_control) {
 -              spin_lock(&c3_lock);
 +              raw_spin_lock(&c3_lock);
                acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
                c3_cpu_count--;
 -              spin_unlock(&c3_lock);
 +              raw_spin_unlock(&c3_lock);
        }
        kt2 = ktime_get_real();
        idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1));
        idle_time = idle_time_ns;
        do_div(idle_time, NSEC_PER_USEC);
  
+       /* Update device last_residency*/
+       dev->last_residency = (int)idle_time;
        /* Tell the scheduler how much we idled: */
        sched_clock_idle_wakeup_event(idle_time_ns);
  
  
        lapic_timer_state_broadcast(pr, cx, 0);
        cx->time += idle_time;
-       return idle_time;
+       return index;
  }
  
  struct cpuidle_driver acpi_idle_driver = {
  };
  
  /**
-  * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE
+  * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE
+  * device i.e. per-cpu data
+  *
   * @pr: the ACPI processor
   */
- static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
+ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
  {
        int i, count = CPUIDLE_DRIVER_STATE_START;
        struct acpi_processor_cx *cx;
-       struct cpuidle_state *state;
+       struct cpuidle_state_usage *state_usage;
        struct cpuidle_device *dev = &pr->power.dev;
  
        if (!pr->flags.power_setup_done)
        }
  
        dev->cpu = pr->id;
+       if (max_cstate == 0)
+               max_cstate = 1;
+       for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
+               cx = &pr->power.states[i];
+               state_usage = &dev->states_usage[count];
+               if (!cx->valid)
+                       continue;
+ #ifdef CONFIG_HOTPLUG_CPU
+               if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
+                   !pr->flags.has_cst &&
+                   !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
+                       continue;
+ #endif
+               cpuidle_set_statedata(state_usage, cx);
+               count++;
+               if (count == CPUIDLE_STATE_MAX)
+                       break;
+       }
+       dev->state_count = count;
+       if (!count)
+               return -EINVAL;
+       return 0;
+ }
+ /**
+  * acpi_processor_setup_cpuidle states- prepares and configures cpuidle
+  * global state data i.e. idle routines
+  *
+  * @pr: the ACPI processor
+  */
+ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+ {
+       int i, count = CPUIDLE_DRIVER_STATE_START;
+       struct acpi_processor_cx *cx;
+       struct cpuidle_state *state;
+       struct cpuidle_driver *drv = &acpi_idle_driver;
+       if (!pr->flags.power_setup_done)
+               return -EINVAL;
+       if (pr->flags.power == 0)
+               return -EINVAL;
+       drv->safe_state_index = -1;
        for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
-               dev->states[i].name[0] = '\0';
-               dev->states[i].desc[0] = '\0';
+               drv->states[i].name[0] = '\0';
+               drv->states[i].desc[0] = '\0';
        }
  
        if (max_cstate == 0)
  
        for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
                cx = &pr->power.states[i];
-               state = &dev->states[count];
  
                if (!cx->valid)
                        continue;
                    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
                        continue;
  #endif
-               cpuidle_set_statedata(state, cx);
  
+               state = &drv->states[count];
                snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
                strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
                state->exit_latency = cx->latency;
                                state->flags |= CPUIDLE_FLAG_TIME_VALID;
  
                        state->enter = acpi_idle_enter_c1;
-                       dev->safe_state = state;
+                       drv->safe_state_index = count;
                        break;
  
                        case ACPI_STATE_C2:
                        state->flags |= CPUIDLE_FLAG_TIME_VALID;
                        state->enter = acpi_idle_enter_simple;
-                       dev->safe_state = state;
+                       drv->safe_state_index = count;
                        break;
  
                        case ACPI_STATE_C3:
                        break;
        }
  
-       dev->state_count = count;
+       drv->state_count = count;
  
        if (!count)
                return -EINVAL;
        return 0;
  }
  
- int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+ int acpi_processor_hotplug(struct acpi_processor *pr)
  {
        int ret = 0;
  
        cpuidle_disable_device(&pr->power.dev);
        acpi_processor_get_power_info(pr);
        if (pr->flags.power) {
-               acpi_processor_setup_cpuidle(pr);
+               acpi_processor_setup_cpuidle_cx(pr);
                ret = cpuidle_enable_device(&pr->power.dev);
        }
        cpuidle_resume_and_unlock();
        return ret;
  }
  
+ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+ {
+       int cpu;
+       struct acpi_processor *_pr;
+       if (disabled_by_idle_boot_param())
+               return 0;
+       if (!pr)
+               return -EINVAL;
+       if (nocst)
+               return -ENODEV;
+       if (!pr->flags.power_setup_done)
+               return -ENODEV;
+       /*
+        * FIXME:  Design the ACPI notification to make it once per
+        * system instead of once per-cpu.  This condition is a hack
+        * to make the code that updates C-States be called once.
+        */
+       if (smp_processor_id() == 0 &&
+                       cpuidle_get_driver() == &acpi_idle_driver) {
+               cpuidle_pause_and_lock();
+               /* Protect against cpu-hotplug */
+               get_online_cpus();
+               /* Disable all cpuidle devices */
+               for_each_online_cpu(cpu) {
+                       _pr = per_cpu(processors, cpu);
+                       if (!_pr || !_pr->flags.power_setup_done)
+                               continue;
+                       cpuidle_disable_device(&_pr->power.dev);
+               }
+               /* Populate Updated C-state information */
+               acpi_processor_setup_cpuidle_states(pr);
+               /* Enable all cpuidle devices */
+               for_each_online_cpu(cpu) {
+                       _pr = per_cpu(processors, cpu);
+                       if (!_pr || !_pr->flags.power_setup_done)
+                               continue;
+                       acpi_processor_get_power_info(_pr);
+                       if (_pr->flags.power) {
+                               acpi_processor_setup_cpuidle_cx(_pr);
+                               cpuidle_enable_device(&_pr->power.dev);
+                       }
+               }
+               put_online_cpus();
+               cpuidle_resume_and_unlock();
+       }
+       return 0;
+ }
+ static int acpi_processor_registered;
  int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
                              struct acpi_device *device)
  {
        acpi_status status = 0;
+       int retval;
        static int first_run;
  
        if (disabled_by_idle_boot_param())
         * platforms that only support C1.
         */
        if (pr->flags.power) {
-               acpi_processor_setup_cpuidle(pr);
-               if (cpuidle_register_device(&pr->power.dev))
-                       return -EIO;
+               /* Register acpi_idle_driver if not already registered */
+               if (!acpi_processor_registered) {
+                       acpi_processor_setup_cpuidle_states(pr);
+                       retval = cpuidle_register_driver(&acpi_idle_driver);
+                       if (retval)
+                               return retval;
+                       printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
+                                       acpi_idle_driver.name);
+               }
+               /* Register per-cpu cpuidle_device. Cpuidle driver
+                * must already be registered before registering device
+                */
+               acpi_processor_setup_cpuidle_cx(pr);
+               retval = cpuidle_register_device(&pr->power.dev);
+               if (retval) {
+                       if (acpi_processor_registered == 0)
+                               cpuidle_unregister_driver(&acpi_idle_driver);
+                       return retval;
+               }
+               acpi_processor_registered++;
        }
        return 0;
  }
@@@ -1139,8 -1297,13 +1297,13 @@@ int acpi_processor_power_exit(struct ac
        if (disabled_by_idle_boot_param())
                return 0;
  
-       cpuidle_unregister_device(&pr->power.dev);
-       pr->flags.power_setup_done = 0;
+       if (pr->flags.power) {
+               cpuidle_unregister_device(&pr->power.dev);
+               acpi_processor_registered--;
+               if (acpi_processor_registered == 0)
+                       cpuidle_unregister_driver(&acpi_idle_driver);
+       }
  
+       pr->flags.power_setup_done = 0;
        return 0;
  }
  #include <linux/mutex.h>
  #include <linux/sched.h>
  #include <linux/notifier.h>
 -#include <linux/pm_qos_params.h>
 +#include <linux/pm_qos.h>
  #include <linux/cpu.h>
  #include <linux/cpuidle.h>
  #include <linux/ktime.h>
  #include <linux/hrtimer.h>
 +#include <linux/module.h>
  #include <trace/events/power.h>
  
  #include "cpuidle.h"
@@@ -62,8 -61,9 +62,9 @@@ static int __cpuidle_register_device(st
  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;
        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 -164,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();
        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");
        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 -225,20 +226,20 @@@ int cpuidle_enable_device(struct cpuidl
                        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 -272,7 +273,7 @@@ void cpuidle_disable_device(struct cpui
        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 -300,6 +301,6 @@@ static int __cpuidle_register_device(st
  
        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))) {
@@@ -14,8 -14,8 +14,8 @@@
  
  #include <linux/kernel.h>
  #include <linux/cpuidle.h>
 -#include <linux/pm_qos_params.h>
 -#include <linux/moduleparam.h>
 +#include <linux/pm_qos.h>
 +#include <linux/module.h>
  #include <linux/jiffies.h>
  
  #include <asm/io.h>
@@@ -60,9 -60,11 +60,11 @@@ static inline void ladder_do_selection(
  
  /**
   * ladder_select_state - selects the next state to enter
+  * @drv: cpuidle driver
   * @dev: the CPU
   */
- static int ladder_select_state(struct cpuidle_device *dev)
+ static int ladder_select_state(struct cpuidle_driver *drv,
+                               struct cpuidle_device *dev)
  {
        struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
        struct ladder_device_state *last_state;
  
        last_state = &ldev->states[last_idx];
  
-       if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID)
-               last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency;
+       if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) {
+               last_residency = cpuidle_get_last_residency(dev) - \
+                                        drv->states[last_idx].exit_latency;
+       }
        else
                last_residency = last_state->threshold.promotion_time + 1;
  
        /* consider promotion */
-       if (last_idx < dev->state_count - 1 &&
+       if (last_idx < drv->state_count - 1 &&
            last_residency > last_state->threshold.promotion_time &&
-           dev->states[last_idx + 1].exit_latency <= latency_req) {
+           drv->states[last_idx + 1].exit_latency <= latency_req) {
                last_state->stats.promotion_count++;
                last_state->stats.demotion_count = 0;
                if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
  
        /* consider demotion */
        if (last_idx > CPUIDLE_DRIVER_STATE_START &&
-           dev->states[last_idx].exit_latency > latency_req) {
+           drv->states[last_idx].exit_latency > latency_req) {
                int i;
  
                for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) {
-                       if (dev->states[i].exit_latency <= latency_req)
+                       if (drv->states[i].exit_latency <= latency_req)
                                break;
                }
                ladder_do_selection(ldev, last_idx, i);
  
  /**
   * ladder_enable_device - setup for the governor
+  * @drv: cpuidle driver
   * @dev: the CPU
   */
- static int ladder_enable_device(struct cpuidle_device *dev)
+ static int ladder_enable_device(struct cpuidle_driver *drv,
+                               struct cpuidle_device *dev)
  {
        int i;
        struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu);
  
        ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START;
  
-       for (i = 0; i < dev->state_count; i++) {
-               state = &dev->states[i];
+       for (i = 0; i < drv->state_count; i++) {
+               state = &drv->states[i];
                lstate = &ldev->states[i];
  
                lstate->stats.promotion_count = 0;
                lstate->threshold.promotion_count = PROMOTION_COUNT;
                lstate->threshold.demotion_count = DEMOTION_COUNT;
  
-               if (i < dev->state_count - 1)
+               if (i < drv->state_count - 1)
                        lstate->threshold.promotion_time = state->exit_latency;
                if (i > 0)
                        lstate->threshold.demotion_time = state->exit_latency;
        return 0;
  }
  
+ /**
+  * ladder_reflect - update the correct last_state_idx
+  * @dev: the CPU
+  * @index: the index of actual state entered
+  */
+ static void ladder_reflect(struct cpuidle_device *dev, int index)
+ {
+       struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
+       if (index > 0)
+               ldev->last_state_idx = index;
+ }
  static struct cpuidle_governor ladder_governor = {
        .name =         "ladder",
        .rating =       10,
        .enable =       ladder_enable_device,
        .select =       ladder_select_state,
+       .reflect =      ladder_reflect,
        .owner =        THIS_MODULE,
  };
  
  
  #include <linux/kernel.h>
  #include <linux/cpuidle.h>
 -#include <linux/pm_qos_params.h>
 +#include <linux/pm_qos.h>
  #include <linux/time.h>
  #include <linux/ktime.h>
  #include <linux/hrtimer.h>
  #include <linux/tick.h>
  #include <linux/sched.h>
  #include <linux/math64.h>
 +#include <linux/module.h>
  
  #define BUCKETS 12
  #define INTERVALS 8
@@@ -183,7 -182,7 +183,7 @@@ static inline int performance_multiplie
  
  static DEFINE_PER_CPU(struct menu_device, menu_devices);
  
- static void menu_update(struct cpuidle_device *dev);
+ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
  
  /* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */
  static u64 div_round64(u64 dividend, u32 divisor)
@@@ -229,9 -228,10 +229,10 @@@ static void detect_repeating_patterns(s
  
  /**
   * menu_select - selects the next idle state to enter
+  * @drv: cpuidle driver containing state data
   * @dev: the CPU
   */
- static int menu_select(struct cpuidle_device *dev)
+ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
  {
        struct menu_device *data = &__get_cpu_var(menu_devices);
        int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
        struct timespec t;
  
        if (data->needs_update) {
-               menu_update(dev);
+               menu_update(drv, dev);
                data->needs_update = 0;
        }
  
         * Find the idle state with the lowest power while satisfying
         * our constraints.
         */
-       for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) {
-               struct cpuidle_state *s = &dev->states[i];
+       for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
+               struct cpuidle_state *s = &drv->states[i];
  
-               if (s->flags & CPUIDLE_FLAG_IGNORE)
-                       continue;
                if (s->target_residency > data->predicted_us)
                        continue;
                if (s->exit_latency > latency_req)
  /**
   * menu_reflect - records that data structures need update
   * @dev: the CPU
+  * @index: the index of actual entered state
   *
   * NOTE: it's important to be fast here because this operation will add to
   *       the overall exit latency.
   */
- static void menu_reflect(struct cpuidle_device *dev)
+ static void menu_reflect(struct cpuidle_device *dev, int index)
  {
        struct menu_device *data = &__get_cpu_var(menu_devices);
-       data->needs_update = 1;
+       data->last_state_idx = index;
+       if (index >= 0)
+               data->needs_update = 1;
  }
  
  /**
   * menu_update - attempts to guess what happened after entry
+  * @drv: cpuidle driver containing state data
   * @dev: the CPU
   */
- static void menu_update(struct cpuidle_device *dev)
+ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
  {
        struct menu_device *data = &__get_cpu_var(menu_devices);
        int last_idx = data->last_state_idx;
        unsigned int last_idle_us = cpuidle_get_last_residency(dev);
-       struct cpuidle_state *target = &dev->states[last_idx];
+       struct cpuidle_state *target = &drv->states[last_idx];
        unsigned int measured_us;
        u64 new_factor;
  
  
  /**
   * menu_enable_device - scans a CPU's states and does setup
+  * @drv: cpuidle driver
   * @dev: the CPU
   */
- static int menu_enable_device(struct cpuidle_device *dev)
+ static int menu_enable_device(struct cpuidle_driver *drv,
+                               struct cpuidle_device *dev)
  {
        struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
  
@@@ -61,7 -61,6 +61,7 @@@
  #include <linux/sched.h>
  #include <linux/notifier.h>
  #include <linux/cpu.h>
 +#include <linux/module.h>
  #include <asm/mwait.h>
  #include <asm/msr.h>
  
@@@ -82,7 -81,8 +82,8 @@@ static unsigned int mwait_substates
  static unsigned int lapic_timer_reliable_states = (1 << 1);    /* Default to only C1 */
  
  static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
- static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
+ static int intel_idle(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv, int index);
  
  static struct cpuidle_state *cpuidle_state_table;
  
@@@ -110,7 -110,6 +111,6 @@@ static struct cpuidle_state nehalem_cst
        { /* MWAIT C1 */
                .name = "C1-NHM",
                .desc = "MWAIT 0x00",
-               .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
                .exit_latency = 3,
                .target_residency = 6,
        { /* MWAIT C2 */
                .name = "C3-NHM",
                .desc = "MWAIT 0x10",
-               .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 20,
                .target_residency = 80,
        { /* MWAIT C3 */
                .name = "C6-NHM",
                .desc = "MWAIT 0x20",
-               .driver_data = (void *) 0x20,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 200,
                .target_residency = 800,
@@@ -138,7 -135,6 +136,6 @@@ static struct cpuidle_state snb_cstates
        { /* MWAIT C1 */
                .name = "C1-SNB",
                .desc = "MWAIT 0x00",
-               .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
                .exit_latency = 1,
                .target_residency = 1,
        { /* MWAIT C2 */
                .name = "C3-SNB",
                .desc = "MWAIT 0x10",
-               .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 80,
                .target_residency = 211,
        { /* MWAIT C3 */
                .name = "C6-SNB",
                .desc = "MWAIT 0x20",
-               .driver_data = (void *) 0x20,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 104,
                .target_residency = 345,
        { /* MWAIT C4 */
                .name = "C7-SNB",
                .desc = "MWAIT 0x30",
-               .driver_data = (void *) 0x30,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 109,
                .target_residency = 345,
@@@ -174,7 -167,6 +168,6 @@@ static struct cpuidle_state atom_cstate
        { /* MWAIT C1 */
                .name = "C1-ATM",
                .desc = "MWAIT 0x00",
-               .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
                .exit_latency = 1,
                .target_residency = 4,
        { /* MWAIT C2 */
                .name = "C2-ATM",
                .desc = "MWAIT 0x10",
-               .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID,
                .exit_latency = 20,
                .target_residency = 80,
        { /* MWAIT C4 */
                .name = "C4-ATM",
                .desc = "MWAIT 0x30",
-               .driver_data = (void *) 0x30,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 100,
                .target_residency = 400,
        { /* MWAIT C6 */
                .name = "C6-ATM",
                .desc = "MWAIT 0x52",
-               .driver_data = (void *) 0x52,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
                .exit_latency = 140,
                .target_residency = 560,
                .enter = &intel_idle },
  };
  
+ static int get_driver_data(int cstate)
+ {
+       int driver_data;
+       switch (cstate) {
+       case 1: /* MWAIT C1 */
+               driver_data = 0x00;
+               break;
+       case 2: /* MWAIT C2 */
+               driver_data = 0x10;
+               break;
+       case 3: /* MWAIT C3 */
+               driver_data = 0x20;
+               break;
+       case 4: /* MWAIT C4 */
+               driver_data = 0x30;
+               break;
+       case 5: /* MWAIT C5 */
+               driver_data = 0x40;
+               break;
+       case 6: /* MWAIT C6 */
+               driver_data = 0x52;
+               break;
+       default:
+               driver_data = 0x00;
+       }
+       return driver_data;
+ }
  /**
   * intel_idle
   * @dev: cpuidle_device
-  * @state: cpuidle state
+  * @drv: cpuidle driver
+  * @index: index of cpuidle state
   *
   */
- static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
+ static int intel_idle(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
  {
        unsigned long ecx = 1; /* break on interrupt flag */
-       unsigned long eax = (unsigned long)cpuidle_get_statedata(state);
+       struct cpuidle_state *state = &drv->states[index];
+       struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+       unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage);
        unsigned int cstate;
        ktime_t kt_before, kt_after;
        s64 usec_delta;
        if (!(lapic_timer_reliable_states & (1 << (cstate))))
                clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
  
-       return usec_delta;
+       /* Update cpuidle counters */
+       dev->last_residency = (int)usec_delta;
+       return index;
  }
  
  static void __setup_broadcast_timer(void *arg)
@@@ -397,6 -422,60 +423,60 @@@ static void intel_idle_cpuidle_devices_
        free_percpu(intel_idle_cpuidle_devices);
        return;
  }
+ /*
+  * intel_idle_cpuidle_driver_init()
+  * allocate, initialize cpuidle_states
+  */
+ static int intel_idle_cpuidle_driver_init(void)
+ {
+       int cstate;
+       struct cpuidle_driver *drv = &intel_idle_driver;
+       drv->state_count = 1;
+       for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
+               int num_substates;
+               if (cstate > max_cstate) {
+                       printk(PREFIX "max_cstate %d reached\n",
+                               max_cstate);
+                       break;
+               }
+               /* does the state exist in CPUID.MWAIT? */
+               num_substates = (mwait_substates >> ((cstate) * 4))
+                                       & MWAIT_SUBSTATE_MASK;
+               if (num_substates == 0)
+                       continue;
+               /* is the state not enabled? */
+               if (cpuidle_state_table[cstate].enter == NULL) {
+                       /* does the driver not know about the state? */
+                       if (*cpuidle_state_table[cstate].name == '\0')
+                               pr_debug(PREFIX "unaware of model 0x%x"
+                                       " MWAIT %d please"
+                                       " contact lenb@kernel.org",
+                               boot_cpu_data.x86_model, cstate);
+                       continue;
+               }
+               if ((cstate > 2) &&
+                       !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+                       mark_tsc_unstable("TSC halts in idle"
+                                       " states deeper than C2");
+               drv->states[drv->state_count] = /* structure copy */
+                       cpuidle_state_table[cstate];
+               drv->state_count += 1;
+       }
+       if (auto_demotion_disable_flags)
+               smp_call_function(auto_demotion_disable, NULL, 1);
+       return 0;
+ }
  /*
   * intel_idle_cpuidle_devices_init()
   * allocate, initialize, register cpuidle_devices
@@@ -431,22 -510,11 +511,11 @@@ static int intel_idle_cpuidle_devices_i
                                continue;
                        /* is the state not enabled? */
                        if (cpuidle_state_table[cstate].enter == NULL) {
-                               /* does the driver not know about the state? */
-                               if (*cpuidle_state_table[cstate].name == '\0')
-                                       pr_debug(PREFIX "unaware of model 0x%x"
-                                               " MWAIT %d please"
-                                               " contact lenb@kernel.org",
-                                       boot_cpu_data.x86_model, cstate);
                                continue;
                        }
  
-                       if ((cstate > 2) &&
-                               !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
-                               mark_tsc_unstable("TSC halts in idle"
-                                       " states deeper than C2");
-                       dev->states[dev->state_count] = /* structure copy */
-                               cpuidle_state_table[cstate];
+                       dev->states_usage[dev->state_count].driver_data =
+                               (void *)get_driver_data(cstate);
  
                        dev->state_count += 1;
                }
                        return -EIO;
                }
        }
-       if (auto_demotion_disable_flags)
-               smp_call_function(auto_demotion_disable, NULL, 1);
  
        return 0;
  }
@@@ -478,6 -544,7 +545,7 @@@ static int __init intel_idle_init(void
        if (retval)
                return retval;
  
+       intel_idle_cpuidle_driver_init();
        retval = cpuidle_register_driver(&intel_idle_driver);
        if (retval) {
                printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
diff --combined include/linux/cpuidle.h
@@@ -13,6 -13,7 +13,6 @@@
  
  #include <linux/percpu.h>
  #include <linux/list.h>
 -#include <linux/module.h>
  #include <linux/kobject.h>
  #include <linux/completion.h>
  
  #define CPUIDLE_NAME_LEN      16
  #define CPUIDLE_DESC_LEN      32
  
 +struct module;
 +
  struct cpuidle_device;
+ struct cpuidle_driver;
  
  
  /****************************
   * CPUIDLE DEVICE INTERFACE *
   ****************************/
  
+ struct cpuidle_state_usage {
+       void            *driver_data;
+       unsigned long long      usage;
+       unsigned long long      time; /* in US */
+ };
  struct cpuidle_state {
        char            name[CPUIDLE_NAME_LEN];
        char            desc[CPUIDLE_DESC_LEN];
-       void            *driver_data;
  
        unsigned int    flags;
        unsigned int    exit_latency; /* in US */
        unsigned int    power_usage; /* in mW */
        unsigned int    target_residency; /* in US */
  
-       unsigned long long      usage;
-       unsigned long long      time; /* in US */
        int (*enter)    (struct cpuidle_device *dev,
-                        struct cpuidle_state *state);
+                       struct cpuidle_driver *drv,
+                       int index);
  };
  
  /* Idle State Flags */
  #define CPUIDLE_FLAG_TIME_VALID       (0x01) /* is residency time measurable? */
- #define CPUIDLE_FLAG_IGNORE   (0x100) /* ignore during this idle period */
  
  #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
  
  /**
   * cpuidle_get_statedata - retrieves private driver state data
-  * @state: the state
+  * @st_usage: the state usage statistics
   */
- static inline void * cpuidle_get_statedata(struct cpuidle_state *state)
+ static inline void *cpuidle_get_statedata(struct cpuidle_state_usage *st_usage)
  {
-       return state->driver_data;
+       return st_usage->driver_data;
  }
  
  /**
   * cpuidle_set_statedata - stores private driver state data
-  * @state: the state
+  * @st_usage: the state usage statistics
   * @data: the private data
   */
  static inline void
- cpuidle_set_statedata(struct cpuidle_state *state, void *data)
+ cpuidle_set_statedata(struct cpuidle_state_usage *st_usage, void *data)
  {
-       state->driver_data = data;
+       st_usage->driver_data = data;
  }
  
  struct cpuidle_state_kobj {
        struct cpuidle_state *state;
+       struct cpuidle_state_usage *state_usage;
        struct completion kobj_unregister;
        struct kobject kobj;
  };
  struct cpuidle_device {
        unsigned int            registered:1;
        unsigned int            enabled:1;
-       unsigned int            power_specified:1;
        unsigned int            cpu;
  
        int                     last_residency;
        int                     state_count;
-       struct cpuidle_state    states[CPUIDLE_STATE_MAX];
+       struct cpuidle_state_usage      states_usage[CPUIDLE_STATE_MAX];
        struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
-       struct cpuidle_state    *last_state;
  
        struct list_head        device_list;
        struct kobject          kobj;
        struct completion       kobj_unregister;
        void                    *governor_data;
-       struct cpuidle_state    *safe_state;
-       int (*prepare)          (struct cpuidle_device *dev);
  };
  
  DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
@@@ -120,6 -119,11 +120,11 @@@ static inline int cpuidle_get_last_resi
  struct cpuidle_driver {
        char                    name[CPUIDLE_NAME_LEN];
        struct module           *owner;
+       unsigned int            power_specified:1;
+       struct cpuidle_state    states[CPUIDLE_STATE_MAX];
+       int                     state_count;
+       int                     safe_state_index;
  };
  
  #ifdef CONFIG_CPU_IDLE
@@@ -166,11 -170,14 +171,14 @@@ struct cpuidle_governor 
        struct list_head        governor_list;
        unsigned int            rating;
  
-       int  (*enable)          (struct cpuidle_device *dev);
-       void (*disable)         (struct cpuidle_device *dev);
+       int  (*enable)          (struct cpuidle_driver *drv,
+                                       struct cpuidle_device *dev);
+       void (*disable)         (struct cpuidle_driver *drv,
+                                       struct cpuidle_device *dev);
  
-       int  (*select)          (struct cpuidle_device *dev);
-       void (*reflect)         (struct cpuidle_device *dev);
+       int  (*select)          (struct cpuidle_driver *drv,
+                                       struct cpuidle_device *dev);
+       void (*reflect)         (struct cpuidle_device *dev, int index);
  
        struct module           *owner;
  };