aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/main.c6
-rw-r--r--drivers/base/power/power.h10
-rw-r--r--drivers/base/power/qos.c160
-rw-r--r--include/linux/pm.h10
-rw-r--r--include/linux/pm_qos.h12
5 files changed, 114 insertions, 84 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}
diff --git a/include/linux/pm.h b/include/linux/pm.h
index d78187e9ca99..62a876ec4d4e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -326,6 +326,7 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
326 * requested by a driver. 326 * requested by a driver.
327 */ 327 */
328 328
329#define PM_EVENT_INVALID (-1)
329#define PM_EVENT_ON 0x0000 330#define PM_EVENT_ON 0x0000
330#define PM_EVENT_FREEZE 0x0001 331#define PM_EVENT_FREEZE 0x0001
331#define PM_EVENT_SUSPEND 0x0002 332#define PM_EVENT_SUSPEND 0x0002
@@ -346,6 +347,7 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
346#define PM_EVENT_AUTO_SUSPEND (PM_EVENT_AUTO | PM_EVENT_SUSPEND) 347#define PM_EVENT_AUTO_SUSPEND (PM_EVENT_AUTO | PM_EVENT_SUSPEND)
347#define PM_EVENT_AUTO_RESUME (PM_EVENT_AUTO | PM_EVENT_RESUME) 348#define PM_EVENT_AUTO_RESUME (PM_EVENT_AUTO | PM_EVENT_RESUME)
348 349
350#define PMSG_INVALID ((struct pm_message){ .event = PM_EVENT_INVALID, })
349#define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, }) 351#define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, })
350#define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, }) 352#define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, })
351#define PMSG_QUIESCE ((struct pm_message){ .event = PM_EVENT_QUIESCE, }) 353#define PMSG_QUIESCE ((struct pm_message){ .event = PM_EVENT_QUIESCE, })
@@ -419,13 +421,6 @@ enum rpm_request {
419 RPM_REQ_RESUME, 421 RPM_REQ_RESUME,
420}; 422};
421 423
422/* Per-device PM QoS constraints data struct state */
423enum dev_pm_qos_state {
424 DEV_PM_QOS_NO_DEVICE, /* No device present */
425 DEV_PM_QOS_DEVICE_PRESENT, /* Device present, data not allocated */
426 DEV_PM_QOS_ALLOCATED, /* Device present, data allocated */
427};
428
429struct wakeup_source; 424struct wakeup_source;
430 425
431struct pm_domain_data { 426struct pm_domain_data {
@@ -488,7 +483,6 @@ struct dev_pm_info {
488#endif 483#endif
489 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ 484 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
490 struct pm_qos_constraints *constraints; 485 struct pm_qos_constraints *constraints;
491 enum dev_pm_qos_state constraints_state;
492}; 486};
493 487
494extern void update_pm_runtime_accounting(struct device *dev); 488extern void update_pm_runtime_accounting(struct device *dev);
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index ca7bd3f98cb4..83b0ea302a80 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -7,6 +7,7 @@
7#include <linux/plist.h> 7#include <linux/plist.h>
8#include <linux/notifier.h> 8#include <linux/notifier.h>
9#include <linux/miscdevice.h> 9#include <linux/miscdevice.h>
10#include <linux/device.h>
10 11
11#define PM_QOS_RESERVED 0 12#define PM_QOS_RESERVED 0
12#define PM_QOS_CPU_DMA_LATENCY 1 13#define PM_QOS_CPU_DMA_LATENCY 1
@@ -77,6 +78,7 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
77int pm_qos_request_active(struct pm_qos_request *req); 78int pm_qos_request_active(struct pm_qos_request *req);
78s32 pm_qos_read_value(struct pm_qos_constraints *c); 79s32 pm_qos_read_value(struct pm_qos_constraints *c);
79 80
81s32 dev_pm_qos_read_value(struct device *dev);
80int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, 82int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
81 s32 value); 83 s32 value);
82int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value); 84int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
@@ -117,6 +119,8 @@ static inline int pm_qos_request_active(struct pm_qos_request *req)
117static inline s32 pm_qos_read_value(struct pm_qos_constraints *c) 119static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
118 { return 0; } 120 { return 0; }
119 121
122static inline s32 dev_pm_qos_read_value(struct device *dev)
123 { return 0; }
120static inline int dev_pm_qos_add_request(struct device *dev, 124static inline int dev_pm_qos_add_request(struct device *dev,
121 struct dev_pm_qos_request *req, 125 struct dev_pm_qos_request *req,
122 s32 value) 126 s32 value)
@@ -139,9 +143,13 @@ static inline int dev_pm_qos_remove_global_notifier(
139 struct notifier_block *notifier) 143 struct notifier_block *notifier)
140 { return 0; } 144 { return 0; }
141static inline void dev_pm_qos_constraints_init(struct device *dev) 145static inline void dev_pm_qos_constraints_init(struct device *dev)
142 { return; } 146{
147 dev->power.power_state = PMSG_ON;
148}
143static inline void dev_pm_qos_constraints_destroy(struct device *dev) 149static inline void dev_pm_qos_constraints_destroy(struct device *dev)
144 { return; } 150{
151 dev->power.power_state = PMSG_INVALID;
152}
145#endif 153#endif
146 154
147#endif 155#endif