|
@@ -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);
|