lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20110322124807.29408.96250.stgit@tringupt.in.ibm.com>
Date:	Tue, 22 Mar 2011 18:18:17 +0530
From:	Trinabh Gupta <trinabh@...ux.vnet.ibm.com>
To:	arjan@...ux.intel.com, peterz@...radead.org, lenb@...nel.org,
	suresh.b.siddha@...el.com, benh@...nel.crashing.org,
	venki@...gle.com, ak@...ux.intel.com
Cc:	linux-kernel@...r.kernel.org
Subject: [RFC PATCH V1 2/2] cpuidle: API changes in callers using new
	cpuidle_state_stats

cpuidle subsystem users will need to use struct cpuidle_state *state
and struct cpuidle_state_stats *state_stats.

Driver's per-cpu context is stored in cpuidle_state_stats for this
RFC. This need to be moved into cpuidle_driver.

Signed-off-by: Trinabh Gupta <trinabh@...ux.vnet.ibm.com>
---

 drivers/acpi/processor_driver.c    |   19 +---
 drivers/acpi/processor_idle.c      |   49 +++++++---
 drivers/cpuidle/cpuidle.c          |  170 +++++++++++++++++++++++-------------
 drivers/cpuidle/cpuidle.h          |    4 -
 drivers/cpuidle/driver.c           |   24 -----
 drivers/cpuidle/governor.c         |   10 +-
 drivers/cpuidle/governors/Makefile |    2 
 drivers/cpuidle/governors/menu.c   |   19 ++--
 drivers/cpuidle/sysfs.c            |   63 +++++++------
 drivers/idle/default_driver.c      |   40 +++-----
 10 files changed, 210 insertions(+), 190 deletions(-)

diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 360a74e..4837861 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -503,9 +503,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
 	acpi_processor_get_throttling_info(pr);
 	acpi_processor_get_limit_info(pr);
 
-
-	if (cpuidle_get_driver() == &acpi_idle_driver)
-		acpi_processor_power_init(pr, device);
+	acpi_processor_power_init(pr, device);
 
 	pr->cdev = thermal_cooling_device_register("Processor", device,
 						&processor_cooling_ops);
@@ -800,17 +798,9 @@ static int __init acpi_processor_init(void)
 
 	memset(&errata, 0, sizeof(errata));
 
-	if (!cpuidle_register_driver(&acpi_idle_driver)) {
-		printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
-			acpi_idle_driver.name);
-	} else {
-		printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n",
-			cpuidle_get_driver()->name);
-	}
-
 	result = acpi_bus_register_driver(&acpi_processor_driver);
 	if (result < 0)
-		goto out_cpuidle;
+		goto out;
 
 	acpi_processor_install_hotplug_notify();
 
@@ -822,8 +812,7 @@ static int __init acpi_processor_init(void)
 
 	return 0;
 
-out_cpuidle:
-	cpuidle_unregister_driver(&acpi_idle_driver);
+out:
 
 	return result;
 }
@@ -841,8 +830,6 @@ static void __exit acpi_processor_exit(void)
 
 	acpi_bus_unregister_driver(&acpi_processor_driver);
 
-	cpuidle_unregister_driver(&acpi_idle_driver);
-
 	return;
 }
 
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 65dde00..407acd7 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -746,12 +746,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
  * This is equivalent to the HALT instruction.
  */
 static int acpi_idle_enter_c1(struct cpuidle_device *dev,
-			      struct cpuidle_state *state)
+			      struct cpuidle_state *state,
+				struct cpuidle_state_stats *state_stats)
 {
 	ktime_t  kt1, kt2;
 	s64 idle_time;
 	struct acpi_processor *pr;
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_stats);
 
 	pr = __this_cpu_read(processors);
 
@@ -786,13 +787,14 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
  * @state: the state data
  */
 static int acpi_idle_enter_simple(struct cpuidle_device *dev,
-				  struct cpuidle_state *state)
+				  struct cpuidle_state *state,
+				struct cpuidle_state_stats *state_stats)
 {
 	struct acpi_processor *pr;
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 	ktime_t  kt1, kt2;
 	s64 idle_time_ns;
 	s64 idle_time;
+	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_stats);
 
 	pr = __this_cpu_read(processors);
 
@@ -800,7 +802,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 		return 0;
 
 	if (acpi_idle_suspend)
-		return(acpi_idle_enter_c1(dev, state));
+		return acpi_idle_enter_c1(dev, state, state_stats);
 
 	local_irq_disable();
 
@@ -862,14 +864,15 @@ static DEFINE_SPINLOCK(c3_lock);
  * If BM is detected, the deepest non-C3 idle state is entered instead.
  */
 static int acpi_idle_enter_bm(struct cpuidle_device *dev,
-			      struct cpuidle_state *state)
+			      struct cpuidle_state *state,
+				struct cpuidle_state_stats *state_stats)
 {
 	struct acpi_processor *pr;
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 	ktime_t  kt1, kt2;
 	s64 idle_time_ns;
 	s64 idle_time;
-
+	struct cpuidle_device_stats *dev_stats;
+	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_stats);
 
 	pr = __this_cpu_read(processors);
 
@@ -877,12 +880,15 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 		return 0;
 
 	if (acpi_idle_suspend)
-		return(acpi_idle_enter_c1(dev, state));
+		return acpi_idle_enter_c1(dev, state, state_stats);
 
 	if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
 		if (dev->safe_state) {
-			dev->last_state = dev->safe_state;
-			return dev->safe_state->enter(dev, dev->safe_state);
+			dev_stats = &per_cpu(cpuidle_dev_stats,
+						smp_processor_id());
+			dev_stats->last_state = dev->safe_state;
+			return dev->safe_state->enter(dev, dev->safe_state,
+							state_stats);
 		} else {
 			local_irq_disable();
 			acpi_safe_halt();
@@ -983,6 +989,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
 	struct cpuidle_state *state;
+	struct cpuidle_state_stats *state_stats;
 	struct cpuidle_device *dev = &pr->power.dev;
 
 	if (!pr->flags.power_setup_done)
@@ -992,7 +999,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 		return -EINVAL;
 	}
 
-	dev->cpu = pr->id;
 	dev->drv = &acpi_idle_driver;
 	for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
 		dev->states[i].name[0] = '\0';
@@ -1005,6 +1011,12 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 	for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
 		cx = &pr->power.states[i];
 		state = &dev->states[count];
+		/*
+		 * To Do: driver_data would have to be made per
+		 * cpuidle driver. It works as there is just one
+		 * driver using this.
+		 * */
+		state_stats = get_cpuidle_state_stats(pr->id, count);
 
 		if (!cx->valid)
 			continue;
@@ -1015,7 +1027,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 		    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
 			continue;
 #endif
-		cpuidle_set_statedata(state, cx);
+		cpuidle_set_statedata(state_stats, cx);
 
 		snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
 		strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
@@ -1127,10 +1139,15 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
 	 * Note that we use previously set idle handler will be used on
 	 * platforms that only support C1.
 	 */
-	if (pr->flags.power) {
+	if (pr->flags.power)
 		acpi_processor_setup_cpuidle(pr);
-		if (cpuidle_register_device(&pr->power.dev))
-			return -EIO;
+	/*
+	 * Driver registration has to be done by last cpu.
+	 * To Do: Remove hard coded cpu number.
+	 */
+	if (pr->flags.power && pr->id == (num_online_cpus() - 1)) {
+		acpi_idle_driver.dev = &pr->power.dev;
+		cpuidle_register_driver(&acpi_idle_driver);
 	}
 	return 0;
 }
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 5335598..a232845 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -21,10 +21,10 @@
 
 #include "cpuidle.h"
 
-DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
+DEFINE_PER_CPU(struct cpuidle_device_stats, cpuidle_dev_stats);
+EXPORT_PER_CPU_SYMBOL(cpuidle_dev_stats);
 
 DEFINE_MUTEX(cpuidle_lock);
-LIST_HEAD(cpuidle_detected_devices);
 static void (*pm_idle_old)(void);
 
 static int enabled_devices;
@@ -41,6 +41,8 @@ static void cpuidle_kick_cpus(void) {}
 #endif
 
 static int __cpuidle_register_device(struct cpuidle_device *dev);
+static int __cpuidle_register_device_stats(
+		struct cpuidle_device_stats *dev_stats);
 
 /**
  * cpuidle_idle_call - the main idle loop
@@ -49,12 +51,16 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
  */
 void cpuidle_idle_call(void)
 {
-	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+	struct cpuidle_device_stats *dev_stats = &per_cpu(cpuidle_dev_stats,
+							smp_processor_id());
+	struct cpuidle_device *dev;
 	struct cpuidle_state *target_state;
+	struct cpuidle_state_stats *target_state_stats;
+	struct cpuidle_driver *drv = cpuidle_get_driver();
 	int next_state;
 
 	/* check if the device is ready */
-	if (!dev || !dev->enabled) {
+	if (!drv || !drv->dev || !drv->dev->enabled) {
 		if (pm_idle_old)
 			pm_idle_old();
 		else
@@ -65,6 +71,7 @@ void cpuidle_idle_call(void)
 #endif
 		return;
 	}
+	dev = drv->dev;
 
 #if 0
 	/* shows regressions, re-enable for 2.6.29 */
@@ -83,37 +90,40 @@ void cpuidle_idle_call(void)
 	 * state availability, latencies, residencies, etc.
 	 */
 	if (dev->prepare)
-		dev->prepare(dev);
+		dev->prepare(dev_stats);
 
 	/* ask the governor for the next state */
-	next_state = cpuidle_curr_governor->select(dev);
+	next_state = cpuidle_curr_governor->select(dev, dev_stats);
 	if (need_resched()) {
 		local_irq_enable();
 		return;
 	}
 
 	target_state = &dev->states[next_state];
+	target_state_stats = &dev_stats->state_stats[next_state];
 
 	/* enter the state and update stats */
-	dev->last_state = target_state;
+	dev_stats->last_state = target_state;
 
-	trace_power_start(POWER_CSTATE, next_state, dev->cpu);
-	trace_cpu_idle(next_state, dev->cpu);
+	trace_power_start(POWER_CSTATE, next_state, dev_stats->cpu);
+	trace_cpu_idle(next_state, dev_stats->cpu);
 
-	dev->last_residency = target_state->enter(dev, target_state);
+	dev_stats->last_residency = target_state->enter(dev, target_state,
+							target_state_stats);
 
-	trace_power_end(dev->cpu);
-	trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
+	trace_power_end(dev_stats->cpu);
+	trace_cpu_idle(PWR_EVENT_EXIT, dev_stats->cpu);
 
-	if (dev->last_state)
-		target_state = dev->last_state;
+	if (dev_stats->last_state)
+		target_state = dev_stats->last_state;
 
-	target_state->time += (unsigned long long)dev->last_residency;
-	target_state->usage++;
+	target_state_stats->time +=
+			(unsigned long long)dev_stats->last_residency;
+	target_state_stats->usage++;
 
 	/* give the governor an opportunity to reflect on the outcome */
 	if (cpuidle_curr_governor->reflect)
-		cpuidle_curr_governor->reflect(dev);
+		cpuidle_curr_governor->reflect(dev_stats);
 }
 
 #ifdef CONFIG_ARCH_USES_PMIDLE
@@ -167,7 +177,8 @@ void cpuidle_resume_and_unlock(void)
 EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
 
 #ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st,
+			struct cpuidle_state_stats *st_stats)
 {
 	ktime_t	t1, t2;
 	s64 diff;
@@ -191,8 +202,6 @@ static void poll_idle_init(struct cpuidle_device *dev)
 {
 	struct cpuidle_state *state = &dev->states[0];
 
-	cpuidle_set_statedata(state, NULL);
-
 	snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
 	snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
 	state->exit_latency = 0;
@@ -205,6 +214,28 @@ static void poll_idle_init(struct cpuidle_device *dev)
 static void poll_idle_init(struct cpuidle_device *dev) {}
 #endif /* CONFIG_ARCH_HAS_CPU_RELAX */
 
+static int cpuidle_enable_device_stats(struct cpuidle_device_stats *dev_stats)
+{
+	int ret, i;
+
+	if ((ret = cpuidle_add_state_sysfs(dev_stats)))
+		return ret;
+
+	if (cpuidle_curr_governor->enable &&
+		(ret = cpuidle_curr_governor->enable(dev_stats)))
+			return ret;
+
+	for (i = 0; i < dev_stats->drv->dev->state_count; i++) {
+		dev_stats->state_stats[i].usage = 0;
+		dev_stats->state_stats[i].time = 0;
+	}
+	dev_stats->last_residency = 0;
+	dev_stats->last_state = NULL;
+
+	smp_wmb();
+	return 0;
+}
+
 /**
  * cpuidle_enable_device - enables idle PM for a CPU
  * @dev: the CPU
@@ -231,35 +262,29 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
 
 	poll_idle_init(dev);
 
-	if ((ret = cpuidle_add_state_sysfs(dev)))
-		return ret;
-
-	if (cpuidle_curr_governor->enable &&
-	    (ret = cpuidle_curr_governor->enable(dev)))
-		goto fail_sysfs;
-
-	for (i = 0; i < dev->state_count; i++) {
-		dev->states[i].usage = 0;
-		dev->states[i].time = 0;
+	for_each_online_cpu(i) {
+		cpuidle_enable_device_stats(&per_cpu(cpuidle_dev_stats, i));
 	}
-	dev->last_residency = 0;
-	dev->last_state = NULL;
 
 	smp_wmb();
 
 	dev->enabled = 1;
 
-	enabled_devices++;
 	return 0;
 
-fail_sysfs:
-	cpuidle_remove_state_sysfs(dev);
-
-	return ret;
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_enable_device);
 
+static void cpuidle_disable_device_stats(struct cpuidle_device_stats *dev_stats)
+{
+	cpuidle_remove_state_sysfs(dev_stats);
+
+	if (cpuidle_curr_governor->disable)
+		cpuidle_curr_governor->disable(dev_stats);
+
+}
+
 /**
  * cpuidle_disable_device - disables idle PM for a CPU
  * @dev: the CPU
@@ -269,6 +294,8 @@ EXPORT_SYMBOL_GPL(cpuidle_enable_device);
  */
 void cpuidle_disable_device(struct cpuidle_device *dev)
 {
+	int i;
+
 	if (!dev->enabled)
 		return;
 	if (!cpuidle_get_driver() || !cpuidle_curr_governor)
@@ -276,15 +303,31 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
 
 	dev->enabled = 0;
 
-	if (cpuidle_curr_governor->disable)
-		cpuidle_curr_governor->disable(dev);
+	for_each_online_cpu(i) {
+		cpuidle_disable_device_stats(&per_cpu(cpuidle_dev_stats, i));
+	}
 
-	cpuidle_remove_state_sysfs(dev);
-	enabled_devices--;
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_disable_device);
 
+static int cpuidle_register_device_stats(struct cpuidle_device_stats *dev_stats)
+{
+	int ret;
+	struct sys_device *sys_dev =
+			get_cpu_sysdev((unsigned long)dev_stats->cpu);
+
+	if (!sys_dev)
+		return -EINVAL;
+
+	init_completion(&dev_stats->kobj_unregister);
+
+	if ((ret = cpuidle_add_sysfs(sys_dev)))
+		return ret;
+
+	return 0;
+}
+
 /**
  * __cpuidle_register_device - internal register function called before register
  * and enable routines
@@ -294,14 +337,10 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device);
  */
 static int __cpuidle_register_device(struct cpuidle_device *dev)
 {
-	int ret;
-	struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
 	struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
 	if (dev->registered)
 		return 0;
-	if (!sys_dev)
-		return -EINVAL;
 	/*
 	 * This will maintain compatibility with old cpuidle_device
 	 * structure where driver pointer is not set.
@@ -315,8 +354,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 	if (!try_module_get(dev->drv->owner))
 		return -EINVAL;
 
-	init_completion(&dev->kobj_unregister);
-
 	/*
 	 * cpuidle driver should set the dev->power_specified bit
 	 * before registering the device if the driver provides
@@ -337,14 +374,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 			dev->states[i].power_usage = -1 - i;
 	}
 
-	if (cpuidle_driver == dev->drv)
-		per_cpu(cpuidle_devices, dev->cpu) = dev;
-	list_add(&dev->device_list, &cpuidle_detected_devices);
-	if ((ret = cpuidle_add_sysfs(sys_dev))) {
-		module_put(dev->drv->owner);
-		return ret;
-	}
-
 	dev->registered = 1;
 	return 0;
 }
@@ -355,7 +384,8 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
  */
 int cpuidle_register_device(struct cpuidle_device *dev)
 {
-	int ret;
+	int ret, i;
+	struct cpuidle_device_stats *dev_stats;
 
 	mutex_lock(&cpuidle_lock);
 
@@ -364,6 +394,13 @@ int cpuidle_register_device(struct cpuidle_device *dev)
 		return ret;
 	}
 
+	for_each_online_cpu(i) {
+		dev_stats = &per_cpu(cpuidle_dev_stats, i);
+		dev_stats->cpu = i;
+		dev_stats->drv = cpuidle_get_driver();
+		cpuidle_register_device_stats(dev_stats);
+	}
+
 	cpuidle_enable_device(dev);
 	cpuidle_install_idle_handler();
 
@@ -375,14 +412,23 @@ int cpuidle_register_device(struct cpuidle_device *dev)
 
 EXPORT_SYMBOL_GPL(cpuidle_register_device);
 
+static void cpuidle_unregister_device_stats(
+				struct cpuidle_device_stats *dev_stats)
+{
+	struct sys_device *sys_dev =
+			get_cpu_sysdev((unsigned long)dev_stats->cpu);
+	cpuidle_remove_sysfs(sys_dev);
+	wait_for_completion(&dev_stats->kobj_unregister);
+}
+
+
 /**
  * cpuidle_unregister_device - unregisters a CPU's idle PM feature
  * @dev: the cpu
  */
 void cpuidle_unregister_device(struct cpuidle_device *dev)
 {
-	struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
-	struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
+	int i;
 
 	if (dev->registered == 0)
 		return;
@@ -390,11 +436,9 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
 	cpuidle_pause_and_lock();
 
 	cpuidle_disable_device(dev);
-
-	cpuidle_remove_sysfs(sys_dev);
-	wait_for_completion(&dev->kobj_unregister);
-	if (cpuidle_driver == dev->drv)
-		per_cpu(cpuidle_devices, dev->cpu) = NULL;
+	for_each_online_cpu(i) {
+		cpuidle_unregister_device_stats(&per_cpu(cpuidle_dev_stats, i));
+	}
 
 	cpuidle_resume_and_unlock();
 
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index 33e50d5..ea48dd8 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -24,8 +24,8 @@ extern int cpuidle_switch_governor(struct cpuidle_governor *gov);
 /* sysfs */
 extern int cpuidle_add_class_sysfs(struct sysdev_class *cls);
 extern void cpuidle_remove_class_sysfs(struct sysdev_class *cls);
-extern int cpuidle_add_state_sysfs(struct cpuidle_device *device);
-extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device);
+extern int cpuidle_add_state_sysfs(struct cpuidle_device_stats *dev_stats);
+extern void cpuidle_remove_state_sysfs(struct cpuidle_device_stats *dev_stats);
 extern int cpuidle_add_sysfs(struct sys_device *sysdev);
 extern void cpuidle_remove_sysfs(struct sys_device *sysdev);
 
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index c235286..19b2000 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -38,18 +38,13 @@ static struct cpuidle_driver *select_cpuidle_driver(void)
 
 static void set_current_cpuidle_driver(struct cpuidle_driver *drv)
 {
-	struct cpuidle_device *item = NULL;
 	if (drv == cpuidle_curr_driver)
 		return;
 
 	/* Unregister the previous drivers devices */
 	/* Do we need to take cpuidle_lock ? {un}register_device takes lock*/
 	if (cpuidle_curr_driver) {
-		list_for_each_entry(item, &cpuidle_detected_devices,
-			device_list) {
-			if (item->drv == cpuidle_curr_driver)
-				cpuidle_unregister_device(item);
-		}
+		cpuidle_unregister_device(cpuidle_curr_driver->dev);
 	}
 
 	cpuidle_curr_driver = drv;
@@ -57,12 +52,7 @@ static void set_current_cpuidle_driver(struct cpuidle_driver *drv)
 	if (drv == NULL)
 		return;
 	else {
-		/* Register the new driver devices */
-		list_for_each_entry(item, &cpuidle_detected_devices,
-			device_list) {
-			if (item->drv == drv)
-				cpuidle_register_device(item);
-		}
+		cpuidle_register_device(drv->dev);
 	}
 }
 
@@ -143,8 +133,6 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver);
  */
 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 {
-	struct cpuidle_device *item = NULL;
-
 	if (arch_allow_unregister(drv))
 		return;
 
@@ -154,14 +142,6 @@ void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 	list_del(&drv->driver_list);
 	set_current_cpuidle_driver(select_cpuidle_driver());
 
-	/* Delete all devices corresponding to this driver */
-	mutex_lock(&cpuidle_lock);
-	list_for_each_entry(item, &cpuidle_detected_devices, device_list) {
-		if (item->drv == drv)
-			list_del(&item->device_list);
-	}
-	mutex_unlock(&cpuidle_lock);
-
 	spin_unlock(&cpuidle_driver_lock);
 }
 
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c
index 724c164..c4bf5f0 100644
--- a/drivers/cpuidle/governor.c
+++ b/drivers/cpuidle/governor.c
@@ -43,7 +43,7 @@ static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
  */
 int cpuidle_switch_governor(struct cpuidle_governor *gov)
 {
-	struct cpuidle_device *dev;
+	struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
 
 	if (gov == cpuidle_curr_governor)
 		return 0;
@@ -51,8 +51,8 @@ int cpuidle_switch_governor(struct cpuidle_governor *gov)
 	cpuidle_uninstall_idle_handler();
 
 	if (cpuidle_curr_governor) {
-		list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
-			cpuidle_disable_device(dev);
+		if (cpuidle_driver)
+			cpuidle_disable_device(cpuidle_driver->dev);
 		module_put(cpuidle_curr_governor->owner);
 	}
 
@@ -61,8 +61,8 @@ int cpuidle_switch_governor(struct cpuidle_governor *gov)
 	if (gov) {
 		if (!try_module_get(cpuidle_curr_governor->owner))
 			return -EINVAL;
-		list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
-			cpuidle_enable_device(dev);
+		if (cpuidle_driver)
+			cpuidle_enable_device(cpuidle_driver->dev);
 		cpuidle_install_idle_handler();
 		printk(KERN_INFO "cpuidle: using governor %s\n", gov->name);
 	}
diff --git a/drivers/cpuidle/governors/Makefile b/drivers/cpuidle/governors/Makefile
index 1b51272..a2afe56 100644
--- a/drivers/cpuidle/governors/Makefile
+++ b/drivers/cpuidle/governors/Makefile
@@ -2,5 +2,5 @@
 # Makefile for cpuidle governors.
 #
 
-obj-$(CONFIG_CPU_IDLE_GOV_LADDER) += ladder.o
+obj-n += ladder.o
 obj-$(CONFIG_CPU_IDLE_GOV_MENU) += menu.o
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f508690..8de7b76 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -182,7 +182,8 @@ static inline int performance_multiplier(void)
 
 static DEFINE_PER_CPU(struct menu_device, menu_devices);
 
-static void menu_update(struct cpuidle_device *dev);
+static void menu_update(struct cpuidle_device *dev,
+			struct cpuidle_device_stats *dev_stats);
 
 /* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */
 static u64 div_round64(u64 dividend, u32 divisor)
@@ -230,7 +231,8 @@ static void detect_repeating_patterns(struct menu_device *data)
  * menu_select - selects the next idle state to enter
  * @dev: the CPU
  */
-static int menu_select(struct cpuidle_device *dev)
+static int menu_select(struct cpuidle_device *dev,
+			struct cpuidle_device_stats *dev_stats)
 {
 	struct menu_device *data = &__get_cpu_var(menu_devices);
 	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
@@ -239,7 +241,7 @@ static int menu_select(struct cpuidle_device *dev)
 	int multiplier;
 
 	if (data->needs_update) {
-		menu_update(dev);
+		menu_update(dev, dev_stats);
 		data->needs_update = 0;
 	}
 
@@ -312,7 +314,7 @@ static int menu_select(struct cpuidle_device *dev)
  * NOTE: it's important to be fast here because this operation will add to
  *       the overall exit latency.
  */
-static void menu_reflect(struct cpuidle_device *dev)
+static void menu_reflect(struct cpuidle_device_stats *dev_stats)
 {
 	struct menu_device *data = &__get_cpu_var(menu_devices);
 	data->needs_update = 1;
@@ -322,11 +324,12 @@ static void menu_reflect(struct cpuidle_device *dev)
  * menu_update - attempts to guess what happened after entry
  * @dev: the CPU
  */
-static void menu_update(struct cpuidle_device *dev)
+static void menu_update(struct cpuidle_device *dev,
+			struct cpuidle_device_stats *dev_stats)
 {
 	struct menu_device *data = &__get_cpu_var(menu_devices);
 	int last_idx = data->last_state_idx;
-	unsigned int last_idle_us = cpuidle_get_last_residency(dev);
+	unsigned int last_idle_us = cpuidle_get_last_residency(dev_stats);
 	struct cpuidle_state *target = &dev->states[last_idx];
 	unsigned int measured_us;
 	u64 new_factor;
@@ -383,9 +386,9 @@ static void menu_update(struct cpuidle_device *dev)
  * menu_enable_device - scans a CPU's states and does setup
  * @dev: the CPU
  */
-static int menu_enable_device(struct cpuidle_device *dev)
+static int menu_enable_device(struct cpuidle_device_stats *dev_stats)
 {
-	struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
+	struct menu_device *data = &per_cpu(menu_devices, dev_stats->cpu);
 
 	memset(data, 0, sizeof(struct menu_device));
 
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 0310ffa..0737fea 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -157,8 +157,9 @@ void cpuidle_remove_class_sysfs(struct sysdev_class *cls)
 
 struct cpuidle_attr {
 	struct attribute attr;
-	ssize_t (*show)(struct cpuidle_device *, char *);
-	ssize_t (*store)(struct cpuidle_device *, const char *, size_t count);
+	ssize_t (*show)(struct cpuidle_device_stats *, char *);
+	ssize_t (*store)(struct cpuidle_device_stats *, const char *,
+							size_t count);
 };
 
 #define define_one_ro(_name, show) \
@@ -166,12 +167,12 @@ struct cpuidle_attr {
 #define define_one_rw(_name, show, store) \
 	static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
 
-#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
+#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device_stats, kobj)
 #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
 static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
 {
 	int ret = -EIO;
-	struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+	struct cpuidle_device_stats *dev = kobj_to_cpuidledev(kobj);
 	struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
 
 	if (cattr->show) {
@@ -186,7 +187,7 @@ static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
 		     const char * buf, size_t count)
 {
 	int ret = -EIO;
-	struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+	struct cpuidle_device_stats *dev = kobj_to_cpuidledev(kobj);
 	struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
 
 	if (cattr->store) {
@@ -204,7 +205,7 @@ static const struct sysfs_ops cpuidle_sysfs_ops = {
 
 static void cpuidle_sysfs_release(struct kobject *kobj)
 {
-	struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+	struct cpuidle_device_stats *dev = kobj_to_cpuidledev(kobj);
 
 	complete(&dev->kobj_unregister);
 }
@@ -245,8 +246,11 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
 
 define_show_state_function(exit_latency)
 define_show_state_function(power_usage)
-define_show_state_ull_function(usage)
-define_show_state_ull_function(time)
+/*
+ * To Do: Show usage and time as well in
+ * sysfs; which are currently removed because
+ * of cpuidle_state structure split.
+ */
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
 
@@ -254,16 +258,12 @@ define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
 define_one_state_ro(latency, show_state_exit_latency);
 define_one_state_ro(power, show_state_power_usage);
-define_one_state_ro(usage, show_state_usage);
-define_one_state_ro(time, show_state_time);
 
 static struct attribute *cpuidle_state_default_attrs[] = {
 	&attr_name.attr,
 	&attr_desc.attr,
 	&attr_latency.attr,
 	&attr_power.attr,
-	&attr_usage.attr,
-	&attr_time.attr,
 	NULL
 };
 
@@ -300,7 +300,8 @@ static struct kobj_type ktype_state_cpuidle = {
 	.release = cpuidle_state_sysfs_release,
 };
 
-static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
+static inline void cpuidle_free_state_kobj(struct cpuidle_device_stats *device,
+								int i)
 {
 	kobject_put(&device->kobjs[i]->kobj);
 	wait_for_completion(&device->kobjs[i]->kobj_unregister);
@@ -312,34 +313,35 @@ static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
  * cpuidle_add_driver_sysfs - adds driver-specific sysfs attributes
  * @device: the target device
  */
-int cpuidle_add_state_sysfs(struct cpuidle_device *device)
+int cpuidle_add_state_sysfs(struct cpuidle_device_stats *dev_stats)
 {
 	int i, ret = -ENOMEM;
 	struct cpuidle_state_kobj *kobj;
 
 	/* state statistics */
-	for (i = 0; i < device->state_count; i++) {
+	for (i = 0; i < dev_stats->drv->dev->state_count; i++) {
 		kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
 		if (!kobj)
 			goto error_state;
-		kobj->state = &device->states[i];
+		kobj->state = &dev_stats->drv->dev->states[i];
 		init_completion(&kobj->kobj_unregister);
 
-		ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj,
-					   "state%d", i);
+		ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
+						&dev_stats->kobj,
+						"state%d", i);
 		if (ret) {
 			kfree(kobj);
 			goto error_state;
 		}
 		kobject_uevent(&kobj->kobj, KOBJ_ADD);
-		device->kobjs[i] = kobj;
+		dev_stats->kobjs[i] = kobj;
 	}
 
 	return 0;
 
 error_state:
 	for (i = i - 1; i >= 0; i--)
-		cpuidle_free_state_kobj(device, i);
+		cpuidle_free_state_kobj(dev_stats, i);
 	return ret;
 }
 
@@ -347,12 +349,12 @@ error_state:
  * cpuidle_remove_driver_sysfs - removes driver-specific sysfs attributes
  * @device: the target device
  */
-void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
+void cpuidle_remove_state_sysfs(struct cpuidle_device_stats *dev_stats)
 {
 	int i;
 
-	for (i = 0; i < device->state_count; i++)
-		cpuidle_free_state_kobj(device, i);
+	for (i = 0; i < dev_stats->drv->dev->state_count; i++)
+		cpuidle_free_state_kobj(dev_stats, i);
 }
 
 /**
@@ -362,14 +364,15 @@ void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
 int cpuidle_add_sysfs(struct sys_device *sysdev)
 {
 	int cpu = sysdev->id;
-	struct cpuidle_device *dev;
+	struct cpuidle_device_stats *dev_stats;
 	int error;
 
-	dev = per_cpu(cpuidle_devices, cpu);
-	error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj,
+	dev_stats = &per_cpu(cpuidle_dev_stats, cpu);
+	error = kobject_init_and_add(&dev_stats->kobj, &ktype_cpuidle,
+					&sysdev->kobj,
 				     "cpuidle");
 	if (!error)
-		kobject_uevent(&dev->kobj, KOBJ_ADD);
+		kobject_uevent(&dev_stats->kobj, KOBJ_ADD);
 	return error;
 }
 
@@ -380,8 +383,8 @@ int cpuidle_add_sysfs(struct sys_device *sysdev)
 void cpuidle_remove_sysfs(struct sys_device *sysdev)
 {
 	int cpu = sysdev->id;
-	struct cpuidle_device *dev;
+	struct cpuidle_device_stats *dev_stats;
 
-	dev = per_cpu(cpuidle_devices, cpu);
-	kobject_put(&dev->kobj);
+	dev_stats = &per_cpu(cpuidle_dev_stats, cpu);
+	kobject_put(&dev_stats->kobj);
 }
diff --git a/drivers/idle/default_driver.c b/drivers/idle/default_driver.c
index c8702b5..41ad63d 100644
--- a/drivers/idle/default_driver.c
+++ b/drivers/idle/default_driver.c
@@ -275,28 +275,32 @@ static void c1e_idle(void)
 }
 
 static int poll_idle_wrapper(struct cpuidle_device *dev,
-		struct cpuidle_state *state)
+		struct cpuidle_state *state,
+		struct cpuidle_state_stats *state_stats)
 {
 	poll_idle();
 	return 0;
 }
 
 static int mwait_idle_wrapper(struct cpuidle_device *dev,
-		struct cpuidle_state *state)
+		struct cpuidle_state *state,
+		struct cpuidle_state_stats *state_stats)
 {
 	mwait_idle();
 	return 0;
 }
 
 static int c1e_idle_wrapper(struct cpuidle_device *dev,
-		struct cpuidle_state *state)
+		struct cpuidle_state *state,
+		struct cpuidle_state_stats *state_stats)
 {
 	c1e_idle();
 	return 0;
 }
 
 int default_idle_wrapper(struct cpuidle_device *dev,
-		struct cpuidle_state *state)
+		struct cpuidle_state *state,
+		struct cpuidle_state_stats *state_stats)
 {
 	default_idle();
 	return 0;
@@ -305,7 +309,6 @@ int default_idle_wrapper(struct cpuidle_device *dev,
 static struct cpuidle_state state_poll = {
 		.name = "POLL",
 		.desc = "POLL",
-		.driver_data = (void *) 0x00,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
 		.target_residency = 1,
@@ -315,7 +318,6 @@ static struct cpuidle_state state_poll = {
 static struct cpuidle_state state_mwait = {
 		.name = "C1",
 		.desc = "MWAIT No Hints",
-		.driver_data = (void *) 0x01,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
 		.target_residency = 1,
@@ -325,7 +327,6 @@ static struct cpuidle_state state_mwait = {
 static struct cpuidle_state state_c1e = {
 		.name = "C1E",
 		.desc = "C1E",
-		.driver_data = (void *) 0x02,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
 		.target_residency = 1,
@@ -335,7 +336,6 @@ static struct cpuidle_state state_c1e = {
 struct cpuidle_state state_default_idle = {
 		.name = "DEFAULT-IDLE",
 		.desc = "Default idle routine",
-		.driver_data = (void *) 0x03,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
 		.target_residency = 1,
@@ -416,34 +416,20 @@ static struct cpuidle_driver default_idle_driver = {
 	.priority = 100,
 };
 
-static int setup_cpuidle(int cpu)
+static int __init default_idle_init(void)
 {
-	struct cpuidle_device *dev = kzalloc(sizeof(struct cpuidle_device),
-					GFP_KERNEL);
+	int retval;
 	int count = CPUIDLE_DRIVER_STATE_START;
-	dev->cpu = cpu;
+	struct cpuidle_device *dev = kzalloc(sizeof(struct cpuidle_device),
+						GFP_KERNEL);
 	dev->drv = &default_idle_driver;
-
-	BUG_ON(opt_state == NULL);
 	dev->states[count] = *opt_state;
 	count++;
-
 	dev->state_count = count;
 
-	if (cpuidle_register_device(dev))
-		return -EIO;
-	return 0;
-}
-
-static int __init default_idle_init(void)
-{
-	int retval, i;
+	default_idle_driver.dev = dev;
 	retval = cpuidle_register_driver(&default_idle_driver);
 
-	for_each_online_cpu(i) {
-		setup_cpuidle(i);
-	}
-
 	return 0;
 }
 

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ