blob: 96d27b821bb8f9d6fb212fb7756b0b0cb4fbddea [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. Wysocki00dc9ad2011-12-01 00:01:31 +010051 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
52 * @dev: Device to get the PM QoS constraint value for.
53 *
54 * This routine must be called with dev->power.lock held.
55 */
56s32 __dev_pm_qos_read_value(struct device *dev)
57{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +020058 return dev->power.qos ? pm_qos_read_value(&dev->power.qos->latency) : 0;
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +010059}
60
61/**
62 * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020063 * @dev: Device to get the PM QoS constraint value for.
64 */
65s32 dev_pm_qos_read_value(struct device *dev)
66{
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020067 unsigned long flags;
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +010068 s32 ret;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020069
70 spin_lock_irqsave(&dev->power.lock, flags);
Rafael J. Wysocki00dc9ad2011-12-01 00:01:31 +010071 ret = __dev_pm_qos_read_value(dev);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +020072 spin_unlock_irqrestore(&dev->power.lock, flags);
73
74 return ret;
75}
76
Jean Pihetb66213c2011-08-25 15:35:47 +020077/*
78 * apply_constraint
79 * @req: constraint request to apply
80 * @action: action to perform add/update/remove, of type enum pm_qos_req_action
81 * @value: defines the qos request
82 *
83 * Internal function to update the constraints list using the PM QoS core
84 * code and if needed call the per-device and the global notification
85 * callbacks
86 */
87static int apply_constraint(struct dev_pm_qos_request *req,
88 enum pm_qos_req_action action, int value)
89{
90 int ret, curr_value;
91
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +020092 ret = pm_qos_update_target(&req->dev->power.qos->latency,
Rafael J. Wysocki021c8702012-10-23 01:09:00 +020093 &req->data.pnode, action, value);
Jean Pihetb66213c2011-08-25 15:35:47 +020094
95 if (ret) {
96 /* Call the global callbacks if needed */
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +020097 curr_value = pm_qos_read_value(&req->dev->power.qos->latency);
Jean Pihetb66213c2011-08-25 15:35:47 +020098 blocking_notifier_call_chain(&dev_pm_notifiers,
99 (unsigned long)curr_value,
100 req);
101 }
102
103 return ret;
104}
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200105
106/*
107 * dev_pm_qos_constraints_allocate
108 * @dev: device to allocate data for
109 *
110 * Called at the first call to add_request, for constraint data allocation
111 * Must be called with the dev_pm_qos_mtx mutex held
112 */
113static int dev_pm_qos_constraints_allocate(struct device *dev)
114{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200115 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200116 struct pm_qos_constraints *c;
117 struct blocking_notifier_head *n;
118
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200119 qos = kzalloc(sizeof(*qos), GFP_KERNEL);
120 if (!qos)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200121 return -ENOMEM;
122
123 n = kzalloc(sizeof(*n), GFP_KERNEL);
124 if (!n) {
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200125 kfree(qos);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200126 return -ENOMEM;
127 }
128 BLOCKING_INIT_NOTIFIER_HEAD(n);
129
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200130 c = &qos->latency;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200131 plist_head_init(&c->list);
132 c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
133 c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
134 c->type = PM_QOS_MIN;
135 c->notifiers = n;
136
137 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200138 dev->power.qos = qos;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200139 spin_unlock_irq(&dev->power.lock);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200140
141 return 0;
142}
143
144/**
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200145 * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200146 * @dev: target device
147 *
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200148 * Called from the device PM subsystem during device insertion under
149 * device_pm_lock().
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200150 */
151void dev_pm_qos_constraints_init(struct device *dev)
152{
153 mutex_lock(&dev_pm_qos_mtx);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200154 dev->power.qos = NULL;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200155 dev->power.power_state = PMSG_ON;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200156 mutex_unlock(&dev_pm_qos_mtx);
157}
158
159/**
160 * dev_pm_qos_constraints_destroy
161 * @dev: target device
162 *
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200163 * Called from the device PM subsystem on device removal under device_pm_lock().
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200164 */
165void dev_pm_qos_constraints_destroy(struct device *dev)
166{
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200167 struct dev_pm_qos *qos;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200168 struct dev_pm_qos_request *req, *tmp;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200169 struct pm_qos_constraints *c;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200170
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100171 /*
172 * If the device's PM QoS resume latency limit has been exposed to user
173 * space, it has to be hidden at this point.
174 */
175 dev_pm_qos_hide_latency_limit(dev);
176
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200177 mutex_lock(&dev_pm_qos_mtx);
178
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200179 dev->power.power_state = PMSG_INVALID;
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200180 qos = dev->power.qos;
181 if (!qos)
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200182 goto out;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200183
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200184 c = &qos->latency;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200185 /* Flush the constraints list for the device */
Rafael J. Wysocki021c8702012-10-23 01:09:00 +0200186 plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200187 /*
188 * Update constraints list and call the notification
189 * callbacks if needed
190 */
191 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
192 memset(req, 0, sizeof(*req));
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200193 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200194
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200195 spin_lock_irq(&dev->power.lock);
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200196 dev->power.qos = NULL;
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200197 spin_unlock_irq(&dev->power.lock);
198
199 kfree(c->notifiers);
200 kfree(c);
201
202 out:
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200203 mutex_unlock(&dev_pm_qos_mtx);
204}
205
206/**
207 * dev_pm_qos_add_request - inserts new qos request into the list
208 * @dev: target device for the constraint
209 * @req: pointer to a preallocated handle
210 * @value: defines the qos request
211 *
212 * This function inserts a new entry in the device constraints list of
213 * requested qos performance characteristics. It recomputes the aggregate
214 * QoS expectations of parameters and initializes the dev_pm_qos_request
215 * handle. Caller needs to save this handle for later use in updates and
216 * removal.
217 *
218 * Returns 1 if the aggregated constraint value has changed,
219 * 0 if the aggregated constraint value has not changed,
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200220 * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
221 * to allocate for data structures, -ENODEV if the device has just been removed
222 * from the system.
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200223 */
224int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
Jean Pihetb66213c2011-08-25 15:35:47 +0200225 s32 value)
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200226{
227 int ret = 0;
228
229 if (!dev || !req) /*guard against callers passing in null */
230 return -EINVAL;
231
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100232 if (WARN(dev_pm_qos_request_active(req),
233 "%s() called for already added request\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200234 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200235
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200236 req->dev = dev;
237
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200238 mutex_lock(&dev_pm_qos_mtx);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200239
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200240 if (!dev->power.qos) {
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200241 if (dev->power.power_state.event == PM_EVENT_INVALID) {
242 /* The device has been removed from the system. */
243 req->dev = NULL;
244 ret = -ENODEV;
245 goto out;
246 } else {
247 /*
248 * Allocate the constraints data on the first call to
249 * add_request, i.e. only if the data is not already
250 * allocated and if the device has not been removed.
251 */
252 ret = dev_pm_qos_constraints_allocate(dev);
253 }
254 }
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200255
256 if (!ret)
Jean Pihetb66213c2011-08-25 15:35:47 +0200257 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200258
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200259 out:
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200260 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200261
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200262 return ret;
263}
264EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
265
266/**
267 * dev_pm_qos_update_request - modifies an existing qos request
268 * @req : handle to list element holding a dev_pm_qos request to use
269 * @new_value: defines the qos request
270 *
271 * Updates an existing dev PM qos request along with updating the
272 * target value.
273 *
274 * Attempts are made to make this code callable on hot code paths.
275 *
276 * Returns 1 if the aggregated constraint value has changed,
277 * 0 if the aggregated constraint value has not changed,
278 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
279 * removed from the system
280 */
281int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
282 s32 new_value)
283{
284 int ret = 0;
285
286 if (!req) /*guard against callers passing in null */
287 return -EINVAL;
288
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100289 if (WARN(!dev_pm_qos_request_active(req),
290 "%s() called for unknown object\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200291 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200292
293 mutex_lock(&dev_pm_qos_mtx);
294
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200295 if (req->dev->power.qos) {
Rafael J. Wysocki021c8702012-10-23 01:09:00 +0200296 if (new_value != req->data.pnode.prio)
Jean Pihetb66213c2011-08-25 15:35:47 +0200297 ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
298 new_value);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200299 } else {
300 /* Return if the device has been removed */
301 ret = -ENODEV;
302 }
303
304 mutex_unlock(&dev_pm_qos_mtx);
305 return ret;
306}
307EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
308
309/**
310 * dev_pm_qos_remove_request - modifies an existing qos request
311 * @req: handle to request list element
312 *
313 * Will remove pm qos request from the list of constraints and
314 * recompute the current target value. Call this on slow code paths.
315 *
316 * Returns 1 if the aggregated constraint value has changed,
317 * 0 if the aggregated constraint value has not changed,
318 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
319 * removed from the system
320 */
321int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
322{
323 int ret = 0;
324
325 if (!req) /*guard against callers passing in null */
326 return -EINVAL;
327
Guennadi Liakhovetskiaf4c7202011-11-10 00:44:18 +0100328 if (WARN(!dev_pm_qos_request_active(req),
329 "%s() called for unknown object\n", __func__))
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200330 return -EINVAL;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200331
332 mutex_lock(&dev_pm_qos_mtx);
333
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200334 if (req->dev->power.qos) {
Jean Pihetb66213c2011-08-25 15:35:47 +0200335 ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
336 PM_QOS_DEFAULT_VALUE);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200337 memset(req, 0, sizeof(*req));
338 } else {
339 /* Return if the device has been removed */
340 ret = -ENODEV;
341 }
342
343 mutex_unlock(&dev_pm_qos_mtx);
344 return ret;
345}
346EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
347
348/**
349 * dev_pm_qos_add_notifier - sets notification entry for changes to target value
350 * of per-device PM QoS constraints
351 *
352 * @dev: target device for the constraint
353 * @notifier: notifier block managed by caller.
354 *
355 * Will register the notifier into a notification chain that gets called
356 * upon changes to the target value for the device.
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200357 *
358 * If the device's constraints object doesn't exist when this routine is called,
359 * it will be created (or error code will be returned if that fails).
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200360 */
361int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
362{
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200363 int ret = 0;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200364
365 mutex_lock(&dev_pm_qos_mtx);
366
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200367 if (!dev->power.qos)
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200368 ret = dev->power.power_state.event != PM_EVENT_INVALID ?
369 dev_pm_qos_constraints_allocate(dev) : -ENODEV;
370
371 if (!ret)
372 ret = blocking_notifier_chain_register(
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200373 dev->power.qos->latency.notifiers, notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200374
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200375 mutex_unlock(&dev_pm_qos_mtx);
Rafael J. Wysocki23e0fc52012-04-29 22:54:47 +0200376 return ret;
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200377}
378EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
379
380/**
381 * dev_pm_qos_remove_notifier - deletes notification for changes to target value
382 * of per-device PM QoS constraints
383 *
384 * @dev: target device for the constraint
385 * @notifier: notifier block to be removed.
386 *
387 * Will remove the notifier from the notification chain that gets called
388 * upon changes to the target value.
389 */
390int dev_pm_qos_remove_notifier(struct device *dev,
391 struct notifier_block *notifier)
392{
393 int retval = 0;
394
395 mutex_lock(&dev_pm_qos_mtx);
396
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200397 /* Silently return if the constraints object is not present. */
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200398 if (dev->power.qos)
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200399 retval = blocking_notifier_chain_unregister(
Rafael J. Wysocki5f986c52012-10-23 01:07:27 +0200400 dev->power.qos->latency.notifiers,
Rafael J. Wysocki1a9a9152011-09-29 22:29:44 +0200401 notifier);
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200402
Jean Pihet91ff4cb2011-08-25 15:35:41 +0200403 mutex_unlock(&dev_pm_qos_mtx);
404 return retval;
405}
406EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
Jean Pihetb66213c2011-08-25 15:35:47 +0200407
408/**
409 * dev_pm_qos_add_global_notifier - sets notification entry for changes to
410 * target value of the PM QoS constraints for any device
411 *
412 * @notifier: notifier block managed by caller.
413 *
414 * Will register the notifier into a notification chain that gets called
415 * upon changes to the target value for any device.
416 */
417int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
418{
419 return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
420}
421EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
422
423/**
424 * dev_pm_qos_remove_global_notifier - deletes notification for changes to
425 * target value of PM QoS constraints for any device
426 *
427 * @notifier: notifier block to be removed.
428 *
429 * Will remove the notifier from the notification chain that gets called
430 * upon changes to the target value for any device.
431 */
432int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
433{
434 return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
435}
436EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
Rafael J. Wysocki40a5f8b2011-12-23 01:23:52 +0100437
438/**
439 * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
440 * @dev: Device whose ancestor to add the request for.
441 * @req: Pointer to the preallocated handle.
442 * @value: Constraint latency value.
443 */
444int dev_pm_qos_add_ancestor_request(struct device *dev,
445 struct dev_pm_qos_request *req, s32 value)
446{
447 struct device *ancestor = dev->parent;
448 int error = -ENODEV;
449
450 while (ancestor && !ancestor->power.ignore_children)
451 ancestor = ancestor->parent;
452
453 if (ancestor)
454 error = dev_pm_qos_add_request(ancestor, req, value);
455
456 if (error)
457 req->dev = NULL;
458
459 return error;
460}
461EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100462
463#ifdef CONFIG_PM_RUNTIME
464static void __dev_pm_qos_drop_user_request(struct device *dev)
465{
466 dev_pm_qos_remove_request(dev->power.pq_req);
Sachin Kamatad0446e2012-07-17 22:38:26 +0200467 dev->power.pq_req = NULL;
Rafael J. Wysocki85dc0b82012-03-13 01:01:39 +0100468}
469
470/**
471 * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
472 * @dev: Device whose PM QoS latency limit is to be exposed to user space.
473 * @value: Initial value of the latency limit.
474 */
475int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
476{
477 struct dev_pm_qos_request *req;
478 int ret;
479
480 if (!device_is_registered(dev) || value < 0)
481 return -EINVAL;
482
483 if (dev->power.pq_req)
484 return -EEXIST;
485
486 req = kzalloc(sizeof(*req), GFP_KERNEL);
487 if (!req)
488 return -ENOMEM;
489
490 ret = dev_pm_qos_add_request(dev, req, value);
491 if (ret < 0)
492 return ret;
493
494 dev->power.pq_req = req;
495 ret = pm_qos_sysfs_add(dev);
496 if (ret)
497 __dev_pm_qos_drop_user_request(dev);
498
499 return ret;
500}
501EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
502
503/**
504 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
505 * @dev: Device whose PM QoS latency limit is to be hidden from user space.
506 */
507void dev_pm_qos_hide_latency_limit(struct device *dev)
508{
509 if (dev->power.pq_req) {
510 pm_qos_sysfs_remove(dev);
511 __dev_pm_qos_drop_user_request(dev);
512 }
513}
514EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
515#endif /* CONFIG_PM_RUNTIME */