summaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-11-07 10:13:52 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-07 10:13:52 -0800
commit3c00303206c3a1ccd86579efdc90bc35f140962e (patch)
tree66170c84b5ddaeb102aea3530517a26657b6ea29 /arch/arm
parent83dbb15e9cd78a3619e3db36777e2f81d09b2914 (diff)
parentefb90582c575084723cc14302c1300cb26c7e01f (diff)
downloadlinux-stable-3c00303206c3a1ccd86579efdc90bc35f140962e.tar.gz
linux-stable-3c00303206c3a1ccd86579efdc90bc35f140962e.tar.bz2
linux-stable-3c00303206c3a1ccd86579efdc90bc35f140962e.zip
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
* '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
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-at91/cpuidle.c41
-rw-r--r--arch/arm/mach-davinci/cpuidle.c51
-rw-r--r--arch/arm/mach-exynos/cpuidle.c30
-rw-r--r--arch/arm/mach-kirkwood/cpuidle.c42
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c133
5 files changed, 178 insertions, 119 deletions
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index f474272c0eac..a851e6c98421 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -34,7 +34,8 @@ 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_state *state)
+ struct cpuidle_driver *drv,
+ int index)
{
struct timeval before, after;
int idle_time;
@@ -42,10 +43,10 @@ static int at91_enter_idle(struct cpuidle_device *dev,
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();
@@ -56,34 +57,38 @@ static int at91_enter_idle(struct cpuidle_device *dev,
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");
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index 60d2f4871afa..a30c7c5a6d83 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -79,9 +79,11 @@ 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_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;
@@ -99,13 +101,17 @@ static int davinci_enter_idle(struct cpuidle_device *dev,
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());
@@ -117,32 +123,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[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) {
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index bf7e96f2793a..35f6502144ae 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -16,7 +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 @@ static struct cpuidle_driver exynos4_idle_driver = {
};
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;
@@ -52,29 +54,31 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
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,");
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index 864e569f684e..7088180b018b 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -33,17 +33,18 @@ 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_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
@@ -58,35 +59,40 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev,
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;
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 4bf6e6e8b100..1fe35c24fba2 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -88,17 +88,21 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
/**
* omap3_enter_idle - Programs OMAP3 to enter the specified state
* @dev: cpuidle device
- * @state: The target state to be programmed
+ * @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_state *state)
+ struct cpuidle_driver *drv,
+ int index)
{
- struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
+ struct omap3_idle_statedata *cx =
+ cpuidle_get_statedata(&dev->states_usage[index]);
struct timespec ts_preidle, ts_postidle, ts_idle;
u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+ int idle_time;
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
@@ -113,7 +117,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
goto return_sleep_time;
/* Deny idle for C1 */
- if (state == &dev->states[0]) {
+ if (index == 0) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
}
@@ -122,7 +126,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
omap_sram_idle();
/* Re-allow idle for C1 */
- if (state == &dev->states[0]) {
+ if (index == 0) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
}
@@ -134,28 +138,38 @@ return_sleep_time:
local_irq_enable();
local_fiq_enable();
- return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
+ idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
+ USEC_PER_SEC;
+
+ /* Update cpuidle counters */
+ dev->last_residency = idle_time;
+
+ return index;
}
/**
* next_valid_state - Find next valid C-state
* @dev: cpuidle device
- * @state: Currently selected C-state
+ * @drv: cpuidle driver
+ * @index: Index of currently selected c-state
*
- * If the current state is valid, it is returned back to the caller.
- * Else, this function searches for a lower c-state which is still
- * valid.
+ * If the state corresponding to index is valid, index is returned back
+ * to the caller. Else, this function searches for a lower c-state which is
+ * still valid (as defined in omap3_power_states[]) and returns its index.
*
* A state is valid if the 'valid' field is enabled and
* if it satisfies the enable_off_mode condition.
*/
-static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
- struct cpuidle_state *curr)
+static int next_valid_state(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
{
- struct cpuidle_state *next = NULL;
- struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
+ struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
+ struct cpuidle_state *curr = &drv->states[index];
+ struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
+ int next_index = -1;
if (enable_off_mode) {
mpu_deepest_state = PWRDM_POWER_OFF;
@@ -172,20 +186,20 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
(cx->core_state >= core_deepest_state)) {
- return curr;
+ return index;
} else {
int idx = OMAP3_NUM_STATES - 1;
/* Reach the current state starting at highest C-state */
for (; idx >= 0; idx--) {
- if (&dev->states[idx] == curr) {
- next = &dev->states[idx];
+ if (&drv->states[idx] == curr) {
+ next_index = idx;
break;
}
}
/* Should never hit this condition */
- WARN_ON(next == NULL);
+ WARN_ON(next_index == -1);
/*
* Drop to next valid state.
@@ -193,41 +207,44 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
*/
idx--;
for (; idx >= 0; idx--) {
- cx = cpuidle_get_statedata(&dev->states[idx]);
+ cx = cpuidle_get_statedata(&dev->states_usage[idx]);
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
(cx->core_state >= core_deepest_state)) {
- next = &dev->states[idx];
+ next_index = idx;
break;
}
}
/*
* C1 is always valid.
- * So, no need to check for 'next==NULL' outside this loop.
+ * So, no need to check for 'next_index == -1' outside
+ * this loop.
*/
}
- return next;
+ return next_index;
}
/**
* omap3_enter_idle_bm - Checks for any bus activity
* @dev: cpuidle device
- * @state: The target state to be programmed
+ * @drv: cpuidle driver
+ * @index: array index of target state to be programmed
*
* This function checks for any pending activity and then programs
* the device to the specified or a safer state.
*/
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ struct cpuidle_driver *drv,
+ int index)
{
- struct cpuidle_state *new_state;
+ int new_state_idx;
u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
struct omap3_idle_statedata *cx;
int ret;
if (!omap3_can_sleep()) {
- new_state = dev->safe_state;
+ new_state_idx = drv->safe_state_index;
goto select_state;
}
@@ -237,7 +254,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 = dev->safe_state;
+ new_state_idx = drv->safe_state_index;
goto select_state;
}
@@ -253,7 +270,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
- cx = cpuidle_get_statedata(state);
+ cx = cpuidle_get_statedata(&dev->states_usage[index]);
core_next_state = cx->core_state;
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state == PWRDM_POWER_OFF) &&
@@ -264,11 +281,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
if (per_next_state != per_saved_state)
pwrdm_set_next_pwrst(per_pd, per_next_state);
- new_state = next_valid_state(dev, state);
+ new_state_idx = next_valid_state(dev, drv, index);
select_state:
- dev->last_state = new_state;
- ret = omap3_enter_idle(dev, new_state);
+ ret = omap3_enter_idle(dev, drv, new_state_idx);
/* Restore original PER state if it was modified */
if (per_next_state != per_saved_state)
@@ -301,22 +317,31 @@ struct cpuidle_driver omap3_idle_driver = {
.owner = THIS_MODULE,
};
-/* Helper to fill the C-state common data and register the driver_data */
-static inline struct omap3_idle_statedata *_fill_cstate(
- struct cpuidle_device *dev,
+/* Helper to fill the C-state common data*/
+static inline void _fill_cstate(struct cpuidle_driver *drv,
int idx, const char *descr)
{
- struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
- struct cpuidle_state *state = &dev->states[idx];
+ struct cpuidle_state *state = &drv->states[idx];
state->exit_latency = cpuidle_params_table[idx].exit_latency;
state->target_residency = cpuidle_params_table[idx].target_residency;
state->flags = CPUIDLE_FLAG_TIME_VALID;
state->enter = omap3_enter_idle_bm;
- cx->valid = cpuidle_params_table[idx].valid;
sprintf(state->name, "C%d", idx + 1);
strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
- cpuidle_set_statedata(state, cx);
+
+}
+
+/* Helper to register the driver_data */
+static inline struct omap3_idle_statedata *_fill_cstate_usage(
+ struct cpuidle_device *dev,
+ int idx)
+{
+ struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
+
+ cx->valid = cpuidle_params_table[idx].valid;
+ cpuidle_set_statedata(state_usage, cx);
return cx;
}
@@ -330,6 +355,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
int __init omap3_idle_init(void)
{
struct cpuidle_device *dev;
+ struct cpuidle_driver *drv = &omap3_idle_driver;
struct omap3_idle_statedata *cx;
mpu_pd = pwrdm_lookup("mpu_pwrdm");
@@ -337,44 +363,52 @@ int __init omap3_idle_init(void)
per_pd = pwrdm_lookup("per_pwrdm");
cam_pd = pwrdm_lookup("cam_pwrdm");
- cpuidle_register_driver(&omap3_idle_driver);
+
+ drv->safe_state_index = -1;
dev = &per_cpu(omap3_idle_dev, smp_processor_id());
/* C1 . MPU WFI + Core active */
- cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
- (&dev->states[0])->enter = omap3_enter_idle;
- dev->safe_state = &dev->states[0];
+ _fill_cstate(drv, 0, "MPU ON + CORE ON");
+ (&drv->states[0])->enter = omap3_enter_idle;
+ drv->safe_state_index = 0;
+ cx = _fill_cstate_usage(dev, 0);
cx->valid = 1; /* C1 is always valid */
cx->mpu_state = PWRDM_POWER_ON;
cx->core_state = PWRDM_POWER_ON;
/* C2 . MPU WFI + Core inactive */
- cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
+ _fill_cstate(drv, 1, "MPU ON + CORE ON");
+ cx = _fill_cstate_usage(dev, 1);
cx->mpu_state = PWRDM_POWER_ON;
cx->core_state = PWRDM_POWER_ON;
/* C3 . MPU CSWR + Core inactive */
- cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
+ _fill_cstate(drv, 2, "MPU RET + CORE ON");
+ cx = _fill_cstate_usage(dev, 2);
cx->mpu_state = PWRDM_POWER_RET;
cx->core_state = PWRDM_POWER_ON;
/* C4 . MPU OFF + Core inactive */
- cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
+ _fill_cstate(drv, 3, "MPU OFF + CORE ON");
+ cx = _fill_cstate_usage(dev, 3);
cx->mpu_state = PWRDM_POWER_OFF;
cx->core_state = PWRDM_POWER_ON;
/* C5 . MPU RET + Core RET */
- cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
+ _fill_cstate(drv, 4, "MPU RET + CORE RET");
+ cx = _fill_cstate_usage(dev, 4);
cx->mpu_state = PWRDM_POWER_RET;
cx->core_state = PWRDM_POWER_RET;
/* C6 . MPU OFF + Core RET */
- cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
+ _fill_cstate(drv, 5, "MPU OFF + CORE RET");
+ cx = _fill_cstate_usage(dev, 5);
cx->mpu_state = PWRDM_POWER_OFF;
cx->core_state = PWRDM_POWER_RET;
/* C7 . MPU OFF + Core OFF */
- cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
+ _fill_cstate(drv, 6, "MPU OFF + CORE OFF");
+ cx = _fill_cstate_usage(dev, 6);
/*
* Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
* enable OFF mode in a stable form for previous revisions.
@@ -388,6 +422,9 @@ int __init omap3_idle_init(void)
cx->mpu_state = PWRDM_POWER_OFF;
cx->core_state = PWRDM_POWER_OFF;
+ drv->state_count = OMAP3_NUM_STATES;
+ cpuidle_register_driver(&omap3_idle_driver);
+
dev->state_count = OMAP3_NUM_STATES;
if (cpuidle_register_device(dev)) {
printk(KERN_ERR "%s: CPUidle register device failed\n",