xref: /openbmc/linux/drivers/base/power/qos.c (revision 1a9a9152)
191ff4cb8SJean Pihet /*
291ff4cb8SJean Pihet  * Devices PM QoS constraints management
391ff4cb8SJean Pihet  *
491ff4cb8SJean Pihet  * Copyright (C) 2011 Texas Instruments, Inc.
591ff4cb8SJean Pihet  *
691ff4cb8SJean Pihet  * This program is free software; you can redistribute it and/or modify
791ff4cb8SJean Pihet  * it under the terms of the GNU General Public License version 2 as
891ff4cb8SJean Pihet  * published by the Free Software Foundation.
991ff4cb8SJean Pihet  *
1091ff4cb8SJean Pihet  *
1191ff4cb8SJean Pihet  * This module exposes the interface to kernel space for specifying
1291ff4cb8SJean Pihet  * per-device PM QoS dependencies. It provides infrastructure for registration
1391ff4cb8SJean Pihet  * of:
1491ff4cb8SJean Pihet  *
1591ff4cb8SJean Pihet  * Dependents on a QoS value : register requests
1691ff4cb8SJean Pihet  * Watchers of QoS value : get notified when target QoS value changes
1791ff4cb8SJean Pihet  *
1891ff4cb8SJean Pihet  * This QoS design is best effort based. Dependents register their QoS needs.
1991ff4cb8SJean Pihet  * Watchers register to keep track of the current QoS needs of the system.
20b66213cdSJean Pihet  * Watchers can register different types of notification callbacks:
21b66213cdSJean Pihet  *  . a per-device notification callback using the dev_pm_qos_*_notifier API.
22b66213cdSJean Pihet  *    The notification chain data is stored in the per-device constraint
23b66213cdSJean Pihet  *    data struct.
24b66213cdSJean Pihet  *  . a system-wide notification callback using the dev_pm_qos_*_global_notifier
25b66213cdSJean Pihet  *    API. The notification chain data is stored in a static variable.
2691ff4cb8SJean Pihet  *
2791ff4cb8SJean Pihet  * Note about the per-device constraint data struct allocation:
2891ff4cb8SJean Pihet  * . The per-device constraints data struct ptr is tored into the device
2991ff4cb8SJean Pihet  *    dev_pm_info.
3091ff4cb8SJean Pihet  * . To minimize the data usage by the per-device constraints, the data struct
3191ff4cb8SJean Pihet  *   is only allocated at the first call to dev_pm_qos_add_request.
3291ff4cb8SJean Pihet  * . The data is later free'd when the device is removed from the system.
3391ff4cb8SJean Pihet  *  . A global mutex protects the constraints users from the data being
3491ff4cb8SJean Pihet  *     allocated and free'd.
3591ff4cb8SJean Pihet  */
3691ff4cb8SJean Pihet 
3791ff4cb8SJean Pihet #include <linux/pm_qos.h>
3891ff4cb8SJean Pihet #include <linux/spinlock.h>
3991ff4cb8SJean Pihet #include <linux/slab.h>
4091ff4cb8SJean Pihet #include <linux/device.h>
4191ff4cb8SJean Pihet #include <linux/mutex.h>
4291ff4cb8SJean Pihet 
4391ff4cb8SJean Pihet 
4491ff4cb8SJean Pihet static DEFINE_MUTEX(dev_pm_qos_mtx);
451a9a9152SRafael J. Wysocki 
46b66213cdSJean Pihet static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
47b66213cdSJean Pihet 
481a9a9152SRafael J. Wysocki /**
491a9a9152SRafael J. Wysocki  * dev_pm_qos_read_value - Get PM QoS constraint for a given device.
501a9a9152SRafael J. Wysocki  * @dev: Device to get the PM QoS constraint value for.
511a9a9152SRafael J. Wysocki  */
521a9a9152SRafael J. Wysocki s32 dev_pm_qos_read_value(struct device *dev)
531a9a9152SRafael J. Wysocki {
541a9a9152SRafael J. Wysocki 	struct pm_qos_constraints *c;
551a9a9152SRafael J. Wysocki 	unsigned long flags;
561a9a9152SRafael J. Wysocki 	s32 ret = 0;
571a9a9152SRafael J. Wysocki 
581a9a9152SRafael J. Wysocki 	spin_lock_irqsave(&dev->power.lock, flags);
591a9a9152SRafael J. Wysocki 
601a9a9152SRafael J. Wysocki 	c = dev->power.constraints;
611a9a9152SRafael J. Wysocki 	if (c)
621a9a9152SRafael J. Wysocki 		ret = pm_qos_read_value(c);
631a9a9152SRafael J. Wysocki 
641a9a9152SRafael J. Wysocki 	spin_unlock_irqrestore(&dev->power.lock, flags);
651a9a9152SRafael J. Wysocki 
661a9a9152SRafael J. Wysocki 	return ret;
671a9a9152SRafael J. Wysocki }
681a9a9152SRafael J. Wysocki 
69b66213cdSJean Pihet /*
70b66213cdSJean Pihet  * apply_constraint
71b66213cdSJean Pihet  * @req: constraint request to apply
72b66213cdSJean Pihet  * @action: action to perform add/update/remove, of type enum pm_qos_req_action
73b66213cdSJean Pihet  * @value: defines the qos request
74b66213cdSJean Pihet  *
75b66213cdSJean Pihet  * Internal function to update the constraints list using the PM QoS core
76b66213cdSJean Pihet  * code and if needed call the per-device and the global notification
77b66213cdSJean Pihet  * callbacks
78b66213cdSJean Pihet  */
79b66213cdSJean Pihet static int apply_constraint(struct dev_pm_qos_request *req,
80b66213cdSJean Pihet 			    enum pm_qos_req_action action, int value)
81b66213cdSJean Pihet {
82b66213cdSJean Pihet 	int ret, curr_value;
83b66213cdSJean Pihet 
84b66213cdSJean Pihet 	ret = pm_qos_update_target(req->dev->power.constraints,
85b66213cdSJean Pihet 				   &req->node, action, value);
86b66213cdSJean Pihet 
87b66213cdSJean Pihet 	if (ret) {
88b66213cdSJean Pihet 		/* Call the global callbacks if needed */
89b66213cdSJean Pihet 		curr_value = pm_qos_read_value(req->dev->power.constraints);
90b66213cdSJean Pihet 		blocking_notifier_call_chain(&dev_pm_notifiers,
91b66213cdSJean Pihet 					     (unsigned long)curr_value,
92b66213cdSJean Pihet 					     req);
93b66213cdSJean Pihet 	}
94b66213cdSJean Pihet 
95b66213cdSJean Pihet 	return ret;
96b66213cdSJean Pihet }
9791ff4cb8SJean Pihet 
9891ff4cb8SJean Pihet /*
9991ff4cb8SJean Pihet  * dev_pm_qos_constraints_allocate
10091ff4cb8SJean Pihet  * @dev: device to allocate data for
10191ff4cb8SJean Pihet  *
10291ff4cb8SJean Pihet  * Called at the first call to add_request, for constraint data allocation
10391ff4cb8SJean Pihet  * Must be called with the dev_pm_qos_mtx mutex held
10491ff4cb8SJean Pihet  */
10591ff4cb8SJean Pihet static int dev_pm_qos_constraints_allocate(struct device *dev)
10691ff4cb8SJean Pihet {
10791ff4cb8SJean Pihet 	struct pm_qos_constraints *c;
10891ff4cb8SJean Pihet 	struct blocking_notifier_head *n;
10991ff4cb8SJean Pihet 
11091ff4cb8SJean Pihet 	c = kzalloc(sizeof(*c), GFP_KERNEL);
11191ff4cb8SJean Pihet 	if (!c)
11291ff4cb8SJean Pihet 		return -ENOMEM;
11391ff4cb8SJean Pihet 
11491ff4cb8SJean Pihet 	n = kzalloc(sizeof(*n), GFP_KERNEL);
11591ff4cb8SJean Pihet 	if (!n) {
11691ff4cb8SJean Pihet 		kfree(c);
11791ff4cb8SJean Pihet 		return -ENOMEM;
11891ff4cb8SJean Pihet 	}
11991ff4cb8SJean Pihet 	BLOCKING_INIT_NOTIFIER_HEAD(n);
12091ff4cb8SJean Pihet 
1211a9a9152SRafael J. Wysocki 	plist_head_init(&c->list);
1221a9a9152SRafael J. Wysocki 	c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
1231a9a9152SRafael J. Wysocki 	c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
1241a9a9152SRafael J. Wysocki 	c->type = PM_QOS_MIN;
1251a9a9152SRafael J. Wysocki 	c->notifiers = n;
1261a9a9152SRafael J. Wysocki 
1271a9a9152SRafael J. Wysocki 	spin_lock_irq(&dev->power.lock);
12891ff4cb8SJean Pihet 	dev->power.constraints = c;
1291a9a9152SRafael J. Wysocki 	spin_unlock_irq(&dev->power.lock);
13091ff4cb8SJean Pihet 
13191ff4cb8SJean Pihet 	return 0;
13291ff4cb8SJean Pihet }
13391ff4cb8SJean Pihet 
13491ff4cb8SJean Pihet /**
1351a9a9152SRafael J. Wysocki  * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
13691ff4cb8SJean Pihet  * @dev: target device
13791ff4cb8SJean Pihet  *
1381a9a9152SRafael J. Wysocki  * Called from the device PM subsystem during device insertion under
1391a9a9152SRafael J. Wysocki  * device_pm_lock().
14091ff4cb8SJean Pihet  */
14191ff4cb8SJean Pihet void dev_pm_qos_constraints_init(struct device *dev)
14291ff4cb8SJean Pihet {
14391ff4cb8SJean Pihet 	mutex_lock(&dev_pm_qos_mtx);
1441a9a9152SRafael J. Wysocki 	dev->power.constraints = NULL;
1451a9a9152SRafael J. Wysocki 	dev->power.power_state = PMSG_ON;
14691ff4cb8SJean Pihet 	mutex_unlock(&dev_pm_qos_mtx);
14791ff4cb8SJean Pihet }
14891ff4cb8SJean Pihet 
14991ff4cb8SJean Pihet /**
15091ff4cb8SJean Pihet  * dev_pm_qos_constraints_destroy
15191ff4cb8SJean Pihet  * @dev: target device
15291ff4cb8SJean Pihet  *
1531a9a9152SRafael J. Wysocki  * Called from the device PM subsystem on device removal under device_pm_lock().
15491ff4cb8SJean Pihet  */
15591ff4cb8SJean Pihet void dev_pm_qos_constraints_destroy(struct device *dev)
15691ff4cb8SJean Pihet {
15791ff4cb8SJean Pihet 	struct dev_pm_qos_request *req, *tmp;
1581a9a9152SRafael J. Wysocki 	struct pm_qos_constraints *c;
15991ff4cb8SJean Pihet 
16091ff4cb8SJean Pihet 	mutex_lock(&dev_pm_qos_mtx);
16191ff4cb8SJean Pihet 
1621a9a9152SRafael J. Wysocki 	dev->power.power_state = PMSG_INVALID;
1631a9a9152SRafael J. Wysocki 	c = dev->power.constraints;
1641a9a9152SRafael J. Wysocki 	if (!c)
1651a9a9152SRafael J. Wysocki 		goto out;
1661a9a9152SRafael J. Wysocki 
16791ff4cb8SJean Pihet 	/* Flush the constraints list for the device */
1681a9a9152SRafael J. Wysocki 	plist_for_each_entry_safe(req, tmp, &c->list, node) {
16991ff4cb8SJean Pihet 		/*
170b66213cdSJean Pihet 		 * Update constraints list and call the notification
17191ff4cb8SJean Pihet 		 * callbacks if needed
17291ff4cb8SJean Pihet 		 */
1731a9a9152SRafael J. Wysocki 		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
17491ff4cb8SJean Pihet 		memset(req, 0, sizeof(*req));
17591ff4cb8SJean Pihet 	}
17691ff4cb8SJean Pihet 
1771a9a9152SRafael J. Wysocki 	spin_lock_irq(&dev->power.lock);
17891ff4cb8SJean Pihet 	dev->power.constraints = NULL;
1791a9a9152SRafael J. Wysocki 	spin_unlock_irq(&dev->power.lock);
18091ff4cb8SJean Pihet 
1811a9a9152SRafael J. Wysocki 	kfree(c->notifiers);
1821a9a9152SRafael J. Wysocki 	kfree(c);
1831a9a9152SRafael J. Wysocki 
1841a9a9152SRafael J. Wysocki  out:
18591ff4cb8SJean Pihet 	mutex_unlock(&dev_pm_qos_mtx);
18691ff4cb8SJean Pihet }
18791ff4cb8SJean Pihet 
18891ff4cb8SJean Pihet /**
18991ff4cb8SJean Pihet  * dev_pm_qos_add_request - inserts new qos request into the list
19091ff4cb8SJean Pihet  * @dev: target device for the constraint
19191ff4cb8SJean Pihet  * @req: pointer to a preallocated handle
19291ff4cb8SJean Pihet  * @value: defines the qos request
19391ff4cb8SJean Pihet  *
19491ff4cb8SJean Pihet  * This function inserts a new entry in the device constraints list of
19591ff4cb8SJean Pihet  * requested qos performance characteristics. It recomputes the aggregate
19691ff4cb8SJean Pihet  * QoS expectations of parameters and initializes the dev_pm_qos_request
19791ff4cb8SJean Pihet  * handle.  Caller needs to save this handle for later use in updates and
19891ff4cb8SJean Pihet  * removal.
19991ff4cb8SJean Pihet  *
20091ff4cb8SJean Pihet  * Returns 1 if the aggregated constraint value has changed,
20191ff4cb8SJean Pihet  * 0 if the aggregated constraint value has not changed,
2021a9a9152SRafael J. Wysocki  * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
2031a9a9152SRafael J. Wysocki  * to allocate for data structures, -ENODEV if the device has just been removed
2041a9a9152SRafael J. Wysocki  * from the system.
20591ff4cb8SJean Pihet  */
20691ff4cb8SJean Pihet int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
20791ff4cb8SJean Pihet 			   s32 value)
20891ff4cb8SJean Pihet {
20991ff4cb8SJean Pihet 	int ret = 0;
21091ff4cb8SJean Pihet 
21191ff4cb8SJean Pihet 	if (!dev || !req) /*guard against callers passing in null */
21291ff4cb8SJean Pihet 		return -EINVAL;
21391ff4cb8SJean Pihet 
21491ff4cb8SJean Pihet 	if (dev_pm_qos_request_active(req)) {
21591ff4cb8SJean Pihet 		WARN(1, KERN_ERR "dev_pm_qos_add_request() called for already "
21691ff4cb8SJean Pihet 			"added request\n");
21791ff4cb8SJean Pihet 		return -EINVAL;
21891ff4cb8SJean Pihet 	}
21991ff4cb8SJean Pihet 
22091ff4cb8SJean Pihet 	req->dev = dev;
22191ff4cb8SJean Pihet 
2221a9a9152SRafael J. Wysocki 	mutex_lock(&dev_pm_qos_mtx);
2231a9a9152SRafael J. Wysocki 
2241a9a9152SRafael J. Wysocki 	if (!dev->power.constraints) {
2251a9a9152SRafael J. Wysocki 		if (dev->power.power_state.event == PM_EVENT_INVALID) {
2261a9a9152SRafael J. Wysocki 			/* The device has been removed from the system. */
2271a9a9152SRafael J. Wysocki 			req->dev = NULL;
22891ff4cb8SJean Pihet 			ret = -ENODEV;
22991ff4cb8SJean Pihet 			goto out;
2301a9a9152SRafael J. Wysocki 		} else {
23191ff4cb8SJean Pihet 			/*
2321a9a9152SRafael J. Wysocki 			 * Allocate the constraints data on the first call to
2331a9a9152SRafael J. Wysocki 			 * add_request, i.e. only if the data is not already
2341a9a9152SRafael J. Wysocki 			 * allocated and if the device has not been removed.
23591ff4cb8SJean Pihet 			 */
23691ff4cb8SJean Pihet 			ret = dev_pm_qos_constraints_allocate(dev);
2371a9a9152SRafael J. Wysocki 		}
2381a9a9152SRafael J. Wysocki 	}
23991ff4cb8SJean Pihet 
24091ff4cb8SJean Pihet 	if (!ret)
241b66213cdSJean Pihet 		ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
24291ff4cb8SJean Pihet 
24391ff4cb8SJean Pihet  out:
24491ff4cb8SJean Pihet 	mutex_unlock(&dev_pm_qos_mtx);
2451a9a9152SRafael J. Wysocki 
24691ff4cb8SJean Pihet 	return ret;
24791ff4cb8SJean Pihet }
24891ff4cb8SJean Pihet EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
24991ff4cb8SJean Pihet 
25091ff4cb8SJean Pihet /**
25191ff4cb8SJean Pihet  * dev_pm_qos_update_request - modifies an existing qos request
25291ff4cb8SJean Pihet  * @req : handle to list element holding a dev_pm_qos request to use
25391ff4cb8SJean Pihet  * @new_value: defines the qos request
25491ff4cb8SJean Pihet  *
25591ff4cb8SJean Pihet  * Updates an existing dev PM qos request along with updating the
25691ff4cb8SJean Pihet  * target value.
25791ff4cb8SJean Pihet  *
25891ff4cb8SJean Pihet  * Attempts are made to make this code callable on hot code paths.
25991ff4cb8SJean Pihet  *
26091ff4cb8SJean Pihet  * Returns 1 if the aggregated constraint value has changed,
26191ff4cb8SJean Pihet  * 0 if the aggregated constraint value has not changed,
26291ff4cb8SJean Pihet  * -EINVAL in case of wrong parameters, -ENODEV if the device has been
26391ff4cb8SJean Pihet  * removed from the system
26491ff4cb8SJean Pihet  */
26591ff4cb8SJean Pihet int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
26691ff4cb8SJean Pihet 			      s32 new_value)
26791ff4cb8SJean Pihet {
26891ff4cb8SJean Pihet 	int ret = 0;
26991ff4cb8SJean Pihet 
27091ff4cb8SJean Pihet 	if (!req) /*guard against callers passing in null */
27191ff4cb8SJean Pihet 		return -EINVAL;
27291ff4cb8SJean Pihet 
27391ff4cb8SJean Pihet 	if (!dev_pm_qos_request_active(req)) {
27491ff4cb8SJean Pihet 		WARN(1, KERN_ERR "dev_pm_qos_update_request() called for "
27591ff4cb8SJean Pihet 			"unknown object\n");
27691ff4cb8SJean Pihet 		return -EINVAL;
27791ff4cb8SJean Pihet 	}
27891ff4cb8SJean Pihet 
27991ff4cb8SJean Pihet 	mutex_lock(&dev_pm_qos_mtx);
28091ff4cb8SJean Pihet 
2811a9a9152SRafael J. Wysocki 	if (req->dev->power.constraints) {
28291ff4cb8SJean Pihet 		if (new_value != req->node.prio)
283b66213cdSJean Pihet 			ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
28491ff4cb8SJean Pihet 					       new_value);
28591ff4cb8SJean Pihet 	} else {
28691ff4cb8SJean Pihet 		/* Return if the device has been removed */
28791ff4cb8SJean Pihet 		ret = -ENODEV;
28891ff4cb8SJean Pihet 	}
28991ff4cb8SJean Pihet 
29091ff4cb8SJean Pihet 	mutex_unlock(&dev_pm_qos_mtx);
29191ff4cb8SJean Pihet 	return ret;
29291ff4cb8SJean Pihet }
29391ff4cb8SJean Pihet EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
29491ff4cb8SJean Pihet 
29591ff4cb8SJean Pihet /**
29691ff4cb8SJean Pihet  * dev_pm_qos_remove_request - modifies an existing qos request
29791ff4cb8SJean Pihet  * @req: handle to request list element
29891ff4cb8SJean Pihet  *
29991ff4cb8SJean Pihet  * Will remove pm qos request from the list of constraints and
30091ff4cb8SJean Pihet  * recompute the current target value. Call this on slow code paths.
30191ff4cb8SJean Pihet  *
30291ff4cb8SJean Pihet  * Returns 1 if the aggregated constraint value has changed,
30391ff4cb8SJean Pihet  * 0 if the aggregated constraint value has not changed,
30491ff4cb8SJean Pihet  * -EINVAL in case of wrong parameters, -ENODEV if the device has been
30591ff4cb8SJean Pihet  * removed from the system
30691ff4cb8SJean Pihet  */
30791ff4cb8SJean Pihet int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
30891ff4cb8SJean Pihet {
30991ff4cb8SJean Pihet 	int ret = 0;
31091ff4cb8SJean Pihet 
31191ff4cb8SJean Pihet 	if (!req) /*guard against callers passing in null */
31291ff4cb8SJean Pihet 		return -EINVAL;
31391ff4cb8SJean Pihet 
31491ff4cb8SJean Pihet 	if (!dev_pm_qos_request_active(req)) {
31591ff4cb8SJean Pihet 		WARN(1, KERN_ERR "dev_pm_qos_remove_request() called for "
31691ff4cb8SJean Pihet 			"unknown object\n");
31791ff4cb8SJean Pihet 		return -EINVAL;
31891ff4cb8SJean Pihet 	}
31991ff4cb8SJean Pihet 
32091ff4cb8SJean Pihet 	mutex_lock(&dev_pm_qos_mtx);
32191ff4cb8SJean Pihet 
3221a9a9152SRafael J. Wysocki 	if (req->dev->power.constraints) {
323b66213cdSJean Pihet 		ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
32491ff4cb8SJean Pihet 				       PM_QOS_DEFAULT_VALUE);
32591ff4cb8SJean Pihet 		memset(req, 0, sizeof(*req));
32691ff4cb8SJean Pihet 	} else {
32791ff4cb8SJean Pihet 		/* Return if the device has been removed */
32891ff4cb8SJean Pihet 		ret = -ENODEV;
32991ff4cb8SJean Pihet 	}
33091ff4cb8SJean Pihet 
33191ff4cb8SJean Pihet 	mutex_unlock(&dev_pm_qos_mtx);
33291ff4cb8SJean Pihet 	return ret;
33391ff4cb8SJean Pihet }
33491ff4cb8SJean Pihet EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
33591ff4cb8SJean Pihet 
33691ff4cb8SJean Pihet /**
33791ff4cb8SJean Pihet  * dev_pm_qos_add_notifier - sets notification entry for changes to target value
33891ff4cb8SJean Pihet  * of per-device PM QoS constraints
33991ff4cb8SJean Pihet  *
34091ff4cb8SJean Pihet  * @dev: target device for the constraint
34191ff4cb8SJean Pihet  * @notifier: notifier block managed by caller.
34291ff4cb8SJean Pihet  *
34391ff4cb8SJean Pihet  * Will register the notifier into a notification chain that gets called
34491ff4cb8SJean Pihet  * upon changes to the target value for the device.
34591ff4cb8SJean Pihet  */
34691ff4cb8SJean Pihet int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
34791ff4cb8SJean Pihet {
34891ff4cb8SJean Pihet 	int retval = 0;
34991ff4cb8SJean Pihet 
35091ff4cb8SJean Pihet 	mutex_lock(&dev_pm_qos_mtx);
35191ff4cb8SJean Pihet 
3521a9a9152SRafael J. Wysocki 	/* Silently return if the constraints object is not present. */
3531a9a9152SRafael J. Wysocki 	if (dev->power.constraints)
35491ff4cb8SJean Pihet 		retval = blocking_notifier_chain_register(
35591ff4cb8SJean Pihet 				dev->power.constraints->notifiers,
35691ff4cb8SJean Pihet 				notifier);
35791ff4cb8SJean Pihet 
35891ff4cb8SJean Pihet 	mutex_unlock(&dev_pm_qos_mtx);
35991ff4cb8SJean Pihet 	return retval;
36091ff4cb8SJean Pihet }
36191ff4cb8SJean Pihet EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
36291ff4cb8SJean Pihet 
36391ff4cb8SJean Pihet /**
36491ff4cb8SJean Pihet  * dev_pm_qos_remove_notifier - deletes notification for changes to target value
36591ff4cb8SJean Pihet  * of per-device PM QoS constraints
36691ff4cb8SJean Pihet  *
36791ff4cb8SJean Pihet  * @dev: target device for the constraint
36891ff4cb8SJean Pihet  * @notifier: notifier block to be removed.
36991ff4cb8SJean Pihet  *
37091ff4cb8SJean Pihet  * Will remove the notifier from the notification chain that gets called
37191ff4cb8SJean Pihet  * upon changes to the target value.
37291ff4cb8SJean Pihet  */
37391ff4cb8SJean Pihet int dev_pm_qos_remove_notifier(struct device *dev,
37491ff4cb8SJean Pihet 			       struct notifier_block *notifier)
37591ff4cb8SJean Pihet {
37691ff4cb8SJean Pihet 	int retval = 0;
37791ff4cb8SJean Pihet 
37891ff4cb8SJean Pihet 	mutex_lock(&dev_pm_qos_mtx);
37991ff4cb8SJean Pihet 
3801a9a9152SRafael J. Wysocki 	/* Silently return if the constraints object is not present. */
3811a9a9152SRafael J. Wysocki 	if (dev->power.constraints)
38291ff4cb8SJean Pihet 		retval = blocking_notifier_chain_unregister(
38391ff4cb8SJean Pihet 				dev->power.constraints->notifiers,
38491ff4cb8SJean Pihet 				notifier);
38591ff4cb8SJean Pihet 
38691ff4cb8SJean Pihet 	mutex_unlock(&dev_pm_qos_mtx);
38791ff4cb8SJean Pihet 	return retval;
38891ff4cb8SJean Pihet }
38991ff4cb8SJean Pihet EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
390b66213cdSJean Pihet 
391b66213cdSJean Pihet /**
392b66213cdSJean Pihet  * dev_pm_qos_add_global_notifier - sets notification entry for changes to
393b66213cdSJean Pihet  * target value of the PM QoS constraints for any device
394b66213cdSJean Pihet  *
395b66213cdSJean Pihet  * @notifier: notifier block managed by caller.
396b66213cdSJean Pihet  *
397b66213cdSJean Pihet  * Will register the notifier into a notification chain that gets called
398b66213cdSJean Pihet  * upon changes to the target value for any device.
399b66213cdSJean Pihet  */
400b66213cdSJean Pihet int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
401b66213cdSJean Pihet {
402b66213cdSJean Pihet 	return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
403b66213cdSJean Pihet }
404b66213cdSJean Pihet EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
405b66213cdSJean Pihet 
406b66213cdSJean Pihet /**
407b66213cdSJean Pihet  * dev_pm_qos_remove_global_notifier - deletes notification for changes to
408b66213cdSJean Pihet  * target value of PM QoS constraints for any device
409b66213cdSJean Pihet  *
410b66213cdSJean Pihet  * @notifier: notifier block to be removed.
411b66213cdSJean Pihet  *
412b66213cdSJean Pihet  * Will remove the notifier from the notification chain that gets called
413b66213cdSJean Pihet  * upon changes to the target value for any device.
414b66213cdSJean Pihet  */
415b66213cdSJean Pihet int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
416b66213cdSJean Pihet {
417b66213cdSJean Pihet 	return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
418b66213cdSJean Pihet }
419b66213cdSJean Pihet EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
420