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