blob: 67c0f4219b02db0a49da6304e9fce13ac39bf94d [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>
Sahara96d9d0b2013-06-21 11:12:30 +090045#include <trace/events/power.h>
Jean Pihet91ff4cb2011-08-25 15:35:41 +020046
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +010047#include "power.h"
Jean Pihet91ff4cb2011-08-25 15:35:41 +020048
49static DEFINE_MUTEX(dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +020050static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020051
Jean Pihetb66213c2011-08-25 15:35:47 +020052static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
53
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020054/**
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +020055 * __dev_pm_qos_flags - Check PM QoS flags for a given device.
56 * @dev: Device to check the PM QoS flags for.
57 * @mask: Flags to check against.
58 *
59 * This routine must be called with dev->power.lock held.
60 */
61enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
62{
63 struct dev_pm_qos *qos = dev->power.qos;
64 struct pm_qos_flags *pqf;
65 s32 val;
66
Rafael J. Wysocki37530f22013-03-04 14:22:57 +010067 if (IS_ERR_OR_NULL(qos))
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +020068 return PM_QOS_FLAGS_UNDEFINED;
69
70 pqf = &qos->flags;
71 if (list_empty(&pqf->list))
72 return PM_QOS_FLAGS_UNDEFINED;
73
74 val = pqf->effective_flags & mask;
75 if (val)
76 return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;
77
78 return PM_QOS_FLAGS_NONE;
79}
80
81/**
82 * dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
83 * @dev: Device to check the PM QoS flags for.
84 * @mask: Flags to check against.
85 */
86enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
87{
88 unsigned long irqflags;
89 enum pm_qos_flags_status ret;
90
91 spin_lock_irqsave(&dev->power.lock, irqflags);
92 ret = __dev_pm_qos_flags(dev, mask);
93 spin_unlock_irqrestore(&dev->power.lock, irqflags);
94
95 return ret;
96}
Lan Tianyu6802771b2013-01-23 04:26:28 +080097EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +020098
99/**
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100100 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
101 * @dev: Device to get the PM QoS constraint value for.
102 *
103 * This routine must be called with dev->power.lock held.
104 */
105s32 __dev_pm_qos_read_value(struct device *dev)
106{
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100107 return IS_ERR_OR_NULL(dev->power.qos) ?
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100108 0 : pm_qos_read_value(&dev->power.qos->resume_latency);
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100109}
110
111/**
112 * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200113 * @dev: Device to get the PM QoS constraint value for.
114 */
115s32 dev_pm_qos_read_value(struct device *dev)
116{
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200117 unsigned long flags;
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100118 s32 ret;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200119
120 spin_lock_irqsave(&dev->power.lock, flags);
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100121 ret = __dev_pm_qos_read_value(dev);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200122 spin_unlock_irqrestore(&dev->power.lock, flags);
123
124 return ret;
125}
126
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200127/**
128 * apply_constraint - Add/modify/remove device PM QoS request.
129 * @req: Constraint request to apply
130 * @action: Action to perform (add/update/remove).
131 * @value: Value to assign to the QoS request.
Jean Pihetb66213c2011-08-25 15:35:47 +0200132 *
133 * Internal function to update the constraints list using the PM QoS core
134 * code and if needed call the per-device and the global notification
135 * callbacks
136 */
137static int apply_constraint(struct dev_pm_qos_request *req,
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200138 enum pm_qos_req_action action, s32 value)
Jean Pihetb66213c2011-08-25 15:35:47 +0200139{
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200140 struct dev_pm_qos *qos = req->dev->power.qos;
141 int ret;
Jean Pihetb66213c2011-08-25 15:35:47 +0200142
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200143 switch(req->type) {
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100144 case DEV_PM_QOS_RESUME_LATENCY:
145 ret = pm_qos_update_target(&qos->resume_latency,
146 &req->data.pnode, action, value);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200147 if (ret) {
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100148 value = pm_qos_read_value(&qos->resume_latency);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200149 blocking_notifier_call_chain(&dev_pm_notifiers,
150 (unsigned long)value,
151 req);
152 }
153 break;
154 case DEV_PM_QOS_FLAGS:
155 ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
156 action, value);
157 break;
158 default:
159 ret = -EINVAL;
Jean Pihetb66213c2011-08-25 15:35:47 +0200160 }
161
162 return ret;
163}
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200164
165/*
166 * dev_pm_qos_constraints_allocate
167 * @dev: device to allocate data for
168 *
169 * Called at the first call to add_request, for constraint data allocation
170 * Must be called with the dev_pm_qos_mtx mutex held
171 */
172static int dev_pm_qos_constraints_allocate(struct device *dev)
173{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200174 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200175 struct pm_qos_constraints *c;
176 struct blocking_notifier_head *n;
177
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200178 qos = kzalloc(sizeof(*qos), GFP_KERNEL);
179 if (!qos)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200180 return -ENOMEM;
181
182 n = kzalloc(sizeof(*n), GFP_KERNEL);
183 if (!n) {
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200184 kfree(qos);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200185 return -ENOMEM;
186 }
187 BLOCKING_INIT_NOTIFIER_HEAD(n);
188
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100189 c = &qos->resume_latency;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200190 plist_head_init(&c->list);
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100191 c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
192 c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200193 c->type = PM_QOS_MIN;
194 c->notifiers = n;
195
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200196 INIT_LIST_HEAD(&qos->flags.list);
197
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200198 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200199 dev->power.qos = qos;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200200 spin_unlock_irq(&dev->power.lock);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200201
202 return 0;
203}
204
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100205static void __dev_pm_qos_hide_latency_limit(struct device *dev);
206static void __dev_pm_qos_hide_flags(struct device *dev);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200207
208/**
209 * dev_pm_qos_constraints_destroy
210 * @dev: target device
211 *
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200212 * Called from the device PM subsystem on device removal under device_pm_lock().
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200213 */
214void dev_pm_qos_constraints_destroy(struct device *dev)
215{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200216 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200217 struct dev_pm_qos_request *req, *tmp;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200218 struct pm_qos_constraints *c;
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100219 struct pm_qos_flags *f;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200220
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200221 mutex_lock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100222
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100223 /*
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100224 * If the device's PM QoS resume latency limit or PM QoS flags have been
225 * exposed to user space, they have to be hidden at this point.
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100226 */
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100227 pm_qos_sysfs_remove_resume_latency(dev);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200228 pm_qos_sysfs_remove_flags(dev);
229
230 mutex_lock(&dev_pm_qos_mtx);
231
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100232 __dev_pm_qos_hide_latency_limit(dev);
233 __dev_pm_qos_hide_flags(dev);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100234
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200235 qos = dev->power.qos;
236 if (!qos)
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200237 goto out;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200238
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100239 /* Flush the constraints lists for the device. */
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100240 c = &qos->resume_latency;
Rafael J. Wysocki021c8702012-10-23 01:09:00 +0200241 plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200242 /*
243 * Update constraints list and call the notification
244 * callbacks if needed
245 */
246 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
247 memset(req, 0, sizeof(*req));
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200248 }
Rafael J. Wysocki35546bd2012-11-24 10:10:51 +0100249 f = &qos->flags;
250 list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
251 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
252 memset(req, 0, sizeof(*req));
253 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200254
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200255 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100256 dev->power.qos = ERR_PTR(-ENODEV);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200257 spin_unlock_irq(&dev->power.lock);
258
259 kfree(c->notifiers);
Lan,Tianyu9eaee2c2012-11-01 22:45:30 +0100260 kfree(qos);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200261
262 out:
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200263 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200264
265 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200266}
267
268/**
269 * dev_pm_qos_add_request - inserts new qos request into the list
270 * @dev: target device for the constraint
271 * @req: pointer to a preallocated handle
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200272 * @type: type of the request
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200273 * @value: defines the qos request
274 *
275 * This function inserts a new entry in the device constraints list of
276 * requested qos performance characteristics. It recomputes the aggregate
277 * QoS expectations of parameters and initializes the dev_pm_qos_request
278 * handle. Caller needs to save this handle for later use in updates and
279 * removal.
280 *
281 * Returns 1 if the aggregated constraint value has changed,
282 * 0 if the aggregated constraint value has not changed,
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200283 * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
284 * to allocate for data structures, -ENODEV if the device has just been removed
285 * from the system.
Rafael J. Wysocki436ede82012-11-02 13:10:09 +0100286 *
287 * Callers should ensure that the target device is not RPM_SUSPENDED before
288 * using this function for requests of type DEV_PM_QOS_FLAGS.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200289 */
290int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200291 enum dev_pm_qos_req_type type, s32 value)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200292{
293 int ret = 0;
294
295 if (!dev || !req) /*guard against callers passing in null */
296 return -EINVAL;
297
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100298 if (WARN(dev_pm_qos_request_active(req),
299 "%s() called for already added request\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200300 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200301
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200302 mutex_lock(&dev_pm_qos_mtx);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200303
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100304 if (IS_ERR(dev->power.qos))
305 ret = -ENODEV;
306 else if (!dev->power.qos)
307 ret = dev_pm_qos_constraints_allocate(dev);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200308
Sahara96d9d0b2013-06-21 11:12:30 +0900309 trace_dev_pm_qos_add_request(dev_name(dev), type, value);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200310 if (!ret) {
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100311 req->dev = dev;
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200312 req->type = type;
Jean Pihetb66213c2011-08-25 15:35:47 +0200313 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200314 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200315
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200316 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200317
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200318 return ret;
319}
320EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
321
322/**
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200323 * __dev_pm_qos_update_request - Modify an existing device PM QoS request.
324 * @req : PM QoS request to modify.
325 * @new_value: New value to request.
326 */
327static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
328 s32 new_value)
329{
330 s32 curr_value;
331 int ret = 0;
332
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100333 if (!req) /*guard against callers passing in null */
334 return -EINVAL;
335
336 if (WARN(!dev_pm_qos_request_active(req),
337 "%s() called for unknown object\n", __func__))
338 return -EINVAL;
339
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100340 if (IS_ERR_OR_NULL(req->dev->power.qos))
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200341 return -ENODEV;
342
343 switch(req->type) {
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100344 case DEV_PM_QOS_RESUME_LATENCY:
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200345 curr_value = req->data.pnode.prio;
346 break;
347 case DEV_PM_QOS_FLAGS:
348 curr_value = req->data.flr.flags;
349 break;
350 default:
351 return -EINVAL;
352 }
353
Sahara96d9d0b2013-06-21 11:12:30 +0900354 trace_dev_pm_qos_update_request(dev_name(req->dev), req->type,
355 new_value);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200356 if (curr_value != new_value)
357 ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
358
359 return ret;
360}
361
362/**
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200363 * dev_pm_qos_update_request - modifies an existing qos request
364 * @req : handle to list element holding a dev_pm_qos request to use
365 * @new_value: defines the qos request
366 *
367 * Updates an existing dev PM qos request along with updating the
368 * target value.
369 *
370 * Attempts are made to make this code callable on hot code paths.
371 *
372 * Returns 1 if the aggregated constraint value has changed,
373 * 0 if the aggregated constraint value has not changed,
374 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
375 * removed from the system
Rafael J. Wysocki436ede82012-11-02 13:10:09 +0100376 *
377 * Callers should ensure that the target device is not RPM_SUSPENDED before
378 * using this function for requests of type DEV_PM_QOS_FLAGS.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200379 */
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200380int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200381{
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200382 int ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200383
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100384 mutex_lock(&dev_pm_qos_mtx);
385 ret = __dev_pm_qos_update_request(req, new_value);
386 mutex_unlock(&dev_pm_qos_mtx);
387 return ret;
388}
389EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
390
391static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
392{
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100393 int ret;
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100394
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200395 if (!req) /*guard against callers passing in null */
396 return -EINVAL;
397
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100398 if (WARN(!dev_pm_qos_request_active(req),
399 "%s() called for unknown object\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200400 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200401
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100402 if (IS_ERR_OR_NULL(req->dev->power.qos))
403 return -ENODEV;
404
Sahara96d9d0b2013-06-21 11:12:30 +0900405 trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type,
406 PM_QOS_DEFAULT_VALUE);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100407 ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
408 memset(req, 0, sizeof(*req));
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200409 return ret;
410}
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200411
412/**
413 * dev_pm_qos_remove_request - modifies an existing qos request
414 * @req: handle to request list element
415 *
416 * Will remove pm qos request from the list of constraints and
417 * recompute the current target value. Call this on slow code paths.
418 *
419 * Returns 1 if the aggregated constraint value has changed,
420 * 0 if the aggregated constraint value has not changed,
421 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
422 * removed from the system
Rafael J. Wysocki436ede82012-11-02 13:10:09 +0100423 *
424 * Callers should ensure that the target device is not RPM_SUSPENDED before
425 * using this function for requests of type DEV_PM_QOS_FLAGS.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200426 */
427int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
428{
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100429 int ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200430
431 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100432 ret = __dev_pm_qos_remove_request(req);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200433 mutex_unlock(&dev_pm_qos_mtx);
434 return ret;
435}
436EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
437
438/**
439 * dev_pm_qos_add_notifier - sets notification entry for changes to target value
440 * of per-device PM QoS constraints
441 *
442 * @dev: target device for the constraint
443 * @notifier: notifier block managed by caller.
444 *
445 * Will register the notifier into a notification chain that gets called
446 * upon changes to the target value for the device.
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200447 *
448 * If the device's constraints object doesn't exist when this routine is called,
449 * it will be created (or error code will be returned if that fails).
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200450 */
451int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
452{
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200453 int ret = 0;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200454
455 mutex_lock(&dev_pm_qos_mtx);
456
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100457 if (IS_ERR(dev->power.qos))
458 ret = -ENODEV;
459 else if (!dev->power.qos)
460 ret = dev_pm_qos_constraints_allocate(dev);
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200461
462 if (!ret)
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100463 ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
464 notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200465
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200466 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200467 return ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200468}
469EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
470
471/**
472 * dev_pm_qos_remove_notifier - deletes notification for changes to target value
473 * of per-device PM QoS constraints
474 *
475 * @dev: target device for the constraint
476 * @notifier: notifier block to be removed.
477 *
478 * Will remove the notifier from the notification chain that gets called
479 * upon changes to the target value.
480 */
481int dev_pm_qos_remove_notifier(struct device *dev,
482 struct notifier_block *notifier)
483{
484 int retval = 0;
485
486 mutex_lock(&dev_pm_qos_mtx);
487
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200488 /* Silently return if the constraints object is not present. */
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100489 if (!IS_ERR_OR_NULL(dev->power.qos))
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100490 retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
491 notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200492
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200493 mutex_unlock(&dev_pm_qos_mtx);
494 return retval;
495}
496EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
Jean Pihetb66213c2011-08-25 15:35:47 +0200497
498/**
499 * dev_pm_qos_add_global_notifier - sets notification entry for changes to
500 * target value of the PM QoS constraints for any device
501 *
502 * @notifier: notifier block managed by caller.
503 *
504 * Will register the notifier into a notification chain that gets called
505 * upon changes to the target value for any device.
506 */
507int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
508{
509 return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
510}
511EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
512
513/**
514 * dev_pm_qos_remove_global_notifier - deletes notification for changes to
515 * target value of PM QoS constraints for any device
516 *
517 * @notifier: notifier block to be removed.
518 *
519 * Will remove the notifier from the notification chain that gets called
520 * upon changes to the target value for any device.
521 */
522int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
523{
524 return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
525}
526EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100527
528/**
529 * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
530 * @dev: Device whose ancestor to add the request for.
531 * @req: Pointer to the preallocated handle.
532 * @value: Constraint latency value.
533 */
534int dev_pm_qos_add_ancestor_request(struct device *dev,
535 struct dev_pm_qos_request *req, s32 value)
536{
537 struct device *ancestor = dev->parent;
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100538 int ret = -ENODEV;
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100539
540 while (ancestor && !ancestor->power.ignore_children)
541 ancestor = ancestor->parent;
542
543 if (ancestor)
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100544 ret = dev_pm_qos_add_request(ancestor, req,
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100545 DEV_PM_QOS_RESUME_LATENCY, value);
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100546
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100547 if (ret < 0)
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100548 req->dev = NULL;
549
Rafael J. Wysocki4ce47802012-12-18 14:07:49 +0100550 return ret;
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100551}
552EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100553
554#ifdef CONFIG_PM_RUNTIME
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200555static void __dev_pm_qos_drop_user_request(struct device *dev,
556 enum dev_pm_qos_req_type type)
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100557{
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100558 struct dev_pm_qos_request *req = NULL;
559
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200560 switch(type) {
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100561 case DEV_PM_QOS_RESUME_LATENCY:
562 req = dev->power.qos->resume_latency_req;
563 dev->power.qos->resume_latency_req = NULL;
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200564 break;
565 case DEV_PM_QOS_FLAGS:
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100566 req = dev->power.qos->flags_req;
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200567 dev->power.qos->flags_req = NULL;
568 break;
569 }
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100570 __dev_pm_qos_remove_request(req);
571 kfree(req);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100572}
573
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200574static void dev_pm_qos_drop_user_request(struct device *dev,
575 enum dev_pm_qos_req_type type)
576{
577 mutex_lock(&dev_pm_qos_mtx);
578 __dev_pm_qos_drop_user_request(dev, type);
579 mutex_unlock(&dev_pm_qos_mtx);
580}
581
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100582/**
583 * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
584 * @dev: Device whose PM QoS latency limit is to be exposed to user space.
585 * @value: Initial value of the latency limit.
586 */
587int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
588{
589 struct dev_pm_qos_request *req;
590 int ret;
591
592 if (!device_is_registered(dev) || value < 0)
593 return -EINVAL;
594
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100595 req = kzalloc(sizeof(*req), GFP_KERNEL);
596 if (!req)
597 return -ENOMEM;
598
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100599 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_RESUME_LATENCY, value);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100600 if (ret < 0) {
601 kfree(req);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100602 return ret;
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100603 }
604
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200605 mutex_lock(&dev_pm_qos_sysfs_mtx);
606
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100607 mutex_lock(&dev_pm_qos_mtx);
608
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100609 if (IS_ERR_OR_NULL(dev->power.qos))
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100610 ret = -ENODEV;
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100611 else if (dev->power.qos->resume_latency_req)
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100612 ret = -EEXIST;
613
614 if (ret < 0) {
615 __dev_pm_qos_remove_request(req);
616 kfree(req);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200617 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100618 goto out;
619 }
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100620 dev->power.qos->resume_latency_req = req;
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200621
622 mutex_unlock(&dev_pm_qos_mtx);
623
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100624 ret = pm_qos_sysfs_add_resume_latency(dev);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100625 if (ret)
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100626 dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100627
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100628 out:
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200629 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100630 return ret;
631}
632EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
633
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100634static void __dev_pm_qos_hide_latency_limit(struct device *dev)
635{
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100636 if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->resume_latency_req)
637 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100638}
639
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100640/**
641 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
642 * @dev: Device whose PM QoS latency limit is to be hidden from user space.
643 */
644void dev_pm_qos_hide_latency_limit(struct device *dev)
645{
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200646 mutex_lock(&dev_pm_qos_sysfs_mtx);
647
Rafael J. Wysockib02f6692014-02-11 00:35:23 +0100648 pm_qos_sysfs_remove_resume_latency(dev);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200649
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100650 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100651 __dev_pm_qos_hide_latency_limit(dev);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100652 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200653
654 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100655}
656EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200657
658/**
659 * dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space.
660 * @dev: Device whose PM QoS flags are to be exposed to user space.
661 * @val: Initial values of the flags.
662 */
663int dev_pm_qos_expose_flags(struct device *dev, s32 val)
664{
665 struct dev_pm_qos_request *req;
666 int ret;
667
668 if (!device_is_registered(dev))
669 return -EINVAL;
670
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200671 req = kzalloc(sizeof(*req), GFP_KERNEL);
672 if (!req)
673 return -ENOMEM;
674
675 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100676 if (ret < 0) {
677 kfree(req);
678 return ret;
679 }
680
681 pm_runtime_get_sync(dev);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200682 mutex_lock(&dev_pm_qos_sysfs_mtx);
683
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100684 mutex_lock(&dev_pm_qos_mtx);
685
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100686 if (IS_ERR_OR_NULL(dev->power.qos))
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100687 ret = -ENODEV;
688 else if (dev->power.qos->flags_req)
689 ret = -EEXIST;
690
691 if (ret < 0) {
692 __dev_pm_qos_remove_request(req);
693 kfree(req);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200694 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100695 goto out;
696 }
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200697 dev->power.qos->flags_req = req;
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200698
699 mutex_unlock(&dev_pm_qos_mtx);
700
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200701 ret = pm_qos_sysfs_add_flags(dev);
702 if (ret)
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200703 dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200704
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100705 out:
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200706 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Lan Tianyu7e4d6842012-11-08 11:14:08 +0800707 pm_runtime_put(dev);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200708 return ret;
709}
710EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
711
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100712static void __dev_pm_qos_hide_flags(struct device *dev)
713{
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200714 if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100715 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100716}
717
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200718/**
719 * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space.
720 * @dev: Device whose PM QoS flags are to be hidden from user space.
721 */
722void dev_pm_qos_hide_flags(struct device *dev)
723{
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100724 pm_runtime_get_sync(dev);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200725 mutex_lock(&dev_pm_qos_sysfs_mtx);
726
727 pm_qos_sysfs_remove_flags(dev);
728
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100729 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100730 __dev_pm_qos_hide_flags(dev);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100731 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki0f703062013-04-02 01:25:24 +0200732
733 mutex_unlock(&dev_pm_qos_sysfs_mtx);
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100734 pm_runtime_put(dev);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200735}
736EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
737
738/**
739 * dev_pm_qos_update_flags - Update PM QoS flags request owned by user space.
740 * @dev: Device to update the PM QoS flags request for.
741 * @mask: Flags to set/clear.
742 * @set: Whether to set or clear the flags (true means set).
743 */
744int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
745{
746 s32 value;
747 int ret;
748
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200749 pm_runtime_get_sync(dev);
750 mutex_lock(&dev_pm_qos_mtx);
751
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100752 if (IS_ERR_OR_NULL(dev->power.qos) || !dev->power.qos->flags_req) {
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100753 ret = -EINVAL;
754 goto out;
755 }
756
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200757 value = dev_pm_qos_requested_flags(dev);
758 if (set)
759 value |= mask;
760 else
761 value &= ~mask;
762
763 ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value);
764
Rafael J. Wysockib81ea1b2013-03-03 22:48:14 +0100765 out:
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200766 mutex_unlock(&dev_pm_qos_mtx);
767 pm_runtime_put(dev);
Rafael J. Wysockie39473d2012-10-24 02:08:18 +0200768 return ret;
769}
Rafael J. Wysocki37530f22013-03-04 14:22:57 +0100770#else /* !CONFIG_PM_RUNTIME */
771static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
772static void __dev_pm_qos_hide_flags(struct device *dev) {}
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100773#endif /* CONFIG_PM_RUNTIME */