blob: 71671c42ef457e3486f13b770114a0c09459a708 [file] [log] [blame]
Jean Pihet91ff4cb2011-08-25 15:35:41 +02001/*
2 * Devices PM QoS constraints management
3 *
4 * Copyright (C) 2011 Texas Instruments, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 *
11 * This module exposes the interface to kernel space for specifying
12 * per-device PM QoS dependencies. It provides infrastructure for registration
13 * of:
14 *
15 * Dependents on a QoS value : register requests
16 * Watchers of QoS value : get notified when target QoS value changes
17 *
18 * This QoS design is best effort based. Dependents register their QoS needs.
19 * Watchers register to keep track of the current QoS needs of the system.
Jean Pihetb66213c2011-08-25 15:35:47 +020020 * Watchers can register different types of notification callbacks:
21 * . a per-device notification callback using the dev_pm_qos_*_notifier API.
22 * The notification chain data is stored in the per-device constraint
23 * data struct.
24 * . a system-wide notification callback using the dev_pm_qos_*_global_notifier
25 * API. The notification chain data is stored in a static variable.
Jean Pihet91ff4cb2011-08-25 15:35:41 +020026 *
27 * Note about the per-device constraint data struct allocation:
28 * . The per-device constraints data struct ptr is tored into the device
29 * dev_pm_info.
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.
32 * . The data is later free'd when the device is removed from the system.
Jean Pihet91ff4cb2011-08-25 15:35:41 +020033 * . A global mutex protects the constraints users from the data being
34 * allocated and free'd.
35 */
36
37#include <linux/pm_qos.h>
38#include <linux/spinlock.h>
39#include <linux/slab.h>
40#include <linux/device.h>
41#include <linux/mutex.h>
Paul Gortmaker1b6bc322011-05-27 07:12:15 -040042#include <linux/export.h>
Rafael J. Wysockie39473d2012-10-24 02:08:18 +020043#include <linux/pm_runtime.h>
Rafael J. Wysocki37530f22013-03-04 14:22:57 +010044#include <linux/err.h>
Jean Pihet91ff4cb2011-08-25 15:35:41 +020045
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +010046#include "power.h"
Jean Pihet91ff4cb2011-08-25 15:35:41 +020047
48static DEFINE_MUTEX(dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +020049static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020050
Jean Pihetb66213c2011-08-25 15:35:47 +020051static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
52
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020053/**
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +020054 * __dev_pm_qos_flags - Check PM QoS flags for a given device.
55 * @dev: Device to check the PM QoS flags for.
56 * @mask: Flags to check against.
57 *
58 * This routine must be called with dev->power.lock held.
59 */
60enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
61{
62 struct dev_pm_qos *qos = dev->power.qos;
63 struct pm_qos_flags *pqf;
64 s32 val;
65
Rafael J. Wysocki37530f22013-03-04 14:22:57 +010066 if (IS_ERR_OR_NULL(qos))
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +020067 return PM_QOS_FLAGS_UNDEFINED;
68
69 pqf = &qos->flags;
70 if (list_empty(&pqf->list))
71 return PM_QOS_FLAGS_UNDEFINED;
72
73 val = pqf->effective_flags & mask;
74 if (val)
75 return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;
76
77 return PM_QOS_FLAGS_NONE;
78}
79
80/**
81 * dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
82 * @dev: Device to check the PM QoS flags for.
83 * @mask: Flags to check against.
84 */
85enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
86{
87 unsigned long irqflags;
88 enum pm_qos_flags_status ret;
89
90 spin_lock_irqsave(&dev->power.lock, irqflags);
91 ret = __dev_pm_qos_flags(dev, mask);
92 spin_unlock_irqrestore(&dev->power.lock, irqflags);
93
94 return ret;
95}
Lan Tianyu6802771b2013-01-23 04:26:28 +080096EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +020097
98/**
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +010099 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
100 * @dev: Device to get the PM QoS constraint value for.
101 *
102 * This routine must be called with dev->power.lock held.
103 */
104s32 __dev_pm_qos_read_value(struct device *dev)
105{
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100106 return IS_ERR_OR_NULL(dev->power.qos) ?
107 0 : pm_qos_read_value(&dev->power.qos->latency);
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100108}
109
110/**
111 * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200112 * @dev: Device to get the PM QoS constraint value for.
113 */
114s32 dev_pm_qos_read_value(struct device *dev)
115{
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200116 unsigned long flags;
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100117 s32 ret;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200118
119 spin_lock_irqsave(&dev->power.lock, flags);
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100120 ret = __dev_pm_qos_read_value(dev);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200121 spin_unlock_irqrestore(&dev->power.lock, flags);
122
123 return ret;
124}
125
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200126/**
127 * apply_constraint - Add/modify/remove device PM QoS request.
128 * @req: Constraint request to apply
129 * @action: Action to perform (add/update/remove).
130 * @value: Value to assign to the QoS request.
Jean Pihetb66213c2011-08-25 15:35:47 +0200131 *
132 * Internal function to update the constraints list using the PM QoS core
133 * code and if needed call the per-device and the global notification
134 * callbacks
135 */
136static int apply_constraint(struct dev_pm_qos_request *req,
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200137 enum pm_qos_req_action action, s32 value)
Jean Pihetb66213c2011-08-25 15:35:47 +0200138{
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200139 struct dev_pm_qos *qos = req->dev->power.qos;
140 int ret;
Jean Pihetb66213c2011-08-25 15:35:47 +0200141
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200142 switch(req->type) {
143 case DEV_PM_QOS_LATENCY:
144 ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
145 action, value);
146 if (ret) {
147 value = pm_qos_read_value(&qos->latency);
148 blocking_notifier_call_chain(&dev_pm_notifiers,
149 (unsigned long)value,
150 req);
151 }
152 break;
153 case DEV_PM_QOS_FLAGS:
154 ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
155 action, value);
156 break;
157 default:
158 ret = -EINVAL;
Jean Pihetb66213c2011-08-25 15:35:47 +0200159 }
160
161 return ret;
162}
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200163
164/*
165 * dev_pm_qos_constraints_allocate
166 * @dev: device to allocate data for
167 *
168 * Called at the first call to add_request, for constraint data allocation
169 * Must be called with the dev_pm_qos_mtx mutex held
170 */
171static int dev_pm_qos_constraints_allocate(struct device *dev)
172{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200173 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200174 struct pm_qos_constraints *c;
175 struct blocking_notifier_head *n;
176
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200177 qos = kzalloc(sizeof(*qos), GFP_KERNEL);
178 if (!qos)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200179 return -ENOMEM;
180
181 n = kzalloc(sizeof(*n), GFP_KERNEL);
182 if (!n) {
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200183 kfree(qos);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200184 return -ENOMEM;
185 }
186 BLOCKING_INIT_NOTIFIER_HEAD(n);
187
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200188 c = &qos->latency;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200189 plist_head_init(&c->list);
190 c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
191 c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
192 c->type = PM_QOS_MIN;
193 c->notifiers = n;
194
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200195 INIT_LIST_HEAD(&qos->flags.list);
196
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200197 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200198 dev->power.qos = qos;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200199 spin_unlock_irq(&dev->power.lock);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200200
201 return 0;
202}
203
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100204static void __dev_pm_qos_hide_latency_limit(struct device *dev);
205static void __dev_pm_qos_hide_flags(struct device *dev);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200206
207/**
208 * dev_pm_qos_constraints_destroy
209 * @dev: target device
210 *
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200211 * Called from the device PM subsystem on device removal under device_pm_lock().
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200212 */
213void dev_pm_qos_constraints_destroy(struct device *dev)
214{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200215 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200216 struct dev_pm_qos_request *req, *tmp;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200217 struct pm_qos_constraints *c;
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100218 struct pm_qos_flags *f;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200219
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200220 mutex_lock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100221
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100222 /*
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100223 * If the device's PM QoS resume latency limit or PM QoS flags have been
224 * exposed to user space, they have to be hidden at this point.
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100225 */
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200226 pm_qos_sysfs_remove_latency(dev);
227 pm_qos_sysfs_remove_flags(dev);
228
229 mutex_lock(&dev_pm_qos_mtx);
230
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100231 __dev_pm_qos_hide_latency_limit(dev);
232 __dev_pm_qos_hide_flags(dev);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100233
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200234 qos = dev->power.qos;
235 if (!qos)
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200236 goto out;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200237
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100238 /* Flush the constraints lists for the device. */
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200239 c = &qos->latency;
Rafael J. Wysocki021c8702012-10-23 01:09:00 +0200240 plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200241 /*
242 * Update constraints list and call the notification
243 * callbacks if needed
244 */
245 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
246 memset(req, 0, sizeof(*req));
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200247 }
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100248 f = &qos->flags;
249 list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
250 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
251 memset(req, 0, sizeof(*req));
252 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200253
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200254 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100255 dev->power.qos = ERR_PTR(-ENODEV);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200256 spin_unlock_irq(&dev->power.lock);
257
258 kfree(c->notifiers);
Lan,Tianyu9eaee2c2012-11-01 22:45:30 +0100259 kfree(qos);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200260
261 out:
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200262 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200263
264 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200265}
266
267/**
268 * dev_pm_qos_add_request - inserts new qos request into the list
269 * @dev: target device for the constraint
270 * @req: pointer to a preallocated handle
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200271 * @type: type of the request
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200272 * @value: defines the qos request
273 *
274 * This function inserts a new entry in the device constraints list of
275 * requested qos performance characteristics. It recomputes the aggregate
276 * QoS expectations of parameters and initializes the dev_pm_qos_request
277 * handle. Caller needs to save this handle for later use in updates and
278 * removal.
279 *
280 * Returns 1 if the aggregated constraint value has changed,
281 * 0 if the aggregated constraint value has not changed,
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200282 * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
283 * to allocate for data structures, -ENODEV if the device has just been removed
284 * from the system.
Rafael J. Wysocki436ede82012-11-02 13:10:09 +0100285 *
286 * Callers should ensure that the target device is not RPM_SUSPENDED before
287 * using this function for requests of type DEV_PM_QOS_FLAGS.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200288 */
289int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200290 enum dev_pm_qos_req_type type, s32 value)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200291{
292 int ret = 0;
293
294 if (!dev || !req) /*guard against callers passing in null */
295 return -EINVAL;
296
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100297 if (WARN(dev_pm_qos_request_active(req),
298 "%s() called for already added request\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200299 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200300
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200301 mutex_lock(&dev_pm_qos_mtx);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200302
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100303 if (IS_ERR(dev->power.qos))
304 ret = -ENODEV;
305 else if (!dev->power.qos)
306 ret = dev_pm_qos_constraints_allocate(dev);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200307
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200308 if (!ret) {
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100309 req->dev = dev;
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200310 req->type = type;
Jean Pihetb66213c2011-08-25 15:35:47 +0200311 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200312 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200313
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200314 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200315
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200316 return ret;
317}
318EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
319
320/**
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200321 * __dev_pm_qos_update_request - Modify an existing device PM QoS request.
322 * @req : PM QoS request to modify.
323 * @new_value: New value to request.
324 */
325static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
326 s32 new_value)
327{
328 s32 curr_value;
329 int ret = 0;
330
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100331 if (!req) /*guard against callers passing in null */
332 return -EINVAL;
333
334 if (WARN(!dev_pm_qos_request_active(req),
335 "%s() called for unknown object\n", __func__))
336 return -EINVAL;
337
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100338 if (IS_ERR_OR_NULL(req->dev->power.qos))
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200339 return -ENODEV;
340
341 switch(req->type) {
342 case DEV_PM_QOS_LATENCY:
343 curr_value = req->data.pnode.prio;
344 break;
345 case DEV_PM_QOS_FLAGS:
346 curr_value = req->data.flr.flags;
347 break;
348 default:
349 return -EINVAL;
350 }
351
352 if (curr_value != new_value)
353 ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
354
355 return ret;
356}
357
358/**
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200359 * dev_pm_qos_update_request - modifies an existing qos request
360 * @req : handle to list element holding a dev_pm_qos request to use
361 * @new_value: defines the qos request
362 *
363 * Updates an existing dev PM qos request along with updating the
364 * target value.
365 *
366 * Attempts are made to make this code callable on hot code paths.
367 *
368 * Returns 1 if the aggregated constraint value has changed,
369 * 0 if the aggregated constraint value has not changed,
370 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
371 * removed from the system
Rafael J. Wysocki436ede82012-11-02 13:10:09 +0100372 *
373 * Callers should ensure that the target device is not RPM_SUSPENDED before
374 * using this function for requests of type DEV_PM_QOS_FLAGS.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200375 */
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200376int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200377{
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200378 int ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200379
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100380 mutex_lock(&dev_pm_qos_mtx);
381 ret = __dev_pm_qos_update_request(req, new_value);
382 mutex_unlock(&dev_pm_qos_mtx);
383 return ret;
384}
385EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
386
387static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
388{
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100389 int ret;
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100390
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200391 if (!req) /*guard against callers passing in null */
392 return -EINVAL;
393
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100394 if (WARN(!dev_pm_qos_request_active(req),
395 "%s() called for unknown object\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200396 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200397
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100398 if (IS_ERR_OR_NULL(req->dev->power.qos))
399 return -ENODEV;
400
401 ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
402 memset(req, 0, sizeof(*req));
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200403 return ret;
404}
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200405
406/**
407 * dev_pm_qos_remove_request - modifies an existing qos request
408 * @req: handle to request list element
409 *
410 * Will remove pm qos request from the list of constraints and
411 * recompute the current target value. Call this on slow code paths.
412 *
413 * Returns 1 if the aggregated constraint value has changed,
414 * 0 if the aggregated constraint value has not changed,
415 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
416 * removed from the system
Rafael J. Wysocki436ede82012-11-02 13:10:09 +0100417 *
418 * Callers should ensure that the target device is not RPM_SUSPENDED before
419 * using this function for requests of type DEV_PM_QOS_FLAGS.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200420 */
421int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
422{
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100423 int ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200424
425 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100426 ret = __dev_pm_qos_remove_request(req);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200427 mutex_unlock(&dev_pm_qos_mtx);
428 return ret;
429}
430EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
431
432/**
433 * dev_pm_qos_add_notifier - sets notification entry for changes to target value
434 * of per-device PM QoS constraints
435 *
436 * @dev: target device for the constraint
437 * @notifier: notifier block managed by caller.
438 *
439 * Will register the notifier into a notification chain that gets called
440 * upon changes to the target value for the device.
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200441 *
442 * If the device's constraints object doesn't exist when this routine is called,
443 * it will be created (or error code will be returned if that fails).
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200444 */
445int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
446{
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200447 int ret = 0;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200448
449 mutex_lock(&dev_pm_qos_mtx);
450
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100451 if (IS_ERR(dev->power.qos))
452 ret = -ENODEV;
453 else if (!dev->power.qos)
454 ret = dev_pm_qos_constraints_allocate(dev);
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200455
456 if (!ret)
457 ret = blocking_notifier_chain_register(
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200458 dev->power.qos->latency.notifiers, notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200459
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200460 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200461 return ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200462}
463EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
464
465/**
466 * dev_pm_qos_remove_notifier - deletes notification for changes to target value
467 * of per-device PM QoS constraints
468 *
469 * @dev: target device for the constraint
470 * @notifier: notifier block to be removed.
471 *
472 * Will remove the notifier from the notification chain that gets called
473 * upon changes to the target value.
474 */
475int dev_pm_qos_remove_notifier(struct device *dev,
476 struct notifier_block *notifier)
477{
478 int retval = 0;
479
480 mutex_lock(&dev_pm_qos_mtx);
481
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200482 /* Silently return if the constraints object is not present. */
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100483 if (!IS_ERR_OR_NULL(dev->power.qos))
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200484 retval = blocking_notifier_chain_unregister(
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200485 dev->power.qos->latency.notifiers,
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200486 notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200487
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200488 mutex_unlock(&dev_pm_qos_mtx);
489 return retval;
490}
491EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
Jean Pihetb66213c2011-08-25 15:35:47 +0200492
493/**
494 * dev_pm_qos_add_global_notifier - sets notification entry for changes to
495 * target value of the PM QoS constraints for any device
496 *
497 * @notifier: notifier block managed by caller.
498 *
499 * Will register the notifier into a notification chain that gets called
500 * upon changes to the target value for any device.
501 */
502int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
503{
504 return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
505}
506EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
507
508/**
509 * dev_pm_qos_remove_global_notifier - deletes notification for changes to
510 * target value of PM QoS constraints for any device
511 *
512 * @notifier: notifier block to be removed.
513 *
514 * Will remove the notifier from the notification chain that gets called
515 * upon changes to the target value for any device.
516 */
517int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
518{
519 return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
520}
521EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100522
523/**
524 * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
525 * @dev: Device whose ancestor to add the request for.
526 * @req: Pointer to the preallocated handle.
527 * @value: Constraint latency value.
528 */
529int dev_pm_qos_add_ancestor_request(struct device *dev,
530 struct dev_pm_qos_request *req, s32 value)
531{
532 struct device *ancestor = dev->parent;
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100533 int ret = -ENODEV;
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100534
535 while (ancestor && !ancestor->power.ignore_children)
536 ancestor = ancestor->parent;
537
538 if (ancestor)
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100539 ret = dev_pm_qos_add_request(ancestor, req,
540 DEV_PM_QOS_LATENCY, value);
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100541
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100542 if (ret < 0)
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100543 req->dev = NULL;
544
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100545 return ret;
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100546}
547EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100548
549#ifdef CONFIG_PM_RUNTIME
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200550static void __dev_pm_qos_drop_user_request(struct device *dev,
551 enum dev_pm_qos_req_type type)
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100552{
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100553 struct dev_pm_qos_request *req = NULL;
554
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200555 switch(type) {
556 case DEV_PM_QOS_LATENCY:
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100557 req = dev->power.qos->latency_req;
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200558 dev->power.qos->latency_req = NULL;
559 break;
560 case DEV_PM_QOS_FLAGS:
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100561 req = dev->power.qos->flags_req;
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200562 dev->power.qos->flags_req = NULL;
563 break;
564 }
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100565 __dev_pm_qos_remove_request(req);
566 kfree(req);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100567}
568
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200569static void dev_pm_qos_drop_user_request(struct device *dev,
570 enum dev_pm_qos_req_type type)
571{
572 mutex_lock(&dev_pm_qos_mtx);
573 __dev_pm_qos_drop_user_request(dev, type);
574 mutex_unlock(&dev_pm_qos_mtx);
575}
576
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100577/**
578 * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
579 * @dev: Device whose PM QoS latency limit is to be exposed to user space.
580 * @value: Initial value of the latency limit.
581 */
582int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
583{
584 struct dev_pm_qos_request *req;
585 int ret;
586
587 if (!device_is_registered(dev) || value < 0)
588 return -EINVAL;
589
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100590 req = kzalloc(sizeof(*req), GFP_KERNEL);
591 if (!req)
592 return -ENOMEM;
593
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200594 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100595 if (ret < 0) {
596 kfree(req);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100597 return ret;
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100598 }
599
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200600 mutex_lock(&dev_pm_qos_sysfs_mtx);
601
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100602 mutex_lock(&dev_pm_qos_mtx);
603
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100604 if (IS_ERR_OR_NULL(dev->power.qos))
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100605 ret = -ENODEV;
606 else if (dev->power.qos->latency_req)
607 ret = -EEXIST;
608
609 if (ret < 0) {
610 __dev_pm_qos_remove_request(req);
611 kfree(req);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200612 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100613 goto out;
614 }
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200615 dev->power.qos->latency_req = req;
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200616
617 mutex_unlock(&dev_pm_qos_mtx);
618
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200619 ret = pm_qos_sysfs_add_latency(dev);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100620 if (ret)
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200621 dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100622
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100623 out:
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200624 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100625 return ret;
626}
627EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
628
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100629static void __dev_pm_qos_hide_latency_limit(struct device *dev)
630{
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200631 if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100632 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100633}
634
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100635/**
636 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
637 * @dev: Device whose PM QoS latency limit is to be hidden from user space.
638 */
639void dev_pm_qos_hide_latency_limit(struct device *dev)
640{
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200641 mutex_lock(&dev_pm_qos_sysfs_mtx);
642
643 pm_qos_sysfs_remove_latency(dev);
644
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100645 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100646 __dev_pm_qos_hide_latency_limit(dev);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100647 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200648
649 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100650}
651EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200652
653/**
654 * dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space.
655 * @dev: Device whose PM QoS flags are to be exposed to user space.
656 * @val: Initial values of the flags.
657 */
658int dev_pm_qos_expose_flags(struct device *dev, s32 val)
659{
660 struct dev_pm_qos_request *req;
661 int ret;
662
663 if (!device_is_registered(dev))
664 return -EINVAL;
665
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200666 req = kzalloc(sizeof(*req), GFP_KERNEL);
667 if (!req)
668 return -ENOMEM;
669
670 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100671 if (ret < 0) {
672 kfree(req);
673 return ret;
674 }
675
676 pm_runtime_get_sync(dev);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200677 mutex_lock(&dev_pm_qos_sysfs_mtx);
678
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100679 mutex_lock(&dev_pm_qos_mtx);
680
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100681 if (IS_ERR_OR_NULL(dev->power.qos))
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100682 ret = -ENODEV;
683 else if (dev->power.qos->flags_req)
684 ret = -EEXIST;
685
686 if (ret < 0) {
687 __dev_pm_qos_remove_request(req);
688 kfree(req);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200689 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100690 goto out;
691 }
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200692 dev->power.qos->flags_req = req;
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200693
694 mutex_unlock(&dev_pm_qos_mtx);
695
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200696 ret = pm_qos_sysfs_add_flags(dev);
697 if (ret)
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200698 dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200699
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100700 out:
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200701 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Lan Tianyu7e4d6842012-11-08 11:14:08 +0800702 pm_runtime_put(dev);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200703 return ret;
704}
705EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
706
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100707static void __dev_pm_qos_hide_flags(struct device *dev)
708{
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200709 if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100710 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100711}
712
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200713/**
714 * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space.
715 * @dev: Device whose PM QoS flags are to be hidden from user space.
716 */
717void dev_pm_qos_hide_flags(struct device *dev)
718{
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100719 pm_runtime_get_sync(dev);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200720 mutex_lock(&dev_pm_qos_sysfs_mtx);
721
722 pm_qos_sysfs_remove_flags(dev);
723
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100724 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100725 __dev_pm_qos_hide_flags(dev);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100726 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200727
728 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100729 pm_runtime_put(dev);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200730}
731EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
732
733/**
734 * dev_pm_qos_update_flags - Update PM QoS flags request owned by user space.
735 * @dev: Device to update the PM QoS flags request for.
736 * @mask: Flags to set/clear.
737 * @set: Whether to set or clear the flags (true means set).
738 */
739int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
740{
741 s32 value;
742 int ret;
743
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200744 pm_runtime_get_sync(dev);
745 mutex_lock(&dev_pm_qos_mtx);
746
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100747 if (IS_ERR_OR_NULL(dev->power.qos) || !dev->power.qos->flags_req) {
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100748 ret = -EINVAL;
749 goto out;
750 }
751
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200752 value = dev_pm_qos_requested_flags(dev);
753 if (set)
754 value |= mask;
755 else
756 value &= ~mask;
757
758 ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value);
759
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100760 out:
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200761 mutex_unlock(&dev_pm_qos_mtx);
762 pm_runtime_put(dev);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200763 return ret;
764}
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100765#else /* !CONFIG_PM_RUNTIME */
766static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
767static void __dev_pm_qos_hide_flags(struct device *dev) {}
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100768#endif /* CONFIG_PM_RUNTIME */