diff options
Diffstat (limited to 'drivers/base/power/qos.c')
| -rw-r--r-- | drivers/base/power/qos.c | 60 | 
1 files changed, 47 insertions, 13 deletions
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 5f74587ef25..71671c42ef4 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -46,6 +46,7 @@  #include "power.h"  static DEFINE_MUTEX(dev_pm_qos_mtx); +static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);  static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); @@ -216,12 +217,17 @@ void dev_pm_qos_constraints_destroy(struct device *dev)  	struct pm_qos_constraints *c;  	struct pm_qos_flags *f; -	mutex_lock(&dev_pm_qos_mtx); +	mutex_lock(&dev_pm_qos_sysfs_mtx);  	/*  	 * If the device's PM QoS resume latency limit or PM QoS flags have been  	 * exposed to user space, they have to be hidden at this point.  	 */ +	pm_qos_sysfs_remove_latency(dev); +	pm_qos_sysfs_remove_flags(dev); + +	mutex_lock(&dev_pm_qos_mtx); +  	__dev_pm_qos_hide_latency_limit(dev);  	__dev_pm_qos_hide_flags(dev); @@ -254,6 +260,8 @@ void dev_pm_qos_constraints_destroy(struct device *dev)   out:  	mutex_unlock(&dev_pm_qos_mtx); + +	mutex_unlock(&dev_pm_qos_sysfs_mtx);  }  /** @@ -558,6 +566,14 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,  	kfree(req);  } +static void dev_pm_qos_drop_user_request(struct device *dev, +					 enum dev_pm_qos_req_type type) +{ +	mutex_lock(&dev_pm_qos_mtx); +	__dev_pm_qos_drop_user_request(dev, type); +	mutex_unlock(&dev_pm_qos_mtx); +} +  /**   * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.   * @dev: Device whose PM QoS latency limit is to be exposed to user space. @@ -581,6 +597,8 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)  		return ret;  	} +	mutex_lock(&dev_pm_qos_sysfs_mtx); +  	mutex_lock(&dev_pm_qos_mtx);  	if (IS_ERR_OR_NULL(dev->power.qos)) @@ -591,26 +609,27 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)  	if (ret < 0) {  		__dev_pm_qos_remove_request(req);  		kfree(req); +		mutex_unlock(&dev_pm_qos_mtx);  		goto out;  	} -  	dev->power.qos->latency_req = req; + +	mutex_unlock(&dev_pm_qos_mtx); +  	ret = pm_qos_sysfs_add_latency(dev);  	if (ret) -		__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); +		dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);   out: -	mutex_unlock(&dev_pm_qos_mtx); +	mutex_unlock(&dev_pm_qos_sysfs_mtx);  	return ret;  }  EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);  static void __dev_pm_qos_hide_latency_limit(struct device *dev)  { -	if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req) { -		pm_qos_sysfs_remove_latency(dev); +	if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)  		__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); -	}  }  /** @@ -619,9 +638,15 @@ static void __dev_pm_qos_hide_latency_limit(struct device *dev)   */  void dev_pm_qos_hide_latency_limit(struct device *dev)  { +	mutex_lock(&dev_pm_qos_sysfs_mtx); + +	pm_qos_sysfs_remove_latency(dev); +  	mutex_lock(&dev_pm_qos_mtx);  	__dev_pm_qos_hide_latency_limit(dev);  	mutex_unlock(&dev_pm_qos_mtx); + +	mutex_unlock(&dev_pm_qos_sysfs_mtx);  }  EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); @@ -649,6 +674,8 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)  	}  	pm_runtime_get_sync(dev); +	mutex_lock(&dev_pm_qos_sysfs_mtx); +  	mutex_lock(&dev_pm_qos_mtx);  	if (IS_ERR_OR_NULL(dev->power.qos)) @@ -659,16 +686,19 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)  	if (ret < 0) {  		__dev_pm_qos_remove_request(req);  		kfree(req); +		mutex_unlock(&dev_pm_qos_mtx);  		goto out;  	} -  	dev->power.qos->flags_req = req; + +	mutex_unlock(&dev_pm_qos_mtx); +  	ret = pm_qos_sysfs_add_flags(dev);  	if (ret) -		__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); +		dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);   out: -	mutex_unlock(&dev_pm_qos_mtx); +	mutex_unlock(&dev_pm_qos_sysfs_mtx);  	pm_runtime_put(dev);  	return ret;  } @@ -676,10 +706,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);  static void __dev_pm_qos_hide_flags(struct device *dev)  { -	if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req) { -		pm_qos_sysfs_remove_flags(dev); +	if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)  		__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); -	}  }  /** @@ -689,9 +717,15 @@ static void __dev_pm_qos_hide_flags(struct device *dev)  void dev_pm_qos_hide_flags(struct device *dev)  {  	pm_runtime_get_sync(dev); +	mutex_lock(&dev_pm_qos_sysfs_mtx); + +	pm_qos_sysfs_remove_flags(dev); +  	mutex_lock(&dev_pm_qos_mtx);  	__dev_pm_qos_hide_flags(dev);  	mutex_unlock(&dev_pm_qos_mtx); + +	mutex_unlock(&dev_pm_qos_sysfs_mtx);  	pm_runtime_put(dev);  }  EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);  |