Commit c2dc121c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'opp/linux-next' of...

Merge branch 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm into pm-opp

Pull more operating performance points (OPP) framework updates for 4.20
from Viresh Kumar:

"That contains some important fixes reported recently."

* 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  PM / OPP: _of_add_opp_table_v2(): increment count only if OPP is added
  cpufreq: dt: Try freeing static OPPs only if we have added them
  OPP: Return error on error from dev_pm_opp_get_opp_count()
  OPP: Improve error handling in dev_pm_opp_of_cpumask_add_table()
parents fb64207b deac8703
Loading
Loading
Loading
Loading
+19 −15
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ struct private_data {
	struct device *cpu_dev;
	struct thermal_cooling_device *cdev;
	const char *reg_name;
	bool have_static_opps;
};

static struct freq_attr *cpufreq_dt_attr[] = {
@@ -204,6 +205,15 @@ static int cpufreq_init(struct cpufreq_policy *policy)
		}
	}

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		ret = -ENOMEM;
		goto out_put_regulator;
	}

	priv->reg_name = name;
	priv->opp_table = opp_table;

	/*
	 * Initialize OPP tables for all policy->cpus. They will be shared by
	 * all CPUs which have marked their CPUs shared with OPP bindings.
@@ -214,7 +224,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
	 *
	 * OPPs might be populated at runtime, don't check for error here
	 */
	dev_pm_opp_of_cpumask_add_table(policy->cpus);
	if (!dev_pm_opp_of_cpumask_add_table(policy->cpus))
		priv->have_static_opps = true;

	/*
	 * But we need OPP table to function so if it is not there let's
@@ -240,19 +251,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
				__func__, ret);
	}

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		ret = -ENOMEM;
		goto out_free_opp;
	}

	priv->reg_name = name;
	priv->opp_table = opp_table;

	ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
	if (ret) {
		dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
		goto out_free_priv;
		goto out_free_opp;
	}

	priv->cpu_dev = cpu_dev;
@@ -282,10 +284,11 @@ static int cpufreq_init(struct cpufreq_policy *policy)

out_free_cpufreq_table:
	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
out_free_priv:
	kfree(priv);
out_free_opp:
	if (priv->have_static_opps)
		dev_pm_opp_of_cpumask_remove_table(policy->cpus);
	kfree(priv);
out_put_regulator:
	if (name)
		dev_pm_opp_put_regulators(opp_table);
out_put_clk:
@@ -300,6 +303,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)

	cpufreq_cooling_unregister(priv->cdev);
	dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
	if (priv->have_static_opps)
		dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
	if (priv->reg_name)
		dev_pm_opp_put_regulators(priv->opp_table);
+1 −1
Original line number Diff line number Diff line
@@ -318,7 +318,7 @@ int dev_pm_opp_get_opp_count(struct device *dev)
		count = PTR_ERR(opp_table);
		dev_dbg(dev, "%s: OPP table not found (%d)\n",
			__func__, count);
		return 0;
		return count;
	}

	count = _get_opp_count(opp_table);
+32 −19
Original line number Diff line number Diff line
@@ -297,15 +297,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
 * removed by dev_pm_opp_remove.
 *
 * Return:
 * 0		On success OR
 * Valid OPP pointer:
 *		On success
 * NULL:
 *		Duplicate OPPs (both freq and volt are same) and opp->available
 * -EEXIST	Freq are same and volt are different OR
 *		OR if the OPP is not supported by hardware.
 * ERR_PTR(-EEXIST):
 *		Freq are same and volt are different OR
 *		Duplicate OPPs (both freq and volt are same) and !opp->available
 * -ENOMEM	Memory allocation failure
 * -EINVAL	Failed parsing the OPP node
 * ERR_PTR(-ENOMEM):
 *		Memory allocation failure
 * ERR_PTR(-EINVAL):
 *		Failed parsing the OPP node
 */
static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
			      struct device_node *np)
static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
		struct device *dev, struct device_node *np)
{
	struct dev_pm_opp *new_opp;
	u64 rate = 0;
@@ -315,7 +321,7 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,

	new_opp = _opp_allocate(opp_table);
	if (!new_opp)
		return -ENOMEM;
		return ERR_PTR(-ENOMEM);

	ret = of_property_read_u64(np, "opp-hz", &rate);
	if (ret < 0) {
@@ -390,12 +396,12 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
	 * frequency/voltage list.
	 */
	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
	return 0;
	return new_opp;

free_opp:
	_opp_free(new_opp);

	return ret;
	return ERR_PTR(ret);
}

/* Initializes OPP tables based on new bindings */
@@ -415,14 +421,15 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)

	/* We have opp-table node now, iterate over it and add OPPs */
	for_each_available_child_of_node(opp_table->np, np) {
		count++;

		ret = _opp_add_static_v2(opp_table, dev, np);
		if (ret) {
		opp = _opp_add_static_v2(opp_table, dev, np);
		if (IS_ERR(opp)) {
			ret = PTR_ERR(opp);
			dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
				ret);
			of_node_put(np);
			goto put_list_kref;
		} else if (opp) {
			count++;
		}
	}

@@ -614,16 +621,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
{
	struct device *cpu_dev;
	int cpu, ret = 0;
	int cpu, ret;

	WARN_ON(cpumask_empty(cpumask));
	if (WARN_ON(cpumask_empty(cpumask)))
		return -ENODEV;

	for_each_cpu(cpu, cpumask) {
		cpu_dev = get_cpu_device(cpu);
		if (!cpu_dev) {
			pr_err("%s: failed to get cpu%d device\n", __func__,
			       cpu);
			continue;
			ret = -ENODEV;
			goto remove_table;
		}

		ret = dev_pm_opp_of_add_table(cpu_dev);
@@ -635,12 +644,16 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
			pr_debug("%s: couldn't find opp table for cpu:%d, %d\n",
				 __func__, cpu, ret);

			/* Free all other OPPs */
			_dev_pm_opp_cpumask_remove_table(cpumask, cpu);
			break;
			goto remove_table;
		}
	}

	return 0;

remove_table:
	/* Free all other OPPs */
	_dev_pm_opp_cpumask_remove_table(cpumask, cpu);

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);