Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 267065
b: refs/heads/master
c: 1a9a915
h: refs/heads/master
i:
  267063: 14b8ad6
v: v3
  • Loading branch information
Rafael J. Wysocki committed Oct 4, 2011
1 parent a10be3b commit 933baa7
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 85 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: b66213cdb002b08b29603d488c451dfe25e2ca20
refs/heads/master: 1a9a91525d806f2b3bd8b57b963755a96fd36ce2
6 changes: 3 additions & 3 deletions trunk/drivers/base/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/resume-trace.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
Expand Down Expand Up @@ -66,6 +65,7 @@ void device_pm_init(struct device *dev)
spin_lock_init(&dev->power.lock);
pm_runtime_init(dev);
INIT_LIST_HEAD(&dev->power.entry);
dev->power.power_state = PMSG_INVALID;
}

/**
Expand Down Expand Up @@ -97,8 +97,8 @@ void device_pm_add(struct device *dev)
dev_warn(dev, "parent %s should not be sleeping\n",
dev_name(dev->parent));
list_add_tail(&dev->power.entry, &dpm_list);
mutex_unlock(&dpm_list_mtx);
dev_pm_qos_constraints_init(dev);
mutex_unlock(&dpm_list_mtx);
}

/**
Expand All @@ -109,9 +109,9 @@ void device_pm_remove(struct device *dev)
{
pr_debug("PM: Removing info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
dev_pm_qos_constraints_destroy(dev);
complete_all(&dev->power.completion);
mutex_lock(&dpm_list_mtx);
dev_pm_qos_constraints_destroy(dev);
list_del_init(&dev->power.entry);
mutex_unlock(&dpm_list_mtx);
device_wakeup_disable(dev);
Expand Down
10 changes: 9 additions & 1 deletion trunk/drivers/base/power/power.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <linux/pm_qos.h>

#ifdef CONFIG_PM_RUNTIME

extern void pm_runtime_init(struct device *dev);
Expand Down Expand Up @@ -35,15 +37,21 @@ extern void device_pm_move_last(struct device *);
static inline void device_pm_init(struct device *dev)
{
spin_lock_init(&dev->power.lock);
dev->power.power_state = PMSG_INVALID;
pm_runtime_init(dev);
}

static inline void device_pm_add(struct device *dev)
{
dev_pm_qos_constraints_init(dev);
}

static inline void device_pm_remove(struct device *dev)
{
dev_pm_qos_constraints_destroy(dev);
pm_runtime_remove(dev);
}

static inline void device_pm_add(struct device *dev) {}
static inline void device_pm_move_before(struct device *deva,
struct device *devb) {}
static inline void device_pm_move_after(struct device *deva,
Expand Down
160 changes: 90 additions & 70 deletions trunk/drivers/base/power/qos.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,6 @@
* . 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.
* . The constraints_state variable from dev_pm_info tracks the data struct
* allocation state:
* DEV_PM_QOS_NO_DEVICE: No device present or device removed, no data
* allocated,
* DEV_PM_QOS_DEVICE_PRESENT: Device present, data not allocated and will be
* allocated at the first call to dev_pm_qos_add_request,
* DEV_PM_QOS_ALLOCATED: Device present, data allocated. The per-device
* PM QoS constraints framework is operational and constraints can be
* added, updated or removed using the dev_pm_qos_* API.
* . A global mutex protects the constraints users from the data being
* allocated and free'd.
*/
Expand All @@ -51,8 +42,30 @@


static DEFINE_MUTEX(dev_pm_qos_mtx);

static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);

/**
* dev_pm_qos_read_value - Get PM QoS constraint for a given device.
* @dev: Device to get the PM QoS constraint value for.
*/
s32 dev_pm_qos_read_value(struct device *dev)
{
struct pm_qos_constraints *c;
unsigned long flags;
s32 ret = 0;

spin_lock_irqsave(&dev->power.lock, flags);

c = dev->power.constraints;
if (c)
ret = pm_qos_read_value(c);

spin_unlock_irqrestore(&dev->power.lock, flags);

return ret;
}

/*
* apply_constraint
* @req: constraint request to apply
Expand Down Expand Up @@ -105,62 +118,70 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
}
BLOCKING_INIT_NOTIFIER_HEAD(n);

plist_head_init(&c->list);
c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
c->type = PM_QOS_MIN;
c->notifiers = n;

spin_lock_irq(&dev->power.lock);
dev->power.constraints = c;
plist_head_init(&dev->power.constraints->list);
dev->power.constraints->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
dev->power.constraints->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
dev->power.constraints->type = PM_QOS_MIN;
dev->power.constraints->notifiers = n;
dev->power.constraints_state = DEV_PM_QOS_ALLOCATED;
spin_unlock_irq(&dev->power.lock);

return 0;
}

/**
* dev_pm_qos_constraints_init
* dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
* @dev: target device
*
* Called from the device PM subsystem at device insertion
* Called from the device PM subsystem during device insertion under
* device_pm_lock().
*/
void dev_pm_qos_constraints_init(struct device *dev)
{
mutex_lock(&dev_pm_qos_mtx);
dev->power.constraints_state = DEV_PM_QOS_DEVICE_PRESENT;
dev->power.constraints = NULL;
dev->power.power_state = PMSG_ON;
mutex_unlock(&dev_pm_qos_mtx);
}

/**
* dev_pm_qos_constraints_destroy
* @dev: target device
*
* Called from the device PM subsystem at device removal
* Called from the device PM subsystem on device removal under device_pm_lock().
*/
void dev_pm_qos_constraints_destroy(struct device *dev)
{
struct dev_pm_qos_request *req, *tmp;
struct pm_qos_constraints *c;

mutex_lock(&dev_pm_qos_mtx);

if (dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) {
/* Flush the constraints list for the device */
plist_for_each_entry_safe(req, tmp,
&dev->power.constraints->list,
node) {
/*
* Update constraints list and call the notification
* callbacks if needed
*/
apply_constraint(req, PM_QOS_REMOVE_REQ,
PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
dev->power.power_state = PMSG_INVALID;
c = dev->power.constraints;
if (!c)
goto out;

kfree(dev->power.constraints->notifiers);
kfree(dev->power.constraints);
dev->power.constraints = NULL;
/* Flush the constraints list for the device */
plist_for_each_entry_safe(req, tmp, &c->list, node) {
/*
* Update constraints list and call the notification
* callbacks if needed
*/
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
dev->power.constraints_state = DEV_PM_QOS_NO_DEVICE;

spin_lock_irq(&dev->power.lock);
dev->power.constraints = NULL;
spin_unlock_irq(&dev->power.lock);

kfree(c->notifiers);
kfree(c);

out:
mutex_unlock(&dev_pm_qos_mtx);
}

Expand All @@ -178,8 +199,9 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
*
* Returns 1 if the aggregated constraint value has changed,
* 0 if the aggregated constraint value has not changed,
* -EINVAL in case of wrong parameters, -ENODEV if the device has been
* removed from the system
* -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
* to allocate for data structures, -ENODEV if the device has just been removed
* from the system.
*/
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
s32 value)
Expand All @@ -195,28 +217,32 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
return -EINVAL;
}

mutex_lock(&dev_pm_qos_mtx);
req->dev = dev;

/* Return if the device has been removed */
if (req->dev->power.constraints_state == DEV_PM_QOS_NO_DEVICE) {
ret = -ENODEV;
goto out;
}
mutex_lock(&dev_pm_qos_mtx);

/*
* Allocate the constraints data on the first call to add_request,
* i.e. only if the data is not already allocated and if the device has
* not been removed
*/
if (dev->power.constraints_state == DEV_PM_QOS_DEVICE_PRESENT)
ret = dev_pm_qos_constraints_allocate(dev);
if (!dev->power.constraints) {
if (dev->power.power_state.event == PM_EVENT_INVALID) {
/* The device has been removed from the system. */
req->dev = NULL;
ret = -ENODEV;
goto out;
} else {
/*
* Allocate the constraints data on the first call to
* add_request, i.e. only if the data is not already
* allocated and if the device has not been removed.
*/
ret = dev_pm_qos_constraints_allocate(dev);
}
}

if (!ret)
ret = apply_constraint(req, PM_QOS_ADD_REQ, value);

out:
out:
mutex_unlock(&dev_pm_qos_mtx);

return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
Expand Down Expand Up @@ -252,7 +278,7 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req,

mutex_lock(&dev_pm_qos_mtx);

if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) {
if (req->dev->power.constraints) {
if (new_value != req->node.prio)
ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
new_value);
Expand Down Expand Up @@ -293,7 +319,7 @@ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)

mutex_lock(&dev_pm_qos_mtx);

if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) {
if (req->dev->power.constraints) {
ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
Expand Down Expand Up @@ -323,15 +349,12 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)

mutex_lock(&dev_pm_qos_mtx);

/* Silently return if the device has been removed */
if (dev->power.constraints_state != DEV_PM_QOS_ALLOCATED)
goto out;

retval = blocking_notifier_chain_register(
dev->power.constraints->notifiers,
notifier);
/* Silently return if the constraints object is not present. */
if (dev->power.constraints)
retval = blocking_notifier_chain_register(
dev->power.constraints->notifiers,
notifier);

out:
mutex_unlock(&dev_pm_qos_mtx);
return retval;
}
Expand All @@ -354,15 +377,12 @@ int dev_pm_qos_remove_notifier(struct device *dev,

mutex_lock(&dev_pm_qos_mtx);

/* Silently return if the device has been removed */
if (dev->power.constraints_state != DEV_PM_QOS_ALLOCATED)
goto out;

retval = blocking_notifier_chain_unregister(
dev->power.constraints->notifiers,
notifier);
/* Silently return if the constraints object is not present. */
if (dev->power.constraints)
retval = blocking_notifier_chain_unregister(
dev->power.constraints->notifiers,
notifier);

out:
mutex_unlock(&dev_pm_qos_mtx);
return retval;
}
Expand Down
10 changes: 2 additions & 8 deletions trunk/include/linux/pm.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
* requested by a driver.
*/

#define PM_EVENT_INVALID (-1)
#define PM_EVENT_ON 0x0000
#define PM_EVENT_FREEZE 0x0001
#define PM_EVENT_SUSPEND 0x0002
Expand All @@ -346,6 +347,7 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
#define PM_EVENT_AUTO_SUSPEND (PM_EVENT_AUTO | PM_EVENT_SUSPEND)
#define PM_EVENT_AUTO_RESUME (PM_EVENT_AUTO | PM_EVENT_RESUME)

#define PMSG_INVALID ((struct pm_message){ .event = PM_EVENT_INVALID, })
#define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, })
#define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, })
#define PMSG_QUIESCE ((struct pm_message){ .event = PM_EVENT_QUIESCE, })
Expand Down Expand Up @@ -419,13 +421,6 @@ enum rpm_request {
RPM_REQ_RESUME,
};

/* Per-device PM QoS constraints data struct state */
enum dev_pm_qos_state {
DEV_PM_QOS_NO_DEVICE, /* No device present */
DEV_PM_QOS_DEVICE_PRESENT, /* Device present, data not allocated */
DEV_PM_QOS_ALLOCATED, /* Device present, data allocated */
};

struct wakeup_source;

struct pm_domain_data {
Expand Down Expand Up @@ -488,7 +483,6 @@ struct dev_pm_info {
#endif
struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
struct pm_qos_constraints *constraints;
enum dev_pm_qos_state constraints_state;
};

extern void update_pm_runtime_accounting(struct device *dev);
Expand Down
Loading

0 comments on commit 933baa7

Please sign in to comment.