blob: 3c66f75d14b07b15d56911a95dae20c234656614 [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>
Jean Pihet91ff4cb2011-08-25 15:35:41 +020043
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +010044#include "power.h"
Jean Pihet91ff4cb2011-08-25 15:35:41 +020045
46static DEFINE_MUTEX(dev_pm_qos_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020047
Jean Pihetb66213c2011-08-25 15:35:47 +020048static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
49
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020050/**
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +020051 * __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 */
57enum 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 */
82enum 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/**
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +010095 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
96 * @dev: Device to get the PM QoS constraint value for.
97 *
98 * This routine must be called with dev->power.lock held.
99 */
100s32 __dev_pm_qos_read_value(struct device *dev)
101{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200102 return dev->power.qos ? pm_qos_read_value(&dev->power.qos->latency) : 0;
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100103}
104
105/**
106 * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200107 * @dev: Device to get the PM QoS constraint value for.
108 */
109s32 dev_pm_qos_read_value(struct device *dev)
110{
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200111 unsigned long flags;
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100112 s32 ret;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200113
114 spin_lock_irqsave(&dev->power.lock, flags);
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +0100115 ret = __dev_pm_qos_read_value(dev);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200116 spin_unlock_irqrestore(&dev->power.lock, flags);
117
118 return ret;
119}
120
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200121/**
122 * apply_constraint - Add/modify/remove device PM QoS request.
123 * @req: Constraint request to apply
124 * @action: Action to perform (add/update/remove).
125 * @value: Value to assign to the QoS request.
Jean Pihetb66213c2011-08-25 15:35:47 +0200126 *
127 * Internal function to update the constraints list using the PM QoS core
128 * code and if needed call the per-device and the global notification
129 * callbacks
130 */
131static int apply_constraint(struct dev_pm_qos_request *req,
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200132 enum pm_qos_req_action action, s32 value)
Jean Pihetb66213c2011-08-25 15:35:47 +0200133{
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200134 struct dev_pm_qos *qos = req->dev->power.qos;
135 int ret;
Jean Pihetb66213c2011-08-25 15:35:47 +0200136
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200137 switch(req->type) {
138 case DEV_PM_QOS_LATENCY:
139 ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
140 action, value);
141 if (ret) {
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;
Jean Pihetb66213c2011-08-25 15:35:47 +0200154 }
155
156 return ret;
157}
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200158
159/*
160 * dev_pm_qos_constraints_allocate
161 * @dev: device to allocate data for
162 *
163 * Called at the first call to add_request, for constraint data allocation
164 * Must be called with the dev_pm_qos_mtx mutex held
165 */
166static int dev_pm_qos_constraints_allocate(struct device *dev)
167{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200168 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200169 struct pm_qos_constraints *c;
170 struct blocking_notifier_head *n;
171
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200172 qos = kzalloc(sizeof(*qos), GFP_KERNEL);
173 if (!qos)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200174 return -ENOMEM;
175
176 n = kzalloc(sizeof(*n), GFP_KERNEL);
177 if (!n) {
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200178 kfree(qos);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200179 return -ENOMEM;
180 }
181 BLOCKING_INIT_NOTIFIER_HEAD(n);
182
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200183 c = &qos->latency;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200184 plist_head_init(&c->list);
185 c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
186 c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
187 c->type = PM_QOS_MIN;
188 c->notifiers = n;
189
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200190 INIT_LIST_HEAD(&qos->flags.list);
191
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200192 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200193 dev->power.qos = qos;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200194 spin_unlock_irq(&dev->power.lock);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200195
196 return 0;
197}
198
199/**
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200200 * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200201 * @dev: target device
202 *
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200203 * Called from the device PM subsystem during device insertion under
204 * device_pm_lock().
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200205 */
206void dev_pm_qos_constraints_init(struct device *dev)
207{
208 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200209 dev->power.qos = NULL;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200210 dev->power.power_state = PMSG_ON;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200211 mutex_unlock(&dev_pm_qos_mtx);
212}
213
214/**
215 * dev_pm_qos_constraints_destroy
216 * @dev: target device
217 *
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200218 * Called from the device PM subsystem on device removal under device_pm_lock().
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200219 */
220void dev_pm_qos_constraints_destroy(struct device *dev)
221{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200222 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200223 struct dev_pm_qos_request *req, *tmp;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200224 struct pm_qos_constraints *c;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200225
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100226 /*
227 * If the device's PM QoS resume latency limit has been exposed to user
228 * space, it has to be hidden at this point.
229 */
230 dev_pm_qos_hide_latency_limit(dev);
231
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200232 mutex_lock(&dev_pm_qos_mtx);
233
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200234 dev->power.power_state = PMSG_INVALID;
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. Wysocki5f986c52012-10-23 01:07:27 +0200239 c = &qos->latency;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200240 /* Flush the constraints list for the device */
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 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200249
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200250 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200251 dev->power.qos = NULL;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200252 spin_unlock_irq(&dev->power.lock);
253
254 kfree(c->notifiers);
255 kfree(c);
256
257 out:
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200258 mutex_unlock(&dev_pm_qos_mtx);
259}
260
261/**
262 * dev_pm_qos_add_request - inserts new qos request into the list
263 * @dev: target device for the constraint
264 * @req: pointer to a preallocated handle
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200265 * @type: type of the request
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200266 * @value: defines the qos request
267 *
268 * This function inserts a new entry in the device constraints list of
269 * requested qos performance characteristics. It recomputes the aggregate
270 * QoS expectations of parameters and initializes the dev_pm_qos_request
271 * handle. Caller needs to save this handle for later use in updates and
272 * removal.
273 *
274 * Returns 1 if the aggregated constraint value has changed,
275 * 0 if the aggregated constraint value has not changed,
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200276 * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
277 * to allocate for data structures, -ENODEV if the device has just been removed
278 * from the system.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200279 */
280int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200281 enum dev_pm_qos_req_type type, s32 value)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200282{
283 int ret = 0;
284
285 if (!dev || !req) /*guard against callers passing in null */
286 return -EINVAL;
287
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100288 if (WARN(dev_pm_qos_request_active(req),
289 "%s() called for already added request\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200290 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200291
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200292 req->dev = dev;
293
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200294 mutex_lock(&dev_pm_qos_mtx);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200295
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200296 if (!dev->power.qos) {
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200297 if (dev->power.power_state.event == PM_EVENT_INVALID) {
298 /* The device has been removed from the system. */
299 req->dev = NULL;
300 ret = -ENODEV;
301 goto out;
302 } else {
303 /*
304 * Allocate the constraints data on the first call to
305 * add_request, i.e. only if the data is not already
306 * allocated and if the device has not been removed.
307 */
308 ret = dev_pm_qos_constraints_allocate(dev);
309 }
310 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200311
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200312 if (!ret) {
313 req->type = type;
Jean Pihetb66213c2011-08-25 15:35:47 +0200314 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200315 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200316
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200317 out:
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200318 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200319
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200320 return ret;
321}
322EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
323
324/**
325 * dev_pm_qos_update_request - modifies an existing qos request
326 * @req : handle to list element holding a dev_pm_qos request to use
327 * @new_value: defines the qos request
328 *
329 * Updates an existing dev PM qos request along with updating the
330 * target value.
331 *
332 * Attempts are made to make this code callable on hot code paths.
333 *
334 * Returns 1 if the aggregated constraint value has changed,
335 * 0 if the aggregated constraint value has not changed,
336 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
337 * removed from the system
338 */
339int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
340 s32 new_value)
341{
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200342 s32 curr_value;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200343 int ret = 0;
344
345 if (!req) /*guard against callers passing in null */
346 return -EINVAL;
347
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100348 if (WARN(!dev_pm_qos_request_active(req),
349 "%s() called for unknown object\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200350 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200351
352 mutex_lock(&dev_pm_qos_mtx);
353
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200354 if (!req->dev->power.qos) {
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200355 ret = -ENODEV;
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200356 goto out;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200357 }
358
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200359 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:
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200375 mutex_unlock(&dev_pm_qos_mtx);
376 return ret;
377}
378EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
379
380/**
381 * dev_pm_qos_remove_request - modifies an existing qos request
382 * @req: handle to request list element
383 *
384 * Will remove pm qos request from the list of constraints and
385 * recompute the current target value. Call this on slow code paths.
386 *
387 * Returns 1 if the aggregated constraint value has changed,
388 * 0 if the aggregated constraint value has not changed,
389 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
390 * removed from the system
391 */
392int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
393{
394 int ret = 0;
395
396 if (!req) /*guard against callers passing in null */
397 return -EINVAL;
398
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100399 if (WARN(!dev_pm_qos_request_active(req),
400 "%s() called for unknown object\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200401 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200402
403 mutex_lock(&dev_pm_qos_mtx);
404
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200405 if (req->dev->power.qos) {
Jean Pihetb66213c2011-08-25 15:35:47 +0200406 ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
407 PM_QOS_DEFAULT_VALUE);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200408 memset(req, 0, sizeof(*req));
409 } else {
410 /* Return if the device has been removed */
411 ret = -ENODEV;
412 }
413
414 mutex_unlock(&dev_pm_qos_mtx);
415 return ret;
416}
417EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
418
419/**
420 * dev_pm_qos_add_notifier - sets notification entry for changes to target value
421 * of per-device PM QoS constraints
422 *
423 * @dev: target device for the constraint
424 * @notifier: notifier block managed by caller.
425 *
426 * Will register the notifier into a notification chain that gets called
427 * upon changes to the target value for the device.
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200428 *
429 * If the device's constraints object doesn't exist when this routine is called,
430 * it will be created (or error code will be returned if that fails).
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200431 */
432int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
433{
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200434 int ret = 0;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200435
436 mutex_lock(&dev_pm_qos_mtx);
437
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200438 if (!dev->power.qos)
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200439 ret = dev->power.power_state.event != PM_EVENT_INVALID ?
440 dev_pm_qos_constraints_allocate(dev) : -ENODEV;
441
442 if (!ret)
443 ret = blocking_notifier_chain_register(
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200444 dev->power.qos->latency.notifiers, notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200445
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200446 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200447 return ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200448}
449EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
450
451/**
452 * dev_pm_qos_remove_notifier - deletes notification for changes to target value
453 * of per-device PM QoS constraints
454 *
455 * @dev: target device for the constraint
456 * @notifier: notifier block to be removed.
457 *
458 * Will remove the notifier from the notification chain that gets called
459 * upon changes to the target value.
460 */
461int dev_pm_qos_remove_notifier(struct device *dev,
462 struct notifier_block *notifier)
463{
464 int retval = 0;
465
466 mutex_lock(&dev_pm_qos_mtx);
467
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200468 /* Silently return if the constraints object is not present. */
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200469 if (dev->power.qos)
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200470 retval = blocking_notifier_chain_unregister(
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200471 dev->power.qos->latency.notifiers,
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200472 notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200473
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200474 mutex_unlock(&dev_pm_qos_mtx);
475 return retval;
476}
477EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
Jean Pihetb66213c2011-08-25 15:35:47 +0200478
479/**
480 * dev_pm_qos_add_global_notifier - sets notification entry for changes to
481 * target value of the PM QoS constraints for any device
482 *
483 * @notifier: notifier block managed by caller.
484 *
485 * Will register the notifier into a notification chain that gets called
486 * upon changes to the target value for any device.
487 */
488int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
489{
490 return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
491}
492EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
493
494/**
495 * dev_pm_qos_remove_global_notifier - deletes notification for changes to
496 * target value of PM QoS constraints for any device
497 *
498 * @notifier: notifier block to be removed.
499 *
500 * Will remove the notifier from the notification chain that gets called
501 * upon changes to the target value for any device.
502 */
503int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
504{
505 return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
506}
507EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100508
509/**
510 * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
511 * @dev: Device whose ancestor to add the request for.
512 * @req: Pointer to the preallocated handle.
513 * @value: Constraint latency value.
514 */
515int dev_pm_qos_add_ancestor_request(struct device *dev,
516 struct dev_pm_qos_request *req, s32 value)
517{
518 struct device *ancestor = dev->parent;
519 int error = -ENODEV;
520
521 while (ancestor && !ancestor->power.ignore_children)
522 ancestor = ancestor->parent;
523
524 if (ancestor)
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200525 error = dev_pm_qos_add_request(ancestor, req,
526 DEV_PM_QOS_LATENCY, value);
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100527
528 if (error)
529 req->dev = NULL;
530
531 return error;
532}
533EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100534
535#ifdef CONFIG_PM_RUNTIME
536static void __dev_pm_qos_drop_user_request(struct device *dev)
537{
538 dev_pm_qos_remove_request(dev->power.pq_req);
Sachin Kamatad0446e2012-07-17 22:38:26 +0200539 dev->power.pq_req = NULL;
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100540}
541
542/**
543 * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
544 * @dev: Device whose PM QoS latency limit is to be exposed to user space.
545 * @value: Initial value of the latency limit.
546 */
547int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
548{
549 struct dev_pm_qos_request *req;
550 int ret;
551
552 if (!device_is_registered(dev) || value < 0)
553 return -EINVAL;
554
555 if (dev->power.pq_req)
556 return -EEXIST;
557
558 req = kzalloc(sizeof(*req), GFP_KERNEL);
559 if (!req)
560 return -ENOMEM;
561
Rafael J. Wysockiae0fb4b2012-10-23 01:09:12 +0200562 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100563 if (ret < 0)
564 return ret;
565
566 dev->power.pq_req = req;
567 ret = pm_qos_sysfs_add(dev);
568 if (ret)
569 __dev_pm_qos_drop_user_request(dev);
570
571 return ret;
572}
573EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
574
575/**
576 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
577 * @dev: Device whose PM QoS latency limit is to be hidden from user space.
578 */
579void dev_pm_qos_hide_latency_limit(struct device *dev)
580{
581 if (dev->power.pq_req) {
582 pm_qos_sysfs_remove(dev);
583 __dev_pm_qos_drop_user_request(dev);
584 }
585}
586EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
587#endif /* CONFIG_PM_RUNTIME */