diff options
author | Jean Pihet <j-pihet@ti.com> | 2011-08-25 09:35:34 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-08-25 09:35:34 -0400 |
commit | abe98ec2d86279fe821c9051003a0abc43444f15 (patch) | |
tree | 014f3ce775504218121194f54e2ba5b88c08c777 /kernel/power/qos.c | |
parent | 4e1779baaa542c83b459b0a56585e0c1a04c7782 (diff) |
PM QoS: Generalize and export constraints management code
In preparation for the per-device constratins support:
- rename update_target to pm_qos_update_target
- generalize and export pm_qos_update_target for usage by the upcoming
per-device latency constraints framework:
* operate on struct pm_qos_constraints for constraints management,
* introduce an 'action' parameter for constraints add/update/remove,
* the return value indicates if the aggregated constraint value has
changed,
- update the internal code to operate on struct pm_qos_constraints
- add a NULL pointer check in the API functions
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'kernel/power/qos.c')
-rw-r--r-- | kernel/power/qos.c | 123 |
1 files changed, 67 insertions, 56 deletions
diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 4a35fe50b777..7c7cd181cabe 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c | |||
@@ -122,17 +122,17 @@ static const struct file_operations pm_qos_power_fops = { | |||
122 | }; | 122 | }; |
123 | 123 | ||
124 | /* unlocked internal variant */ | 124 | /* unlocked internal variant */ |
125 | static inline int pm_qos_get_value(struct pm_qos_object *o) | 125 | static inline int pm_qos_get_value(struct pm_qos_constraints *c) |
126 | { | 126 | { |
127 | if (plist_head_empty(&o->constraints->list)) | 127 | if (plist_head_empty(&c->list)) |
128 | return o->constraints->default_value; | 128 | return c->default_value; |
129 | 129 | ||
130 | switch (o->constraints->type) { | 130 | switch (c->type) { |
131 | case PM_QOS_MIN: | 131 | case PM_QOS_MIN: |
132 | return plist_first(&o->constraints->list)->prio; | 132 | return plist_first(&c->list)->prio; |
133 | 133 | ||
134 | case PM_QOS_MAX: | 134 | case PM_QOS_MAX: |
135 | return plist_last(&o->constraints->list)->prio; | 135 | return plist_last(&c->list)->prio; |
136 | 136 | ||
137 | default: | 137 | default: |
138 | /* runtime check for not using enum */ | 138 | /* runtime check for not using enum */ |
@@ -140,47 +140,73 @@ static inline int pm_qos_get_value(struct pm_qos_object *o) | |||
140 | } | 140 | } |
141 | } | 141 | } |
142 | 142 | ||
143 | static inline s32 pm_qos_read_value(struct pm_qos_object *o) | 143 | static inline s32 pm_qos_read_value(struct pm_qos_constraints *c) |
144 | { | 144 | { |
145 | return o->constraints->target_value; | 145 | return c->target_value; |
146 | } | 146 | } |
147 | 147 | ||
148 | static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value) | 148 | static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value) |
149 | { | 149 | { |
150 | o->constraints->target_value = value; | 150 | c->target_value = value; |
151 | } | 151 | } |
152 | 152 | ||
153 | static void update_target(struct pm_qos_object *o, struct plist_node *node, | 153 | /** |
154 | int del, int value) | 154 | * pm_qos_update_target - manages the constraints list and calls the notifiers |
155 | * if needed | ||
156 | * @c: constraints data struct | ||
157 | * @node: request to add to the list, to update or to remove | ||
158 | * @action: action to take on the constraints list | ||
159 | * @value: value of the request to add or update | ||
160 | * | ||
161 | * This function returns 1 if the aggregated constraint value has changed, 0 | ||
162 | * otherwise. | ||
163 | */ | ||
164 | int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, | ||
165 | enum pm_qos_req_action action, int value) | ||
155 | { | 166 | { |
156 | unsigned long flags; | 167 | unsigned long flags; |
157 | int prev_value, curr_value; | 168 | int prev_value, curr_value, new_value; |
158 | 169 | ||
159 | spin_lock_irqsave(&pm_qos_lock, flags); | 170 | spin_lock_irqsave(&pm_qos_lock, flags); |
160 | prev_value = pm_qos_get_value(o); | 171 | prev_value = pm_qos_get_value(c); |
161 | /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */ | 172 | if (value == PM_QOS_DEFAULT_VALUE) |
162 | if (value != PM_QOS_DEFAULT_VALUE) { | 173 | new_value = c->default_value; |
174 | else | ||
175 | new_value = value; | ||
176 | |||
177 | switch (action) { | ||
178 | case PM_QOS_REMOVE_REQ: | ||
179 | plist_del(node, &c->list); | ||
180 | break; | ||
181 | case PM_QOS_UPDATE_REQ: | ||
163 | /* | 182 | /* |
164 | * to change the list, we atomically remove, reinit | 183 | * to change the list, we atomically remove, reinit |
165 | * with new value and add, then see if the extremal | 184 | * with new value and add, then see if the extremal |
166 | * changed | 185 | * changed |
167 | */ | 186 | */ |
168 | plist_del(node, &o->constraints->list); | 187 | plist_del(node, &c->list); |
169 | plist_node_init(node, value); | 188 | case PM_QOS_ADD_REQ: |
170 | plist_add(node, &o->constraints->list); | 189 | plist_node_init(node, new_value); |
171 | } else if (del) { | 190 | plist_add(node, &c->list); |
172 | plist_del(node, &o->constraints->list); | 191 | break; |
173 | } else { | 192 | default: |
174 | plist_add(node, &o->constraints->list); | 193 | /* no action */ |
194 | ; | ||
175 | } | 195 | } |
176 | curr_value = pm_qos_get_value(o); | 196 | |
177 | pm_qos_set_value(o, curr_value); | 197 | curr_value = pm_qos_get_value(c); |
198 | pm_qos_set_value(c, curr_value); | ||
199 | |||
178 | spin_unlock_irqrestore(&pm_qos_lock, flags); | 200 | spin_unlock_irqrestore(&pm_qos_lock, flags); |
179 | 201 | ||
180 | if (prev_value != curr_value) | 202 | if (prev_value != curr_value) { |
181 | blocking_notifier_call_chain(o->constraints->notifiers, | 203 | blocking_notifier_call_chain(c->notifiers, |
182 | (unsigned long)curr_value, | 204 | (unsigned long)curr_value, |
183 | NULL); | 205 | NULL); |
206 | return 1; | ||
207 | } else { | ||
208 | return 0; | ||
209 | } | ||
184 | } | 210 | } |
185 | 211 | ||
186 | /** | 212 | /** |
@@ -191,7 +217,7 @@ static void update_target(struct pm_qos_object *o, struct plist_node *node, | |||
191 | */ | 217 | */ |
192 | int pm_qos_request(int pm_qos_class) | 218 | int pm_qos_request(int pm_qos_class) |
193 | { | 219 | { |
194 | return pm_qos_read_value(pm_qos_array[pm_qos_class]); | 220 | return pm_qos_read_value(pm_qos_array[pm_qos_class]->constraints); |
195 | } | 221 | } |
196 | EXPORT_SYMBOL_GPL(pm_qos_request); | 222 | EXPORT_SYMBOL_GPL(pm_qos_request); |
197 | 223 | ||
@@ -217,20 +243,16 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active); | |||
217 | void pm_qos_add_request(struct pm_qos_request *req, | 243 | void pm_qos_add_request(struct pm_qos_request *req, |
218 | int pm_qos_class, s32 value) | 244 | int pm_qos_class, s32 value) |
219 | { | 245 | { |
220 | struct pm_qos_object *o = pm_qos_array[pm_qos_class]; | 246 | if (!req) /*guard against callers passing in null */ |
221 | int new_value; | 247 | return; |
222 | 248 | ||
223 | if (pm_qos_request_active(req)) { | 249 | if (pm_qos_request_active(req)) { |
224 | WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n"); | 250 | WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n"); |
225 | return; | 251 | return; |
226 | } | 252 | } |
227 | if (value == PM_QOS_DEFAULT_VALUE) | ||
228 | new_value = o->constraints->default_value; | ||
229 | else | ||
230 | new_value = value; | ||
231 | plist_node_init(&req->node, new_value); | ||
232 | req->pm_qos_class = pm_qos_class; | 253 | req->pm_qos_class = pm_qos_class; |
233 | update_target(o, &req->node, 0, PM_QOS_DEFAULT_VALUE); | 254 | pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints, |
255 | &req->node, PM_QOS_ADD_REQ, value); | ||
234 | } | 256 | } |
235 | EXPORT_SYMBOL_GPL(pm_qos_add_request); | 257 | EXPORT_SYMBOL_GPL(pm_qos_add_request); |
236 | 258 | ||
@@ -247,9 +269,6 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request); | |||
247 | void pm_qos_update_request(struct pm_qos_request *req, | 269 | void pm_qos_update_request(struct pm_qos_request *req, |
248 | s32 new_value) | 270 | s32 new_value) |
249 | { | 271 | { |
250 | s32 temp; | ||
251 | struct pm_qos_object *o; | ||
252 | |||
253 | if (!req) /*guard against callers passing in null */ | 272 | if (!req) /*guard against callers passing in null */ |
254 | return; | 273 | return; |
255 | 274 | ||
@@ -258,15 +277,10 @@ void pm_qos_update_request(struct pm_qos_request *req, | |||
258 | return; | 277 | return; |
259 | } | 278 | } |
260 | 279 | ||
261 | o = pm_qos_array[req->pm_qos_class]; | 280 | if (new_value != req->node.prio) |
262 | 281 | pm_qos_update_target( | |
263 | if (new_value == PM_QOS_DEFAULT_VALUE) | 282 | pm_qos_array[req->pm_qos_class]->constraints, |
264 | temp = o->constraints->default_value; | 283 | &req->node, PM_QOS_UPDATE_REQ, new_value); |
265 | else | ||
266 | temp = new_value; | ||
267 | |||
268 | if (temp != req->node.prio) | ||
269 | update_target(o, &req->node, 0, temp); | ||
270 | } | 284 | } |
271 | EXPORT_SYMBOL_GPL(pm_qos_update_request); | 285 | EXPORT_SYMBOL_GPL(pm_qos_update_request); |
272 | 286 | ||
@@ -280,9 +294,7 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request); | |||
280 | */ | 294 | */ |
281 | void pm_qos_remove_request(struct pm_qos_request *req) | 295 | void pm_qos_remove_request(struct pm_qos_request *req) |
282 | { | 296 | { |
283 | struct pm_qos_object *o; | 297 | if (!req) /*guard against callers passing in null */ |
284 | |||
285 | if (req == NULL) | ||
286 | return; | 298 | return; |
287 | /* silent return to keep pcm code cleaner */ | 299 | /* silent return to keep pcm code cleaner */ |
288 | 300 | ||
@@ -291,8 +303,9 @@ void pm_qos_remove_request(struct pm_qos_request *req) | |||
291 | return; | 303 | return; |
292 | } | 304 | } |
293 | 305 | ||
294 | o = pm_qos_array[req->pm_qos_class]; | 306 | pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints, |
295 | update_target(o, &req->node, 1, PM_QOS_DEFAULT_VALUE); | 307 | &req->node, PM_QOS_REMOVE_REQ, |
308 | PM_QOS_DEFAULT_VALUE); | ||
296 | memset(req, 0, sizeof(*req)); | 309 | memset(req, 0, sizeof(*req)); |
297 | } | 310 | } |
298 | EXPORT_SYMBOL_GPL(pm_qos_remove_request); | 311 | EXPORT_SYMBOL_GPL(pm_qos_remove_request); |
@@ -396,7 +409,6 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf, | |||
396 | { | 409 | { |
397 | s32 value; | 410 | s32 value; |
398 | unsigned long flags; | 411 | unsigned long flags; |
399 | struct pm_qos_object *o; | ||
400 | struct pm_qos_request *req = filp->private_data; | 412 | struct pm_qos_request *req = filp->private_data; |
401 | 413 | ||
402 | if (!req) | 414 | if (!req) |
@@ -404,9 +416,8 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf, | |||
404 | if (!pm_qos_request_active(req)) | 416 | if (!pm_qos_request_active(req)) |
405 | return -EINVAL; | 417 | return -EINVAL; |
406 | 418 | ||
407 | o = pm_qos_array[req->pm_qos_class]; | ||
408 | spin_lock_irqsave(&pm_qos_lock, flags); | 419 | spin_lock_irqsave(&pm_qos_lock, flags); |
409 | value = pm_qos_get_value(o); | 420 | value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints); |
410 | spin_unlock_irqrestore(&pm_qos_lock, flags); | 421 | spin_unlock_irqrestore(&pm_qos_lock, flags); |
411 | 422 | ||
412 | return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32)); | 423 | return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32)); |