diff options
-rw-r--r-- | Documentation/power/pm_qos_interface.txt | 2 | ||||
-rw-r--r-- | drivers/base/power/qos.c | 124 | ||||
-rw-r--r-- | drivers/mtd/nand/sh_flctl.c | 4 | ||||
-rw-r--r-- | include/linux/pm_qos.h | 26 |
4 files changed, 127 insertions, 29 deletions
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt index 17e130a80347..79a2a58425ee 100644 --- a/Documentation/power/pm_qos_interface.txt +++ b/Documentation/power/pm_qos_interface.txt | |||
@@ -99,7 +99,7 @@ reading the aggregated value does not require any locking mechanism. | |||
99 | 99 | ||
100 | From kernel mode the use of this interface is the following: | 100 | From kernel mode the use of this interface is the following: |
101 | 101 | ||
102 | int dev_pm_qos_add_request(device, handle, value): | 102 | int dev_pm_qos_add_request(device, handle, type, value): |
103 | Will insert an element into the list for that identified device with the | 103 | Will insert an element into the list for that identified device with the |
104 | target value. Upon change to this list the new target is recomputed and any | 104 | target value. Upon change to this list the new target is recomputed and any |
105 | registered notifiers are called only if the target value is now different. | 105 | registered notifiers are called only if the target value is now different. |
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 96d27b821bb8..3c66f75d14b0 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
@@ -48,6 +48,50 @@ static DEFINE_MUTEX(dev_pm_qos_mtx); | |||
48 | static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); | 48 | static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); |
49 | 49 | ||
50 | /** | 50 | /** |
51 | * __dev_pm_qos_flags - Check PM QoS flags for a given device. | ||
52 | * @dev: Device to check the PM QoS flags for. | ||
53 | * @mask: Flags to check against. | ||
54 | * | ||
55 | * This routine must be called with dev->power.lock held. | ||
56 | */ | ||
57 | enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask) | ||
58 | { | ||
59 | struct dev_pm_qos *qos = dev->power.qos; | ||
60 | struct pm_qos_flags *pqf; | ||
61 | s32 val; | ||
62 | |||
63 | if (!qos) | ||
64 | return PM_QOS_FLAGS_UNDEFINED; | ||
65 | |||
66 | pqf = &qos->flags; | ||
67 | if (list_empty(&pqf->list)) | ||
68 | return PM_QOS_FLAGS_UNDEFINED; | ||
69 | |||
70 | val = pqf->effective_flags & mask; | ||
71 | if (val) | ||
72 | return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME; | ||
73 | |||
74 | return PM_QOS_FLAGS_NONE; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * dev_pm_qos_flags - Check PM QoS flags for a given device (locked). | ||
79 | * @dev: Device to check the PM QoS flags for. | ||
80 | * @mask: Flags to check against. | ||
81 | */ | ||
82 | enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask) | ||
83 | { | ||
84 | unsigned long irqflags; | ||
85 | enum pm_qos_flags_status ret; | ||
86 | |||
87 | spin_lock_irqsave(&dev->power.lock, irqflags); | ||
88 | ret = __dev_pm_qos_flags(dev, mask); | ||
89 | spin_unlock_irqrestore(&dev->power.lock, irqflags); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | /** | ||
51 | * __dev_pm_qos_read_value - Get PM QoS constraint for a given device. | 95 | * __dev_pm_qos_read_value - Get PM QoS constraint for a given device. |
52 | * @dev: Device to get the PM QoS constraint value for. | 96 | * @dev: Device to get the PM QoS constraint value for. |
53 | * | 97 | * |
@@ -74,30 +118,39 @@ s32 dev_pm_qos_read_value(struct device *dev) | |||
74 | return ret; | 118 | return ret; |
75 | } | 119 | } |
76 | 120 | ||
77 | /* | 121 | /** |
78 | * apply_constraint | 122 | * apply_constraint - Add/modify/remove device PM QoS request. |
79 | * @req: constraint request to apply | 123 | * @req: Constraint request to apply |
80 | * @action: action to perform add/update/remove, of type enum pm_qos_req_action | 124 | * @action: Action to perform (add/update/remove). |
81 | * @value: defines the qos request | 125 | * @value: Value to assign to the QoS request. |
82 | * | 126 | * |
83 | * Internal function to update the constraints list using the PM QoS core | 127 | * Internal function to update the constraints list using the PM QoS core |
84 | * code and if needed call the per-device and the global notification | 128 | * code and if needed call the per-device and the global notification |
85 | * callbacks | 129 | * callbacks |
86 | */ | 130 | */ |
87 | static int apply_constraint(struct dev_pm_qos_request *req, | 131 | static int apply_constraint(struct dev_pm_qos_request *req, |
88 | enum pm_qos_req_action action, int value) | 132 | enum pm_qos_req_action action, s32 value) |
89 | { | 133 | { |
90 | int ret, curr_value; | 134 | struct dev_pm_qos *qos = req->dev->power.qos; |
91 | 135 | int ret; | |
92 | ret = pm_qos_update_target(&req->dev->power.qos->latency, | ||
93 | &req->data.pnode, action, value); | ||
94 | 136 | ||
95 | if (ret) { | 137 | switch(req->type) { |
96 | /* Call the global callbacks if needed */ | 138 | case DEV_PM_QOS_LATENCY: |
97 | curr_value = pm_qos_read_value(&req->dev->power.qos->latency); | 139 | ret = pm_qos_update_target(&qos->latency, &req->data.pnode, |
98 | blocking_notifier_call_chain(&dev_pm_notifiers, | 140 | action, value); |
99 | (unsigned long)curr_value, | 141 | if (ret) { |
100 | req); | 142 | value = pm_qos_read_value(&qos->latency); |
143 | blocking_notifier_call_chain(&dev_pm_notifiers, | ||
144 | (unsigned long)value, | ||
145 | req); | ||
146 | } | ||
147 | break; | ||
148 | case DEV_PM_QOS_FLAGS: | ||
149 | ret = pm_qos_update_flags(&qos->flags, &req->data.flr, | ||
150 | action, value); | ||
151 | break; | ||
152 | default: | ||
153 | ret = -EINVAL; | ||
101 | } | 154 | } |
102 | 155 | ||
103 | return ret; | 156 | return ret; |
@@ -134,6 +187,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) | |||
134 | c->type = PM_QOS_MIN; | 187 | c->type = PM_QOS_MIN; |
135 | c->notifiers = n; | 188 | c->notifiers = n; |
136 | 189 | ||
190 | INIT_LIST_HEAD(&qos->flags.list); | ||
191 | |||
137 | spin_lock_irq(&dev->power.lock); | 192 | spin_lock_irq(&dev->power.lock); |
138 | dev->power.qos = qos; | 193 | dev->power.qos = qos; |
139 | spin_unlock_irq(&dev->power.lock); | 194 | spin_unlock_irq(&dev->power.lock); |
@@ -207,6 +262,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) | |||
207 | * dev_pm_qos_add_request - inserts new qos request into the list | 262 | * dev_pm_qos_add_request - inserts new qos request into the list |
208 | * @dev: target device for the constraint | 263 | * @dev: target device for the constraint |
209 | * @req: pointer to a preallocated handle | 264 | * @req: pointer to a preallocated handle |
265 | * @type: type of the request | ||
210 | * @value: defines the qos request | 266 | * @value: defines the qos request |
211 | * | 267 | * |
212 | * This function inserts a new entry in the device constraints list of | 268 | * This function inserts a new entry in the device constraints list of |
@@ -222,7 +278,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) | |||
222 | * from the system. | 278 | * from the system. |
223 | */ | 279 | */ |
224 | int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, | 280 | int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, |
225 | s32 value) | 281 | enum dev_pm_qos_req_type type, s32 value) |
226 | { | 282 | { |
227 | int ret = 0; | 283 | int ret = 0; |
228 | 284 | ||
@@ -253,8 +309,10 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, | |||
253 | } | 309 | } |
254 | } | 310 | } |
255 | 311 | ||
256 | if (!ret) | 312 | if (!ret) { |
313 | req->type = type; | ||
257 | ret = apply_constraint(req, PM_QOS_ADD_REQ, value); | 314 | ret = apply_constraint(req, PM_QOS_ADD_REQ, value); |
315 | } | ||
258 | 316 | ||
259 | out: | 317 | out: |
260 | mutex_unlock(&dev_pm_qos_mtx); | 318 | mutex_unlock(&dev_pm_qos_mtx); |
@@ -281,6 +339,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); | |||
281 | int dev_pm_qos_update_request(struct dev_pm_qos_request *req, | 339 | int dev_pm_qos_update_request(struct dev_pm_qos_request *req, |
282 | s32 new_value) | 340 | s32 new_value) |
283 | { | 341 | { |
342 | s32 curr_value; | ||
284 | int ret = 0; | 343 | int ret = 0; |
285 | 344 | ||
286 | if (!req) /*guard against callers passing in null */ | 345 | if (!req) /*guard against callers passing in null */ |
@@ -292,15 +351,27 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, | |||
292 | 351 | ||
293 | mutex_lock(&dev_pm_qos_mtx); | 352 | mutex_lock(&dev_pm_qos_mtx); |
294 | 353 | ||
295 | if (req->dev->power.qos) { | 354 | if (!req->dev->power.qos) { |
296 | if (new_value != req->data.pnode.prio) | ||
297 | ret = apply_constraint(req, PM_QOS_UPDATE_REQ, | ||
298 | new_value); | ||
299 | } else { | ||
300 | /* Return if the device has been removed */ | ||
301 | ret = -ENODEV; | 355 | ret = -ENODEV; |
356 | goto out; | ||
302 | } | 357 | } |
303 | 358 | ||
359 | switch(req->type) { | ||
360 | case DEV_PM_QOS_LATENCY: | ||
361 | curr_value = req->data.pnode.prio; | ||
362 | break; | ||
363 | case DEV_PM_QOS_FLAGS: | ||
364 | curr_value = req->data.flr.flags; | ||
365 | break; | ||
366 | default: | ||
367 | ret = -EINVAL; | ||
368 | goto out; | ||
369 | } | ||
370 | |||
371 | if (curr_value != new_value) | ||
372 | ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); | ||
373 | |||
374 | out: | ||
304 | mutex_unlock(&dev_pm_qos_mtx); | 375 | mutex_unlock(&dev_pm_qos_mtx); |
305 | return ret; | 376 | return ret; |
306 | } | 377 | } |
@@ -451,7 +522,8 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, | |||
451 | ancestor = ancestor->parent; | 522 | ancestor = ancestor->parent; |
452 | 523 | ||
453 | if (ancestor) | 524 | if (ancestor) |
454 | error = dev_pm_qos_add_request(ancestor, req, value); | 525 | error = dev_pm_qos_add_request(ancestor, req, |
526 | DEV_PM_QOS_LATENCY, value); | ||
455 | 527 | ||
456 | if (error) | 528 | if (error) |
457 | req->dev = NULL; | 529 | req->dev = NULL; |
@@ -487,7 +559,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) | |||
487 | if (!req) | 559 | if (!req) |
488 | return -ENOMEM; | 560 | return -ENOMEM; |
489 | 561 | ||
490 | ret = dev_pm_qos_add_request(dev, req, value); | 562 | ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value); |
491 | if (ret < 0) | 563 | if (ret < 0) |
492 | return ret; | 564 | return ret; |
493 | 565 | ||
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 4fbfe96e37a1..f48ac5d80bbf 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c | |||
@@ -727,7 +727,9 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr) | |||
727 | 727 | ||
728 | if (!flctl->qos_request) { | 728 | if (!flctl->qos_request) { |
729 | ret = dev_pm_qos_add_request(&flctl->pdev->dev, | 729 | ret = dev_pm_qos_add_request(&flctl->pdev->dev, |
730 | &flctl->pm_qos, 100); | 730 | &flctl->pm_qos, |
731 | DEV_PM_QOS_LATENCY, | ||
732 | 100); | ||
731 | if (ret < 0) | 733 | if (ret < 0) |
732 | dev_err(&flctl->pdev->dev, | 734 | dev_err(&flctl->pdev->dev, |
733 | "PM QoS request failed: %d\n", ret); | 735 | "PM QoS request failed: %d\n", ret); |
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 3b9d14964d2b..3af7d8573c23 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h | |||
@@ -20,6 +20,13 @@ enum { | |||
20 | PM_QOS_NUM_CLASSES, | 20 | PM_QOS_NUM_CLASSES, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | enum pm_qos_flags_status { | ||
24 | PM_QOS_FLAGS_UNDEFINED = -1, | ||
25 | PM_QOS_FLAGS_NONE, | ||
26 | PM_QOS_FLAGS_SOME, | ||
27 | PM_QOS_FLAGS_ALL, | ||
28 | }; | ||
29 | |||
23 | #define PM_QOS_DEFAULT_VALUE -1 | 30 | #define PM_QOS_DEFAULT_VALUE -1 |
24 | 31 | ||
25 | #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) | 32 | #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) |
@@ -38,9 +45,16 @@ struct pm_qos_flags_request { | |||
38 | s32 flags; /* Do not change to 64 bit */ | 45 | s32 flags; /* Do not change to 64 bit */ |
39 | }; | 46 | }; |
40 | 47 | ||
48 | enum dev_pm_qos_req_type { | ||
49 | DEV_PM_QOS_LATENCY = 1, | ||
50 | DEV_PM_QOS_FLAGS, | ||
51 | }; | ||
52 | |||
41 | struct dev_pm_qos_request { | 53 | struct dev_pm_qos_request { |
54 | enum dev_pm_qos_req_type type; | ||
42 | union { | 55 | union { |
43 | struct plist_node pnode; | 56 | struct plist_node pnode; |
57 | struct pm_qos_flags_request flr; | ||
44 | } data; | 58 | } data; |
45 | struct device *dev; | 59 | struct device *dev; |
46 | }; | 60 | }; |
@@ -71,6 +85,7 @@ struct pm_qos_flags { | |||
71 | 85 | ||
72 | struct dev_pm_qos { | 86 | struct dev_pm_qos { |
73 | struct pm_qos_constraints latency; | 87 | struct pm_qos_constraints latency; |
88 | struct pm_qos_flags flags; | ||
74 | }; | 89 | }; |
75 | 90 | ||
76 | /* Action requested to pm_qos_update_target */ | 91 | /* Action requested to pm_qos_update_target */ |
@@ -105,10 +120,12 @@ int pm_qos_request_active(struct pm_qos_request *req); | |||
105 | s32 pm_qos_read_value(struct pm_qos_constraints *c); | 120 | s32 pm_qos_read_value(struct pm_qos_constraints *c); |
106 | 121 | ||
107 | #ifdef CONFIG_PM | 122 | #ifdef CONFIG_PM |
123 | enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask); | ||
124 | enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask); | ||
108 | s32 __dev_pm_qos_read_value(struct device *dev); | 125 | s32 __dev_pm_qos_read_value(struct device *dev); |
109 | s32 dev_pm_qos_read_value(struct device *dev); | 126 | s32 dev_pm_qos_read_value(struct device *dev); |
110 | int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, | 127 | int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, |
111 | s32 value); | 128 | enum dev_pm_qos_req_type type, s32 value); |
112 | int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value); | 129 | int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value); |
113 | int dev_pm_qos_remove_request(struct dev_pm_qos_request *req); | 130 | int dev_pm_qos_remove_request(struct dev_pm_qos_request *req); |
114 | int dev_pm_qos_add_notifier(struct device *dev, | 131 | int dev_pm_qos_add_notifier(struct device *dev, |
@@ -122,12 +139,19 @@ void dev_pm_qos_constraints_destroy(struct device *dev); | |||
122 | int dev_pm_qos_add_ancestor_request(struct device *dev, | 139 | int dev_pm_qos_add_ancestor_request(struct device *dev, |
123 | struct dev_pm_qos_request *req, s32 value); | 140 | struct dev_pm_qos_request *req, s32 value); |
124 | #else | 141 | #else |
142 | static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, | ||
143 | s32 mask) | ||
144 | { return PM_QOS_FLAGS_UNDEFINED; } | ||
145 | static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, | ||
146 | s32 mask) | ||
147 | { return PM_QOS_FLAGS_UNDEFINED; } | ||
125 | static inline s32 __dev_pm_qos_read_value(struct device *dev) | 148 | static inline s32 __dev_pm_qos_read_value(struct device *dev) |
126 | { return 0; } | 149 | { return 0; } |
127 | static inline s32 dev_pm_qos_read_value(struct device *dev) | 150 | static inline s32 dev_pm_qos_read_value(struct device *dev) |
128 | { return 0; } | 151 | { return 0; } |
129 | static inline int dev_pm_qos_add_request(struct device *dev, | 152 | static inline int dev_pm_qos_add_request(struct device *dev, |
130 | struct dev_pm_qos_request *req, | 153 | struct dev_pm_qos_request *req, |
154 | enum dev_pm_qos_req_type type, | ||
131 | s32 value) | 155 | s32 value) |
132 | { return 0; } | 156 | { return 0; } |
133 | static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req, | 157 | static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req, |