* Re: [PATCH 02/15] PM QoS: minor clean-ups
From: mark gross @ 2011-08-13 2:48 UTC (permalink / raw)
To: jean.pihet
Cc: markgross, Mark Brown, Linux PM mailing list, linux-omap,
Jean Pihet
In-Reply-To: <1313075212-8366-3-git-send-email-j-pihet@ti.com>
On Thu, Aug 11, 2011 at 05:06:39PM +0200, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
>
> - Misc fixes to improve code readability:
> . rename struct pm_qos_request_list to struct pm_qos_request,
> . rename pm_qos_req parameter to req in internal code,
> consistenly use req in the API parameters,
> . update the in-kernel API callers to the new parameters names,
> . rename of fields names (requests, list, node, constraints)
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
> drivers/media/video/via-camera.c | 2 +-
> drivers/net/wireless/ipw2x00/ipw2100.c | 2 +-
> include/linux/netdevice.h | 2 +-
> include/linux/pm_qos.h | 22 ++++----
> include/sound/pcm.h | 2 +-
> kernel/power/qos.c | 90 ++++++++++++++++---------------
> 6 files changed, 61 insertions(+), 59 deletions(-)
>
> diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
> index b3ca389..fba6c64 100644
> --- a/drivers/media/video/via-camera.c
> +++ b/drivers/media/video/via-camera.c
> @@ -69,7 +69,7 @@ struct via_camera {
> struct mutex lock;
> enum viacam_opstate opstate;
> unsigned long flags;
> - struct pm_qos_request_list qos_request;
> + struct pm_qos_request qos_request;
> /*
> * GPIO info for power/reset management
> */
> diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
> index d9df575..f323ec0 100644
> --- a/drivers/net/wireless/ipw2x00/ipw2100.c
> +++ b/drivers/net/wireless/ipw2x00/ipw2100.c
> @@ -174,7 +174,7 @@ that only one external action is invoked at a time.
> #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
> #define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
>
> -static struct pm_qos_request_list ipw2100_pm_qos_req;
> +static struct pm_qos_request ipw2100_pm_qos_req;
>
> /* Debugging stuff */
> #ifdef CONFIG_IPW2100_DEBUG
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index cc1eb9e..82f01d9 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -999,7 +999,7 @@ struct net_device {
> */
> char name[IFNAMSIZ];
>
> - struct pm_qos_request_list pm_qos_req;
> + struct pm_qos_request pm_qos_req;
>
> /* device name hash chain */
> struct hlist_node name_hlist;
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index 7ba67541..6b0968f 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -20,30 +20,30 @@
> #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
> #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
>
> -struct pm_qos_request_list {
> - struct plist_node list;
> +struct pm_qos_request {
> + struct plist_node node;
> int pm_qos_class;
> };
>
> #ifdef CONFIG_PM
> -void pm_qos_add_request(struct pm_qos_request_list *l,
> - int pm_qos_class, s32 value);
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> +void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class,
> + s32 value);
> +void pm_qos_update_request(struct pm_qos_request *req,
> s32 new_value);
> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
> +void pm_qos_remove_request(struct pm_qos_request *req);
>
> int pm_qos_request(int pm_qos_class);
> int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
> int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
> -int pm_qos_request_active(struct pm_qos_request_list *req);
> +int pm_qos_request_active(struct pm_qos_request *req);
> #else
> -static inline void pm_qos_add_request(struct pm_qos_request_list *l,
> +static inline void pm_qos_add_request(struct pm_qos_request *req,
> int pm_qos_class, s32 value)
> { return; }
> -static inline void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> +static inline void pm_qos_update_request(struct pm_qos_request *req,
> s32 new_value)
> { return; }
> -static inline void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
> +static inline void pm_qos_remove_request(struct pm_qos_request *req)
> { return; }
>
> static inline int pm_qos_request(int pm_qos_class)
> @@ -54,7 +54,7 @@ static inline int pm_qos_add_notifier(int pm_qos_class,
> static inline int pm_qos_remove_notifier(int pm_qos_class,
> struct notifier_block *notifier)
> { return 0; }
> -static inline int pm_qos_request_active(struct pm_qos_request_list *req)
> +static inline int pm_qos_request_active(struct pm_qos_request *req)
> { return 0; }
> #endif
>
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index 1204f17..d3b068f 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -373,7 +373,7 @@ struct snd_pcm_substream {
> int number;
> char name[32]; /* substream name */
> int stream; /* stream (direction) */
> - struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
> + struct pm_qos_request latency_pm_qos_req; /* pm_qos request */
> size_t buffer_bytes_max; /* limit ring buffer size */
> struct snd_dma_buffer dma_buffer;
> unsigned int dma_buf_id;
> diff --git a/kernel/power/qos.c b/kernel/power/qos.c
> index 3bf69f1..61275f2 100644
> --- a/kernel/power/qos.c
> +++ b/kernel/power/qos.c
> @@ -45,7 +45,7 @@
> #include <linux/uaccess.h>
>
> /*
> - * locking rule: all changes to requests or notifiers lists
> + * locking rule: all changes to constraints or notifiers lists
> * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
> * held, taken with _irqsave. One lock to rule them all
> */
> @@ -60,7 +60,7 @@ enum pm_qos_type {
> * types linux supports for 32 bit quantites
> */
> struct pm_qos_object {
> - struct plist_head requests;
> + struct plist_head constraints;
> struct blocking_notifier_head *notifiers;
> struct miscdevice pm_qos_power_miscdev;
> char *name;
> @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(pm_qos_lock);
> static struct pm_qos_object null_pm_qos;
> static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
> static struct pm_qos_object cpu_dma_pm_qos = {
> - .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
> + .constraints = PLIST_HEAD_INIT(cpu_dma_pm_qos.constraints, pm_qos_lock),
> .notifiers = &cpu_dma_lat_notifier,
> .name = "cpu_dma_latency",
> .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> @@ -84,7 +84,8 @@ static struct pm_qos_object cpu_dma_pm_qos = {
>
> static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
> static struct pm_qos_object network_lat_pm_qos = {
> - .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
> + .constraints = PLIST_HEAD_INIT(network_lat_pm_qos.constraints,
> + pm_qos_lock),
> .notifiers = &network_lat_notifier,
> .name = "network_latency",
> .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> @@ -95,7 +96,8 @@ static struct pm_qos_object network_lat_pm_qos = {
>
> static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
> static struct pm_qos_object network_throughput_pm_qos = {
> - .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
> + .constraints = PLIST_HEAD_INIT(network_throughput_pm_qos.constraints,
> + pm_qos_lock),
> .notifiers = &network_throughput_notifier,
> .name = "network_throughput",
> .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> @@ -129,15 +131,15 @@ static const struct file_operations pm_qos_power_fops = {
> /* unlocked internal variant */
> static inline int pm_qos_get_value(struct pm_qos_object *o)
> {
> - if (plist_head_empty(&o->requests))
> + if (plist_head_empty(&o->constraints))
> return o->default_value;
>
> switch (o->type) {
> case PM_QOS_MIN:
> - return plist_first(&o->requests)->prio;
> + return plist_first(&o->constraints)->prio;
>
> case PM_QOS_MAX:
> - return plist_last(&o->requests)->prio;
> + return plist_last(&o->constraints)->prio;
>
> default:
> /* runtime check for not using enum */
> @@ -170,13 +172,13 @@ static void update_target(struct pm_qos_object *o, struct plist_node *node,
> * with new value and add, then see if the extremal
> * changed
> */
> - plist_del(node, &o->requests);
> + plist_del(node, &o->constraints);
> plist_node_init(node, value);
> - plist_add(node, &o->requests);
> + plist_add(node, &o->constraints);
> } else if (del) {
> - plist_del(node, &o->requests);
> + plist_del(node, &o->constraints);
> } else {
> - plist_add(node, &o->requests);
> + plist_add(node, &o->constraints);
> }
> curr_value = pm_qos_get_value(o);
> pm_qos_set_value(o, curr_value);
> @@ -222,7 +224,7 @@ int pm_qos_request(int pm_qos_class)
> }
> EXPORT_SYMBOL_GPL(pm_qos_request);
>
> -int pm_qos_request_active(struct pm_qos_request_list *req)
> +int pm_qos_request_active(struct pm_qos_request *req)
> {
> return req->pm_qos_class != 0;
> }
> @@ -230,24 +232,24 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active);
>
> /**
> * pm_qos_add_request - inserts new qos request into the list
> - * @dep: pointer to a preallocated handle
> + * @req: pointer to a preallocated handle
> * @pm_qos_class: identifies which list of qos request to use
> * @value: defines the qos request
> *
> * This function inserts a new entry in the pm_qos_class list of requested qos
> * performance characteristics. It recomputes the aggregate QoS expectations
> - * for the pm_qos_class of parameters and initializes the pm_qos_request_list
> + * for the pm_qos_class of parameters and initializes the pm_qos_request
> * handle. Caller needs to save this handle for later use in updates and
> * removal.
> */
>
> -void pm_qos_add_request(struct pm_qos_request_list *dep,
> +void pm_qos_add_request(struct pm_qos_request *req,
> int pm_qos_class, s32 value)
> {
> struct pm_qos_object *o = pm_qos_array[pm_qos_class];
> int new_value;
>
> - if (pm_qos_request_active(dep)) {
> + if (pm_qos_request_active(req)) {
> WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
> return;
> }
> @@ -255,15 +257,15 @@ void pm_qos_add_request(struct pm_qos_request_list *dep,
> new_value = o->default_value;
> else
> new_value = value;
> - plist_node_init(&dep->list, new_value);
> - dep->pm_qos_class = pm_qos_class;
> - update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
> + plist_node_init(&req->node, new_value);
> + req->pm_qos_class = pm_qos_class;
> + update_target(o, &req->node, 0, PM_QOS_DEFAULT_VALUE);
> }
> EXPORT_SYMBOL_GPL(pm_qos_add_request);
>
> /**
> * pm_qos_update_request - modifies an existing qos request
> - * @pm_qos_req : handle to list element holding a pm_qos request to use
> + * @req : handle to list element holding a pm_qos request to use
> * @value: defines the qos request
> *
> * Updates an existing qos request for the pm_qos_class of parameters along
> @@ -271,56 +273,56 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
> *
> * Attempts are made to make this code callable on hot code paths.
> */
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> +void pm_qos_update_request(struct pm_qos_request *req,
> s32 new_value)
> {
> s32 temp;
> struct pm_qos_object *o;
>
> - if (!pm_qos_req) /*guard against callers passing in null */
> + if (!req) /*guard against callers passing in null */
> return;
>
> - if (!pm_qos_request_active(pm_qos_req)) {
> + if (!pm_qos_request_active(req)) {
> WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
> return;
> }
>
> - o = pm_qos_array[pm_qos_req->pm_qos_class];
> + o = pm_qos_array[req->pm_qos_class];
>
> if (new_value == PM_QOS_DEFAULT_VALUE)
> temp = o->default_value;
> else
> temp = new_value;
>
> - if (temp != pm_qos_req->list.prio)
> - update_target(o, &pm_qos_req->list, 0, temp);
> + if (temp != req->node.prio)
> + update_target(o, &req->node, 0, temp);
> }
> EXPORT_SYMBOL_GPL(pm_qos_update_request);
>
> /**
> * pm_qos_remove_request - modifies an existing qos request
> - * @pm_qos_req: handle to request list element
> + * @req: handle to request list element
> *
> - * Will remove pm qos request from the list of requests and
> + * Will remove pm qos request from the list of constraints and
> * recompute the current target value for the pm_qos_class. Call this
> * on slow code paths.
> */
> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
> +void pm_qos_remove_request(struct pm_qos_request *req)
> {
> struct pm_qos_object *o;
>
> - if (pm_qos_req == NULL)
> + if (req == NULL)
> return;
> /* silent return to keep pcm code cleaner */
>
> - if (!pm_qos_request_active(pm_qos_req)) {
> + if (!pm_qos_request_active(req)) {
> WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
> return;
> }
>
> - o = pm_qos_array[pm_qos_req->pm_qos_class];
> - update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
> - memset(pm_qos_req, 0, sizeof(*pm_qos_req));
> + o = pm_qos_array[req->pm_qos_class];
> + update_target(o, &req->node, 1, PM_QOS_DEFAULT_VALUE);
> + memset(req, 0, sizeof(*req));
> }
> EXPORT_SYMBOL_GPL(pm_qos_remove_request);
>
> @@ -368,7 +370,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
>
> pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
> if (pm_qos_class >= 0) {
> - struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL);
> + struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL);
> if (!req)
> return -ENOMEM;
>
> @@ -383,7 +385,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
>
> static int pm_qos_power_release(struct inode *inode, struct file *filp)
> {
> - struct pm_qos_request_list *req;
> + struct pm_qos_request *req;
>
> req = filp->private_data;
> pm_qos_remove_request(req);
> @@ -399,14 +401,14 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
> s32 value;
> unsigned long flags;
> struct pm_qos_object *o;
> - struct pm_qos_request_list *pm_qos_req = filp->private_data;
> + struct pm_qos_request *req = filp->private_data;
>
> - if (!pm_qos_req)
> + if (!req)
> return -EINVAL;
> - if (!pm_qos_request_active(pm_qos_req))
> + if (!pm_qos_request_active(req))
> return -EINVAL;
>
> - o = pm_qos_array[pm_qos_req->pm_qos_class];
> + o = pm_qos_array[req->pm_qos_class];
> spin_lock_irqsave(&pm_qos_lock, flags);
> value = pm_qos_get_value(o);
> spin_unlock_irqrestore(&pm_qos_lock, flags);
> @@ -418,7 +420,7 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
> size_t count, loff_t *f_pos)
> {
> s32 value;
> - struct pm_qos_request_list *pm_qos_req;
> + struct pm_qos_request *req;
>
> if (count == sizeof(s32)) {
> if (copy_from_user(&value, buf, sizeof(s32)))
> @@ -449,8 +451,8 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
> return -EINVAL;
> }
>
> - pm_qos_req = filp->private_data;
> - pm_qos_update_request(pm_qos_req, value);
> + req = filp->private_data;
> + pm_qos_update_request(req, value);
>
> return count;
> }
> --
> 1.7.2.5
>
Acked-by: markgross<markgross@thegnar.org>
^ permalink raw reply
* Re: [PATCH 01/15] PM QoS: move and rename the implementation files
From: mark gross @ 2011-08-13 2:47 UTC (permalink / raw)
To: jean.pihet
Cc: markgross, Mark Brown, Linux PM mailing list, linux-omap,
Jean Pihet
In-Reply-To: <1313075212-8366-2-git-send-email-j-pihet@ti.com>
On Thu, Aug 11, 2011 at 05:06:38PM +0200, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
>
> The PM QoS implementation files are better named
> kernel/power/qos.c and include/linux/pm_qos.h.
>
> The PM QoS support is compiled under the CONFIG_PM option.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> ---
> arch/arm/mach-msm/clock.c | 2 +-
> drivers/acpi/processor_idle.c | 2 +-
> drivers/cpuidle/cpuidle.c | 2 +-
> drivers/cpuidle/governors/ladder.c | 2 +-
> drivers/cpuidle/governors/menu.c | 2 +-
> drivers/media/video/via-camera.c | 2 +-
> drivers/net/e1000e/netdev.c | 2 +-
> drivers/net/wireless/ipw2x00/ipw2100.c | 2 +-
> drivers/staging/msm/lcdc.c | 2 +-
> drivers/staging/msm/tvenc.c | 2 +-
> include/linux/netdevice.h | 2 +-
> include/linux/pm_qos.h | 61 ++++
> include/linux/pm_qos_params.h | 38 ---
> include/sound/pcm.h | 2 +-
> kernel/Makefile | 2 +-
> kernel/pm_qos_params.c | 481 --------------------------------
> kernel/power/Makefile | 2 +-
> kernel/power/qos.c | 481 ++++++++++++++++++++++++++++++++
> net/mac80211/main.c | 2 +-
> net/mac80211/mlme.c | 2 +-
> net/mac80211/scan.c | 2 +-
> sound/core/pcm_native.c | 2 +-
> 22 files changed, 560 insertions(+), 537 deletions(-)
> create mode 100644 include/linux/pm_qos.h
> delete mode 100644 include/linux/pm_qos_params.h
> delete mode 100644 kernel/pm_qos_params.c
> create mode 100644 kernel/power/qos.c
>
> diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
> index 22a5376..d9145df 100644
> --- a/arch/arm/mach-msm/clock.c
> +++ b/arch/arm/mach-msm/clock.c
> @@ -18,7 +18,7 @@
> #include <linux/list.h>
> #include <linux/err.h>
> #include <linux/spinlock.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/mutex.h>
> #include <linux/clk.h>
> #include <linux/string.h>
> diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
> index 431ab11..2e69e09 100644
> --- a/drivers/acpi/processor_idle.c
> +++ b/drivers/acpi/processor_idle.c
> @@ -37,7 +37,7 @@
> #include <linux/dmi.h>
> #include <linux/moduleparam.h>
> #include <linux/sched.h> /* need_resched() */
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/clockchips.h>
> #include <linux/cpuidle.h>
> #include <linux/irqflags.h>
> diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
> index bf50924..eed4c47 100644
> --- a/drivers/cpuidle/cpuidle.c
> +++ b/drivers/cpuidle/cpuidle.c
> @@ -12,7 +12,7 @@
> #include <linux/mutex.h>
> #include <linux/sched.h>
> #include <linux/notifier.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/cpu.h>
> #include <linux/cpuidle.h>
> #include <linux/ktime.h>
> diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
> index 12c9890..f62fde2 100644
> --- a/drivers/cpuidle/governors/ladder.c
> +++ b/drivers/cpuidle/governors/ladder.c
> @@ -14,7 +14,7 @@
>
> #include <linux/kernel.h>
> #include <linux/cpuidle.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/moduleparam.h>
> #include <linux/jiffies.h>
>
> diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
> index c47f3d0..3600f19 100644
> --- a/drivers/cpuidle/governors/menu.c
> +++ b/drivers/cpuidle/governors/menu.c
> @@ -12,7 +12,7 @@
>
> #include <linux/kernel.h>
> #include <linux/cpuidle.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/time.h>
> #include <linux/ktime.h>
> #include <linux/hrtimer.h>
> diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
> index 85d3048..b3ca389 100644
> --- a/drivers/media/video/via-camera.c
> +++ b/drivers/media/video/via-camera.c
> @@ -21,7 +21,7 @@
> #include <media/videobuf-dma-sg.h>
> #include <linux/delay.h>
> #include <linux/dma-mapping.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/via-core.h>
> #include <linux/via-gpio.h>
> #include <linux/via_i2c.h>
> diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
> index 3310c3d..a8a18e1 100644
> --- a/drivers/net/e1000e/netdev.c
> +++ b/drivers/net/e1000e/netdev.c
> @@ -46,7 +46,7 @@
> #include <linux/if_vlan.h>
> #include <linux/cpu.h>
> #include <linux/smp.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/pm_runtime.h>
> #include <linux/aer.h>
> #include <linux/prefetch.h>
> diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
> index 4430775..d9df575 100644
> --- a/drivers/net/wireless/ipw2x00/ipw2100.c
> +++ b/drivers/net/wireless/ipw2x00/ipw2100.c
> @@ -161,7 +161,7 @@ that only one external action is invoked at a time.
> #include <linux/firmware.h>
> #include <linux/acpi.h>
> #include <linux/ctype.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
>
> #include <net/lib80211.h>
>
> diff --git a/drivers/staging/msm/lcdc.c b/drivers/staging/msm/lcdc.c
> index 8183394..1d5183d 100644
> --- a/drivers/staging/msm/lcdc.c
> +++ b/drivers/staging/msm/lcdc.c
> @@ -32,7 +32,7 @@
> #include <linux/uaccess.h>
> #include <linux/clk.h>
> #include <linux/platform_device.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
>
> #include "msm_fb.h"
>
> diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c
> index 4fbb77b..5a798b8 100644
> --- a/drivers/staging/msm/tvenc.c
> +++ b/drivers/staging/msm/tvenc.c
> @@ -32,7 +32,7 @@
> #include <linux/uaccess.h>
> #include <linux/clk.h>
> #include <linux/platform_device.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
>
> #define TVENC_C
> #include "tvenc.h"
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 54b8b4d..cc1eb9e 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -31,7 +31,7 @@
> #include <linux/if_link.h>
>
> #ifdef __KERNEL__
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/timer.h>
> #include <linux/delay.h>
> #include <linux/mm.h>
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> new file mode 100644
> index 0000000..7ba67541
> --- /dev/null
> +++ b/include/linux/pm_qos.h
> @@ -0,0 +1,61 @@
> +#ifndef _LINUX_PM_QOS_H
> +#define _LINUX_PM_QOS_H
> +/* interface for the pm_qos_power infrastructure of the linux kernel.
> + *
> + * Mark Gross <mgross@linux.intel.com>
> + */
> +#include <linux/plist.h>
> +#include <linux/notifier.h>
> +#include <linux/miscdevice.h>
> +
> +#define PM_QOS_RESERVED 0
> +#define PM_QOS_CPU_DMA_LATENCY 1
> +#define PM_QOS_NETWORK_LATENCY 2
> +#define PM_QOS_NETWORK_THROUGHPUT 3
> +
> +#define PM_QOS_NUM_CLASSES 4
> +#define PM_QOS_DEFAULT_VALUE -1
> +
> +#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
> +#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
> +#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
> +
> +struct pm_qos_request_list {
> + struct plist_node list;
> + int pm_qos_class;
> +};
> +
> +#ifdef CONFIG_PM
> +void pm_qos_add_request(struct pm_qos_request_list *l,
> + int pm_qos_class, s32 value);
> +void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> + s32 new_value);
> +void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
> +
> +int pm_qos_request(int pm_qos_class);
> +int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
> +int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
> +int pm_qos_request_active(struct pm_qos_request_list *req);
> +#else
> +static inline void pm_qos_add_request(struct pm_qos_request_list *l,
> + int pm_qos_class, s32 value)
> + { return; }
> +static inline void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> + s32 new_value)
> + { return; }
> +static inline void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
> + { return; }
> +
> +static inline int pm_qos_request(int pm_qos_class)
> + { return 0; }
> +static inline int pm_qos_add_notifier(int pm_qos_class,
> + struct notifier_block *notifier)
> + { return 0; }
> +static inline int pm_qos_remove_notifier(int pm_qos_class,
> + struct notifier_block *notifier)
> + { return 0; }
> +static inline int pm_qos_request_active(struct pm_qos_request_list *req)
> + { return 0; }
> +#endif
> +
> +#endif
> diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
> deleted file mode 100644
> index a7d87f9..0000000
> --- a/include/linux/pm_qos_params.h
> +++ /dev/null
> @@ -1,38 +0,0 @@
> -#ifndef _LINUX_PM_QOS_PARAMS_H
> -#define _LINUX_PM_QOS_PARAMS_H
> -/* interface for the pm_qos_power infrastructure of the linux kernel.
> - *
> - * Mark Gross <mgross@linux.intel.com>
> - */
> -#include <linux/plist.h>
> -#include <linux/notifier.h>
> -#include <linux/miscdevice.h>
> -
> -#define PM_QOS_RESERVED 0
> -#define PM_QOS_CPU_DMA_LATENCY 1
> -#define PM_QOS_NETWORK_LATENCY 2
> -#define PM_QOS_NETWORK_THROUGHPUT 3
> -
> -#define PM_QOS_NUM_CLASSES 4
> -#define PM_QOS_DEFAULT_VALUE -1
> -
> -#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
> -#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
> -#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
> -
> -struct pm_qos_request_list {
> - struct plist_node list;
> - int pm_qos_class;
> -};
> -
> -void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> - s32 new_value);
> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
> -
> -int pm_qos_request(int pm_qos_class);
> -int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
> -int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
> -int pm_qos_request_active(struct pm_qos_request_list *req);
> -
> -#endif
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index e1bad11..1204f17 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -29,7 +29,7 @@
> #include <linux/poll.h>
> #include <linux/mm.h>
> #include <linux/bitops.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
>
> #define snd_pcm_substream_chip(substream) ((substream)->private_data)
> #define snd_pcm_chip(pcm) ((pcm)->private_data)
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 2d64cfc..c4547c7 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -9,7 +9,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
> rcupdate.o extable.o params.o posix-timers.o \
> kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
> hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
> - notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
> + notifier.o ksysfs.o sched_clock.o cred.o \
> async.o range.o jump_label.o
> obj-y += groups.o
>
> diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
> deleted file mode 100644
> index 6824ca7..0000000
> --- a/kernel/pm_qos_params.c
> +++ /dev/null
> @@ -1,481 +0,0 @@
> -/*
> - * This module exposes the interface to kernel space for specifying
> - * QoS dependencies. It provides infrastructure for registration of:
> - *
> - * Dependents on a QoS value : register requests
> - * Watchers of QoS value : get notified when target QoS value changes
> - *
> - * This QoS design is best effort based. Dependents register their QoS needs.
> - * Watchers register to keep track of the current QoS needs of the system.
> - *
> - * There are 3 basic classes of QoS parameter: latency, timeout, throughput
> - * each have defined units:
> - * latency: usec
> - * timeout: usec <-- currently not used.
> - * throughput: kbs (kilo byte / sec)
> - *
> - * There are lists of pm_qos_objects each one wrapping requests, notifiers
> - *
> - * User mode requests on a QOS parameter register themselves to the
> - * subsystem by opening the device node /dev/... and writing there request to
> - * the node. As long as the process holds a file handle open to the node the
> - * client continues to be accounted for. Upon file release the usermode
> - * request is removed and a new qos target is computed. This way when the
> - * request that the application has is cleaned up when closes the file
> - * pointer or exits the pm_qos_object will get an opportunity to clean up.
> - *
> - * Mark Gross <mgross@linux.intel.com>
> - */
> -
> -/*#define DEBUG*/
> -
> -#include <linux/pm_qos_params.h>
> -#include <linux/sched.h>
> -#include <linux/spinlock.h>
> -#include <linux/slab.h>
> -#include <linux/time.h>
> -#include <linux/fs.h>
> -#include <linux/device.h>
> -#include <linux/miscdevice.h>
> -#include <linux/string.h>
> -#include <linux/platform_device.h>
> -#include <linux/init.h>
> -#include <linux/kernel.h>
> -
> -#include <linux/uaccess.h>
> -
> -/*
> - * locking rule: all changes to requests or notifiers lists
> - * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
> - * held, taken with _irqsave. One lock to rule them all
> - */
> -enum pm_qos_type {
> - PM_QOS_MAX, /* return the largest value */
> - PM_QOS_MIN /* return the smallest value */
> -};
> -
> -/*
> - * Note: The lockless read path depends on the CPU accessing
> - * target_value atomically. Atomic access is only guaranteed on all CPU
> - * types linux supports for 32 bit quantites
> - */
> -struct pm_qos_object {
> - struct plist_head requests;
> - struct blocking_notifier_head *notifiers;
> - struct miscdevice pm_qos_power_miscdev;
> - char *name;
> - s32 target_value; /* Do not change to 64 bit */
> - s32 default_value;
> - enum pm_qos_type type;
> -};
> -
> -static DEFINE_SPINLOCK(pm_qos_lock);
> -
> -static struct pm_qos_object null_pm_qos;
> -static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
> -static struct pm_qos_object cpu_dma_pm_qos = {
> - .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
> - .notifiers = &cpu_dma_lat_notifier,
> - .name = "cpu_dma_latency",
> - .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> - .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> - .type = PM_QOS_MIN,
> -};
> -
> -static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
> -static struct pm_qos_object network_lat_pm_qos = {
> - .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
> - .notifiers = &network_lat_notifier,
> - .name = "network_latency",
> - .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> - .default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> - .type = PM_QOS_MIN
> -};
> -
> -
> -static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
> -static struct pm_qos_object network_throughput_pm_qos = {
> - .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
> - .notifiers = &network_throughput_notifier,
> - .name = "network_throughput",
> - .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> - .default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> - .type = PM_QOS_MAX,
> -};
> -
> -
> -static struct pm_qos_object *pm_qos_array[] = {
> - &null_pm_qos,
> - &cpu_dma_pm_qos,
> - &network_lat_pm_qos,
> - &network_throughput_pm_qos
> -};
> -
> -static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
> - size_t count, loff_t *f_pos);
> -static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
> - size_t count, loff_t *f_pos);
> -static int pm_qos_power_open(struct inode *inode, struct file *filp);
> -static int pm_qos_power_release(struct inode *inode, struct file *filp);
> -
> -static const struct file_operations pm_qos_power_fops = {
> - .write = pm_qos_power_write,
> - .read = pm_qos_power_read,
> - .open = pm_qos_power_open,
> - .release = pm_qos_power_release,
> - .llseek = noop_llseek,
> -};
> -
> -/* unlocked internal variant */
> -static inline int pm_qos_get_value(struct pm_qos_object *o)
> -{
> - if (plist_head_empty(&o->requests))
> - return o->default_value;
> -
> - switch (o->type) {
> - case PM_QOS_MIN:
> - return plist_first(&o->requests)->prio;
> -
> - case PM_QOS_MAX:
> - return plist_last(&o->requests)->prio;
> -
> - default:
> - /* runtime check for not using enum */
> - BUG();
> - }
> -}
> -
> -static inline s32 pm_qos_read_value(struct pm_qos_object *o)
> -{
> - return o->target_value;
> -}
> -
> -static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
> -{
> - o->target_value = value;
> -}
> -
> -static void update_target(struct pm_qos_object *o, struct plist_node *node,
> - int del, int value)
> -{
> - unsigned long flags;
> - int prev_value, curr_value;
> -
> - spin_lock_irqsave(&pm_qos_lock, flags);
> - prev_value = pm_qos_get_value(o);
> - /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
> - if (value != PM_QOS_DEFAULT_VALUE) {
> - /*
> - * to change the list, we atomically remove, reinit
> - * with new value and add, then see if the extremal
> - * changed
> - */
> - plist_del(node, &o->requests);
> - plist_node_init(node, value);
> - plist_add(node, &o->requests);
> - } else if (del) {
> - plist_del(node, &o->requests);
> - } else {
> - plist_add(node, &o->requests);
> - }
> - curr_value = pm_qos_get_value(o);
> - pm_qos_set_value(o, curr_value);
> - spin_unlock_irqrestore(&pm_qos_lock, flags);
> -
> - if (prev_value != curr_value)
> - blocking_notifier_call_chain(o->notifiers,
> - (unsigned long)curr_value,
> - NULL);
> -}
> -
> -static int register_pm_qos_misc(struct pm_qos_object *qos)
> -{
> - qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> - qos->pm_qos_power_miscdev.name = qos->name;
> - qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
> -
> - return misc_register(&qos->pm_qos_power_miscdev);
> -}
> -
> -static int find_pm_qos_object_by_minor(int minor)
> -{
> - int pm_qos_class;
> -
> - for (pm_qos_class = 0;
> - pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> - if (minor ==
> - pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> - return pm_qos_class;
> - }
> - return -1;
> -}
> -
> -/**
> - * pm_qos_request - returns current system wide qos expectation
> - * @pm_qos_class: identification of which qos value is requested
> - *
> - * This function returns the current target value.
> - */
> -int pm_qos_request(int pm_qos_class)
> -{
> - return pm_qos_read_value(pm_qos_array[pm_qos_class]);
> -}
> -EXPORT_SYMBOL_GPL(pm_qos_request);
> -
> -int pm_qos_request_active(struct pm_qos_request_list *req)
> -{
> - return req->pm_qos_class != 0;
> -}
> -EXPORT_SYMBOL_GPL(pm_qos_request_active);
> -
> -/**
> - * pm_qos_add_request - inserts new qos request into the list
> - * @dep: pointer to a preallocated handle
> - * @pm_qos_class: identifies which list of qos request to use
> - * @value: defines the qos request
> - *
> - * This function inserts a new entry in the pm_qos_class list of requested qos
> - * performance characteristics. It recomputes the aggregate QoS expectations
> - * for the pm_qos_class of parameters and initializes the pm_qos_request_list
> - * handle. Caller needs to save this handle for later use in updates and
> - * removal.
> - */
> -
> -void pm_qos_add_request(struct pm_qos_request_list *dep,
> - int pm_qos_class, s32 value)
> -{
> - struct pm_qos_object *o = pm_qos_array[pm_qos_class];
> - int new_value;
> -
> - if (pm_qos_request_active(dep)) {
> - WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
> - return;
> - }
> - if (value == PM_QOS_DEFAULT_VALUE)
> - new_value = o->default_value;
> - else
> - new_value = value;
> - plist_node_init(&dep->list, new_value);
> - dep->pm_qos_class = pm_qos_class;
> - update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
> -}
> -EXPORT_SYMBOL_GPL(pm_qos_add_request);
> -
> -/**
> - * pm_qos_update_request - modifies an existing qos request
> - * @pm_qos_req : handle to list element holding a pm_qos request to use
> - * @value: defines the qos request
> - *
> - * Updates an existing qos request for the pm_qos_class of parameters along
> - * with updating the target pm_qos_class value.
> - *
> - * Attempts are made to make this code callable on hot code paths.
> - */
> -void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> - s32 new_value)
> -{
> - s32 temp;
> - struct pm_qos_object *o;
> -
> - if (!pm_qos_req) /*guard against callers passing in null */
> - return;
> -
> - if (!pm_qos_request_active(pm_qos_req)) {
> - WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
> - return;
> - }
> -
> - o = pm_qos_array[pm_qos_req->pm_qos_class];
> -
> - if (new_value == PM_QOS_DEFAULT_VALUE)
> - temp = o->default_value;
> - else
> - temp = new_value;
> -
> - if (temp != pm_qos_req->list.prio)
> - update_target(o, &pm_qos_req->list, 0, temp);
> -}
> -EXPORT_SYMBOL_GPL(pm_qos_update_request);
> -
> -/**
> - * pm_qos_remove_request - modifies an existing qos request
> - * @pm_qos_req: handle to request list element
> - *
> - * Will remove pm qos request from the list of requests and
> - * recompute the current target value for the pm_qos_class. Call this
> - * on slow code paths.
> - */
> -void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
> -{
> - struct pm_qos_object *o;
> -
> - if (pm_qos_req == NULL)
> - return;
> - /* silent return to keep pcm code cleaner */
> -
> - if (!pm_qos_request_active(pm_qos_req)) {
> - WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
> - return;
> - }
> -
> - o = pm_qos_array[pm_qos_req->pm_qos_class];
> - update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
> - memset(pm_qos_req, 0, sizeof(*pm_qos_req));
> -}
> -EXPORT_SYMBOL_GPL(pm_qos_remove_request);
> -
> -/**
> - * pm_qos_add_notifier - sets notification entry for changes to target value
> - * @pm_qos_class: identifies which qos target changes should be notified.
> - * @notifier: notifier block managed by caller.
> - *
> - * will register the notifier into a notification chain that gets called
> - * upon changes to the pm_qos_class target value.
> - */
> -int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
> -{
> - int retval;
> -
> - retval = blocking_notifier_chain_register(
> - pm_qos_array[pm_qos_class]->notifiers, notifier);
> -
> - return retval;
> -}
> -EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
> -
> -/**
> - * pm_qos_remove_notifier - deletes notification entry from chain.
> - * @pm_qos_class: identifies which qos target changes are notified.
> - * @notifier: notifier block to be removed.
> - *
> - * will remove the notifier from the notification chain that gets called
> - * upon changes to the pm_qos_class target value.
> - */
> -int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
> -{
> - int retval;
> -
> - retval = blocking_notifier_chain_unregister(
> - pm_qos_array[pm_qos_class]->notifiers, notifier);
> -
> - return retval;
> -}
> -EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
> -
> -static int pm_qos_power_open(struct inode *inode, struct file *filp)
> -{
> - long pm_qos_class;
> -
> - pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
> - if (pm_qos_class >= 0) {
> - struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL);
> - if (!req)
> - return -ENOMEM;
> -
> - pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
> - filp->private_data = req;
> -
> - if (filp->private_data)
> - return 0;
> - }
> - return -EPERM;
> -}
> -
> -static int pm_qos_power_release(struct inode *inode, struct file *filp)
> -{
> - struct pm_qos_request_list *req;
> -
> - req = filp->private_data;
> - pm_qos_remove_request(req);
> - kfree(req);
> -
> - return 0;
> -}
> -
> -
> -static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
> - size_t count, loff_t *f_pos)
> -{
> - s32 value;
> - unsigned long flags;
> - struct pm_qos_object *o;
> - struct pm_qos_request_list *pm_qos_req = filp->private_data;
> -
> - if (!pm_qos_req)
> - return -EINVAL;
> - if (!pm_qos_request_active(pm_qos_req))
> - return -EINVAL;
> -
> - o = pm_qos_array[pm_qos_req->pm_qos_class];
> - spin_lock_irqsave(&pm_qos_lock, flags);
> - value = pm_qos_get_value(o);
> - spin_unlock_irqrestore(&pm_qos_lock, flags);
> -
> - return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
> -}
> -
> -static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
> - size_t count, loff_t *f_pos)
> -{
> - s32 value;
> - struct pm_qos_request_list *pm_qos_req;
> -
> - if (count == sizeof(s32)) {
> - if (copy_from_user(&value, buf, sizeof(s32)))
> - return -EFAULT;
> - } else if (count <= 11) { /* ASCII perhaps? */
> - char ascii_value[11];
> - unsigned long int ulval;
> - int ret;
> -
> - if (copy_from_user(ascii_value, buf, count))
> - return -EFAULT;
> -
> - if (count > 10) {
> - if (ascii_value[10] == '\n')
> - ascii_value[10] = '\0';
> - else
> - return -EINVAL;
> - } else {
> - ascii_value[count] = '\0';
> - }
> - ret = strict_strtoul(ascii_value, 16, &ulval);
> - if (ret) {
> - pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
> - return -EINVAL;
> - }
> - value = (s32)lower_32_bits(ulval);
> - } else {
> - return -EINVAL;
> - }
> -
> - pm_qos_req = filp->private_data;
> - pm_qos_update_request(pm_qos_req, value);
> -
> - return count;
> -}
> -
> -
> -static int __init pm_qos_power_init(void)
> -{
> - int ret = 0;
> -
> - ret = register_pm_qos_misc(&cpu_dma_pm_qos);
> - if (ret < 0) {
> - printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
> - return ret;
> - }
> - ret = register_pm_qos_misc(&network_lat_pm_qos);
> - if (ret < 0) {
> - printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
> - return ret;
> - }
> - ret = register_pm_qos_misc(&network_throughput_pm_qos);
> - if (ret < 0)
> - printk(KERN_ERR
> - "pm_qos_param: network_throughput setup failed\n");
> -
> - return ret;
> -}
> -
> -late_initcall(pm_qos_power_init);
> diff --git a/kernel/power/Makefile b/kernel/power/Makefile
> index c5ebc6a..ad6bdd8 100644
> --- a/kernel/power/Makefile
> +++ b/kernel/power/Makefile
> @@ -1,7 +1,7 @@
>
> ccflags-$(CONFIG_PM_DEBUG) := -DDEBUG
>
> -obj-$(CONFIG_PM) += main.o
> +obj-$(CONFIG_PM) += main.o qos.o
> obj-$(CONFIG_PM_SLEEP) += console.o
> obj-$(CONFIG_FREEZER) += process.o
> obj-$(CONFIG_SUSPEND) += suspend.o
> diff --git a/kernel/power/qos.c b/kernel/power/qos.c
> new file mode 100644
> index 0000000..3bf69f1
> --- /dev/null
> +++ b/kernel/power/qos.c
> @@ -0,0 +1,481 @@
> +/*
> + * This module exposes the interface to kernel space for specifying
> + * QoS dependencies. It provides infrastructure for registration of:
> + *
> + * Dependents on a QoS value : register requests
> + * Watchers of QoS value : get notified when target QoS value changes
> + *
> + * This QoS design is best effort based. Dependents register their QoS needs.
> + * Watchers register to keep track of the current QoS needs of the system.
> + *
> + * There are 3 basic classes of QoS parameter: latency, timeout, throughput
> + * each have defined units:
> + * latency: usec
> + * timeout: usec <-- currently not used.
> + * throughput: kbs (kilo byte / sec)
> + *
> + * There are lists of pm_qos_objects each one wrapping requests, notifiers
> + *
> + * User mode requests on a QOS parameter register themselves to the
> + * subsystem by opening the device node /dev/... and writing there request to
> + * the node. As long as the process holds a file handle open to the node the
> + * client continues to be accounted for. Upon file release the usermode
> + * request is removed and a new qos target is computed. This way when the
> + * request that the application has is cleaned up when closes the file
> + * pointer or exits the pm_qos_object will get an opportunity to clean up.
> + *
> + * Mark Gross <mgross@linux.intel.com>
> + */
> +
> +/*#define DEBUG*/
> +
> +#include <linux/pm_qos.h>
> +#include <linux/sched.h>
> +#include <linux/spinlock.h>
> +#include <linux/slab.h>
> +#include <linux/time.h>
> +#include <linux/fs.h>
> +#include <linux/device.h>
> +#include <linux/miscdevice.h>
> +#include <linux/string.h>
> +#include <linux/platform_device.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/uaccess.h>
> +
> +/*
> + * locking rule: all changes to requests or notifiers lists
> + * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
> + * held, taken with _irqsave. One lock to rule them all
> + */
> +enum pm_qos_type {
> + PM_QOS_MAX, /* return the largest value */
> + PM_QOS_MIN /* return the smallest value */
> +};
> +
> +/*
> + * Note: The lockless read path depends on the CPU accessing
> + * target_value atomically. Atomic access is only guaranteed on all CPU
> + * types linux supports for 32 bit quantites
> + */
> +struct pm_qos_object {
> + struct plist_head requests;
> + struct blocking_notifier_head *notifiers;
> + struct miscdevice pm_qos_power_miscdev;
> + char *name;
> + s32 target_value; /* Do not change to 64 bit */
> + s32 default_value;
> + enum pm_qos_type type;
> +};
> +
> +static DEFINE_SPINLOCK(pm_qos_lock);
> +
> +static struct pm_qos_object null_pm_qos;
> +static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
> +static struct pm_qos_object cpu_dma_pm_qos = {
> + .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
> + .notifiers = &cpu_dma_lat_notifier,
> + .name = "cpu_dma_latency",
> + .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> + .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
> + .type = PM_QOS_MIN,
> +};
> +
> +static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
> +static struct pm_qos_object network_lat_pm_qos = {
> + .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
> + .notifiers = &network_lat_notifier,
> + .name = "network_latency",
> + .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> + .default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
> + .type = PM_QOS_MIN
> +};
> +
> +
> +static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
> +static struct pm_qos_object network_throughput_pm_qos = {
> + .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
> + .notifiers = &network_throughput_notifier,
> + .name = "network_throughput",
> + .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> + .default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
> + .type = PM_QOS_MAX,
> +};
> +
> +
> +static struct pm_qos_object *pm_qos_array[] = {
> + &null_pm_qos,
> + &cpu_dma_pm_qos,
> + &network_lat_pm_qos,
> + &network_throughput_pm_qos
> +};
> +
> +static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
> + size_t count, loff_t *f_pos);
> +static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
> + size_t count, loff_t *f_pos);
> +static int pm_qos_power_open(struct inode *inode, struct file *filp);
> +static int pm_qos_power_release(struct inode *inode, struct file *filp);
> +
> +static const struct file_operations pm_qos_power_fops = {
> + .write = pm_qos_power_write,
> + .read = pm_qos_power_read,
> + .open = pm_qos_power_open,
> + .release = pm_qos_power_release,
> + .llseek = noop_llseek,
> +};
> +
> +/* unlocked internal variant */
> +static inline int pm_qos_get_value(struct pm_qos_object *o)
> +{
> + if (plist_head_empty(&o->requests))
> + return o->default_value;
> +
> + switch (o->type) {
> + case PM_QOS_MIN:
> + return plist_first(&o->requests)->prio;
> +
> + case PM_QOS_MAX:
> + return plist_last(&o->requests)->prio;
> +
> + default:
> + /* runtime check for not using enum */
> + BUG();
> + }
> +}
> +
> +static inline s32 pm_qos_read_value(struct pm_qos_object *o)
> +{
> + return o->target_value;
> +}
> +
> +static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
> +{
> + o->target_value = value;
> +}
> +
> +static void update_target(struct pm_qos_object *o, struct plist_node *node,
> + int del, int value)
> +{
> + unsigned long flags;
> + int prev_value, curr_value;
> +
> + spin_lock_irqsave(&pm_qos_lock, flags);
> + prev_value = pm_qos_get_value(o);
> + /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
> + if (value != PM_QOS_DEFAULT_VALUE) {
> + /*
> + * to change the list, we atomically remove, reinit
> + * with new value and add, then see if the extremal
> + * changed
> + */
> + plist_del(node, &o->requests);
> + plist_node_init(node, value);
> + plist_add(node, &o->requests);
> + } else if (del) {
> + plist_del(node, &o->requests);
> + } else {
> + plist_add(node, &o->requests);
> + }
> + curr_value = pm_qos_get_value(o);
> + pm_qos_set_value(o, curr_value);
> + spin_unlock_irqrestore(&pm_qos_lock, flags);
> +
> + if (prev_value != curr_value)
> + blocking_notifier_call_chain(o->notifiers,
> + (unsigned long)curr_value,
> + NULL);
> +}
> +
> +static int register_pm_qos_misc(struct pm_qos_object *qos)
> +{
> + qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
> + qos->pm_qos_power_miscdev.name = qos->name;
> + qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
> +
> + return misc_register(&qos->pm_qos_power_miscdev);
> +}
> +
> +static int find_pm_qos_object_by_minor(int minor)
> +{
> + int pm_qos_class;
> +
> + for (pm_qos_class = 0;
> + pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
> + if (minor ==
> + pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
> + return pm_qos_class;
> + }
> + return -1;
> +}
> +
> +/**
> + * pm_qos_request - returns current system wide qos expectation
> + * @pm_qos_class: identification of which qos value is requested
> + *
> + * This function returns the current target value.
> + */
> +int pm_qos_request(int pm_qos_class)
> +{
> + return pm_qos_read_value(pm_qos_array[pm_qos_class]);
> +}
> +EXPORT_SYMBOL_GPL(pm_qos_request);
> +
> +int pm_qos_request_active(struct pm_qos_request_list *req)
> +{
> + return req->pm_qos_class != 0;
> +}
> +EXPORT_SYMBOL_GPL(pm_qos_request_active);
> +
> +/**
> + * pm_qos_add_request - inserts new qos request into the list
> + * @dep: pointer to a preallocated handle
> + * @pm_qos_class: identifies which list of qos request to use
> + * @value: defines the qos request
> + *
> + * This function inserts a new entry in the pm_qos_class list of requested qos
> + * performance characteristics. It recomputes the aggregate QoS expectations
> + * for the pm_qos_class of parameters and initializes the pm_qos_request_list
> + * handle. Caller needs to save this handle for later use in updates and
> + * removal.
> + */
> +
> +void pm_qos_add_request(struct pm_qos_request_list *dep,
> + int pm_qos_class, s32 value)
> +{
> + struct pm_qos_object *o = pm_qos_array[pm_qos_class];
> + int new_value;
> +
> + if (pm_qos_request_active(dep)) {
> + WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
> + return;
> + }
> + if (value == PM_QOS_DEFAULT_VALUE)
> + new_value = o->default_value;
> + else
> + new_value = value;
> + plist_node_init(&dep->list, new_value);
> + dep->pm_qos_class = pm_qos_class;
> + update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
> +}
> +EXPORT_SYMBOL_GPL(pm_qos_add_request);
> +
> +/**
> + * pm_qos_update_request - modifies an existing qos request
> + * @pm_qos_req : handle to list element holding a pm_qos request to use
> + * @value: defines the qos request
> + *
> + * Updates an existing qos request for the pm_qos_class of parameters along
> + * with updating the target pm_qos_class value.
> + *
> + * Attempts are made to make this code callable on hot code paths.
> + */
> +void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> + s32 new_value)
> +{
> + s32 temp;
> + struct pm_qos_object *o;
> +
> + if (!pm_qos_req) /*guard against callers passing in null */
> + return;
> +
> + if (!pm_qos_request_active(pm_qos_req)) {
> + WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
> + return;
> + }
> +
> + o = pm_qos_array[pm_qos_req->pm_qos_class];
> +
> + if (new_value == PM_QOS_DEFAULT_VALUE)
> + temp = o->default_value;
> + else
> + temp = new_value;
> +
> + if (temp != pm_qos_req->list.prio)
> + update_target(o, &pm_qos_req->list, 0, temp);
> +}
> +EXPORT_SYMBOL_GPL(pm_qos_update_request);
> +
> +/**
> + * pm_qos_remove_request - modifies an existing qos request
> + * @pm_qos_req: handle to request list element
> + *
> + * Will remove pm qos request from the list of requests and
> + * recompute the current target value for the pm_qos_class. Call this
> + * on slow code paths.
> + */
> +void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
> +{
> + struct pm_qos_object *o;
> +
> + if (pm_qos_req == NULL)
> + return;
> + /* silent return to keep pcm code cleaner */
> +
> + if (!pm_qos_request_active(pm_qos_req)) {
> + WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
> + return;
> + }
> +
> + o = pm_qos_array[pm_qos_req->pm_qos_class];
> + update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
> + memset(pm_qos_req, 0, sizeof(*pm_qos_req));
> +}
> +EXPORT_SYMBOL_GPL(pm_qos_remove_request);
> +
> +/**
> + * pm_qos_add_notifier - sets notification entry for changes to target value
> + * @pm_qos_class: identifies which qos target changes should be notified.
> + * @notifier: notifier block managed by caller.
> + *
> + * will register the notifier into a notification chain that gets called
> + * upon changes to the pm_qos_class target value.
> + */
> +int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
> +{
> + int retval;
> +
> + retval = blocking_notifier_chain_register(
> + pm_qos_array[pm_qos_class]->notifiers, notifier);
> +
> + return retval;
> +}
> +EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
> +
> +/**
> + * pm_qos_remove_notifier - deletes notification entry from chain.
> + * @pm_qos_class: identifies which qos target changes are notified.
> + * @notifier: notifier block to be removed.
> + *
> + * will remove the notifier from the notification chain that gets called
> + * upon changes to the pm_qos_class target value.
> + */
> +int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
> +{
> + int retval;
> +
> + retval = blocking_notifier_chain_unregister(
> + pm_qos_array[pm_qos_class]->notifiers, notifier);
> +
> + return retval;
> +}
> +EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
> +
> +static int pm_qos_power_open(struct inode *inode, struct file *filp)
> +{
> + long pm_qos_class;
> +
> + pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
> + if (pm_qos_class >= 0) {
> + struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL);
> + if (!req)
> + return -ENOMEM;
> +
> + pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
> + filp->private_data = req;
> +
> + if (filp->private_data)
> + return 0;
> + }
> + return -EPERM;
> +}
> +
> +static int pm_qos_power_release(struct inode *inode, struct file *filp)
> +{
> + struct pm_qos_request_list *req;
> +
> + req = filp->private_data;
> + pm_qos_remove_request(req);
> + kfree(req);
> +
> + return 0;
> +}
> +
> +
> +static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
> + size_t count, loff_t *f_pos)
> +{
> + s32 value;
> + unsigned long flags;
> + struct pm_qos_object *o;
> + struct pm_qos_request_list *pm_qos_req = filp->private_data;
> +
> + if (!pm_qos_req)
> + return -EINVAL;
> + if (!pm_qos_request_active(pm_qos_req))
> + return -EINVAL;
> +
> + o = pm_qos_array[pm_qos_req->pm_qos_class];
> + spin_lock_irqsave(&pm_qos_lock, flags);
> + value = pm_qos_get_value(o);
> + spin_unlock_irqrestore(&pm_qos_lock, flags);
> +
> + return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
> +}
> +
> +static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
> + size_t count, loff_t *f_pos)
> +{
> + s32 value;
> + struct pm_qos_request_list *pm_qos_req;
> +
> + if (count == sizeof(s32)) {
> + if (copy_from_user(&value, buf, sizeof(s32)))
> + return -EFAULT;
> + } else if (count <= 11) { /* ASCII perhaps? */
> + char ascii_value[11];
> + unsigned long int ulval;
> + int ret;
> +
> + if (copy_from_user(ascii_value, buf, count))
> + return -EFAULT;
> +
> + if (count > 10) {
> + if (ascii_value[10] == '\n')
> + ascii_value[10] = '\0';
> + else
> + return -EINVAL;
> + } else {
> + ascii_value[count] = '\0';
> + }
> + ret = strict_strtoul(ascii_value, 16, &ulval);
> + if (ret) {
> + pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
> + return -EINVAL;
> + }
> + value = (s32)lower_32_bits(ulval);
> + } else {
> + return -EINVAL;
> + }
> +
> + pm_qos_req = filp->private_data;
> + pm_qos_update_request(pm_qos_req, value);
> +
> + return count;
> +}
> +
> +
> +static int __init pm_qos_power_init(void)
> +{
> + int ret = 0;
> +
> + ret = register_pm_qos_misc(&cpu_dma_pm_qos);
> + if (ret < 0) {
> + printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
> + return ret;
> + }
> + ret = register_pm_qos_misc(&network_lat_pm_qos);
> + if (ret < 0) {
> + printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
> + return ret;
> + }
> + ret = register_pm_qos_misc(&network_throughput_pm_qos);
> + if (ret < 0)
> + printk(KERN_ERR
> + "pm_qos_param: network_throughput setup failed\n");
> +
> + return ret;
> +}
> +
> +late_initcall(pm_qos_power_init);
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 866f269..bb771e9 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -19,7 +19,7 @@
> #include <linux/if_arp.h>
> #include <linux/rtnetlink.h>
> #include <linux/bitmap.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/inetdevice.h>
> #include <net/net_namespace.h>
> #include <net/cfg80211.h>
> diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
> index d595265..f07705d 100644
> --- a/net/mac80211/mlme.c
> +++ b/net/mac80211/mlme.c
> @@ -17,7 +17,7 @@
> #include <linux/if_arp.h>
> #include <linux/etherdevice.h>
> #include <linux/rtnetlink.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/crc32.h>
> #include <linux/slab.h>
> #include <net/mac80211.h>
> diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
> index 58ffa7d..41393c4 100644
> --- a/net/mac80211/scan.c
> +++ b/net/mac80211/scan.c
> @@ -14,7 +14,7 @@
>
> #include <linux/if_arp.h>
> #include <linux/rtnetlink.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <net/sch_generic.h>
> #include <linux/slab.h>
> #include <net/mac80211.h>
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index 1c6be91..c74e228 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -23,7 +23,7 @@
> #include <linux/file.h>
> #include <linux/slab.h>
> #include <linux/time.h>
> -#include <linux/pm_qos_params.h>
> +#include <linux/pm_qos.h>
> #include <linux/uio.h>
> #include <linux/dma-mapping.h>
> #include <sound/core.h>
> --
> 1.7.2.5
Acked-by: markgross <markgross@thegnar.org>
^ permalink raw reply
* Re: [PATCH v4 00/15] PM QoS: add a per-device latency constraints class
From: Rafael J. Wysocki @ 2011-08-12 21:56 UTC (permalink / raw)
To: Jean Pihet
Cc: markgross, Mark Brown, Linux PM mailing list, linux-omap,
Jean Pihet
In-Reply-To: <CAORVsuVT8RFrE9YWzErp3dy7qeZuJ59upKd8bjDthx_622UM9g@mail.gmail.com>
Hi,
On Friday, August 12, 2011, Jean Pihet wrote:
> Hi Rafael,
>
> 2011/8/12 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Thursday, August 11, 2011, jean.pihet@newoldbits.com wrote:
> >> From: Jean Pihet <j-pihet@ti.com>
> >>
> >> This patch set is in an RFC state, for review and comments.
> >>
> ...
> >>
> >>
> >> Questions:
> >> 1. the user space API is still under discussions on linux-omap and linux-pm MLs,
> >> cf. [1]. The idea is to add a user-space API for the devices constratins
> >> PM QoS, using a sysfs entry per device
> >>
> >> [1] http://marc.info/?l=linux-omap&m=131232344503327&w=2
> >>
> >> ToDo:
> >> 1. write Documentation for the new PM QoS class, once the RFC is agreed on
> >> 2. validate the constraints framework on OMAP4 HW (done on OMAP3)
> >> 3. Need testing on platforms other than OMAP
> >> 4. refine the power domains wake-up latency and the cpuidle figures
> >> 5. re-visit the OMAP power domains states initialization procedure. Currently
> >> the power states that have been changed from the constraints API which were
> >> applied before the initialization of the power domains are lost
> >>
> >>
> >> Based on the master branch of the linux-omap git tree (3.0.0-rc7). Compile
> >> tested using OMAP and x86 generic defconfigs.
> >>
> >> Lightly tested on OMAP3 Beagleboard (ES2.x).
> >> Need testing on platforms other than OMAP, because of the impact on the
> >> device insertion/removal in device_pm_add/remove
> >
> > The patchset looks really good to me, I don't think I have any major
> > complaints about this version.
> Ok good to hear it! I tried to address all comments and concerns in
> this release.
>
> >
> > The only thing I'd like to ask at the moment is whether or not the
> > compilation of drivers/base/power/qos.c should depend on
> > CONFIG_PM_RUNTIME. Do you think it will be used by system suspend code on any
> > platforms?
> I would say it should only depend on CONFIG_PM because the dev PM QoS
> API can be used from any kernel code, being runtime PM code or not.
> I leave the decision to the PM framework experts.
>
> >
> > Also, I'd like to take the final patchset for 3.2,
> Ok good!
>
> > but I don't feel
> > confident enough about the OMAP patches.
> The OMAP patches have been reviewed a few times already and the
> comments have been taken into account. Also i has been tested
> correctly on OMAP3.
>
> > If you want me to take them too,
> > please make sure they are ACKed by the OMAP maintainers.
> For sure I need the Acks. I guess I now need to annoy OMAP folks about it ;p
> In the case the Acks are not gathered on time the generic patches
> could be merged in, then the OMAP generic code. Do you think it is a
> viable option?
Yes, it is. I can take patches [1-7/15] alone.
> The only concern I have is about the on-going OMAP PM initialization
> clean-up task, cf. ToDo list:
> >> 5. re-visit the OMAP power domains states initialization
> procedure. Currently
> >> the power states that have been changed from the constraints
> API which were
> >> applied before the initialization of the power domains are lost
>
> On the other hand some testing is needed on platforms other than OMAP,
> because of the impact on the device insertion/removal in
> device_pm_add/remove functions. I tested the SD card insertion/removal
> on OMAP3.
OK, so are you going to make any more changes to patches [1-7/15]?
Rafael
^ permalink raw reply
* Re: [PATCH v4 00/15] PM QoS: add a per-device latency constraints class
From: Jean Pihet @ 2011-08-12 11:56 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: markgross, Mark Brown, Linux PM mailing list, linux-omap,
Jean Pihet
In-Reply-To: <201108121002.25207.rjw@sisk.pl>
Hi Rafael,
2011/8/12 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, August 11, 2011, jean.pihet@newoldbits.com wrote:
>> From: Jean Pihet <j-pihet@ti.com>
>>
>> This patch set is in an RFC state, for review and comments.
>>
...
>>
>>
>> Questions:
>> 1. the user space API is still under discussions on linux-omap and linux-pm MLs,
>> cf. [1]. The idea is to add a user-space API for the devices constratins
>> PM QoS, using a sysfs entry per device
>>
>> [1] http://marc.info/?l=linux-omap&m=131232344503327&w=2
>>
>> ToDo:
>> 1. write Documentation for the new PM QoS class, once the RFC is agreed on
>> 2. validate the constraints framework on OMAP4 HW (done on OMAP3)
>> 3. Need testing on platforms other than OMAP
>> 4. refine the power domains wake-up latency and the cpuidle figures
>> 5. re-visit the OMAP power domains states initialization procedure. Currently
>> the power states that have been changed from the constraints API which were
>> applied before the initialization of the power domains are lost
>>
>>
>> Based on the master branch of the linux-omap git tree (3.0.0-rc7). Compile
>> tested using OMAP and x86 generic defconfigs.
>>
>> Lightly tested on OMAP3 Beagleboard (ES2.x).
>> Need testing on platforms other than OMAP, because of the impact on the
>> device insertion/removal in device_pm_add/remove
>
> The patchset looks really good to me, I don't think I have any major
> complaints about this version.
Ok good to hear it! I tried to address all comments and concerns in
this release.
>
> The only thing I'd like to ask at the moment is whether or not the
> compilation of drivers/base/power/qos.c should depend on
> CONFIG_PM_RUNTIME. Do you think it will be used by system suspend code on any
> platforms?
I would say it should only depend on CONFIG_PM because the dev PM QoS
API can be used from any kernel code, being runtime PM code or not.
I leave the decision to the PM framework experts.
>
> Also, I'd like to take the final patchset for 3.2,
Ok good!
> but I don't feel
> confident enough about the OMAP patches.
The OMAP patches have been reviewed a few times already and the
comments have been taken into account. Also i has been tested
correctly on OMAP3.
> If you want me to take them too,
> please make sure they are ACKed by the OMAP maintainers.
For sure I need the Acks. I guess I now need to annoy OMAP folks about it ;p
In the case the Acks are not gathered on time the generic patches
could be merged in, then the OMAP generic code. Do you think it is a
viable option?
The only concern I have is about the on-going OMAP PM initialization
clean-up task, cf. ToDo list:
>> 5. re-visit the OMAP power domains states initialization
procedure. Currently
>> the power states that have been changed from the constraints
API which were
>> applied before the initialization of the power domains are lost
On the other hand some testing is needed on platforms other than OMAP,
because of the impact on the device insertion/removal in
device_pm_add/remove functions. I tested the SD card insertion/removal
on OMAP3.
>
> Thanks,
> Rafael
>
Thanks,
Jean
^ permalink raw reply
* Re: [PATCH v4 00/15] PM QoS: add a per-device latency constraints class
From: Rafael J. Wysocki @ 2011-08-12 8:02 UTC (permalink / raw)
To: jean.pihet
Cc: markgross, Mark Brown, Linux PM mailing list, linux-omap,
Jean Pihet
In-Reply-To: <1313075212-8366-1-git-send-email-j-pihet@ti.com>
On Thursday, August 11, 2011, jean.pihet@newoldbits.com wrote:
> From: Jean Pihet <j-pihet@ti.com>
>
> This patch set is in an RFC state, for review and comments.
>
> High level implementation:
>
> 1. Preparation of the PM QoS for the addition of a device PM QoS constraints
> framework:
> . rename and move of the PM QoS implementation files to kernel/power/qos.c
> and include/linux/pm_qos.h
> . rename of API parameters and internal fields names
> . Move around the PM QoS misc devices management code for better readability
> . re-organize the internal data structs
> . generalize and export the constraints management core code
>
> 2. Implementation of the per-device PM QoS constraints:
> . create drivers/base/power/qos.c for the implementation
> . create a device PM QoS API, which calls the PM QoS constraints management
> core code
> . the per-device latency constraints data strctures are stored in the device
> dev_pm_info struct
> . the device PM code calls the init and destroy of the per-device constraints
> data struct in order to support the dynamic insertion and removal of the
> devices in the system.
> . to minimize the data usage by the per-device constraints, the data struct
> is only allocated at the first call to dev_pm_qos_add_request. The data
> is later free'd when the device is removed from the system
> . per-device notification callbacks can be registered and called upon a
> change to the aggregated constraint value
>
> 3. add a global notification mechanism for the device constraints
> . add a global notification chain that gets called upon changes to the
> aggregated constraint value for any device.
> . the notification callbacks are passing the full constraint request data
> in order for the callees to have access to it. The current use is for the
> platform low-level code to access the target device of the constraint
>
> 4. Implement the OMAP low level constraints management code
> . create a PM layer plugin for per-device constraints, compiled under
> CONFIG_OMAP_PM_CONSTRAINTS=y
> . implement the devices wake-up latency constraints using the global
> device PM QoS notification handler which applies the constraints to the
> underlying layer
> . implement the low level code which controls the power domains next power
> states, through the hwmod and pwrdm layers
> . add (preliminary) power domains wake-up latency figures for OMAP3&4
> . cpuidle is a CPU centric framework so it decides the MPU next power state
> based on the MPU exit_latency and target_residency figures. The rest of
> the power domains get their next power state programmed from the devices
> PM QoS framework, via the devices wake-up latency constraints.
> . convert the OMAP I2C driver to the PM QoS API for MPU latency constraints
>
>
> Questions:
> 1. the user space API is still under discussions on linux-omap and linux-pm MLs,
> cf. [1]. The idea is to add a user-space API for the devices constratins
> PM QoS, using a sysfs entry per device
>
> [1] http://marc.info/?l=linux-omap&m=131232344503327&w=2
>
> ToDo:
> 1. write Documentation for the new PM QoS class, once the RFC is agreed on
> 2. validate the constraints framework on OMAP4 HW (done on OMAP3)
> 3. Need testing on platforms other than OMAP
> 4. refine the power domains wake-up latency and the cpuidle figures
> 5. re-visit the OMAP power domains states initialization procedure. Currently
> the power states that have been changed from the constraints API which were
> applied before the initialization of the power domains are lost
>
>
> Based on the master branch of the linux-omap git tree (3.0.0-rc7). Compile
> tested using OMAP and x86 generic defconfigs.
>
> Lightly tested on OMAP3 Beagleboard (ES2.x).
> Need testing on platforms other than OMAP, because of the impact on the
> device insertion/removal in device_pm_add/remove
The patchset looks really good to me, I don't think I have any major
complaints about this version.
The only thing I'd like to ask at the moment is whether or not the
compilation of drivers/base/power/qos.c should depend on
CONFIG_PM_RUNTIME. Do you think it will be used by system suspend code on any
platforms?
Also, I'd like to take the final patchset for 3.2, but I don't feel
confident enough about the OMAP patches. If you want me to take them too,
please make sure they are ACKed by the OMAP maintainers.
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH v4] PM: add statistics debugfs file for suspend to ram
From: Rafael J. Wysocki @ 2011-08-12 7:13 UTC (permalink / raw)
To: Pavel Machek
Cc: Brown, Len, Yanmin_zhang@linux.intel.com, Liu, ShuoX, Greg KH,
linux-kernel@vger.kernel.org, linux-pm@lists.linux-foundation.org
In-Reply-To: <20110812070424.GA5249@ucw.cz>
On Friday, August 12, 2011, Pavel Machek wrote:
> On Wed 2011-08-10 12:58:54, Greg KH wrote:
> > On Thu, Aug 11, 2011 at 01:22:56AM +0530, Mansoor, Illyas wrote:
> > > static pm_message_t pm_transition;
> > > > > >
> > > > > > @@ -464,8 +465,12 @@ void dpm_resume_noirq(pm_message_t state)
> > > > > > mutex_unlock(&dpm_list_mtx);
> > > > > >
> > > > > > error = device_resume_noirq(dev, state);
> > > > > > - if (error)
> > > > > > + if (error) {
> > > > > > + suspend_stats.failed_resume_noirq++;
> > > > > > + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
> > > > > > + dpm_save_failed_dev(dev_name(dev));
> > > > >
> > > > > Please make these statistics conditionally enabled, so on a production system
> > > > > If we need to disable these statistics code we should be able to do so.
> > > >
> > > > Why, are they taking time or space that is needed for something else?
> > > > What's the downside here of just not always having this enabled?
> > >
> > > Why have something that is not required/Used?
> >
> > Because someone might need it and rebuilding a kernel isn't possible on
> > lots of devices.
>
> Yeah, and someone may need tetris, lets put it into kernel and enable
> unconditionaly :-(.
>
> Really, this is just patch to provide dmesg subset, because someone is
> cool enough to hack kernel, but will not just use grep.
>
> The patch should be just dropped.
And what's the _technical_ reason?
Do you think it's generally wrong to have two different ways of getting
the same debug information from the kernel?
Really, the truth is that suspend debugging is still way too difficult
for the majority of users and I don't quite see a reason to drop patches
that may improve the situation in this area.
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH v4] PM: add statistics debugfs file for suspend to ram
From: Pavel Machek @ 2011-08-12 7:04 UTC (permalink / raw)
To: Greg KH
Cc: Brown, Len, Yanmin_zhang@linux.intel.com, Liu, ShuoX,
linux-kernel@vger.kernel.org, linux-pm@lists.linux-foundation.org
In-Reply-To: <20110810195854.GA5939@suse.de>
On Wed 2011-08-10 12:58:54, Greg KH wrote:
> On Thu, Aug 11, 2011 at 01:22:56AM +0530, Mansoor, Illyas wrote:
> > static pm_message_t pm_transition;
> > > > >
> > > > > @@ -464,8 +465,12 @@ void dpm_resume_noirq(pm_message_t state)
> > > > > mutex_unlock(&dpm_list_mtx);
> > > > >
> > > > > error = device_resume_noirq(dev, state);
> > > > > - if (error)
> > > > > + if (error) {
> > > > > + suspend_stats.failed_resume_noirq++;
> > > > > + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
> > > > > + dpm_save_failed_dev(dev_name(dev));
> > > >
> > > > Please make these statistics conditionally enabled, so on a production system
> > > > If we need to disable these statistics code we should be able to do so.
> > >
> > > Why, are they taking time or space that is needed for something else?
> > > What's the downside here of just not always having this enabled?
> >
> > Why have something that is not required/Used?
>
> Because someone might need it and rebuilding a kernel isn't possible on
> lots of devices.
Yeah, and someone may need tetris, lets put it into kernel and enable
unconditionaly :-(.
Really, this is just patch to provide dmesg subset, because someone is
cool enough to hack kernel, but will not just use grep.
The patch should be just dropped. Use perf or dmesg parsing to collect
data; fix printks() to be easier to grep for if needed.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: LPC2011 Power Management Micro Conf
From: Rafael J. Wysocki @ 2011-08-12 7:01 UTC (permalink / raw)
To: Mark Brown
Cc: tytso, Arnd Bergmann, Greg Kroah-Hartman, Stephen Boyd, LKML,
Grant Likely, MyungJoo Ham, linux-pm, Jean Pihet,
Arjan van de Ven
In-Reply-To: <20110812033221.GA5671@sirena.org.uk>
On Friday, August 12, 2011, Mark Brown wrote:
> On Sun, Jul 03, 2011 at 09:29:28AM +0200, Rafael J. Wysocki wrote:
>
> > If there's anything you'd like to discuss or give a presentation on related to
> > Power Management, please let me know, preferably by replying to this message.
>
> The issue of cross-bus sequencing within suspend has come up again - we
> really need to work out how we make sure that dependencies between
> devices that aren't accounted for in the control bus sorting we do as
> standard. This may be worth bringing up a KS also as it's device model
> related.
I agree, I'll add it to the agenda of the LPC microconf.
Thanks,
Rafael
^ permalink raw reply
* Re: LPC2011 Power Management Micro Conf
From: Mark Brown @ 2011-08-12 3:32 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: tytso, Arnd Bergmann, Greg Kroah-Hartman, Stephen Boyd, LKML,
Grant Likely, MyungJoo Ham, linux-pm, Jean Pihet,
Arjan van de Ven
In-Reply-To: <201107030929.28555.rjw@sisk.pl>
On Sun, Jul 03, 2011 at 09:29:28AM +0200, Rafael J. Wysocki wrote:
> If there's anything you'd like to discuss or give a presentation on related to
> Power Management, please let me know, preferably by replying to this message.
The issue of cross-bus sequencing within suspend has come up again - we
really need to work out how we make sure that dependencies between
devices that aren't accounted for in the control bus sorting we do as
standard. This may be worth bringing up a KS also as it's device model
related.
^ permalink raw reply
* Re: linux-next: Tree for Aug 11 (suspend_stats build error)
From: Rafael J. Wysocki @ 2011-08-11 20:44 UTC (permalink / raw)
To: Randy Dunlap; +Cc: Stephen Rothwell, linux-pm, linux-next, LKML
In-Reply-To: <20110811115931.8007900d.rdunlap@xenotime.net>
On Thursday, August 11, 2011, Randy Dunlap wrote:
> On Thu, 11 Aug 2011 16:20:58 +1000 Stephen Rothwell wrote:
>
> > Hi all,
>
> When CONFIG_PM_SLEEP is not enabled:
>
> kernel/built-in.o: In function `suspend_stats_show':
> main.c:(.text+0x40a25): undefined reference to `suspend_stats'
> main.c:(.text+0x40a2c): undefined reference to `suspend_stats'
> main.c:(.text+0x40a32): undefined reference to `suspend_stats'
> main.c:(.text+0x40a73): undefined reference to `suspend_stats'
> main.c:(.text+0x40a82): undefined reference to `suspend_stats'
> kernel/built-in.o:main.c:(.text+0x40a91): more undefined references to `suspend_stats' follow
Should be fixed in my tree now.
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH v3 1/2] cpumask: introduce cpumask for hotpluggable CPUs
From: Peter Zijlstra @ 2011-08-11 20:02 UTC (permalink / raw)
To: Mike Turquette
Cc: linaro-dev, patches, gregkh, linux-kernel, amit.kucheria,
linux-pm
In-Reply-To: <1313092487-15858-1-git-send-email-mturquette@ti.com>
On Thu, 2011-08-11 at 12:54 -0700, Mike Turquette wrote:
> On some platforms it is possible to have some CPUs which support CPU
> hotplug and some which do not. Currently the prescence of an 'online'
> sysfs entry in userspace is adequate for applications to know that a CPU
> supports hotplug, but there is no convenient way to make the same
> determination in the kernel.
>
> To better model this relationship this patch introduces a new cpumask to
> track CPUs that support CPU hotplug operations.
>
> This new cpumask is populated at boot-time and remains static for the
> life of the machine. Bits set in the mask indicate a CPU which supports
> hotplug, but make no guarantees about whether that CPU is currently
> online or not. Likewise a cleared bit in the mask indicates either a
> CPU which cannot hotplug or a lack of a populated CPU.
>
> The purpose of this new cpumask is to aid kernel code which uses CPU to
> take CPUs online and offline. Possible uses are as a thermal event
> mitigation technique or as a power capping mechanism.
Nacked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
the kernel really shouldn't be using hotplug for this (nor should
userspace really). hot-unplugging random cpus wrecks things like
cpusets. Furthermore hotplug does way too much work to use as a simple
means to idle a cpu.
Even the availability of this mask is wrong, since that implies the
information is useful, which per the above it is not, the kernel
shouldn't care about this full-stop.
The only reason for the OS to unplug a CPU is imminent and unavoidable
hardware failure. Thermal capping is not that (and yes ACPI-4.0 is a
broken piece of shit).
^ permalink raw reply
* [PATCH v3 2/2] cpu: update cpu_hotpluggable_mask in register_cpu
From: Mike Turquette @ 2011-08-11 19:54 UTC (permalink / raw)
To: linux-kernel; +Cc: linaro-dev, patches, peterz, gregkh, amit.kucheria, linux-pm
In-Reply-To: <1313092487-15858-1-git-send-email-mturquette@ti.com>
Update the cpu_hotpluggable_mask for each registered CPU which supports
hotplug. This makes it trivial for kernel code to know which CPUs
support hotplug operations.
Signed-off-by: Mike Turquette <mturquette@ti.com>
---
Change log:
v2: no change
v3: no change
drivers/base/cpu.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 251acea..91ddcf8 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -224,8 +224,10 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
error = sysdev_register(&cpu->sysdev);
- if (!error && cpu->hotpluggable)
+ if (!error && cpu->hotpluggable) {
register_cpu_control(cpu);
+ set_cpu_hotpluggable(num, true);
+ }
if (!error)
per_cpu(cpu_sys_devices, num) = &cpu->sysdev;
if (!error)
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 1/2] cpumask: introduce cpumask for hotpluggable CPUs
From: Mike Turquette @ 2011-08-11 19:54 UTC (permalink / raw)
To: linux-kernel; +Cc: linaro-dev, patches, peterz, gregkh, amit.kucheria, linux-pm
In-Reply-To: <1313006614-28702-1-git-send-email-mturquette@ti.com>
On some platforms it is possible to have some CPUs which support CPU
hotplug and some which do not. Currently the prescence of an 'online'
sysfs entry in userspace is adequate for applications to know that a CPU
supports hotplug, but there is no convenient way to make the same
determination in the kernel.
To better model this relationship this patch introduces a new cpumask to
track CPUs that support CPU hotplug operations.
This new cpumask is populated at boot-time and remains static for the
life of the machine. Bits set in the mask indicate a CPU which supports
hotplug, but make no guarantees about whether that CPU is currently
online or not. Likewise a cleared bit in the mask indicates either a
CPU which cannot hotplug or a lack of a populated CPU.
The purpose of this new cpumask is to aid kernel code which uses CPU to
take CPUs online and offline. Possible uses are as a thermal event
mitigation technique or as a power capping mechanism.
Signed-off-by: Mike Turquette <mturquette@ti.com>
---
Change log:
v2: fixed missing parentheses in cpumask_test_cpu and improved grammar
in comments
v3: really fixed the parentheses issue from v2
include/linux/cpumask.h | 27 ++++++++++++++++++++++-----
kernel/cpu.c | 18 ++++++++++++++++++
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index b24ac56..9584807 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -39,10 +39,11 @@ extern int nr_cpu_ids;
* The following particular system cpumasks and operations manage
* possible, present, active and online cpus.
*
- * cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
- * cpu_present_mask - has bit 'cpu' set iff cpu is populated
- * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
- * cpu_active_mask - has bit 'cpu' set iff cpu available to migration
+ * cpu_possible_mask - has bit 'cpu' set iff cpu is populatable
+ * cpu_hotpluggable_mask - has bit 'cpu' set iff cpu is hotpluggable
+ * cpu_present_mask - has bit 'cpu' set iff cpu is populated
+ * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
+ * cpu_active_mask - has bit 'cpu' set iff cpu available to migration
*
* If !CONFIG_HOTPLUG_CPU, present == possible, and active == online.
*
@@ -51,7 +52,11 @@ extern int nr_cpu_ids;
* life of that system boot. The cpu_present_mask is dynamic(*),
* representing which CPUs are currently plugged in. And
* cpu_online_mask is the dynamic subset of cpu_present_mask,
- * indicating those CPUs available for scheduling.
+ * indicating those CPUs available for scheduling. The
+ * cpu_hotpluggable_mask is also fixed at boot time as the set of CPU
+ * id's which are possible AND can hotplug. Cleared bits in this mask
+ * mean that either the CPU is not possible, or it is possible but does
+ * not support CPU hotplug operations.
*
* If HOTPLUG is enabled, then cpu_possible_mask is forced to have
* all NR_CPUS bits set, otherwise it is just the set of CPUs that
@@ -61,6 +66,9 @@ extern int nr_cpu_ids;
* depending on what ACPI reports as currently plugged in, otherwise
* cpu_present_mask is just a copy of cpu_possible_mask.
*
+ * If HOTPLUG is not enabled then cpu_hotpluggable_mask is the empty
+ * set.
+ *
* (*) Well, cpu_present_mask is dynamic in the hotplug case. If not
* hotplug, it's a copy of cpu_possible_mask, hence fixed at boot.
*
@@ -76,6 +84,7 @@ extern int nr_cpu_ids;
*/
extern const struct cpumask *const cpu_possible_mask;
+extern const struct cpumask *const cpu_hotpluggable_mask;
extern const struct cpumask *const cpu_online_mask;
extern const struct cpumask *const cpu_present_mask;
extern const struct cpumask *const cpu_active_mask;
@@ -85,19 +94,23 @@ extern const struct cpumask *const cpu_active_mask;
#define num_possible_cpus() cpumask_weight(cpu_possible_mask)
#define num_present_cpus() cpumask_weight(cpu_present_mask)
#define num_active_cpus() cpumask_weight(cpu_active_mask)
+#define num_hotpluggable_cpus() cpumask_weight(cpu_hotpluggable_mask)
#define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask)
#define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask)
#define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask)
#define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask)
+#define cpu_hotpluggable(cpu) cpumask_test_cpu((cpu), cpu_hotpluggable_mask)
#else
#define num_online_cpus() 1U
#define num_possible_cpus() 1U
#define num_present_cpus() 1U
#define num_active_cpus() 1U
+#define num_hotpluggable_cpus() 0
#define cpu_online(cpu) ((cpu) == 0)
#define cpu_possible(cpu) ((cpu) == 0)
#define cpu_present(cpu) ((cpu) == 0)
#define cpu_active(cpu) ((cpu) == 0)
+#define cpu_hotpluggable(cpu) 0
#endif
/* verify cpu argument to cpumask_* operators */
@@ -678,16 +691,20 @@ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS);
#define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
+#define for_each_hotpluggable_cpu(cpu) \
+ for_each_cpu((cpu), cpu_hotpluggable_mask)
#define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask)
#define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask)
/* Wrappers for arch boot code to manipulate normally-constant masks */
void set_cpu_possible(unsigned int cpu, bool possible);
+void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable);
void set_cpu_present(unsigned int cpu, bool present);
void set_cpu_online(unsigned int cpu, bool online);
void set_cpu_active(unsigned int cpu, bool active);
void init_cpu_present(const struct cpumask *src);
void init_cpu_possible(const struct cpumask *src);
+void init_cpu_hotpluggable(const struct cpumask *src);
void init_cpu_online(const struct cpumask *src);
/**
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 12b7458..8c397c9 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -536,6 +536,11 @@ static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
EXPORT_SYMBOL(cpu_possible_mask);
+static DECLARE_BITMAP(cpu_hotpluggable_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_hotpluggable_mask =
+ to_cpumask(cpu_hotpluggable_bits);
+EXPORT_SYMBOL(cpu_hotpluggable_mask);
+
static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
EXPORT_SYMBOL(cpu_online_mask);
@@ -556,6 +561,14 @@ void set_cpu_possible(unsigned int cpu, bool possible)
cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits));
}
+void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable)
+{
+ if (hotpluggable)
+ cpumask_set_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
+ else
+ cpumask_clear_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
+}
+
void set_cpu_present(unsigned int cpu, bool present)
{
if (present)
@@ -590,6 +603,11 @@ void init_cpu_possible(const struct cpumask *src)
cpumask_copy(to_cpumask(cpu_possible_bits), src);
}
+void init_cpu_hotpluggable(const struct cpumask *src)
+{
+ cpumask_copy(to_cpumask(cpu_hotpluggable_bits), src);
+}
+
void init_cpu_online(const struct cpumask *src)
{
cpumask_copy(to_cpumask(cpu_online_bits), src);
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH] PM: add statistics sysfs file for suspend to ram
From: Rafael J. Wysocki @ 2011-08-11 19:48 UTC (permalink / raw)
To: Pavel Machek
Cc: Liu, ShuoX, yanmin_zhang, Greg KH,
linux-pm@lists.linux-foundation.org, Brown, Len
In-Reply-To: <20110810222725.GA2012@elf.ucw.cz>
On Thursday, August 11, 2011, Pavel Machek wrote:
> On Tue 2011-08-09 00:09:42, Rafael J. Wysocki wrote:
> > On Monday, August 08, 2011, Pavel Machek wrote:
> > > Hi!
> > >
> > > > > > > > Thanks for the nice pointer. I checked dynamic debug. It's really a good debug tool.
> > > > > > > > With the dynamic debug:
> > > > > > > > 1) user need write a user space parser to process the syslog output;
> > > > > > > > 2) Our testing scenario is we leave the mobile for at least hours. Then, check its status.
> > > > > > > > No serial console available during the testing. One is because console would be suspended,
> > > > > > > > and the other is serial console connecting with spi or HSU devices would consume power. These
> > > > > > > > devices are powered off at suspend-2-ram.
> > > ...
> > > > Not in the case described by Yanmin.
> > >
> > > Really? I see the description above.
> > >
> > > Yes, they'd need to set up syslog to only log >= KERN_ERR, then parse
> > > the (small) results. Even hours worth of suspends should not cause
> > > _that_ many errors.
> > >
> > > Serial console is irrelevant. You need live machine to dump dmesg, but
> > > again, you need live machine to access debugfs, too.
> >
> > This sounds like substantial overhead to collect statistics that we can
> > collect at a much lower cost in the kernel.
>
> That's always the case, right? Everyone wants different subsets of
> syslog, and doing selection in kernel is always lowest overhead.
>
> > The patch isn't very intrusive and rather straightforward.
>
> No, it is not _too_ bad; but
>
> 1) the code stays there when not debugging
Fine. I don't really think that matters a lot, does it?
> 2) different users want different syslog subsets. Putting all the
> "interesting" subsets into /sys/debug/my_syslog_subset just does not
> seem like a way to go.
I don't agree with such a broad generalization. From the system management
point of view suspend is rather special and the information the patch
collects is useful and would require substantial overhead to collect from
user space (and I can imagine test setups where it can't be collected from
user space).
I think that the explanation why dynamic debug isn't sufficient provided
by Yanmin is convincing. Apparently, you think it isn't, but you haven't
proven him wrong yet.
Rafael
^ permalink raw reply
* Re: [PATCH v2 0/2] new cpumask for hotpluggable CPUs
From: Peter Zijlstra @ 2011-08-11 19:38 UTC (permalink / raw)
To: Turquette, Mike; +Cc: linux-pm, gregkh, linaro-dev, linux-kernel, patches
In-Reply-To: <CAJOA=zNoTbPViL81esyD0So_D70_0_BAxrM2ks3SgV5=FSTWHQ@mail.gmail.com>
On Thu, 2011-08-11 at 12:25 -0700, Turquette, Mike wrote:
> On Thu, Aug 11, 2011 at 11:30 AM, Peter Zijlstra <peterz@infradead.org> wrote:
> > On Wed, 2011-08-10 at 13:03 -0700, Mike Turquette wrote:
> >> This patch series introduces a new cpumask which tracks CPUs that
> >> support hotplugging. The purpose of this patch series is to provide a
> >> simple method for kernel code to know which CPUs can be hotplugged and
> >> which ones cannot. Potential users of this code might be a thermal
> >> mitigation technique which uses hotplug to lower temperature, or a power
> >> capping mechanism which uses hotplug to lower power consumption.
> >>
> >> All the of usual cpumask helper functions are created for this new mask.
> >> The second patch in this series simply sets the bit for elligible CPUs
> >> while they are being registered. The cpumask itself is static after
> >> boot and should not change (like the possbile mask).
> >
> > I still most strongly object to people using hotplug for these goals.
> >
> > Why do you need to go through the entire dance of hotplug just to idle a
> > cpu? Hotplug not only idles the cpu but tears down (and rebuilds) an
> > insane amount of resources associated with the cpu.
>
> I think you're nacking the wrong series. This patchset simply allows
> kernel space to know which CPUs can go offline and which one can't,
> which seems pretty innocuous. Are you fundamentally opposed to the
> kernel having better accessor functions to this data?
Yeah, people might think its sane to use it..
> I'll soon be posting some code which does implement hotplug as a
> power-capping feature. I think *that* is the patch that you'll want
> to nack.
That too of course..
^ permalink raw reply
* Re: [PATCH v2 0/2] new cpumask for hotpluggable CPUs
From: Turquette, Mike @ 2011-08-11 19:25 UTC (permalink / raw)
To: Peter Zijlstra; +Cc: linux-pm, gregkh, linaro-dev, linux-kernel, patches
In-Reply-To: <1313087423.8491.11.camel@twins>
On Thu, Aug 11, 2011 at 11:30 AM, Peter Zijlstra <peterz@infradead.org> wrote:
> On Wed, 2011-08-10 at 13:03 -0700, Mike Turquette wrote:
>> This patch series introduces a new cpumask which tracks CPUs that
>> support hotplugging. The purpose of this patch series is to provide a
>> simple method for kernel code to know which CPUs can be hotplugged and
>> which ones cannot. Potential users of this code might be a thermal
>> mitigation technique which uses hotplug to lower temperature, or a power
>> capping mechanism which uses hotplug to lower power consumption.
>>
>> All the of usual cpumask helper functions are created for this new mask.
>> The second patch in this series simply sets the bit for elligible CPUs
>> while they are being registered. The cpumask itself is static after
>> boot and should not change (like the possbile mask).
>
> I still most strongly object to people using hotplug for these goals.
>
> Why do you need to go through the entire dance of hotplug just to idle a
> cpu? Hotplug not only idles the cpu but tears down (and rebuilds) an
> insane amount of resources associated with the cpu.
I think you're nacking the wrong series. This patchset simply allows
kernel space to know which CPUs can go offline and which one can't,
which seems pretty innocuous. Are you fundamentally opposed to the
kernel having better accessor functions to this data?
I'll soon be posting some code which does implement hotplug as a
power-capping feature. I think *that* is the patch that you'll want
to nack.
Thanks for reviewing,
Mike
> Nacked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
>
^ permalink raw reply
* Re: linux-next: Tree for Aug 11 (suspend_stats build error)
From: Randy Dunlap @ 2011-08-11 18:59 UTC (permalink / raw)
To: Stephen Rothwell, linux-pm; +Cc: linux-next, LKML
In-Reply-To: <20110811162058.42b462bc80e67d7a80ecff93@canb.auug.org.au>
On Thu, 11 Aug 2011 16:20:58 +1000 Stephen Rothwell wrote:
> Hi all,
When CONFIG_PM_SLEEP is not enabled:
kernel/built-in.o: In function `suspend_stats_show':
main.c:(.text+0x40a25): undefined reference to `suspend_stats'
main.c:(.text+0x40a2c): undefined reference to `suspend_stats'
main.c:(.text+0x40a32): undefined reference to `suspend_stats'
main.c:(.text+0x40a73): undefined reference to `suspend_stats'
main.c:(.text+0x40a82): undefined reference to `suspend_stats'
kernel/built-in.o:main.c:(.text+0x40a91): more undefined references to `suspend_stats' follow
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply
* Re: [PATCH v2 1/2] cpumask: introduce cpumask for hotpluggable CPUs
From: Turquette, Mike @ 2011-08-11 18:39 UTC (permalink / raw)
To: Mike Turquette, linux-kernel, linux-pm, gregkh, linaro-dev,
patches
In-Reply-To: <20110811060622.GA2549@matterhorn1>
On Wed, Aug 10, 2011 at 11:06 PM, Amit Kucheria
<amit.kucheria@linaro.org> wrote:
> See comments inline.
>
> On 11 Aug 10, Mike Turquette wrote:
>> On some platforms it is possible to have some CPUs which support CPU
>> hotplug and some which do not. Currently the prescence of an 'online'
>> sysfs entry in userspace is adequate for applications to know that a CPU
>> supports hotplug, but there is no convenient way to make the same
>> determination in the kernel.
>>
>> To better model this relationship this patch introduces a new cpumask to
>> track CPUs that support CPU hotplug operations.
>>
>> This new cpumask is populated at boot-time and remains static for the
>> life of the machine. Bits set in the mask indicate a CPU which supports
>> hotplug, but make no guarantees about whether that CPU is currently
>> online or not. Likewise a cleared bit in the mask indicates either a
>> CPU which cannot hotplug or a lack of a populated CPU.
>>
>> The purpose of this new cpumask is to aid kernel code which uses CPU to
>> take CPUs online and offline. Possible uses are as a thermal event
>> mitigation technique or as a power capping mechanism.
>>
>> Signed-off-by: Mike Turquette <mturquette@ti.com>
>> ---
>> Change log:
>> v2: fixed missing parentheses in cpumask_test_cpu and improved grammar
>> in comments
>>
>> include/linux/cpumask.h | 27 ++++++++++++++++++++++-----
>> kernel/cpu.c | 18 ++++++++++++++++++
>> 2 files changed, 40 insertions(+), 5 deletions(-)
>>
>> diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
>> index b24ac56..52e64a7 100644
>> --- a/include/linux/cpumask.h
>> +++ b/include/linux/cpumask.h
>> @@ -39,10 +39,11 @@ extern int nr_cpu_ids;
>> * The following particular system cpumasks and operations manage
>> * possible, present, active and online cpus.
>> *
>> - * cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
>> - * cpu_present_mask - has bit 'cpu' set iff cpu is populated
>> - * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
>> - * cpu_active_mask - has bit 'cpu' set iff cpu available to migration
>> + * cpu_possible_mask - has bit 'cpu' set iff cpu is populatable
>> + * cpu_hotpluggable_mask - has bit 'cpu' set iff cpu is hotpluggable
>> + * cpu_present_mask - has bit 'cpu' set iff cpu is populated
>> + * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
>> + * cpu_active_mask - has bit 'cpu' set iff cpu available to migration
>> *
>> * If !CONFIG_HOTPLUG_CPU, present == possible, and active == online.
>> *
>> @@ -51,7 +52,11 @@ extern int nr_cpu_ids;
>> * life of that system boot. The cpu_present_mask is dynamic(*),
>> * representing which CPUs are currently plugged in. And
>> * cpu_online_mask is the dynamic subset of cpu_present_mask,
>> - * indicating those CPUs available for scheduling.
>> + * indicating those CPUs available for scheduling. The
>> + * cpu_hotpluggable_mask is also fixed at boot time as the set of CPU
>> + * id's which are possible AND can hotplug. Cleared bits in this mask
>> + * mean that either the CPU is not possible, or it is possible but does
>> + * not support CPU hotplug operations.
>> *
>> * If HOTPLUG is enabled, then cpu_possible_mask is forced to have
>> * all NR_CPUS bits set, otherwise it is just the set of CPUs that
>> @@ -61,6 +66,9 @@ extern int nr_cpu_ids;
>> * depending on what ACPI reports as currently plugged in, otherwise
>> * cpu_present_mask is just a copy of cpu_possible_mask.
>> *
>> + * If HOTPLUG is not enabled then cpu_hotpluggable_mask is the empty
>> + * set.
>> + *
>> * (*) Well, cpu_present_mask is dynamic in the hotplug case. If not
>> * hotplug, it's a copy of cpu_possible_mask, hence fixed at boot.
>> *
>> @@ -76,6 +84,7 @@ extern int nr_cpu_ids;
>> */
>>
>> extern const struct cpumask *const cpu_possible_mask;
>> +extern const struct cpumask *const cpu_hotpluggable_mask;
>> extern const struct cpumask *const cpu_online_mask;
>> extern const struct cpumask *const cpu_present_mask;
>> extern const struct cpumask *const cpu_active_mask;
>> @@ -85,19 +94,23 @@ extern const struct cpumask *const cpu_active_mask;
>> #define num_possible_cpus() cpumask_weight(cpu_possible_mask)
>> #define num_present_cpus() cpumask_weight(cpu_present_mask)
>> #define num_active_cpus() cpumask_weight(cpu_active_mask)
>> +#define num_hotpluggable_cpus() cpumask_weight(cpu_hotpluggable_mask)
>> #define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask)
>> #define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask)
>> #define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask)
>> #define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask)
>> +#define cpu_hotpluggable(cpu) cpumask_test_cpu((cpu, cpu_hotpluggable_mask))
>
> The bracket should be around cpu, like this (cpu) so that there are no
> side-effects when passing anything to the macro. See the other #defines above.
Wow, not sure how that happened... will send in V3...
>> #else
>> #define num_online_cpus() 1U
>> #define num_possible_cpus() 1U
>> #define num_present_cpus() 1U
>> #define num_active_cpus() 1U
>> +#define num_hotpluggable_cpus() 0
>> #define cpu_online(cpu) ((cpu) == 0)
>> #define cpu_possible(cpu) ((cpu) == 0)
>> #define cpu_present(cpu) ((cpu) == 0)
>> #define cpu_active(cpu) ((cpu) == 0)
>> +#define cpu_hotpluggable(cpu) 0
>> #endif
>>
>> /* verify cpu argument to cpumask_* operators */
>> @@ -678,16 +691,20 @@ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS);
>> #define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
>>
>> #define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
>> +#define for_each_hotpluggable_cpu(cpu) \
>> + for_each_cpu((cpu), cpu_hotpluggable_mask)
>> #define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask)
>> #define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask)
>>
>> /* Wrappers for arch boot code to manipulate normally-constant masks */
>> void set_cpu_possible(unsigned int cpu, bool possible);
>> +void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable);
>> void set_cpu_present(unsigned int cpu, bool present);
>> void set_cpu_online(unsigned int cpu, bool online);
>> void set_cpu_active(unsigned int cpu, bool active);
>> void init_cpu_present(const struct cpumask *src);
>> void init_cpu_possible(const struct cpumask *src);
>> +void init_cpu_hotpluggable(const struct cpumask *src);
>> void init_cpu_online(const struct cpumask *src);
>>
>> /**
>> diff --git a/kernel/cpu.c b/kernel/cpu.c
>> index 12b7458..8c397c9 100644
>> --- a/kernel/cpu.c
>> +++ b/kernel/cpu.c
>> @@ -536,6 +536,11 @@ static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
>> const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
>> EXPORT_SYMBOL(cpu_possible_mask);
>>
>> +static DECLARE_BITMAP(cpu_hotpluggable_bits, CONFIG_NR_CPUS) __read_mostly;
>> +const struct cpumask *const cpu_hotpluggable_mask =
>> + to_cpumask(cpu_hotpluggable_bits);
>> +EXPORT_SYMBOL(cpu_hotpluggable_mask);
>> +
>> static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
>> const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
>> EXPORT_SYMBOL(cpu_online_mask);
>> @@ -556,6 +561,14 @@ void set_cpu_possible(unsigned int cpu, bool possible)
>> cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits));
>> }
>>
>> +void set_cpu_hotpluggable(unsigned int cpu, bool hotpluggable)
>> +{
>> + if (hotpluggable)
>> + cpumask_set_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
>> + else
>> + cpumask_clear_cpu(cpu, to_cpumask(cpu_hotpluggable_bits));
>> +}
>> +
>> void set_cpu_present(unsigned int cpu, bool present)
>> {
>> if (present)
>> @@ -590,6 +603,11 @@ void init_cpu_possible(const struct cpumask *src)
>> cpumask_copy(to_cpumask(cpu_possible_bits), src);
>> }
>>
>> +void init_cpu_hotpluggable(const struct cpumask *src)
>> +{
>> + cpumask_copy(to_cpumask(cpu_hotpluggable_bits), src);
>> +}
>> +
>
> Just to be clear I understand this code, init_cpu_hotpluggable will be called
> in arch code, right? e.g. arch/arm/kernel/smp.c or do you intend for it to be
> called in platform-specific code?
It could be called in either, though I assume arch code is a better
place to call this.
This call is made redundant by patch 2 which populates the
hotpluggable bits in register_cpu, but some platforms might still need
it so it is included for completeness sake. x86 and ARM will not call
this, for example. In fact I could not find any users of the
init_cpu_xxx cpumask helpers on any architectures.
Thanks,
Mike
>> void init_cpu_online(const struct cpumask *src)
>> {
>> cpumask_copy(to_cpumask(cpu_online_bits), src);
>> --
>> 1.7.4.1
>
^ permalink raw reply
* Re: [PATCH v2 0/2] new cpumask for hotpluggable CPUs
From: Peter Zijlstra @ 2011-08-11 18:30 UTC (permalink / raw)
To: Mike Turquette; +Cc: linux-pm, gregkh, linaro-dev, linux-kernel, patches
In-Reply-To: <1313006614-28702-1-git-send-email-mturquette@ti.com>
On Wed, 2011-08-10 at 13:03 -0700, Mike Turquette wrote:
> This patch series introduces a new cpumask which tracks CPUs that
> support hotplugging. The purpose of this patch series is to provide a
> simple method for kernel code to know which CPUs can be hotplugged and
> which ones cannot. Potential users of this code might be a thermal
> mitigation technique which uses hotplug to lower temperature, or a power
> capping mechanism which uses hotplug to lower power consumption.
>
> All the of usual cpumask helper functions are created for this new mask.
> The second patch in this series simply sets the bit for elligible CPUs
> while they are being registered. The cpumask itself is static after
> boot and should not change (like the possbile mask).
I still most strongly object to people using hotplug for these goals.
Why do you need to go through the entire dance of hotplug just to idle a
cpu? Hotplug not only idles the cpu but tears down (and rebuilds) an
insane amount of resources associated with the cpu.
Nacked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
^ permalink raw reply
* Re: [PATCH v4 1/2] Input: enable i8042-level wakeup control
From: Daniel Drake @ 2011-08-11 18:02 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-pm, dilinger, linux-input
In-Reply-To: <CAMLZHHTnTTbD7mn_QsjwyFZ=XU6paddrtXEVuLYossk9qBGFfw@mail.gmail.com>
Hi Dmitry,
On Fri, Aug 5, 2011 at 4:24 PM, Daniel Drake <dsd@laptop.org> wrote:
> I've started looking at this, but my first problem is that when the
> input layer asks atkbd to turn off LEDs, atkbd schedules a workqueue
> item to undertake this work. However, as there is no synchronization,
> this work only seems to get executed during or after system resume.
> This makes it hard to catch with such a scheme. Any ideas?
I've looked closer, and am keeping my eyes open for other options too.
During suspend of the input layer, input_dev_suspend() calls
input_dev_toggle(dev, false) which turns off LEDs and sounds.
On the XO laptops, we don't have LEDs, nor sounds, and we don't have
num lock, scroll lock or caps lock keys. So the suspend code does
nothing - there are no lights to turn off. So far so good.
Moving to the resume case: input_dev_resume() calls
input_reset_device(). This calls input_dev_toggle(dev, true), which
asks atkbd to turn the non-existent keyboard LEDs off. I guess this is
harmless and is unlikely to be the cause of the problems which led us
to need to disable this code in light of the following:
After calling input_dev_toggle(), input_dev_resume() does this:
/*
* Keys that have been pressed at suspend time are unlikely
* to be still pressed when we resume.
*/
spin_lock_irq(&dev->event_lock);
input_dev_release_keys(dev);
spin_unlock_irq(&dev->event_lock);
We definitely don't want this to happen in our case, where we have
maintained full control and power of the device during suspend/resume.
This particular important code snippet would not even have been
disabled by your suggestion of blocking data transfer at the
i8042-level.
So, I think we need a new approach at solving this, and I think it has
to be one that interacts at the input_dev layer.
Thoughts?
Thanks,
Daniel
^ permalink raw reply
* Re: [PATCH 07/13] OMAP PM: early init of the pwrdms states
From: Jean Pihet @ 2011-08-11 15:12 UTC (permalink / raw)
To: Todd Poynor
Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet
In-Reply-To: <CAORVsuVHAvQRxPz8cCfQ0L1jN1nT5aNDVZ7fpuajAUosyvumeA@mail.gmail.com>
Todd,
On Tue, Aug 2, 2011 at 10:57 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
> Todd,
>
> On Fri, Jul 29, 2011 at 10:50 AM, Jean Pihet <jean.pihet@newoldbits.com> wrote:
>> On Fri, Jul 29, 2011 at 10:08 AM, Todd Poynor <toddpoynor@google.com> wrote:
>>> On Thu, Jul 28, 2011 at 10:30:14AM +0200, jean.pihet@newoldbits.com wrote:
> ...
>
>>>> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
>>>> index 9af0847..63c3e7a 100644
>>>> --- a/arch/arm/mach-omap2/powerdomain.c
>>>> +++ b/arch/arm/mach-omap2/powerdomain.c
>>>> @@ -108,6 +108,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
>>>> pwrdm->state = pwrdm_read_pwrst(pwrdm);
>>>> pwrdm->state_counter[pwrdm->state] = 1;
>>>>
>>>> + /* Early init of the next power state */
>>>> + pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET);
>>>> +
>>>
>>> Wanted to check that it's OK to initialize the next state of a power
>>> domain to RETENTION early in the boot sequence. I believe patches
>>> have been previously discussed that set the state to ON to ensure the
>>> domain doesn't go to a lower state, and possibly lose context, before
>>> the PM subsystem is setup to handle it? Not sure, thought maybe worth
>>> a doublecheck.
>> Indeed I need to check the behavior for OMAP3 & 4 which seem to
>> initialize the pwrdm states differently.
>> BTW the patch that inits all pwrdms to ON is not yet in l-o master
>> that is why I (lazily) submitted this one for now.
>
> Ok I will update the patch to make it compliant with [1]. v4 will
> include this change.
>
> Thanks,
> Jean
>
> [1] http://marc.info/?l=linux-arm-kernel&m=131052762623823&w=2
After more thinking I now realize there is a problem with the PM early
init, PM late init and the constraints framework which all setup the
power domains next states in a non-coherent way.
Definitely this needs to be revisited. More to come on this!
There is a comment about that in [00/15] of the v4 patch set.
Regards,
Jean
>
>>
>>>
>>>
>>> Todd
>
^ permalink raw reply
* Re: [PATCH 08/13] OMAP2+: powerdomain: control power domains next state
From: Jean Pihet @ 2011-08-11 15:09 UTC (permalink / raw)
To: Todd Poynor
Cc: markgross, broonie, Linux PM mailing list, linux-omap, Jean Pihet
In-Reply-To: <20110729180047.GA14228@google.com>
Hi Todd,
On Fri, Jul 29, 2011 at 8:00 PM, Todd Poynor <toddpoynor@google.com> wrote:
> On Fri, Jul 29, 2011 at 10:47:43AM +0200, Jean Pihet wrote:
>> On Fri, Jul 29, 2011 at 9:59 AM, Todd Poynor <toddpoynor@google.com> wrote:
> ...
>> > All min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE paths need
>> > free_new_user = 1.
>> free_new_user = 1 is only needed if no existing constraint has been
>> found, i.e. user stays at NULL. This is implemented in the check for
>> an existing constraint (plist_for_each_entry(...)).
>
> Oops, I meant to say it applies in all cases where min_latency ==
> PM_QOS_DEV_LAT_DEFAULT_VALUE, since the new node is only used for
> adding a constraint (and no existing constraint found). I'd suggest
> something like:
>
> if (min_latency != PM_QOS_DEV_LAT_DEFAULT_VALUE) {
> new_user = kzalloc(sizeof(struct pwrdm_wkup_constraints_entry),
> GFP_KERNEL);
> <check NULL return>
> free_new_user = 1;
> }
>
> and then set free_new_user = 0 only if no existing constraint is found
> for the add case. Because it's easy to miss cases where the
> allocated memory needs to be freed when that's not the default, and you
> might as well skip the allocate on a constraint removal. Pretty minor
> point, though.
This has been addressed in the latest patch set (v4).
Regards,
Jean
>
>
> Todd
>
^ permalink raw reply
* [PATCH 15/15] OMAP2+: cpuidle only influences the MPU state
From: jean.pihet @ 2011-08-11 15:06 UTC (permalink / raw)
To: Mark Brown, Kevin Hilman, markgross, Linux PM mailing list; +Cc: Jean Pihet
In-Reply-To: <1313075212-8366-1-git-send-email-j-pihet@ti.com>
From: Jean Pihet <j-pihet@ti.com>
Since cpuidle is a CPU centric framework it decides the MPU
next power state based on the MPU exit_latency and target_residency
figures.
The rest of the power domains get their next power state programmed
from the devices PM QoS framework, via the devices wake-up latency
constraints.
Note: the exit_latency and target_residency figures of the MPU
include the MPU itself and the peripherals needed for the MPU to
execute instructions (e.g. main memory, caches, IRQ controller,
MMU etc). Some of those peripherals can belong to other power domains
than the MPU subsystem and so the corresponding latencies must be
included in this figure.
Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
arch/arm/mach-omap2/cpuidle34xx.c | 42 +++++++++++-------------------------
arch/arm/mach-omap2/pm.h | 17 +++++++++++++-
2 files changed, 28 insertions(+), 31 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 4bf6e6e..b43d1d2 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -37,26 +37,26 @@
#ifdef CONFIG_CPU_IDLE
/*
- * The latencies/thresholds for various C states have
+ * The MPU latencies/thresholds for various C states have
* to be configured from the respective board files.
* These are some default values (which might not provide
* the best power savings) used on boards which do not
* pass these details from the board file.
*/
static struct cpuidle_params cpuidle_params_table[] = {
- /* C1 */
+ /* C1 . MPU WFI + Core active */
{2 + 2, 5, 1},
- /* C2 */
+ /* C2 . MPU WFI + Core inactive */
{10 + 10, 30, 1},
- /* C3 */
+ /* C3 . MPU CSWR + Core inactive */
{50 + 50, 300, 1},
- /* C4 */
+ /* C4 . MPU OFF + Core inactive */
{1500 + 1800, 4000, 1},
- /* C5 */
+ /* C5 . MPU RET + Core RET */
{2500 + 7500, 12000, 1},
- /* C6 */
+ /* C6 . MPU OFF + Core RET */
{3000 + 8500, 15000, 1},
- /* C7 */
+ /* C7 . MPU OFF + Core OFF */
{10000 + 30000, 300000, 1},
};
#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
@@ -64,7 +64,6 @@ static struct cpuidle_params cpuidle_params_table[] = {
/* Mach specific information to be recorded in the C-state driver_data */
struct omap3_idle_statedata {
u32 mpu_state;
- u32 core_state;
u8 valid;
};
struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
@@ -98,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
{
struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
struct timespec ts_preidle, ts_postidle, ts_idle;
- u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+ u32 mpu_state = cx->mpu_state;
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
@@ -107,7 +106,6 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
local_fiq_disable();
pwrdm_set_next_pwrst(mpu_pd, mpu_state);
- pwrdm_set_next_pwrst(core_pd, core_state);
if (omap_irq_pending() || need_resched())
goto return_sleep_time;
@@ -156,6 +154,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
+ u32 core_next_state = pwrdm_read_next_pwrst(core_pd);
if (enable_off_mode) {
mpu_deepest_state = PWRDM_POWER_OFF;
@@ -171,7 +170,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
/* Check if current state is valid */
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
+ (core_next_state >= core_deepest_state)) {
return curr;
} else {
int idx = OMAP3_NUM_STATES - 1;
@@ -196,7 +195,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
cx = cpuidle_get_statedata(&dev->states[idx]);
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
+ (core_next_state >= core_deepest_state)) {
next = &dev->states[idx];
break;
}
@@ -242,19 +241,11 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
}
/*
- * FIXME: we currently manage device-specific idle states
- * for PER and CORE in combination with CPU-specific
- * idle states. This is wrong, and device-specific
- * idle management needs to be separated out into
- * its own code.
- */
-
- /*
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
cx = cpuidle_get_statedata(state);
- core_next_state = cx->core_state;
+ core_next_state = pwrdm_read_next_pwrst(core_pd);
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state == PWRDM_POWER_OFF) &&
(core_next_state > PWRDM_POWER_RET))
@@ -346,32 +337,26 @@ int __init omap3_idle_init(void)
dev->safe_state = &dev->states[0];
cx->valid = 1; /* C1 is always valid */
cx->mpu_state = PWRDM_POWER_ON;
- cx->core_state = PWRDM_POWER_ON;
/* C2 . MPU WFI + Core inactive */
cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
cx->mpu_state = PWRDM_POWER_ON;
- cx->core_state = PWRDM_POWER_ON;
/* C3 . MPU CSWR + Core inactive */
cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
cx->mpu_state = PWRDM_POWER_RET;
- cx->core_state = PWRDM_POWER_ON;
/* C4 . MPU OFF + Core inactive */
cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_ON;
/* C5 . MPU RET + Core RET */
cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
cx->mpu_state = PWRDM_POWER_RET;
- cx->core_state = PWRDM_POWER_RET;
/* C6 . MPU OFF + Core RET */
cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_RET;
/* C7 . MPU OFF + Core OFF */
cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
@@ -386,7 +371,6 @@ int __init omap3_idle_init(void)
__func__);
}
cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_OFF;
dev->state_count = OMAP3_NUM_STATES;
if (cpuidle_register_device(dev)) {
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index babac19..38327dc 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -43,9 +43,22 @@ static inline int omap4_opp_init(void)
* omap3_pm_init_cpuidle
*/
struct cpuidle_params {
- u32 exit_latency; /* exit_latency = sleep + wake-up latencies */
+ /*
+ * exit_latency = sleep + wake-up latencies of the MPU,
+ * which include the MPU itself and the peripherals needed
+ * for the MPU to execute instructions (e.g. main memory,
+ * caches, IRQ controller, MMU etc). Some of those peripherals
+ * can belong to other power domains than the MPU subsystem and so
+ * the corresponding latencies must be included in this figure.
+ */
+ u32 exit_latency;
+ /*
+ * target_residency: required amount of time in the C state
+ * to break even on energy cost
+ */
u32 target_residency;
- u8 valid; /* validates the C-state */
+ /* validates the C-state on the given board */
+ u8 valid;
};
#if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
--
1.7.2.5
^ permalink raw reply related
* [PATCH 14/15] OMAP: PM CONSTRAINTS: implement the devices wake-up latency constraints
From: jean.pihet @ 2011-08-11 15:06 UTC (permalink / raw)
To: Mark Brown, Kevin Hilman, markgross, Linux PM mailing list; +Cc: Jean Pihet
In-Reply-To: <1313075212-8366-1-git-send-email-j-pihet@ti.com>
From: Jean Pihet <j-pihet@ti.com>
Implement the devices wake-up latency constraints using the global
device PM QoS notification handler which applies the constraints to the
underlying layer by calling the corresponding function at hwmod level.
Note: the bus throughput function is implemented but currently is
a no-op. A new PM QoS class for the bus throughput needs to be
added.
Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
arch/arm/plat-omap/include/plat/omap-pm.h | 128 ---------------------
arch/arm/plat-omap/omap-pm-constraints.c | 173 +++++++++++++---------------
arch/arm/plat-omap/omap-pm-noop.c | 89 ---------------
3 files changed, 80 insertions(+), 310 deletions(-)
diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index 0840df8..d276082 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -62,136 +62,8 @@ void omap_pm_if_exit(void);
* Device-driver-originated constraints (via board-*.c files, platform_data)
*/
-
-/**
- * omap_pm_set_max_mpu_wakeup_lat - set the maximum MPU wakeup latency
- * @dev: struct device * requesting the constraint
- * @t: maximum MPU wakeup latency in microseconds
- *
- * Request that the maximum interrupt latency for the MPU to be no
- * greater than @t microseconds. "Interrupt latency" in this case is
- * defined as the elapsed time from the occurrence of a hardware or
- * timer interrupt to the time when the device driver's interrupt
- * service routine has been entered by the MPU.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the MPU powerdomain into, and
- * possibly the CORE powerdomain as well, since interrupt handling
- * code currently runs from SDRAM. Advanced PM or board*.c code may
- * also configure interrupt controller priorities, OCP bus priorities,
- * CPU speed(s), etc.
- *
- * This function will not affect device wakeup latency, e.g., time
- * elapsed from when a device driver enables a hardware device with
- * clk_enable(), to when the device is ready for register access or
- * other use. To control this device wakeup latency, use
- * omap_pm_set_max_dev_wakeup_lat()
- *
- * Multiple calls to omap_pm_set_max_mpu_wakeup_lat() will replace the
- * previous t value. To remove the latency target for the MPU, call
- * with t = -1.
- *
- * XXX This constraint will be deprecated soon in favor of the more
- * general omap_pm_set_max_dev_wakeup_lat()
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t);
-
-
-/**
- * omap_pm_set_min_bus_tput - set minimum bus throughput needed by device
- * @dev: struct device * requesting the constraint
- * @tbus_id: interconnect to operate on (OCP_{INITIATOR,TARGET}_AGENT)
- * @r: minimum throughput (in KiB/s)
- *
- * Request that the minimum data throughput on the OCP interconnect
- * attached to device @dev interconnect agent @tbus_id be no less
- * than @r KiB/s.
- *
- * It is expected that the OMAP PM or bus code will use this
- * information to set the interconnect clock to run at the lowest
- * possible speed that satisfies all current system users. The PM or
- * bus code will adjust the estimate based on its model of the bus, so
- * device driver authors should attempt to specify an accurate
- * quantity for their device use case, and let the PM or bus code
- * overestimate the numbers as necessary to handle request/response
- * latency, other competing users on the system, etc. On OMAP2/3, if
- * a driver requests a minimum L4 interconnect speed constraint, the
- * code will also need to add an minimum L3 interconnect speed
- * constraint,
- *
- * Multiple calls to omap_pm_set_min_bus_tput() will replace the
- * previous rate value for this device. To remove the interconnect
- * throughput restriction for this device, call with r = 0.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r);
-
-/**
- * omap_pm_set_max_dev_wakeup_lat - set the maximum device enable latency
- * @req_dev: struct device * requesting the constraint, or NULL if none
- * @dev: struct device * to set the constraint one
- * @t: maximum device wakeup latency in microseconds
- *
- * Request that the maximum amount of time necessary for a device @dev
- * to become accessible after its clocks are enabled should be no
- * greater than @t microseconds. Specifically, this represents the
- * time from when a device driver enables device clocks with
- * clk_enable(), to when the register reads and writes on the device
- * will succeed. This function should be called before clk_disable()
- * is called, since the power state transition decision may be made
- * during clk_disable().
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the powerdomain enclosing this
- * device into.
- *
- * Multiple calls to omap_pm_set_max_dev_wakeup_lat() will replace the
- * previous wakeup latency values for this device. To remove the
- * wakeup latency restriction for this device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
- long t);
-
-
-/**
- * omap_pm_set_max_sdma_lat - set the maximum system DMA transfer start latency
- * @dev: struct device *
- * @t: maximum DMA transfer start latency in microseconds
- *
- * Request that the maximum system DMA transfer start latency for this
- * device 'dev' should be no greater than 't' microseconds. "DMA
- * transfer start latency" here is defined as the elapsed time from
- * when a device (e.g., McBSP) requests that a system DMA transfer
- * start or continue, to the time at which data starts to flow into
- * that device from the system DMA controller.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the CORE powerdomain into.
- *
- * Since system DMA transfers may not involve the MPU, this function
- * will not affect MPU wakeup latency. Use set_max_cpu_lat() to do
- * so. Similarly, this function will not affect device wakeup latency
- * -- use set_max_dev_wakeup_lat() to affect that.
- *
- * Multiple calls to set_max_sdma_lat() will replace the previous t
- * value for this device. To remove the maximum DMA latency for this
- * device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_sdma_lat(struct device *dev, long t);
-
-
/**
* omap_pm_set_min_clk_rate - set minimum clock rate requested by @dev
* @dev: struct device * requesting the constraint
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
index c8b4e4c..efec5df 100644
--- a/arch/arm/plat-omap/omap-pm-constraints.c
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -17,132 +17,112 @@
#undef DEBUG
#include <linux/init.h>
+#include <linux/notifier.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
/* Interface documentation is in mach/omap-pm.h */
#include <plat/omap-pm.h>
#include <plat/omap_device.h>
+#include <plat/common.h>
+#include <plat/omap_hwmod.h>
static bool off_mode_enabled;
static u32 dummy_context_loss_counter;
-/*
- * Device-driver-originated constraints (via board-*.c files)
- */
+static int _dev_pm_qos_wakeup_latency_handler(struct notifier_block *,
+ unsigned long, void *);
+static struct notifier_block _dev_pm_qos_wakeup_latency_notifier = {
+ .notifier_call = _dev_pm_qos_wakeup_latency_handler,
+};
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+
+static int _apply_dev_pm_qos_constraint(void *req, unsigned long new_value)
{
- if (!dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+ struct dev_pm_qos_request *dev_pm_qos_req = req;
- if (t == -1)
- pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
+ pr_debug("OMAP PM CONSTRAINTS: req@0x%p, new_value=%lu\n",
+ req, new_value);
- /*
- * For current Linux, this needs to map the MPU to a
- * powerdomain, then go through the list of current max lat
- * constraints on the MPU and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state.
- *
- * TI CDP code can call constraint_set here.
- */
+ /* Look for the platform device for the constraint target device */
+ pdev = to_platform_device(dev_pm_qos_req->dev);
- return 0;
-}
+ /* Try to catch non platform devices */
+ if (pdev->name == NULL) {
+ pr_err("%s: Error: platform device for device %s not valid\n",
+ __func__, dev_name(dev_pm_qos_req->dev));
+ return -EINVAL;
+ }
-int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
-{
- if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
- agent_id != OCP_TARGET_AGENT)) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ /* Find the associated omap_device for dev */
+ od = container_of(pdev, struct omap_device, pdev);
+ if (od->hwmods_cnt != 1) {
+ pr_err("%s: Error: No unique hwmod for device %s\n",
+ __func__, dev_name(dev_pm_qos_req->dev));
return -EINVAL;
- };
+ }
- if (r == 0)
- pr_debug("OMAP PM: remove min bus tput constraint: "
- "dev %s for agent_id %d\n", dev_name(dev), agent_id);
- else
- pr_debug("OMAP PM: add min bus tput constraint: "
- "dev %s for agent_id %d: rate %ld KiB\n",
- dev_name(dev), agent_id, r);
+ /* Find the primary omap_hwmod for dev */
+ oh = od->hwmods[0];
- /*
- * This code should model the interconnect and compute the
- * required clock frequency, convert that to a VDD2 OPP ID, then
- * set the VDD2 OPP appropriately.
- *
- * TI CDP code can call constraint_set here on the VDD2 OPP.
- */
+ pr_debug("OMAP PM CONSTRAINTS: req@0x%p, dev=0x%p, new_value=%lu\n",
+ req, dev_pm_qos_req->dev, new_value);
- return 0;
+ /* Apply the constraint */
+ return omap_hwmod_set_wkup_lat_constraint(oh, dev_pm_qos_req,
+ new_value);
}
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
- long t)
+/* PM QoS classes handlers */
+static int _dev_pm_qos_wakeup_latency_handler(struct notifier_block *nb,
+ unsigned long new_value,
+ void *req)
{
- if (!req_dev || !dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max device latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max device latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux, this needs to map the device to a
- * powerdomain, then go through the list of current max lat
- * constraints on that powerdomain and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state. Conceivably, this code should also determine
- * whether to actually disable the device clocks or not,
- * depending on how long it takes to re-enable the clocks.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
+ return _apply_dev_pm_qos_constraint(req, new_value);
}
-int omap_pm_set_max_sdma_lat(struct device *dev, long t)
+/*
+ * omap_pm_set_min_bus_tput - set/release bus throughput constraints
+ * ToDo: currently is a no-op, to be converted to a PM QoS handler
+ * for the TPUT class
+ */
+int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
{
- if (!dev || t < -1) {
+ long t;
+ struct device *req_dev = NULL;
+
+ if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
+ agent_id != OCP_TARGET_AGENT)) {
WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
return -EINVAL;
};
- if (t == -1)
- pr_debug("OMAP PM: remove max DMA latency constraint: "
- "dev %s\n", dev_name(dev));
+ /*
+ * A value of r == 0 removes the constraint. Convert it to the
+ * generic _set_dev_constraint convention (-1 for constraint removal)
+ */
+ if (r == 0)
+ t = -1;
else
- pr_debug("OMAP PM: add max DMA latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
+ t = r;
/*
- * For current Linux PM QOS params, this code should scan the
- * list of maximum CPU and DMA latencies and select the
- * smallest, then set cpu_dma_latency pm_qos_param
- * accordingly.
- *
- * For future Linux PM QOS params, with separate CPU and DMA
- * latency params, this code should just set the dma_latency param.
- *
- * TI CDP code can call constraint_set here.
+ * Assign the device for L3 or L4 interconnect to req_dev,
+ * based on the value of agent_id
*/
+ switch (agent_id) {
+ case OCP_INITIATOR_AGENT:
+ req_dev = omap2_get_l3_device();
+ break;
+ case OCP_TARGET_AGENT:
+ /* Fixme: need the device for L4 interconnect */
+ break;
+ }
return 0;
}
@@ -350,10 +330,17 @@ int __init omap_pm_if_early_init(void)
return 0;
}
-/* Must be called after clock framework is initialized */
+/* Must be called after the clock framework is initialized */
int __init omap_pm_if_init(void)
{
- return 0;
+ int ret;
+
+ ret = dev_pm_qos_add_global_notifier(
+ &_dev_pm_qos_wakeup_latency_notifier);
+ if (ret)
+ WARN(1, KERN_ERR "Cannot add global notifier for dev PM QoS\n");
+
+ return ret;
}
void omap_pm_if_exit(void)
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index b0471bb2..8ad902f 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -32,35 +32,6 @@ static u32 dummy_context_loss_counter;
/*
* Device-driver-originated constraints (via board-*.c files)
*/
-
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
-{
- if (!dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux, this needs to map the MPU to a
- * powerdomain, then go through the list of current max lat
- * constraints on the MPU and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
-}
-
int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
{
if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
@@ -88,66 +59,6 @@ int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
return 0;
}
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
- long t)
-{
- if (!req_dev || !dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max device latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max device latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux, this needs to map the device to a
- * powerdomain, then go through the list of current max lat
- * constraints on that powerdomain and find the smallest. If
- * the latency constraint has changed, the code should
- * recompute the state to enter for the next powerdomain
- * state. Conceivably, this code should also determine
- * whether to actually disable the device clocks or not,
- * depending on how long it takes to re-enable the clocks.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
-}
-
-int omap_pm_set_max_sdma_lat(struct device *dev, long t)
-{
- if (!dev || t < -1) {
- WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
- return -EINVAL;
- };
-
- if (t == -1)
- pr_debug("OMAP PM: remove max DMA latency constraint: "
- "dev %s\n", dev_name(dev));
- else
- pr_debug("OMAP PM: add max DMA latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
-
- /*
- * For current Linux PM QOS params, this code should scan the
- * list of maximum CPU and DMA latencies and select the
- * smallest, then set cpu_dma_latency pm_qos_param
- * accordingly.
- *
- * For future Linux PM QOS params, with separate CPU and DMA
- * latency params, this code should just set the dma_latency param.
- *
- * TI CDP code can call constraint_set here.
- */
-
- return 0;
-}
-
int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
{
if (!dev || !c || r < 0) {
--
1.7.2.5
^ permalink raw reply related
* [PATCH 13/15] OMAP2+: omap_hwmod: manage the wake-up latency constraints
From: jean.pihet @ 2011-08-11 15:06 UTC (permalink / raw)
To: Mark Brown, Kevin Hilman, markgross, Linux PM mailing list; +Cc: Jean Pihet
In-Reply-To: <1313075212-8366-1-git-send-email-j-pihet@ti.com>
From: Jean Pihet <j-pihet@ti.com>
Hwmod is queried from the OMAP_PM layer to manage the power domains
wake-up latency constraints. Hwmod retrieves the correct power domain
and if it exists it calls the corresponding power domain function.
Tested on OMAP3 Beagleboard and OMAP4 Pandaboard in RET/OFF using wake-up
latency constraints on MPU, CORE and PER.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 26 +++++++++++++++++++++++++-
arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 ++
2 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 84cc0bd..c6b1cc9 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -143,6 +143,7 @@
#include "powerdomain.h"
#include <plat/clock.h>
#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
#include <plat/prcm.h>
#include "cm2xxx_3xxx.h"
@@ -2618,11 +2619,34 @@ ohsps_unlock:
return ret;
}
+/*
+ * omap_hwmod_set_wkup_constraint- set/release a wake-up latency constraint
+ *
+ * @oh: struct omap_hwmod* to which the target device belongs to.
+ * @cookie: identifier of the constraints list for @oh.
+ * @min_latency: the minimum allowed wake-up latency for @oh.
+ *
+ * Returns 0 upon success.
+ */
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh,
+ void *cookie, long min_latency)
+{
+ struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
+
+ if (!pwrdm) {
+ pr_err("%s: Error: could not find powerdomain "
+ "for %s\n", __func__, oh->name);
+ return -EINVAL;
+ }
+
+ return pwrdm_set_wkup_lat_constraint(pwrdm, cookie, min_latency);
+}
+
/**
* omap_hwmod_get_context_loss_count - get lost context count
* @oh: struct omap_hwmod *
*
- * Query the powerdomain of of @oh to get the context loss
+ * Query the powerdomain of @oh to get the context loss
* count for this device.
*
* Returns the context loss count of the powerdomain assocated with @oh
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 0e329ca..75e0e7a 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -603,6 +603,8 @@ int omap_hwmod_for_each_by_class(const char *classname,
void *user);
int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh, void *cookie,
+ long min_latency);
u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
--
1.7.2.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox