PM: domains: Allocate gpd_timing_data dynamically based on governor
authorUlf Hansson <ulf.hansson@linaro.org>
Wed, 11 May 2022 14:56:56 +0000 (16:56 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 19 May 2022 18:16:05 +0000 (20:16 +0200)
If a genpd doesn't have an associated governor assigned, there's really no
point to allocate the per device gpd_timing_data, as the data isn't being
used by a governor anyway.

To avoid wasting memory, let's therefore convert the corresponding td
variable in the struct generic_pm_domain_data into a pointer and manage the
allocation of its data dynamically.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
include/linux/pm_domain.h

index a3e727c..ca86fb3 100644 (file)
@@ -773,13 +773,16 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
        for (;;) {
                struct generic_pm_domain *genpd;
                struct pm_domain_data *pdd;
+               struct gpd_timing_data *td;
 
                spin_lock_irq(&dev->power.lock);
 
                pdd = dev->power.subsys_data ?
                                dev->power.subsys_data->domain_data : NULL;
                if (pdd) {
-                       to_gpd_data(pdd)->td.constraint_changed = true;
+                       td = to_gpd_data(pdd)->td;
+                       if (td)
+                               td->constraint_changed = true;
                        genpd = dev_to_genpd(dev);
                } else {
                        genpd = ERR_PTR(-ENODATA);
@@ -875,7 +878,7 @@ static int genpd_runtime_suspend(struct device *dev)
        struct generic_pm_domain *genpd;
        bool (*suspend_ok)(struct device *__dev);
        struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
-       struct gpd_timing_data *td = &gpd_data->td;
+       struct gpd_timing_data *td = gpd_data->td;
        bool runtime_pm = pm_runtime_enabled(dev);
        ktime_t time_start;
        s64 elapsed_ns;
@@ -915,7 +918,7 @@ static int genpd_runtime_suspend(struct device *dev)
        /* Update suspend latency value if the measured time exceeds it. */
        if (runtime_pm) {
                elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-               if (elapsed_ns > td->suspend_latency_ns) {
+               if (td && (elapsed_ns > td->suspend_latency_ns)) {
                        td->suspend_latency_ns = elapsed_ns;
                        dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
                                elapsed_ns);
@@ -951,7 +954,7 @@ static int genpd_runtime_resume(struct device *dev)
 {
        struct generic_pm_domain *genpd;
        struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
-       struct gpd_timing_data *td = &gpd_data->td;
+       struct gpd_timing_data *td = gpd_data->td;
        bool runtime_pm = pm_runtime_enabled(dev);
        ktime_t time_start;
        s64 elapsed_ns;
@@ -999,7 +1002,7 @@ static int genpd_runtime_resume(struct device *dev)
        /* Update resume latency value if the measured time exceeds it. */
        if (timed && runtime_pm) {
                elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-               if (elapsed_ns > td->resume_latency_ns) {
+               if (td && (elapsed_ns > td->resume_latency_ns)) {
                        td->resume_latency_ns = elapsed_ns;
                        dev_dbg(dev, "resume latency exceeded, %lld ns\n",
                                elapsed_ns);
@@ -1496,9 +1499,11 @@ EXPORT_SYMBOL_GPL(dev_pm_genpd_resume);
 
 #endif /* CONFIG_PM_SLEEP */
 
-static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
+static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
+                                                          bool has_governor)
 {
        struct generic_pm_domain_data *gpd_data;
+       struct gpd_timing_data *td;
        int ret;
 
        ret = dev_pm_get_subsys_data(dev);
@@ -1512,26 +1517,38 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
        }
 
        gpd_data->base.dev = dev;
-       gpd_data->td.constraint_changed = true;
-       gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
        gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
        gpd_data->next_wakeup = KTIME_MAX;
 
-       spin_lock_irq(&dev->power.lock);
+       /* Allocate data used by a governor. */
+       if (has_governor) {
+               td = kzalloc(sizeof(*td), GFP_KERNEL);
+               if (!td) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
 
-       if (dev->power.subsys_data->domain_data) {
-               ret = -EINVAL;
-               goto err_free;
+               td->constraint_changed = true;
+               td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
+               gpd_data->td = td;
        }
 
-       dev->power.subsys_data->domain_data = &gpd_data->base;
+       spin_lock_irq(&dev->power.lock);
+
+       if (dev->power.subsys_data->domain_data)
+               ret = -EINVAL;
+       else
+               dev->power.subsys_data->domain_data = &gpd_data->base;
 
        spin_unlock_irq(&dev->power.lock);
 
+       if (ret)
+               goto err_free;
+
        return gpd_data;
 
  err_free:
-       spin_unlock_irq(&dev->power.lock);
+       kfree(gpd_data->td);
        kfree(gpd_data);
  err_put:
        dev_pm_put_subsys_data(dev);
@@ -1547,6 +1564,7 @@ static void genpd_free_dev_data(struct device *dev,
 
        spin_unlock_irq(&dev->power.lock);
 
+       kfree(gpd_data->td);
        kfree(gpd_data);
        dev_pm_put_subsys_data(dev);
 }
@@ -1611,7 +1629,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
                return -EINVAL;
 
-       gpd_data = genpd_alloc_dev_data(dev);
+       gpd_data = genpd_alloc_dev_data(dev, genpd->gov);
        if (IS_ERR(gpd_data))
                return PTR_ERR(gpd_data);
 
index c13e448..62be9b3 100644 (file)
@@ -18,6 +18,8 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
        s64 constraint_ns;
 
        if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
+               struct gpd_timing_data *td = dev_gpd_data(dev)->td;
+
                /*
                 * Only take suspend-time QoS constraints of devices into
                 * account, because constraints updated after the device has
@@ -25,7 +27,8 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
                 * anyway.  In order for them to take effect, the device has to
                 * be resumed and suspended again.
                 */
-               constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+               constraint_ns = td ? td->effective_constraint_ns :
+                               PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
        } else {
                /*
                 * The child is not in a domain and there's no info on its
@@ -49,7 +52,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
  */
 static bool default_suspend_ok(struct device *dev)
 {
-       struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       struct gpd_timing_data *td = dev_gpd_data(dev)->td;
        unsigned long flags;
        s64 constraint_ns;
 
@@ -215,7 +218,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
                 * domain to turn off and on (that's how much time it will
                 * have to wait worst case).
                 */
-               td = &to_gpd_data(pdd)->td;
+               td = to_gpd_data(pdd)->td;
                constraint_ns = td->effective_constraint_ns;
                /*
                 * Zero means "no suspend at all" and this runs only when all
index 043d48e..126a4b9 100644 (file)
@@ -193,7 +193,7 @@ struct pm_domain_data {
 
 struct generic_pm_domain_data {
        struct pm_domain_data base;
-       struct gpd_timing_data td;
+       struct gpd_timing_data *td;
        struct notifier_block nb;
        struct notifier_block *power_nb;
        int cpu;