Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 336735
b: refs/heads/master
c: bf4d1b5
h: refs/heads/master
i:
  336733: 03ab655
  336731: 0c127d0
  336727: 572b23d
  336719: 7f0dbfc
  336703: 34d14e4
v: v3
  • Loading branch information
Daniel Lezcano authored and Rafael J. Wysocki committed Nov 14, 2012
1 parent 66b7dc0 commit d679e16
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 41 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 13dd52f11a04e616900f565d6a1e5138e58d579f
refs/heads/master: bf4d1b5ddb78f86078ac6ae0415802d5f0c68f92
9 changes: 9 additions & 0 deletions trunk/drivers/cpuidle/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ config CPU_IDLE

If you're using an ACPI-enabled platform, you should say Y here.

config CPU_IDLE_MULTIPLE_DRIVERS
bool "Support multiple cpuidle drivers"
depends on CPU_IDLE
default n
help
Allows the cpuidle framework to use different drivers for each CPU.
This is useful if you have a system with different CPU latencies and
states. If unsure say N.

config CPU_IDLE_GOV_LADDER
bool
depends on CPU_IDLE
Expand Down
36 changes: 23 additions & 13 deletions trunk/drivers/cpuidle/cpuidle.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static cpuidle_enter_t cpuidle_enter_ops;
int cpuidle_play_dead(void)
{
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
struct cpuidle_driver *drv = cpuidle_get_driver();
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
int i, dead_state = -1;
int power_usage = -1;

Expand Down Expand Up @@ -128,7 +128,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
int cpuidle_idle_call(void)
{
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
struct cpuidle_driver *drv = cpuidle_get_driver();
struct cpuidle_driver *drv;
int next_state, entered_state;

if (off)
Expand All @@ -141,6 +141,8 @@ int cpuidle_idle_call(void)
if (!dev || !dev->enabled)
return -EBUSY;

drv = cpuidle_get_cpu_driver(dev);

/* ask the governor for the next state */
next_state = cpuidle_curr_governor->select(drv, dev);
if (need_resched()) {
Expand Down Expand Up @@ -312,15 +314,19 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
int cpuidle_enable_device(struct cpuidle_device *dev)
{
int ret, i;
struct cpuidle_driver *drv = cpuidle_get_driver();
struct cpuidle_driver *drv;

if (!dev)
return -EINVAL;

if (dev->enabled)
return 0;

drv = cpuidle_get_cpu_driver(dev);

if (!drv || !cpuidle_curr_governor)
return -EIO;

if (!dev->state_count)
dev->state_count = drv->state_count;

Expand All @@ -335,7 +341,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev)

poll_idle_init(drv);

if ((ret = cpuidle_add_state_sysfs(dev)))
ret = cpuidle_add_device_sysfs(dev);
if (ret)
return ret;

if (cpuidle_curr_governor->enable &&
Expand All @@ -356,7 +363,7 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
return 0;

fail_sysfs:
cpuidle_remove_state_sysfs(dev);
cpuidle_remove_device_sysfs(dev);

return ret;
}
Expand All @@ -372,17 +379,20 @@ EXPORT_SYMBOL_GPL(cpuidle_enable_device);
*/
void cpuidle_disable_device(struct cpuidle_device *dev)
{
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);

if (!dev || !dev->enabled)
return;
if (!cpuidle_get_driver() || !cpuidle_curr_governor)

if (!drv || !cpuidle_curr_governor)
return;

dev->enabled = 0;

if (cpuidle_curr_governor->disable)
cpuidle_curr_governor->disable(cpuidle_get_driver(), dev);
cpuidle_curr_governor->disable(drv, dev);

cpuidle_remove_state_sysfs(dev);
cpuidle_remove_device_sysfs(dev);
enabled_devices--;
}

Expand All @@ -398,9 +408,9 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device);
static int __cpuidle_register_device(struct cpuidle_device *dev)
{
int ret;
struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);

if (!try_module_get(cpuidle_driver->owner))
if (!try_module_get(drv->owner))
return -EINVAL;

per_cpu(cpuidle_devices, dev->cpu) = dev;
Expand All @@ -421,7 +431,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
err_sysfs:
list_del(&dev->device_list);
per_cpu(cpuidle_devices, dev->cpu) = NULL;
module_put(cpuidle_driver->owner);
module_put(drv->owner);
return ret;
}

Expand Down Expand Up @@ -460,7 +470,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device);
*/
void cpuidle_unregister_device(struct cpuidle_device *dev)
{
struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);

if (dev->registered == 0)
return;
Expand All @@ -477,7 +487,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)

cpuidle_resume_and_unlock();

module_put(cpuidle_driver->owner);
module_put(drv->owner);
}

EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
Expand Down
4 changes: 2 additions & 2 deletions trunk/drivers/cpuidle/cpuidle.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ struct device;

extern int cpuidle_add_interface(struct device *dev);
extern void cpuidle_remove_interface(struct device *dev);
extern int cpuidle_add_state_sysfs(struct cpuidle_device *device);
extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device);
extern int cpuidle_add_device_sysfs(struct cpuidle_device *device);
extern void cpuidle_remove_device_sysfs(struct cpuidle_device *device);
extern int cpuidle_add_sysfs(struct cpuidle_device *dev);
extern void cpuidle_remove_sysfs(struct cpuidle_device *dev);

Expand Down
166 changes: 149 additions & 17 deletions trunk/drivers/cpuidle/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@

#include "cpuidle.h"

static struct cpuidle_driver *cpuidle_curr_driver;
DEFINE_SPINLOCK(cpuidle_driver_lock);

static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);

static void set_power_states(struct cpuidle_driver *drv)
{
int i;
Expand Down Expand Up @@ -47,36 +49,92 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
set_power_states(drv);
}

static void cpuidle_set_driver(struct cpuidle_driver *drv)
{
cpuidle_curr_driver = drv;
}

static int __cpuidle_register_driver(struct cpuidle_driver *drv)
static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
{
if (!drv || !drv->state_count)
return -EINVAL;

if (cpuidle_disabled())
return -ENODEV;

if (cpuidle_get_driver())
if (__cpuidle_get_cpu_driver(cpu))
return -EBUSY;

__cpuidle_driver_init(drv);

cpuidle_set_driver(drv);
__cpuidle_set_cpu_driver(drv, cpu);

return 0;
}

static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
{
if (drv != cpuidle_get_driver())
if (drv != __cpuidle_get_cpu_driver(cpu))
return;

if (!WARN_ON(drv->refcnt > 0))
cpuidle_set_driver(NULL);
__cpuidle_set_cpu_driver(NULL, cpu);
}

#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS

static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);

static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
{
per_cpu(cpuidle_drivers, cpu) = drv;
}

static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
{
return per_cpu(cpuidle_drivers, cpu);
}

static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
{
int cpu;
for_each_present_cpu(cpu)
__cpuidle_unregister_driver(drv, cpu);
}

static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
{
int ret = 0;
int i, cpu;

for_each_present_cpu(cpu) {
ret = __cpuidle_register_driver(drv, cpu);
if (ret)
break;
}

if (ret)
for_each_present_cpu(i) {
if (i == cpu)
break;
__cpuidle_unregister_driver(drv, i);
}


return ret;
}

int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
{
int ret;

spin_lock(&cpuidle_driver_lock);
ret = __cpuidle_register_driver(drv, cpu);
spin_unlock(&cpuidle_driver_lock);

return ret;
}

void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
{
spin_lock(&cpuidle_driver_lock);
__cpuidle_unregister_driver(drv, cpu);
spin_unlock(&cpuidle_driver_lock);
}

/**
Expand All @@ -88,33 +146,107 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
int ret;

spin_lock(&cpuidle_driver_lock);
ret = __cpuidle_register_driver(drv);
ret = __cpuidle_register_all_cpu_driver(drv);
spin_unlock(&cpuidle_driver_lock);

return ret;
}
EXPORT_SYMBOL_GPL(cpuidle_register_driver);

/**
* cpuidle_get_driver - return the current driver
* cpuidle_unregister_driver - unregisters a driver
* @drv: the driver
*/
struct cpuidle_driver *cpuidle_get_driver(void)
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
{
spin_lock(&cpuidle_driver_lock);
__cpuidle_unregister_all_cpu_driver(drv);
spin_unlock(&cpuidle_driver_lock);
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);

#else

static struct cpuidle_driver *cpuidle_curr_driver;

static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
{
cpuidle_curr_driver = drv;
}

static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
{
return cpuidle_curr_driver;
}
EXPORT_SYMBOL_GPL(cpuidle_get_driver);

/**
* cpuidle_register_driver - registers a driver
* @drv: the driver
*/
int cpuidle_register_driver(struct cpuidle_driver *drv)
{
int ret, cpu;

cpu = get_cpu();
spin_lock(&cpuidle_driver_lock);
ret = __cpuidle_register_driver(drv, cpu);
spin_unlock(&cpuidle_driver_lock);
put_cpu();

return ret;
}
EXPORT_SYMBOL_GPL(cpuidle_register_driver);

/**
* cpuidle_unregister_driver - unregisters a driver
* @drv: the driver
*/
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
{
int cpu;

cpu = get_cpu();
spin_lock(&cpuidle_driver_lock);
__cpuidle_unregister_driver(drv);
__cpuidle_unregister_driver(drv, cpu);
spin_unlock(&cpuidle_driver_lock);
put_cpu();
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
#endif

/**
* cpuidle_get_driver - return the current driver
*/
struct cpuidle_driver *cpuidle_get_driver(void)
{
struct cpuidle_driver *drv;
int cpu;

cpu = get_cpu();
drv = __cpuidle_get_cpu_driver(cpu);
put_cpu();

return drv;
}
EXPORT_SYMBOL_GPL(cpuidle_get_driver);

/**
* cpuidle_get_cpu_driver - return the driver tied with a cpu
*/
struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
{
struct cpuidle_driver *drv;

if (!dev)
return NULL;

spin_lock(&cpuidle_driver_lock);
drv = __cpuidle_get_cpu_driver(dev->cpu);
spin_unlock(&cpuidle_driver_lock);

return drv;
}
EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);

struct cpuidle_driver *cpuidle_driver_ref(void)
{
Expand Down
Loading

0 comments on commit d679e16

Please sign in to comment.