[RFC PATCH V4 5/5] cpuidle: cpuidle driver for apm

From: Trinabh Gupta
Date: Tue Mar 22 2011 - 08:33:51 EST


Signed-off-by: Trinabh Gupta <trinabh@xxxxxxxxxxxxxxxxxx>
---

arch/x86/kernel/apm_32.c | 75 +++++++++++++++++++++++++++++++++++++---------
1 files changed, 60 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 0e4f24c..22d40bf 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -882,8 +882,6 @@ static void apm_do_busy(void)
#define IDLE_CALC_LIMIT (HZ * 100)
#define IDLE_LEAKY_MAX 16

-static void (*original_pm_idle)(void) __read_mostly;
-
/**
* apm_cpu_idle - cpu idling for APM capable Linux
*
@@ -947,10 +945,7 @@ recalc:
break;
}
}
- if (original_pm_idle)
- original_pm_idle();
- else
- default_idle();
+ default_idle();
local_irq_disable();
jiffies_since_last_check = jiffies - last_jiffies;
if (jiffies_since_last_check > idle_period)
@@ -2256,6 +2251,63 @@ static struct dmi_system_id __initdata apm_dmi_table[] = {
{ }
};

+int apm_idle_wrapper(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ apm_cpu_idle();
+ return 0;
+}
+
+struct cpuidle_state state_apm_idle = {
+ .name = "APM-IDLE",
+ .desc = "APM idle routine",
+ .exit_latency = 1,
+ .target_residency = 1,
+ .enter = &apm_idle_wrapper,
+};
+
+static struct cpuidle_driver apm_idle_driver = {
+ .name = "apm_idle",
+ .owner = THIS_MODULE,
+ .priority = 1,
+};
+
+static int apm_setup_cpuidle(int cpu)
+{
+ struct cpuidle_device *dev = kzalloc(sizeof(struct cpuidle_device),
+ GFP_KERNEL);
+ int count = CPUIDLE_DRIVER_STATE_START;
+ dev->cpu = cpu;
+ dev->drv = &apm_idle_driver;
+
+ dev->states[count] = state_apm_idle;
+ count++;
+
+ dev->state_count = count;
+
+ if (cpuidle_register_device(dev))
+ return -EIO;
+ return 0;
+}
+
+static int apm_idle_init(void)
+{
+ int retval, i;
+ retval = cpuidle_register_driver(&apm_idle_driver);
+
+ for_each_online_cpu(i) {
+ apm_setup_cpuidle(i);
+ }
+
+ return 0;
+}
+
+static void apm_idle_exit(void)
+{
+ cpuidle_unregister_driver(&apm_idle_driver);
+ return;
+}
+
/*
* Just start the APM thread. We do NOT want to do APM BIOS
* calls from anything but the APM thread, if for no other reason
@@ -2393,8 +2445,7 @@ static int __init apm_init(void)
if (HZ != 100)
idle_period = (idle_period * HZ) / 100;
if (idle_threshold < 100) {
- original_pm_idle = pm_idle;
- pm_idle = apm_cpu_idle;
+ apm_idle_init();
set_pm_idle = 1;
}

@@ -2406,13 +2457,7 @@ static void __exit apm_exit(void)
int error;

if (set_pm_idle) {
- pm_idle = original_pm_idle;
- /*
- * We are about to unload the current idle thread pm callback
- * (pm_idle), Wait for all processors to update cached/local
- * copies of pm_idle before proceeding.
- */
- cpu_idle_wait();
+ apm_idle_exit();
}
if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
&& (apm_info.connection_version > 0x0100)) {

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/