This patch makes the cpuidle_states structure global (single copy)
instead of per-cpu. The statistics needed on per-cpu basis
by the governor are kept per-cpu. This simplifies the cpuidle
subsystem as state registration is done by single cpu only.
Having single copy of cpuidle_states saves memory. Rare case
of asymmetric C-states can be handled within the cpuidle driver
and architectures such as POWER do not have asymmetric C-states.

ToDo:
1. Handle the case when idle states may change at run time
and acpi_processor_cst_has_changed() routine is called in a
better way than the current solution in this patch.
Ref: https://lkml.org/lkml/2011/4/25/83

Signed-off-by: Trinabh Gupta <[email protected]>
---

 arch/arm/mach-at91/cpuidle.c          |   31 +++--
 arch/arm/mach-davinci/cpuidle.c       |   39 ++++---
 arch/arm/mach-kirkwood/cpuidle.c      |   30 +++--
 arch/arm/mach-omap2/cpuidle34xx.c     |   95 ++++++++++++----
 arch/sh/kernel/cpu/shmobile/cpuidle.c |   18 ++-
 drivers/acpi/processor_driver.c       |   20 +--
 drivers/acpi/processor_idle.c         |  193 +++++++++++++++++++++++++++++----
 drivers/cpuidle/cpuidle.c             |   45 ++------
 drivers/cpuidle/driver.c              |   25 ++++
 drivers/cpuidle/governors/ladder.c    |   26 +++-
 drivers/cpuidle/governors/menu.c      |   20 ++-
 drivers/cpuidle/sysfs.c               |    3 -
 drivers/idle/intel_idle.c             |   80 ++++++++++----
 include/acpi/processor.h              |    1 
 include/linux/cpuidle.h               |   19 ++-
 15 files changed, 448 insertions(+), 197 deletions(-)

diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index 4696a0d..93178f6 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -33,6 +33,7 @@ static struct cpuidle_driver at91_idle_driver = {
 
 /* Actual code that puts the SoC in different idle states */
 static int at91_enter_idle(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv,
                               int index)
 {
        struct timeval before, after;
@@ -64,27 +65,29 @@ static int at91_enter_idle(struct cpuidle_device *dev,
 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");
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index f2d2f34..dbeeccd 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -78,6 +78,7 @@ static struct davinci_ops 
davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
 
 /* Actual code that puts the SoC in different idle states */
 static int davinci_enter_idle(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
                                                int index)
 {
        struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -109,6 +110,7 @@ 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());
@@ -120,32 +122,33 @@ static int __init davinci_cpuidle_probe(struct 
platform_device *pdev)
 
        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_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) {
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index 358dd80..ffd690d 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -32,6 +32,7 @@ static DEFINE_PER_CPU(struct cpuidle_device, 
kirkwood_cpuidle_device);
 
 /* Actual code that puts the SoC in different idle states */
 static int kirkwood_enter_idle(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
                               int index)
 {
        struct timeval before, after;
@@ -68,28 +69,29 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev,
 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;
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c 
b/arch/arm/mach-omap2/cpuidle34xx.c
index 3f89036..f041353 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -114,12 +114,14 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
 /**
  * omap3_enter_idle - Programs OMAP3 to enter the specified state
  * @dev: cpuidle device
+ * @drv: cpuidle driver
  * @index: the index of state to be entered
  *
  * Called from the CPUidle framework to program the device to the
  * specified target state selected by the governor.
  */
 static int omap3_enter_idle(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv,
                        int index)
 {
        struct omap3_processor_cx *cx =
@@ -173,6 +175,7 @@ return_sleep_time:
 /**
  * next_valid_state - Find next valid c-state
  * @dev: cpuidle device
+ * @drv: cpuidle driver
  * @index: Index of currently selected c-state
  *
  * If the state corresponding to index is valid, index is returned back
@@ -180,9 +183,10 @@ return_sleep_time:
  * still valid (as defined in omap3_power_states[]) and returns its index.
  */
 static int next_valid_state(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
                                                int index)
 {
-       struct cpuidle_state *curr = &dev->states[index];
+       struct cpuidle_state *curr = &drv->states[index];
        struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
        struct omap3_processor_cx *cx;
        int next_index = -1;
@@ -199,7 +203,7 @@ static int next_valid_state(struct cpuidle_device *dev,
                 * Reach the current state starting at highest C-state
                 */
                for (; idx >= OMAP3_STATE_C1; idx--) {
-                       if (&dev->states[idx] == curr) {
+                       if (&drv->states[idx] == curr) {
                                next_index = idx;
                                break;
                        }
@@ -236,6 +240,7 @@ static int next_valid_state(struct cpuidle_device *dev,
 /**
  * omap3_enter_idle_bm - Checks for any bus activity
  * @dev: cpuidle device
+ * @drv: cpuidle driver
  * @index: array index of target state to be programmed
  *
  * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This
@@ -243,18 +248,19 @@ static int next_valid_state(struct cpuidle_device *dev,
  * device to the specified or a safer state.
  */
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
                               int index)
 {
-       struct cpuidle_state *state = &dev->states[index];
-       int new_state_idx = next_valid_state(dev, index);
+       struct cpuidle_state *state = &drv->states[index];
+       int new_state_idx = next_valid_state(dev, drv, index);
        u32 core_next_state, per_next_state = 0, per_saved_state = 0;
        u32 cam_state;
        struct omap3_processor_cx *cx;
        int ret;
 
        if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
-               BUG_ON(dev->safe_state_index < 0);
-               new_state_idx = dev->safe_state_index;
+               BUG_ON(drv->safe_state_index < 0);
+               new_state_idx = drv->safe_state_index;
                goto select_state;
        }
 
@@ -275,7 +281,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
         */
        cam_state = pwrdm_read_pwrst(cam_pd);
        if (cam_state == PWRDM_POWER_ON) {
-               new_state_idx = dev->safe_state_index;
+               new_state_idx = drv->safe_state_index;
                goto select_state;
        }
 
@@ -293,7 +299,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
                pwrdm_set_next_pwrst(per_pd, per_next_state);
 
 select_state:
-       ret = omap3_enter_idle(dev, new_state_idx);
+       ret = omap3_enter_idle(dev, drv, new_state_idx);
 
        /* Restore original PER state if it was modified */
        if (per_next_state != per_saved_state)
@@ -492,18 +498,16 @@ struct cpuidle_driver omap3_idle_driver = {
 };
 
 /**
- * omap3_idle_init - Init routine for OMAP3 idle
+ * omap3_cpuidle_driver_init
  *
- * Registers the OMAP3 specific cpuidle driver with the cpuidle
- * framework with the valid set of states.
+ * Sets up and registers omap3 idle driver
  */
-int __init omap3_idle_init(void)
+static int omap3_cpuidle_driver_init(void)
 {
-       int i, count = 0;
+       int i, retval, count = 0;
        struct omap3_processor_cx *cx;
        struct cpuidle_state *state;
-       struct cpuidle_state_usage *state_usage;
-       struct cpuidle_device *dev;
+       struct cpuidle_driver *drv = &omap3_idle_driver;
 
        mpu_pd = pwrdm_lookup("mpu_pwrdm");
        core_pd = pwrdm_lookup("core_pwrdm");
@@ -511,26 +515,21 @@ int __init omap3_idle_init(void)
        cam_pd = pwrdm_lookup("cam_pwrdm");
 
        omap_init_power_states();
-       cpuidle_register_driver(&omap3_idle_driver);
-
-       dev = &per_cpu(omap3_idle_dev, smp_processor_id());
-       dev->safe_state_index = -1;
+       drv->safe_state_index = -1;
 
        for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
                cx = &omap3_power_states[i];
-               state = &dev->states[count];
-               state_usage = &dev->states_usage[count];
+               state = &drv->states[count];
 
                if (!cx->valid)
                        continue;
-               cpuidle_set_statedata(state_usage, cx);
                state->exit_latency = cx->sleep_latency + cx->wakeup_latency;
                state->target_residency = cx->threshold;
                state->flags = cx->flags;
                state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ?
                        omap3_enter_idle_bm : omap3_enter_idle;
                if (cx->type == OMAP3_STATE_C1)
-                       dev->safe_state_index = count;
+                       drv->safe_state_index = count;
                sprintf(state->name, "C%d", count+1);
                strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
                count++;
@@ -538,13 +537,61 @@ int __init omap3_idle_init(void)
 
        if (!count)
                return -EINVAL;
-       dev->state_count = count;
+       drv->state_count = count;
 
        if (enable_off_mode)
                omap3_cpuidle_update_states(PWRDM_POWER_OFF, PWRDM_POWER_OFF);
        else
                omap3_cpuidle_update_states(PWRDM_POWER_RET, PWRDM_POWER_RET);
 
+       retval = cpuidle_register_driver(&omap3_idle_driver);
+       if (retval) {
+               printk(KERN_ERR "%s: CPUidle register driver failed\n",
+                      __func__);
+               return retval;
+       }
+
+       return 0;
+}
+
+/**
+ * omap3_idle_init
+ *
+ * Registers the OMAP3 specific cpuidle driver with the cpuidle
+ * framework with the valid set of states, registers per cpu
+ * cpuidle device.
+ */
+int __init omap3_idle_init(void)
+{
+       int i, retval, count = 0;
+       static int cpuidle_drv_init;
+       struct omap3_processor_cx *cx;
+       struct cpuidle_state_usage *state_usage;
+       struct cpuidle_device *dev;
+
+       if (!cpuidle_drv_init) {
+               retval = omap3_cpuidle_driver_init();
+               if (retval)
+                       return retval;
+               cpuidle_drv_init++;
+       }
+
+       dev = &per_cpu(omap3_idle_dev, smp_processor_id());
+
+       for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
+               cx = &omap3_power_states[i];
+               state_usage = &dev->states_usage[count];
+
+               if (!cx->valid)
+                       continue;
+               cpuidle_set_statedata(state_usage, cx);
+               count++;
+       }
+
+       if (!count)
+               return -EINVAL;
+       dev->state_count = count;
+
        if (cpuidle_register_device(dev)) {
                printk(KERN_ERR "%s: CPUidle register device failed\n",
                       __func__);
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c 
b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 7be50d4..ad1012a 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -25,6 +25,7 @@ static unsigned long cpuidle_mode[] = {
 };
 
 static int cpuidle_sleep_enter(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
                                int index)
 {
        unsigned long allowed_mode = arch_hwblk_sleep_mode();
@@ -64,19 +65,19 @@ static struct cpuidle_driver cpuidle_driver = {
 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;
@@ -86,10 +87,10 @@ void sh_mobile_setup_cpuidle(void)
        state->flags |= CPUIDLE_FLAG_TIME_VALID;
        state->enter = cpuidle_sleep_enter;
 
-       dev->safe_state_index = i-1;
+       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);
@@ -102,7 +103,7 @@ void sh_mobile_setup_cpuidle(void)
        }
 
        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);
@@ -114,7 +115,10 @@ void sh_mobile_setup_cpuidle(void)
                state->enter = cpuidle_sleep_enter;
        }
 
+       drv->state_count = i;
        dev->state_count = i;
 
+       cpuidle_register_driver(&cpuidle_driver);
+
        cpuidle_register_device(dev);
 }
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index a4e0f1b..9d7bc9f 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -426,7 +426,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
 
        if (action == CPU_ONLINE && pr) {
                acpi_processor_ppc_has_changed(pr, 0);
-               acpi_processor_cst_has_changed(pr);
+               acpi_processor_hotplug(pr);
                acpi_processor_reevaluate_tstate(pr, action);
                acpi_processor_tstate_has_changed(pr);
        }
@@ -503,8 +503,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device 
*device)
        acpi_processor_get_throttling_info(pr);
        acpi_processor_get_limit_info(pr);
 
-
-       if (cpuidle_get_driver() == &acpi_idle_driver)
+       if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
                acpi_processor_power_init(pr, device);
 
        pr->cdev = thermal_cooling_device_register("Processor", device,
@@ -800,17 +799,9 @@ static int __init acpi_processor_init(void)
 
        memset(&errata, 0, sizeof(errata));
 
-       if (!cpuidle_register_driver(&acpi_idle_driver)) {
-               printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
-                       acpi_idle_driver.name);
-       } else {
-               printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n",
-                       cpuidle_get_driver()->name);
-       }
-
        result = acpi_bus_register_driver(&acpi_processor_driver);
        if (result < 0)
-               goto out_cpuidle;
+               return result;
 
        acpi_processor_install_hotplug_notify();
 
@@ -821,11 +812,6 @@ static int __init acpi_processor_init(void)
        acpi_processor_throttling_init();
 
        return 0;
-
-out_cpuidle:
-       cpuidle_unregister_driver(&acpi_idle_driver);
-
-       return result;
 }
 
 static void __exit acpi_processor_exit(void)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e888c9e..aa3a9c7 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -740,11 +740,13 @@ static inline void acpi_idle_do_entry(struct 
acpi_processor_cx *cx)
 /**
  * acpi_idle_enter_c1 - enters an ACPI C1 state-type
  * @dev: the target CPU
+ * @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, int index)
+static int acpi_idle_enter_c1(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
 {
        ktime_t  kt1, kt2;
        s64 idle_time;
@@ -786,9 +788,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, 
int index)
 /**
  * acpi_idle_enter_simple - enters an ACPI state without BM handling
  * @dev: the target CPU
+ * @drv: cpuidle driver with cpuidle state information
  * @index: the index of suggested state
  */
-static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index)
+static int acpi_idle_enter_simple(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
 {
        struct acpi_processor *pr;
        struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -868,11 +872,13 @@ static DEFINE_SPINLOCK(c3_lock);
 /**
  * acpi_idle_enter_bm - enters C3 with proper BM handling
  * @dev: the target CPU
+ * @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, int index)
+static int acpi_idle_enter_bm(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
 {
        struct acpi_processor *pr;
        struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -895,9 +901,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, 
int index)
        }
 
        if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
-               if (dev->safe_state_index >= 0) {
-                       return dev->states[dev->safe_state_index].enter(dev,
-                                               dev->safe_state_index);
+               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();
@@ -992,14 +998,15 @@ 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;
 
@@ -1011,18 +1018,12 @@ static int acpi_processor_setup_cpuidle(struct 
acpi_processor *pr)
        }
 
        dev->cpu = pr->id;
-       dev->safe_state_index = -1;
-       for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
-               dev->states[i].name[0] = '\0';
-               dev->states[i].desc[0] = '\0';
-       }
 
        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 = &dev->states[count];
                state_usage = &dev->states_usage[count];
 
                if (!cx->valid)
@@ -1034,8 +1035,65 @@ static int acpi_processor_setup_cpuidle(struct 
acpi_processor *pr)
                    !(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++) {
+               drv->states[i].name[0] = '\0';
+               drv->states[i].desc[0] = '\0';
+       }
+
+       if (max_cstate == 0)
+               max_cstate = 1;
+
+       for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
+               cx = &pr->power.states[i];
+
+               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
+
+               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;
@@ -1048,13 +1106,13 @@ static int acpi_processor_setup_cpuidle(struct 
acpi_processor *pr)
                                state->flags |= CPUIDLE_FLAG_TIME_VALID;
 
                        state->enter = acpi_idle_enter_c1;
-                       dev->safe_state_index = count;
+                       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_index = count;
+                       drv->safe_state_index = count;
                        break;
 
                        case ACPI_STATE_C3:
@@ -1070,7 +1128,7 @@ static int acpi_processor_setup_cpuidle(struct 
acpi_processor *pr)
                        break;
        }
 
-       dev->state_count = count;
+       drv->state_count = count;
 
        if (!count)
                return -EINVAL;
@@ -1078,7 +1136,7 @@ static int acpi_processor_setup_cpuidle(struct 
acpi_processor *pr)
        return 0;
 }
 
-int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+int acpi_processor_hotplug(struct acpi_processor *pr)
 {
        int ret = 0;
 
@@ -1099,7 +1157,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor 
*pr)
        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();
@@ -1107,10 +1165,73 @@ int acpi_processor_cst_has_changed(struct 
acpi_processor *pr)
        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())
@@ -1147,9 +1268,26 @@ int __cpuinit acpi_processor_power_init(struct 
acpi_processor *pr,
         * 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;
 }
@@ -1160,8 +1298,13 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
        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;
 }
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 6afc754..f45fa4f 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -61,6 +61,7 @@ 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, entered_state;
 
@@ -84,19 +85,19 @@ int cpuidle_idle_call(void)
 #endif
 
        /* 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];
+       target_state = &drv->states[next_state];
 
        /* Is using next_state here correct ?? */
        trace_power_start(POWER_CSTATE, next_state, dev->cpu);
        trace_cpu_idle(next_state, dev->cpu);
 
-       entered_state = target_state->enter(dev, next_state);
+       entered_state = target_state->enter(dev, drv, next_state);
 
        trace_power_end(dev->cpu);
        trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
@@ -164,7 +165,8 @@ 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, int index)
+static int poll_idle(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
 {
        ktime_t t1, t2;
        s64 diff;
@@ -184,12 +186,9 @@ static int poll_idle(struct cpuidle_device *dev, int index)
        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];
-       struct cpuidle_state_usage *state_usage = &dev->states_usage[0];
-
-       cpuidle_set_statedata(state_usage, 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");
@@ -200,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 */
 
 /**
@@ -227,13 +226,13 @@ 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++) {
@@ -274,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--;
@@ -302,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))) {
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 3f7e3ce..284d7af 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -17,6 +17,30 @@
 static struct cpuidle_driver *cpuidle_curr_driver;
 DEFINE_SPINLOCK(cpuidle_driver_lock);
 
+static void __cpuidle_register_driver(struct cpuidle_driver *drv)
+{
+       int i;
+       /*
+        * cpuidle driver should set the drv->power_specified bit
+        * before registering if the driver provides
+        * power_usage numbers.
+        *
+        * If 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 (!drv->power_specified) {
+               for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
+                       drv->states[i].power_usage = -1 - i;
+       }
+}
+
+
 /**
  * cpuidle_register_driver - registers a driver
  * @drv: the driver
@@ -34,6 +58,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
                spin_unlock(&cpuidle_driver_lock);
                return -EBUSY;
        }
+       __cpuidle_register_driver(drv);
        cpuidle_curr_driver = drv;
        spin_unlock(&cpuidle_driver_lock);
 
diff --git a/drivers/cpuidle/governors/ladder.c 
b/drivers/cpuidle/governors/ladder.c
index 6a686a7..988d813 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -60,9 +60,11 @@ static inline void ladder_do_selection(struct ladder_device 
*ldev,
 
 /**
  * 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;
@@ -77,15 +79,15 @@ static int ladder_select_state(struct cpuidle_device *dev)
 
        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) {
@@ -96,11 +98,11 @@ static int ladder_select_state(struct cpuidle_device *dev)
 
        /* 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);
@@ -123,9 +125,11 @@ static int ladder_select_state(struct cpuidle_device *dev)
 
 /**
  * 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);
@@ -134,8 +138,8 @@ static int ladder_enable_device(struct cpuidle_device *dev)
 
        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;
@@ -144,7 +148,7 @@ static int ladder_enable_device(struct cpuidle_device *dev)
                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;
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index af724e8..bcbe881 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -182,7 +182,7 @@ static inline int performance_multiplier(void)
 
 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)
@@ -228,9 +228,10 @@ static void detect_repeating_patterns(struct menu_device 
*data)
 
 /**
  * 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);
@@ -240,7 +241,7 @@ static int menu_select(struct cpuidle_device *dev)
        struct timespec t;
 
        if (data->needs_update) {
-               menu_update(dev);
+               menu_update(drv, dev);
                data->needs_update = 0;
        }
 
@@ -285,8 +286,8 @@ static int menu_select(struct cpuidle_device *dev)
         * 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->target_residency > data->predicted_us)
                        continue;
@@ -323,14 +324,15 @@ static void menu_reflect(struct cpuidle_device *dev, int 
index)
 
 /**
  * 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;
 
@@ -384,9 +386,11 @@ static void menu_update(struct cpuidle_device *dev)
 
 /**
  * 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);
 
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 09c9c77..90be2ad 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -318,13 +318,14 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device)
 {
        int i, ret = -ENOMEM;
        struct cpuidle_state_kobj *kobj;
+       struct cpuidle_driver *drv = cpuidle_get_driver();
 
        /* state statistics */
        for (i = 0; i < device->state_count; i++) {
                kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
                if (!kobj)
                        goto error_state;
-               kobj->state = &device->states[i];
+               kobj->state = &drv->states[i];
                kobj->state_usage = &device->states_usage[i];
                init_completion(&kobj->kobj_unregister);
 
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 3aa8d4c..5be9d59 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -81,7 +81,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, int index);
+static int intel_idle(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv, int index);
 
 static struct cpuidle_state *cpuidle_state_table;
 
@@ -227,13 +228,15 @@ static int get_driver_data(int cstate)
 /**
  * intel_idle
  * @dev: cpuidle_device
+ * @drv: cpuidle driver
  * @index: index of cpuidle state
  *
  */
-static int intel_idle(struct cpuidle_device *dev, int index)
+static int intel_idle(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
 {
        unsigned long ecx = 1; /* break on interrupt flag */
-       struct cpuidle_state *state = &dev->states[index];
+       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;
@@ -420,6 +423,60 @@ static void intel_idle_cpuidle_devices_uninit(void)
        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 [email protected]",
+                               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
  */
@@ -453,23 +510,9 @@ static int intel_idle_cpuidle_devices_init(void)
                                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 [email protected]",
-                                       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);
 
@@ -484,8 +527,6 @@ static int intel_idle_cpuidle_devices_init(void)
                        return -EIO;
                }
        }
-       if (auto_demotion_disable_flags)
-               smp_call_function(auto_demotion_disable, NULL, 1);
 
        return 0;
 }
@@ -503,6 +544,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 --git a/include/acpi/processor.h b/include/acpi/processor.h
index 55192ac..5655322 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -336,6 +336,7 @@ extern void acpi_processor_throttling_init(void);
 int acpi_processor_power_init(struct acpi_processor *pr,
                              struct acpi_device *device);
 int acpi_processor_cst_has_changed(struct acpi_processor *pr);
+int acpi_processor_hotplug(struct acpi_processor *pr);
 int acpi_processor_power_exit(struct acpi_processor *pr,
                              struct acpi_device *device);
 int acpi_processor_suspend(struct acpi_device * device, pm_message_t state);
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 0156540..c904188 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -22,6 +22,7 @@
 #define CPUIDLE_DESC_LEN       32
 
 struct cpuidle_device;
+struct cpuidle_driver;
 
 
 /****************************
@@ -45,6 +46,7 @@ struct cpuidle_state {
        unsigned int    target_residency; /* in US */
 
        int (*enter)    (struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv,
                        int index);
 };
 
@@ -83,12 +85,10 @@ struct cpuidle_state_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];
 
@@ -96,7 +96,6 @@ struct cpuidle_device {
        struct kobject          kobj;
        struct completion       kobj_unregister;
        void                    *governor_data;
-       int                     safe_state_index;
 };
 
 DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
@@ -120,6 +119,11 @@ static inline int cpuidle_get_last_residency(struct 
cpuidle_device *dev)
 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,10 +170,13 @@ 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);
+       int  (*select)          (struct cpuidle_driver *drv,
+                                       struct cpuidle_device *dev);
        void (*reflect)         (struct cpuidle_device *dev, int index);
 
        struct module           *owner;

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to