Skip to content

Commit

Permalink
APM idle: register apm_cpu_idle via cpuidle
Browse files Browse the repository at this point in the history
Update APM to register its local idle routine with cpuidle.

This allows us to stop exporting pm_idle to modules on x86.

The Kconfig sub-option, APM_CPU_IDLE, now depends on on CPU_IDLE.

Compile-tested only.

Signed-off-by: Len Brown <len.brown@intel.com>
Reviewed-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
Len Brown committed Feb 18, 2013
1 parent 88b62b9 commit dd8af07
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 26 deletions.
1 change: 1 addition & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,7 @@ config APM_DO_ENABLE
this feature.

config APM_CPU_IDLE
depends on CPU_IDLE
bool "Make CPU Idle calls when idle"
---help---
Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
Expand Down
57 changes: 34 additions & 23 deletions arch/x86/kernel/apm_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -360,13 +361,35 @@ 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,
.en_core_tk_irqen = 1,
.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
*/
Expand All @@ -377,7 +400,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;
Expand Down Expand Up @@ -884,8 +906,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
*
Expand All @@ -894,7 +914,8 @@ 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 */
Expand All @@ -904,7 +925,6 @@ static void apm_cpu_idle(void)
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:
if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
use_apm_idle = 0;
Expand Down Expand Up @@ -950,10 +970,7 @@ static void apm_cpu_idle(void)
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)
Expand All @@ -963,7 +980,7 @@ static void apm_cpu_idle(void)
if (apm_idle_done)
apm_do_busy();

local_irq_enable();
return index;
}

/**
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,6 @@ EXPORT_SYMBOL(boot_option_idle_override);
* Powermanagement idle function, if any..
*/
void (*pm_idle)(void);
#ifdef CONFIG_APM_MODULE
EXPORT_SYMBOL(pm_idle);
#endif

#ifndef CONFIG_SMP
static inline void play_dead(void)
Expand Down

0 comments on commit dd8af07

Please sign in to comment.