|
|
@@ -68,7 +68,36 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
|
|
|
return genpd;
|
|
|
}
|
|
|
|
|
|
-struct generic_pm_domain *dev_to_genpd(struct device *dev)
|
|
|
+/*
|
|
|
+ * Get the generic PM domain for a particular struct device.
|
|
|
+ * This validates the struct device pointer, the PM domain pointer,
|
|
|
+ * and checks that the PM domain pointer is a real generic PM domain.
|
|
|
+ * Any failure results in NULL being returned.
|
|
|
+ */
|
|
|
+struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev)
|
|
|
+{
|
|
|
+ struct generic_pm_domain *genpd = NULL, *gpd;
|
|
|
+
|
|
|
+ if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ mutex_lock(&gpd_list_lock);
|
|
|
+ list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
|
|
|
+ if (&gpd->domain == dev->pm_domain) {
|
|
|
+ genpd = gpd;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mutex_unlock(&gpd_list_lock);
|
|
|
+
|
|
|
+ return genpd;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This should only be used where we are certain that the pm_domain
|
|
|
+ * attached to the device is a genpd domain.
|
|
|
+ */
|
|
|
+static struct generic_pm_domain *dev_to_genpd(struct device *dev)
|
|
|
{
|
|
|
if (IS_ERR_OR_NULL(dev->pm_domain))
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
@@ -173,8 +202,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
|
|
|
genpd->power_on_latency_ns = elapsed_ns;
|
|
|
genpd->max_off_time_changed = true;
|
|
|
genpd_recalc_cpu_exit_latency(genpd);
|
|
|
- pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
|
|
|
- genpd->name, "on", elapsed_ns);
|
|
|
+ pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
|
|
|
+ genpd->name, "on", elapsed_ns);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -199,8 +228,8 @@ static int genpd_power_off(struct generic_pm_domain *genpd)
|
|
|
|
|
|
genpd->power_off_latency_ns = elapsed_ns;
|
|
|
genpd->max_off_time_changed = true;
|
|
|
- pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
|
|
|
- genpd->name, "off", elapsed_ns);
|
|
|
+ pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
|
|
|
+ genpd->name, "off", elapsed_ns);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -1513,9 +1542,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
|
|
|
|
|
dev_dbg(dev, "%s()\n", __func__);
|
|
|
|
|
|
- if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
|
|
|
- || IS_ERR_OR_NULL(dev->pm_domain)
|
|
|
- || pd_to_genpd(dev->pm_domain) != genpd)
|
|
|
+ if (!genpd || genpd != pm_genpd_lookup_dev(dev))
|
|
|
return -EINVAL;
|
|
|
|
|
|
/* The above validation also means we have existing domain_data. */
|
|
|
@@ -2093,21 +2120,10 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
|
|
|
*/
|
|
|
static void genpd_dev_pm_detach(struct device *dev, bool power_off)
|
|
|
{
|
|
|
- struct generic_pm_domain *pd = NULL, *gpd;
|
|
|
+ struct generic_pm_domain *pd;
|
|
|
int ret = 0;
|
|
|
|
|
|
- if (!dev->pm_domain)
|
|
|
- return;
|
|
|
-
|
|
|
- mutex_lock(&gpd_list_lock);
|
|
|
- list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
|
|
|
- if (&gpd->domain == dev->pm_domain) {
|
|
|
- pd = gpd;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- mutex_unlock(&gpd_list_lock);
|
|
|
-
|
|
|
+ pd = pm_genpd_lookup_dev(dev);
|
|
|
if (!pd)
|
|
|
return;
|
|
|
|
|
|
@@ -2130,6 +2146,17 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
|
|
|
genpd_queue_power_off_work(pd);
|
|
|
}
|
|
|
|
|
|
+static void genpd_dev_pm_sync(struct device *dev)
|
|
|
+{
|
|
|
+ struct generic_pm_domain *pd;
|
|
|
+
|
|
|
+ pd = dev_to_genpd(dev);
|
|
|
+ if (IS_ERR(pd))
|
|
|
+ return;
|
|
|
+
|
|
|
+ genpd_queue_power_off_work(pd);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* genpd_dev_pm_attach - Attach a device to its PM domain using DT.
|
|
|
* @dev: Device to attach.
|
|
|
@@ -2196,6 +2223,7 @@ int genpd_dev_pm_attach(struct device *dev)
|
|
|
}
|
|
|
|
|
|
dev->pm_domain->detach = genpd_dev_pm_detach;
|
|
|
+ dev->pm_domain->sync = genpd_dev_pm_sync;
|
|
|
pm_genpd_poweron(pd);
|
|
|
|
|
|
return 0;
|