Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 336589
b: refs/heads/master
c: ae0fb4b
h: refs/heads/master
i:
  336587: e295441
v: v3
  • Loading branch information
Rafael J. Wysocki committed Oct 22, 2012
1 parent 46a31e6 commit 8ac0c4b
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 30 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 021c870ba4ab4bc9a23d5db4e324f50f26d8ab24
refs/heads/master: ae0fb4b72c8db7e6c4ef32bc58a43a759ad414b9
2 changes: 1 addition & 1 deletion trunk/Documentation/power/pm_qos_interface.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ reading the aggregated value does not require any locking mechanism.

From kernel mode the use of this interface is the following:

int dev_pm_qos_add_request(device, handle, value):
int dev_pm_qos_add_request(device, handle, type, value):
Will insert an element into the list for that identified device with the
target value. Upon change to this list the new target is recomputed and any
registered notifiers are called only if the target value is now different.
Expand Down
124 changes: 98 additions & 26 deletions trunk/drivers/base/power/qos.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,50 @@ static DEFINE_MUTEX(dev_pm_qos_mtx);

static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);

/**
* __dev_pm_qos_flags - Check PM QoS flags for a given device.
* @dev: Device to check the PM QoS flags for.
* @mask: Flags to check against.
*
* This routine must be called with dev->power.lock held.
*/
enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
{
struct dev_pm_qos *qos = dev->power.qos;
struct pm_qos_flags *pqf;
s32 val;

if (!qos)
return PM_QOS_FLAGS_UNDEFINED;

pqf = &qos->flags;
if (list_empty(&pqf->list))
return PM_QOS_FLAGS_UNDEFINED;

val = pqf->effective_flags & mask;
if (val)
return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;

return PM_QOS_FLAGS_NONE;
}

/**
* dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
* @dev: Device to check the PM QoS flags for.
* @mask: Flags to check against.
*/
enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
{
unsigned long irqflags;
enum pm_qos_flags_status ret;

spin_lock_irqsave(&dev->power.lock, irqflags);
ret = __dev_pm_qos_flags(dev, mask);
spin_unlock_irqrestore(&dev->power.lock, irqflags);

return ret;
}

/**
* __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
* @dev: Device to get the PM QoS constraint value for.
Expand Down Expand Up @@ -74,30 +118,39 @@ s32 dev_pm_qos_read_value(struct device *dev)
return ret;
}

/*
* apply_constraint
* @req: constraint request to apply
* @action: action to perform add/update/remove, of type enum pm_qos_req_action
* @value: defines the qos request
/**
* apply_constraint - Add/modify/remove device PM QoS request.
* @req: Constraint request to apply
* @action: Action to perform (add/update/remove).
* @value: Value to assign to the QoS request.
*
* Internal function to update the constraints list using the PM QoS core
* code and if needed call the per-device and the global notification
* callbacks
*/
static int apply_constraint(struct dev_pm_qos_request *req,
enum pm_qos_req_action action, int value)
enum pm_qos_req_action action, s32 value)
{
int ret, curr_value;

ret = pm_qos_update_target(&req->dev->power.qos->latency,
&req->data.pnode, action, value);
struct dev_pm_qos *qos = req->dev->power.qos;
int ret;

if (ret) {
/* Call the global callbacks if needed */
curr_value = pm_qos_read_value(&req->dev->power.qos->latency);
blocking_notifier_call_chain(&dev_pm_notifiers,
(unsigned long)curr_value,
req);
switch(req->type) {
case DEV_PM_QOS_LATENCY:
ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
action, value);
if (ret) {
value = pm_qos_read_value(&qos->latency);
blocking_notifier_call_chain(&dev_pm_notifiers,
(unsigned long)value,
req);
}
break;
case DEV_PM_QOS_FLAGS:
ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
action, value);
break;
default:
ret = -EINVAL;
}

return ret;
Expand Down Expand Up @@ -134,6 +187,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
c->type = PM_QOS_MIN;
c->notifiers = n;

INIT_LIST_HEAD(&qos->flags.list);

spin_lock_irq(&dev->power.lock);
dev->power.qos = qos;
spin_unlock_irq(&dev->power.lock);
Expand Down Expand Up @@ -207,6 +262,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
* dev_pm_qos_add_request - inserts new qos request into the list
* @dev: target device for the constraint
* @req: pointer to a preallocated handle
* @type: type of the request
* @value: defines the qos request
*
* This function inserts a new entry in the device constraints list of
Expand All @@ -222,7 +278,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
* from the system.
*/
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
s32 value)
enum dev_pm_qos_req_type type, s32 value)
{
int ret = 0;

Expand Down Expand Up @@ -253,8 +309,10 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
}
}

if (!ret)
if (!ret) {
req->type = type;
ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
}

out:
mutex_unlock(&dev_pm_qos_mtx);
Expand All @@ -281,6 +339,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
s32 new_value)
{
s32 curr_value;
int ret = 0;

if (!req) /*guard against callers passing in null */
Expand All @@ -292,15 +351,27 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req,

mutex_lock(&dev_pm_qos_mtx);

if (req->dev->power.qos) {
if (new_value != req->data.pnode.prio)
ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
new_value);
} else {
/* Return if the device has been removed */
if (!req->dev->power.qos) {
ret = -ENODEV;
goto out;
}

switch(req->type) {
case DEV_PM_QOS_LATENCY:
curr_value = req->data.pnode.prio;
break;
case DEV_PM_QOS_FLAGS:
curr_value = req->data.flr.flags;
break;
default:
ret = -EINVAL;
goto out;
}

if (curr_value != new_value)
ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);

out:
mutex_unlock(&dev_pm_qos_mtx);
return ret;
}
Expand Down Expand Up @@ -451,7 +522,8 @@ int dev_pm_qos_add_ancestor_request(struct device *dev,
ancestor = ancestor->parent;

if (ancestor)
error = dev_pm_qos_add_request(ancestor, req, value);
error = dev_pm_qos_add_request(ancestor, req,
DEV_PM_QOS_LATENCY, value);

if (error)
req->dev = NULL;
Expand Down Expand Up @@ -487,7 +559,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
if (!req)
return -ENOMEM;

ret = dev_pm_qos_add_request(dev, req, value);
ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
if (ret < 0)
return ret;

Expand Down
4 changes: 3 additions & 1 deletion trunk/drivers/mtd/nand/sh_flctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,9 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)

if (!flctl->qos_request) {
ret = dev_pm_qos_add_request(&flctl->pdev->dev,
&flctl->pm_qos, 100);
&flctl->pm_qos,
DEV_PM_QOS_LATENCY,
100);
if (ret < 0)
dev_err(&flctl->pdev->dev,
"PM QoS request failed: %d\n", ret);
Expand Down
26 changes: 25 additions & 1 deletion trunk/include/linux/pm_qos.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ enum {
PM_QOS_NUM_CLASSES,
};

enum pm_qos_flags_status {
PM_QOS_FLAGS_UNDEFINED = -1,
PM_QOS_FLAGS_NONE,
PM_QOS_FLAGS_SOME,
PM_QOS_FLAGS_ALL,
};

#define PM_QOS_DEFAULT_VALUE -1

#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
Expand All @@ -38,9 +45,16 @@ struct pm_qos_flags_request {
s32 flags; /* Do not change to 64 bit */
};

enum dev_pm_qos_req_type {
DEV_PM_QOS_LATENCY = 1,
DEV_PM_QOS_FLAGS,
};

struct dev_pm_qos_request {
enum dev_pm_qos_req_type type;
union {
struct plist_node pnode;
struct pm_qos_flags_request flr;
} data;
struct device *dev;
};
Expand Down Expand Up @@ -71,6 +85,7 @@ struct pm_qos_flags {

struct dev_pm_qos {
struct pm_qos_constraints latency;
struct pm_qos_flags flags;
};

/* Action requested to pm_qos_update_target */
Expand Down Expand Up @@ -105,10 +120,12 @@ int pm_qos_request_active(struct pm_qos_request *req);
s32 pm_qos_read_value(struct pm_qos_constraints *c);

#ifdef CONFIG_PM
enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask);
enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask);
s32 __dev_pm_qos_read_value(struct device *dev);
s32 dev_pm_qos_read_value(struct device *dev);
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
s32 value);
enum dev_pm_qos_req_type type, s32 value);
int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
int dev_pm_qos_remove_request(struct dev_pm_qos_request *req);
int dev_pm_qos_add_notifier(struct device *dev,
Expand All @@ -122,12 +139,19 @@ void dev_pm_qos_constraints_destroy(struct device *dev);
int dev_pm_qos_add_ancestor_request(struct device *dev,
struct dev_pm_qos_request *req, s32 value);
#else
static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
s32 mask)
{ return PM_QOS_FLAGS_UNDEFINED; }
static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev,
s32 mask)
{ return PM_QOS_FLAGS_UNDEFINED; }
static inline s32 __dev_pm_qos_read_value(struct device *dev)
{ return 0; }
static inline s32 dev_pm_qos_read_value(struct device *dev)
{ return 0; }
static inline int dev_pm_qos_add_request(struct device *dev,
struct dev_pm_qos_request *req,
enum dev_pm_qos_req_type type,
s32 value)
{ return 0; }
static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
Expand Down

0 comments on commit 8ac0c4b

Please sign in to comment.