* [PATCH 1/2][RFC] cpuidle : move driver's refcount to cpuidle
@ 2012-09-20 13:14 Daniel Lezcano
2012-09-20 13:14 ` [PATCH 2/2][RFC] cpudidle : use a per cpu cpuidle driver Daniel Lezcano
0 siblings, 1 reply; 2+ messages in thread
From: Daniel Lezcano @ 2012-09-20 13:14 UTC (permalink / raw)
To: rjw, lenb; +Cc: linux-pm, linux-acpi, patches, linaro-dev
In the next patch, we will support different cpuidle drivers
tied with a cpu. In this case we should move the refcount to
the cpuidle_driver structure to handle several drivers at a time.
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
drivers/cpuidle/driver.c | 11 ++++++-----
include/linux/cpuidle.h | 1 +
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 87db387..676febd 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -16,7 +16,6 @@
static struct cpuidle_driver *cpuidle_curr_driver;
DEFINE_SPINLOCK(cpuidle_driver_lock);
-int cpuidle_driver_refcount;
static void set_power_states(struct cpuidle_driver *drv)
{
@@ -92,7 +91,7 @@ void cpuidle_unregister_driver(struct cpuidle_driver *drv)
spin_lock(&cpuidle_driver_lock);
- if (!WARN_ON(cpuidle_driver_refcount > 0))
+ if (!WARN_ON(drv->refcnt > 0))
cpuidle_curr_driver = NULL;
spin_unlock(&cpuidle_driver_lock);
@@ -106,7 +105,7 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
spin_lock(&cpuidle_driver_lock);
drv = cpuidle_curr_driver;
- cpuidle_driver_refcount++;
+ drv->refcnt++;
spin_unlock(&cpuidle_driver_lock);
return drv;
@@ -114,10 +113,12 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
void cpuidle_driver_unref(void)
{
+ struct cpuidle_driver *drv = cpuidle_curr_driver;
+
spin_lock(&cpuidle_driver_lock);
- if (!WARN_ON(cpuidle_driver_refcount <= 0))
- cpuidle_driver_refcount--;
+ if (drv && !WARN_ON(drv->refcnt <= 0))
+ drv->refcnt--;
spin_unlock(&cpuidle_driver_lock);
}
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 279b1ea..a4ff9f8 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -131,6 +131,7 @@ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
struct cpuidle_driver {
const char *name;
struct module *owner;
+ int refcnt;
unsigned int power_specified:1;
/* set to 1 to use the core cpuidle time keeping (for all states). */
--
1.7.5.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH 2/2][RFC] cpudidle : use a per cpu cpuidle driver
2012-09-20 13:14 [PATCH 1/2][RFC] cpuidle : move driver's refcount to cpuidle Daniel Lezcano
@ 2012-09-20 13:14 ` Daniel Lezcano
0 siblings, 0 replies; 2+ messages in thread
From: Daniel Lezcano @ 2012-09-20 13:14 UTC (permalink / raw)
To: rjw, lenb; +Cc: linux-pm, linux-acpi, patches, linaro-dev
The discussion about having different cpus on the system with
different latencies bring us to a first attemp by adding a
pointer in the cpuidle_device to the states array.
But as Rafael suggested, it would make more sense to create a
driver per cpu [1].
This patch add support for multiple cpuidle drivers and as Rafael
expected, it had less impact than the first approach and is much
more clean.
It creates a per cpu cpuidle driver pointer.
In order to not break the different drivers, the function cpuidle_register_driver
assign for each cpu, the driver.
If this patch is accepted, I will add a cpuidle_register_cpu_driver and modify
the cpuidle drivers to make use of it and then remove the cpuidle_register_driver.
Note the output of sysfs for "/sys/devices/system/cpu/cpuidle/current_driver" has
been changed and instead of showing a single driver name, it shows the cpu and the
associated driver name.
[1] http://www.spinics.net/lists/linux-acpi/msg37921.html
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
drivers/cpuidle/driver.c | 62 +++++++++++++++++++++++++++++++---------------
drivers/cpuidle/sysfs.c | 28 ++++++++++++++++----
include/linux/cpuidle.h | 1 +
3 files changed, 65 insertions(+), 26 deletions(-)
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 676febd..b2f8823 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -11,10 +11,11 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/cpuidle.h>
+#include <linux/smp.h>
#include "cpuidle.h"
-static struct cpuidle_driver *cpuidle_curr_driver;
+DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
DEFINE_SPINLOCK(cpuidle_driver_lock);
static void set_power_states(struct cpuidle_driver *drv)
@@ -45,6 +46,8 @@ static void set_power_states(struct cpuidle_driver *drv)
*/
int cpuidle_register_driver(struct cpuidle_driver *drv)
{
+ int cpu, ret, i;
+
if (!drv || !drv->state_count)
return -EINVAL;
@@ -52,28 +55,44 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
return -ENODEV;
spin_lock(&cpuidle_driver_lock);
- if (cpuidle_curr_driver) {
- spin_unlock(&cpuidle_driver_lock);
- return -EBUSY;
- }
-
- if (!drv->power_specified)
- set_power_states(drv);
+ ret = -EBUSY;
+ for_each_present_cpu(cpu) {
+ if (per_cpu(cpuidle_drivers, cpu))
+ goto unregister;
- cpuidle_curr_driver = drv;
+ if (!drv->power_specified)
+ set_power_states(drv);
+ per_cpu(cpuidle_drivers, cpu) = drv;
+ }
+ ret = 0;
+out:
spin_unlock(&cpuidle_driver_lock);
+ return ret;
- return 0;
+unregister:
+ for (i = cpu; i >= 0; i--)
+ per_cpu(cpuidle_drivers, i) = NULL;
+ goto out;
}
EXPORT_SYMBOL_GPL(cpuidle_register_driver);
/**
+ * cpuidle_get_cpu_driver - return the driver tied with the cpu
+ * @cpu : the cpu number
+ */
+struct cpuidle_driver *cpuidle_get_cpu_driver(int cpu)
+{
+ return per_cpu(cpuidle_drivers, cpu);
+}
+EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
+
+/**
* cpuidle_get_driver - return the current driver
*/
struct cpuidle_driver *cpuidle_get_driver(void)
{
- return cpuidle_curr_driver;
+ return cpuidle_get_cpu_driver(smp_processor_id());
}
EXPORT_SYMBOL_GPL(cpuidle_get_driver);
@@ -83,17 +102,20 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver);
*/
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
{
- if (drv != cpuidle_curr_driver) {
- WARN(1, "invalid cpuidle_unregister_driver(%s)\n",
- drv->name);
- return;
- }
+ int cpu;
+ struct cpuidle_driver *d;
spin_lock(&cpuidle_driver_lock);
+ for_each_present_cpu(cpu) {
+
+ d = per_cpu(cpuidle_drivers, cpu);
+ if (drv != d)
+ continue;
- if (!WARN_ON(drv->refcnt > 0))
- cpuidle_curr_driver = NULL;
+ if (!WARN_ON(drv->refcnt > 0))
+ per_cpu(cpuidle_drivers, cpu) = NULL;
+ }
spin_unlock(&cpuidle_driver_lock);
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
@@ -104,7 +126,7 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
spin_lock(&cpuidle_driver_lock);
- drv = cpuidle_curr_driver;
+ drv = cpuidle_get_driver();
drv->refcnt++;
spin_unlock(&cpuidle_driver_lock);
@@ -113,7 +135,7 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
void cpuidle_driver_unref(void)
{
- struct cpuidle_driver *drv = cpuidle_curr_driver;
+ struct cpuidle_driver *drv = cpuidle_get_driver();
spin_lock(&cpuidle_driver_lock);
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 5f809e3..05abebe 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -47,14 +47,30 @@ static ssize_t show_current_driver(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- ssize_t ret;
- struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
+ int cpu;
+ ssize_t ret, count = 0;
+ struct cpuidle_driver *drv;
spin_lock(&cpuidle_driver_lock);
- if (cpuidle_driver)
- ret = sprintf(buf, "%s\n", cpuidle_driver->name);
- else
- ret = sprintf(buf, "none\n");
+ for_each_online_cpu(cpu) {
+
+ drv = cpuidle_get_cpu_driver(cpu);
+
+ ret = -EOVERFLOW;
+ if ((drv && (strlen(drv->name) + count) >= PAGE_SIZE) ||
+ (!drv && (strlen("none") + count) >= PAGE_SIZE))
+ goto out;
+
+ ret = sprintf(buf + count, "cpu%d: %s\n",
+ cpu, drv ? drv->name : "none" );
+
+ if (ret < 0)
+ goto out;
+
+ count += ret;
+ }
+ ret = count;
+out:
spin_unlock(&cpuidle_driver_lock);
return ret;
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index a4ff9f8..ab6a3ed 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -146,6 +146,7 @@ extern void disable_cpuidle(void);
extern int cpuidle_idle_call(void);
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
extern struct cpuidle_driver *cpuidle_get_driver(void);
+extern struct cpuidle_driver *cpuidle_get_cpu_driver(int cpu);
extern struct cpuidle_driver *cpuidle_driver_ref(void);
extern void cpuidle_driver_unref(void);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2012-09-20 13:14 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-20 13:14 [PATCH 1/2][RFC] cpuidle : move driver's refcount to cpuidle Daniel Lezcano
2012-09-20 13:14 ` [PATCH 2/2][RFC] cpudidle : use a per cpu cpuidle driver Daniel Lezcano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).