diff options
Diffstat (limited to 'arch/x86/kernel/apm_32.c')
| -rw-r--r-- | arch/x86/kernel/apm_32.c | 67 | 
1 files changed, 39 insertions, 28 deletions
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index d65464e4350..53a4e274484 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -232,6 +232,7 @@  #include <linux/acpi.h>  #include <linux/syscore_ops.h>  #include <linux/i8253.h> +#include <linux/cpuidle.h>  #include <asm/uaccess.h>  #include <asm/desc.h> @@ -360,13 +361,34 @@ struct apm_user {   * idle percentage above which bios idle calls are done   */  #ifdef CONFIG_APM_CPU_IDLE -#warning deprecated CONFIG_APM_CPU_IDLE will be deleted in 2012  #define DEFAULT_IDLE_THRESHOLD	95  #else  #define DEFAULT_IDLE_THRESHOLD	100  #endif  #define DEFAULT_IDLE_PERIOD	(100 / 3) +static int apm_cpu_idle(struct cpuidle_device *dev, +			struct cpuidle_driver *drv, int index); + +static struct cpuidle_driver apm_idle_driver = { +	.name = "apm_idle", +	.owner = THIS_MODULE, +	.states = { +		{ /* entry 0 is for polling */ }, +		{ /* entry 1 is for APM idle */ +			.name = "APM", +			.desc = "APM idle", +			.flags = CPUIDLE_FLAG_TIME_VALID, +			.exit_latency = 250,	/* WAG */ +			.target_residency = 500,	/* WAG */ +			.enter = &apm_cpu_idle +		}, +	}, +	.state_count = 2, +}; + +static struct cpuidle_device apm_cpuidle_device; +  /*   * Local variables   */ @@ -377,7 +399,6 @@ static struct {  static int clock_slowed;  static int idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;  static int idle_period __read_mostly = DEFAULT_IDLE_PERIOD; -static int set_pm_idle;  static int suspends_pending;  static int standbys_pending;  static int ignore_sys_suspend; @@ -884,8 +905,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   * @@ -894,35 +913,36 @@ static void (*original_pm_idle)(void) __read_mostly;   * Furthermore it calls the system default idle routine.   */ -static void apm_cpu_idle(void) +static int apm_cpu_idle(struct cpuidle_device *dev, +	struct cpuidle_driver *drv, int index)  {  	static int use_apm_idle; /* = 0 */  	static unsigned int last_jiffies; /* = 0 */  	static unsigned int last_stime; /* = 0 */ +	cputime_t stime;  	int apm_idle_done = 0;  	unsigned int jiffies_since_last_check = jiffies - last_jiffies;  	unsigned int bucket; -	WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012");  recalc: +	task_cputime(current, NULL, &stime);  	if (jiffies_since_last_check > IDLE_CALC_LIMIT) {  		use_apm_idle = 0; -		last_jiffies = jiffies; -		last_stime = current->stime;  	} else if (jiffies_since_last_check > idle_period) {  		unsigned int idle_percentage; -		idle_percentage = current->stime - last_stime; +		idle_percentage = stime - last_stime;  		idle_percentage *= 100;  		idle_percentage /= jiffies_since_last_check;  		use_apm_idle = (idle_percentage > idle_threshold);  		if (apm_info.forbid_idle)  			use_apm_idle = 0; -		last_jiffies = jiffies; -		last_stime = current->stime;  	} +	last_jiffies = jiffies; +	last_stime = stime; +  	bucket = IDLE_LEAKY_MAX;  	while (!need_resched()) { @@ -950,10 +970,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) @@ -963,7 +980,7 @@ recalc:  	if (apm_idle_done)  		apm_do_busy(); -	local_irq_enable(); +	return index;  }  /** @@ -2381,9 +2398,9 @@ 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; -		set_pm_idle = 1; +		if (!cpuidle_register_driver(&apm_idle_driver)) +			if (cpuidle_register_device(&apm_cpuidle_device)) +				cpuidle_unregister_driver(&apm_idle_driver);  	}  	return 0; @@ -2393,15 +2410,9 @@ 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. -		 */ -		kick_all_cpus_sync(); -	} +	cpuidle_unregister_device(&apm_cpuidle_device); +	cpuidle_unregister_driver(&apm_idle_driver); +  	if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)  	    && (apm_info.connection_version > 0x0100)) {  		error = apm_engage_power_management(APM_DEVICE_ALL, 0);  |