aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-09-29 16:29:44 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-10-04 15:54:26 -0400
commit1a9a91525d806f2b3bd8b57b963755a96fd36ce2 (patch)
tree511db2ab0871872bce759d35b7ffd22b9d7fc3f5 /drivers/base
parentb66213cdb002b08b29603d488c451dfe25e2ca20 (diff)
PM / QoS: Add function dev_pm_qos_read_value() (v3)
To read the current PM QoS value for a given device we need to make sure that the device's power.constraints object won't be removed while we're doing that. For this reason, put the operation under dev->power.lock and acquire the lock around the initialization and removal of power.constraints. Moreover, since we're using the value of power.constraints to determine whether or not the object is present, the power.constraints_state field isn't necessary any more and may be removed. However, dev_pm_qos_add_request() needs to check if the device is being removed from the system before allocating a new PM QoS constraints object for it, so make it use the power.power_state field of struct device for this purpose. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/main.c6
-rw-r--r--drivers/base/power/power.h10
-rw-r--r--drivers/base/power/qos.c160
3 files changed, 102 insertions, 74 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 956443f86254..c6291ab725a3 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -22,7 +22,6 @@
22#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <linux/pm.h> 23#include <linux/pm.h>
24#include <linux/pm_runtime.h> 24#include <linux/pm_runtime.h>
25#include <linux/pm_qos.h>
26#include <linux/resume-trace.h> 25#include <linux/resume-trace.h>
27#include <linux/interrupt.h> 26#include <linux/interrupt.h>
28#include <linux/sched.h> 27#include <linux/sched.h>
@@ -66,6 +65,7 @@ void device_pm_init(struct device *dev)
66 spin_lock_init(&dev->power.lock); 65 spin_lock_init(&dev->power.lock);
67 pm_runtime_init(dev); 66 pm_runtime_init(dev);
68 INIT_LIST_HEAD(&dev->power.entry); 67 INIT_LIST_HEAD(&dev->power.entry);
68 dev->power.power_state = PMSG_INVALID;
69} 69}
70 70
71/** 71/**
@@ -97,8 +97,8 @@ void device_pm_add(struct device *dev)
97 dev_warn(dev, "parent %s should not be sleeping\n", 97 dev_warn(dev, "parent %s should not be sleeping\n",
98 dev_name(dev->parent)); 98 dev_name(dev->parent));
99 list_add_tail(&dev->power.entry, &dpm_list); 99 list_add_tail(&dev->power.entry, &dpm_list);
100 mutex_unlock(&dpm_list_mtx);
101 dev_pm_qos_constraints_init(dev); 100 dev_pm_qos_constraints_init(dev);
101 mutex_unlock(&dpm_list_mtx);
102} 102}
103 103
104/** 104/**
@@ -109,9 +109,9 @@ void device_pm_remove(struct device *dev)
109{ 109{
110 pr_debug("PM: Removing info for %s:%s\n", 110 pr_debug("PM: Removing info for %s:%s\n",
111 dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); 111 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
112 dev_pm_qos_constraints_destroy(dev);
113 complete_all(&dev->power.completion); 112 complete_all(&dev->power.completion);
114 mutex_lock(&dpm_list_mtx); 113 mutex_lock(&dpm_list_mtx);
114 dev_pm_qos_constraints_destroy(dev);
115 list_del_init(&dev->power.entry); 115 list_del_init(&dev->power.entry);
116 mutex_unlock(&dpm_list_mtx); 116 mutex_unlock(&dpm_list_mtx);
117 device_wakeup_disable(dev); 117 device_wakeup_disable(dev);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index f2a25f18fde7..9bf62323aaf3 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -1,3 +1,5 @@
1#include <linux/pm_qos.h>
2
1#ifdef CONFIG_PM_RUNTIME 3#ifdef CONFIG_PM_RUNTIME
2 4
3extern void pm_runtime_init(struct device *dev); 5extern void pm_runtime_init(struct device *dev);
@@ -35,15 +37,21 @@ extern void device_pm_move_last(struct device *);
35static inline void device_pm_init(struct device *dev) 37static inline void device_pm_init(struct device *dev)
36{ 38{
37 spin_lock_init(&dev->power.lock); 39 spin_lock_init(&dev->power.lock);
40 dev->power.power_state = PMSG_INVALID;
38 pm_runtime_init(dev); 41 pm_runtime_init(dev);
39} 42}
40 43
44static inline void device_pm_add(struct device *dev)
45{
46 dev_pm_qos_constraints_init(dev);
47}
48
41static inline void device_pm_remove(struct device *dev) 49static inline void device_pm_remove(struct device *dev)
42{ 50{
51 dev_pm_qos_constraints_destroy(dev);
43 pm_runtime_remove(dev); 52 pm_runtime_remove(dev);
44} 53}
45 54
46static inline void device_pm_add(struct device *dev) {}
47static inline void device_pm_move_before(struct device *deva, 55static inline void device_pm_move_before(struct device *deva,
48 struct device *devb) {} 56 struct device *devb) {}
49static inline void device_pm_move_after(struct device *deva, 57static inline void device_pm_move_after(struct device *deva,
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 8d0b81151c14..91e061417382 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -30,15 +30,6 @@
30 * . To minimize the data usage by the per-device constraints, the data struct 30 * . To minimize the data usage by the per-device constraints, the data struct
31 * is only allocated at the first call to dev_pm_qos_add_request. 31 * is only allocated at the first call to dev_pm_qos_add_request.
32 * . The data is later free'd when the device is removed from the system. 32 * . The data is later free'd when the device is removed from the system.
33 * . The constraints_state variable from dev_pm_info tracks the data struct
34 * allocation state:
35 * DEV_PM_QOS_NO_DEVICE: No device present or device removed, no data
36 * allocated,
37 * DEV_PM_QOS_DEVICE_PRESENT: Device present, data not allocated and will be
38 * allocated at the first call to dev_pm_qos_add_request,
39 * DEV_PM_QOS_ALLOCATED: Device present, data allocated. The per-device
40 * PM QoS constraints framework is operational and constraints can be
41 * added, updated or removed using the dev_pm_qos_* API.
42 * . A global mutex protects the constraints users from the data being 33 * . A global mutex protects the constraints users from the data being
43 * allocated and free'd. 34 * allocated and free'd.
44 */ 35 */
@@ -51,8 +42,30 @@
51 42
52 43
53static DEFINE_MUTEX(dev_pm_qos_mtx); 44static DEFINE_MUTEX(dev_pm_qos_mtx);
45
54static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); 46static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
55 47
48/**
49 * dev_pm_qos_read_value - Get PM QoS constraint for a given device.
50 * @dev: Device to get the PM QoS constraint value for.
51 */
52s32 dev_pm_qos_read_value(struct device *dev)
53{
54 struct pm_qos_constraints *c;
55 unsigned long flags;
56 s32 ret = 0;
57
58 spin_lock_irqsave(&dev->power.lock, flags);
59
60 c = dev->power.constraints;
61 if (c)
62 ret = pm_qos_read_value(c);
63
64 spin_unlock_irqrestore(&dev->power.lock, flags);
65
66 return ret;
67}
68
56/* 69/*
57 * apply_constraint 70 * apply_constraint
58 * @req: constraint request to apply 71 * @req: constraint request to apply
@@ -105,27 +118,31 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
105 } 118 }
106 BLOCKING_INIT_NOTIFIER_HEAD(n); 119 BLOCKING_INIT_NOTIFIER_HEAD(n);
107 120
121 plist_head_init(&c->list);
122 c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
123 c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
124 c->type = PM_QOS_MIN;
125 c->notifiers = n;
126
127 spin_lock_irq(&dev->power.lock);
108 dev->power.constraints = c; 128 dev->power.constraints = c;
109 plist_head_init(&dev->power.constraints->list); 129 spin_unlock_irq(&dev->power.lock);
110 dev->power.constraints->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
111 dev->power.constraints->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
112 dev->power.constraints->type = PM_QOS_MIN;
113 dev->power.constraints->notifiers = n;
114 dev->power.constraints_state = DEV_PM_QOS_ALLOCATED;
115 130
116 return 0; 131 return 0;
117} 132}
118 133
119/** 134/**
120 * dev_pm_qos_constraints_init 135 * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
121 * @dev: target device 136 * @dev: target device
122 * 137 *
123 * Called from the device PM subsystem at device insertion 138 * Called from the device PM subsystem during device insertion under
139 * device_pm_lock().
124 */ 140 */
125void dev_pm_qos_constraints_init(struct device *dev) 141void dev_pm_qos_constraints_init(struct device *dev)
126{ 142{
127 mutex_lock(&dev_pm_qos_mtx); 143 mutex_lock(&dev_pm_qos_mtx);
128 dev->power.constraints_state = DEV_PM_QOS_DEVICE_PRESENT; 144 dev->power.constraints = NULL;
145 dev->power.power_state = PMSG_ON;
129 mutex_unlock(&dev_pm_qos_mtx); 146 mutex_unlock(&dev_pm_qos_mtx);
130} 147}
131 148
@@ -133,34 +150,38 @@ void dev_pm_qos_constraints_init(struct device *dev)
133 * dev_pm_qos_constraints_destroy 150 * dev_pm_qos_constraints_destroy
134 * @dev: target device 151 * @dev: target device
135 * 152 *
136 * Called from the device PM subsystem at device removal 153 * Called from the device PM subsystem on device removal under device_pm_lock().
137 */ 154 */
138void dev_pm_qos_constraints_destroy(struct device *dev) 155void dev_pm_qos_constraints_destroy(struct device *dev)
139{ 156{
140 struct dev_pm_qos_request *req, *tmp; 157 struct dev_pm_qos_request *req, *tmp;
158 struct pm_qos_constraints *c;
141 159
142 mutex_lock(&dev_pm_qos_mtx); 160 mutex_lock(&dev_pm_qos_mtx);
143 161
144 if (dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) { 162 dev->power.power_state = PMSG_INVALID;
145 /* Flush the constraints list for the device */ 163 c = dev->power.constraints;
146 plist_for_each_entry_safe(req, tmp, 164 if (!c)
147 &dev->power.constraints->list, 165 goto out;
148 node) {
149 /*
150 * Update constraints list and call the notification
151 * callbacks if needed
152 */
153 apply_constraint(req, PM_QOS_REMOVE_REQ,
154 PM_QOS_DEFAULT_VALUE);
155 memset(req, 0, sizeof(*req));
156 }
157 166
158 kfree(dev->power.constraints->notifiers); 167 /* Flush the constraints list for the device */
159 kfree(dev->power.constraints); 168 plist_for_each_entry_safe(req, tmp, &c->list, node) {
160 dev->power.constraints = NULL; 169 /*
170 * Update constraints list and call the notification
171 * callbacks if needed
172 */
173 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
174 memset(req, 0, sizeof(*req));
161 } 175 }
162 dev->power.constraints_state = DEV_PM_QOS_NO_DEVICE;
163 176
177 spin_lock_irq(&dev->power.lock);
178 dev->power.constraints = NULL;
179 spin_unlock_irq(&dev->power.lock);
180
181 kfree(c->notifiers);
182 kfree(c);
183
184 out:
164 mutex_unlock(&dev_pm_qos_mtx); 185 mutex_unlock(&dev_pm_qos_mtx);
165} 186}
166 187
@@ -178,8 +199,9 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
178 * 199 *
179 * Returns 1 if the aggregated constraint value has changed, 200 * Returns 1 if the aggregated constraint value has changed,
180 * 0 if the aggregated constraint value has not changed, 201 * 0 if the aggregated constraint value has not changed,
181 * -EINVAL in case of wrong parameters, -ENODEV if the device has been 202 * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
182 * removed from the system 203 * to allocate for data structures, -ENODEV if the device has just been removed
204 * from the system.
183 */ 205 */
184int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, 206int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
185 s32 value) 207 s32 value)
@@ -195,28 +217,32 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
195 return -EINVAL; 217 return -EINVAL;
196 } 218 }
197 219
198 mutex_lock(&dev_pm_qos_mtx);
199 req->dev = dev; 220 req->dev = dev;
200 221
201 /* Return if the device has been removed */ 222 mutex_lock(&dev_pm_qos_mtx);
202 if (req->dev->power.constraints_state == DEV_PM_QOS_NO_DEVICE) {
203 ret = -ENODEV;
204 goto out;
205 }
206 223
207 /* 224 if (!dev->power.constraints) {
208 * Allocate the constraints data on the first call to add_request, 225 if (dev->power.power_state.event == PM_EVENT_INVALID) {
209 * i.e. only if the data is not already allocated and if the device has 226 /* The device has been removed from the system. */
210 * not been removed 227 req->dev = NULL;
211 */ 228 ret = -ENODEV;
212 if (dev->power.constraints_state == DEV_PM_QOS_DEVICE_PRESENT) 229 goto out;
213 ret = dev_pm_qos_constraints_allocate(dev); 230 } else {
231 /*
232 * Allocate the constraints data on the first call to
233 * add_request, i.e. only if the data is not already
234 * allocated and if the device has not been removed.
235 */
236 ret = dev_pm_qos_constraints_allocate(dev);
237 }
238 }
214 239
215 if (!ret) 240 if (!ret)
216 ret = apply_constraint(req, PM_QOS_ADD_REQ, value); 241 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
217 242
218out: 243 out:
219 mutex_unlock(&dev_pm_qos_mtx); 244 mutex_unlock(&dev_pm_qos_mtx);
245
220 return ret; 246 return ret;
221} 247}
222EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); 248EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
@@ -252,7 +278,7 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
252 278
253 mutex_lock(&dev_pm_qos_mtx); 279 mutex_lock(&dev_pm_qos_mtx);
254 280
255 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) { 281 if (req->dev->power.constraints) {
256 if (new_value != req->node.prio) 282 if (new_value != req->node.prio)
257 ret = apply_constraint(req, PM_QOS_UPDATE_REQ, 283 ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
258 new_value); 284 new_value);
@@ -293,7 +319,7 @@ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
293 319
294 mutex_lock(&dev_pm_qos_mtx); 320 mutex_lock(&dev_pm_qos_mtx);
295 321
296 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) { 322 if (req->dev->power.constraints) {
297 ret = apply_constraint(req, PM_QOS_REMOVE_REQ, 323 ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
298 PM_QOS_DEFAULT_VALUE); 324 PM_QOS_DEFAULT_VALUE);
299 memset(req, 0, sizeof(*req)); 325 memset(req, 0, sizeof(*req));
@@ -323,15 +349,12 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
323 349
324 mutex_lock(&dev_pm_qos_mtx); 350 mutex_lock(&dev_pm_qos_mtx);
325 351
326 /* Silently return if the device has been removed */ 352 /* Silently return if the constraints object is not present. */
327 if (dev->power.constraints_state != DEV_PM_QOS_ALLOCATED) 353 if (dev->power.constraints)
328 goto out; 354 retval = blocking_notifier_chain_register(
329 355 dev->power.constraints->notifiers,
330 retval = blocking_notifier_chain_register( 356 notifier);
331 dev->power.constraints->notifiers,
332 notifier);
333 357
334out:
335 mutex_unlock(&dev_pm_qos_mtx); 358 mutex_unlock(&dev_pm_qos_mtx);
336 return retval; 359 return retval;
337} 360}
@@ -354,15 +377,12 @@ int dev_pm_qos_remove_notifier(struct device *dev,
354 377
355 mutex_lock(&dev_pm_qos_mtx); 378 mutex_lock(&dev_pm_qos_mtx);
356 379
357 /* Silently return if the device has been removed */ 380 /* Silently return if the constraints object is not present. */
358 if (dev->power.constraints_state != DEV_PM_QOS_ALLOCATED) 381 if (dev->power.constraints)
359 goto out; 382 retval = blocking_notifier_chain_unregister(
360 383 dev->power.constraints->notifiers,
361 retval = blocking_notifier_chain_unregister( 384 notifier);
362 dev->power.constraints->notifiers,
363 notifier);
364 385
365out:
366 mutex_unlock(&dev_pm_qos_mtx); 386 mutex_unlock(&dev_pm_qos_mtx);
367 return retval; 387 return retval;
368} 388}