Commit 66d29d80 authored by Ulf Hansson's avatar Ulf Hansson Committed by Rafael J. Wysocki
Browse files

PM: domains: Allocate gpd_timing_data dynamically based on governor



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: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent bcc19f69
Loading
Loading
Loading
Loading
+33 −15
Original line number Diff line number Diff line
@@ -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);

	if (dev->power.subsys_data->domain_data) {
		ret = -EINVAL;
	/* Allocate data used by a governor. */
	if (has_governor) {
		td = kzalloc(sizeof(*td), GFP_KERNEL);
		if (!td) {
			ret = -ENOMEM;
			goto err_free;
		}

		td->constraint_changed = true;
		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
		gpd_data->td = td;
	}

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

+6 −3
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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;