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

Merge branch 'pm-opp'

* pm-opp:
  PM / OPP: using kfree_rcu() to simplify the code
  PM / OPP: predictable fail results for opp_find* functions, v2
  PM / OPP: Export symbols for module usage.
  PM / OPP: RCU reclaim
parents 9ee71f51 ea83f81b
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/rcupdate.h>
#include <linux/opp.h>
#include <linux/of.h>
#include <linux/export.h>

/*
 * Internal data structure organization with the OPP layer library is as
@@ -65,6 +66,7 @@ struct opp {
	unsigned long u_volt;

	struct device_opp *dev_opp;
	struct rcu_head head;
};

/**
@@ -160,6 +162,7 @@ unsigned long opp_get_voltage(struct opp *opp)

	return v;
}
EXPORT_SYMBOL(opp_get_voltage);

/**
 * opp_get_freq() - Gets the frequency corresponding to an available opp
@@ -189,6 +192,7 @@ unsigned long opp_get_freq(struct opp *opp)

	return f;
}
EXPORT_SYMBOL(opp_get_freq);

/**
 * opp_get_opp_count() - Get number of opps available in the opp list
@@ -221,6 +225,7 @@ int opp_get_opp_count(struct device *dev)

	return count;
}
EXPORT_SYMBOL(opp_get_opp_count);

/**
 * opp_find_freq_exact() - search for an exact frequency
@@ -230,7 +235,10 @@ int opp_get_opp_count(struct device *dev)
 *
 * Searches for exact match in the opp list and returns pointer to the matching
 * opp if found, else returns ERR_PTR in case of error and should be handled
 * using IS_ERR.
 * using IS_ERR. Error return values can be:
 * EINVAL:	for bad pointer
 * ERANGE:	no match found for search
 * ENODEV:	if device not found in list of registered devices
 *
 * Note: available is a modifier for the search. if available=true, then the
 * match is for exact matching frequency and is available in the stored OPP
@@ -249,7 +257,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
				bool available)
{
	struct device_opp *dev_opp;
	struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
	struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);

	dev_opp = find_device_opp(dev);
	if (IS_ERR(dev_opp)) {
@@ -268,6 +276,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,

	return opp;
}
EXPORT_SYMBOL(opp_find_freq_exact);

/**
 * opp_find_freq_ceil() - Search for an rounded ceil freq
@@ -278,7 +287,11 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
 * for a device.
 *
 * Returns matching *opp and refreshes *freq accordingly, else returns
 * ERR_PTR in case of error and should be handled using IS_ERR.
 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
 * values can be:
 * EINVAL:	for bad pointer
 * ERANGE:	no match found for search
 * ENODEV:	if device not found in list of registered devices
 *
 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
 * protected pointer. The reason for the same is that the opp pointer which is
@@ -289,7 +302,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
{
	struct device_opp *dev_opp;
	struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
	struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);

	if (!dev || !freq) {
		dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -298,7 +311,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)

	dev_opp = find_device_opp(dev);
	if (IS_ERR(dev_opp))
		return opp;
		return ERR_CAST(dev_opp);

	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
		if (temp_opp->available && temp_opp->rate >= *freq) {
@@ -310,6 +323,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)

	return opp;
}
EXPORT_SYMBOL(opp_find_freq_ceil);

/**
 * opp_find_freq_floor() - Search for a rounded floor freq
@@ -320,7 +334,11 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
 * for a device.
 *
 * Returns matching *opp and refreshes *freq accordingly, else returns
 * ERR_PTR in case of error and should be handled using IS_ERR.
 * ERR_PTR in case of error and should be handled using IS_ERR. Error return
 * values can be:
 * EINVAL:	for bad pointer
 * ERANGE:	no match found for search
 * ENODEV:	if device not found in list of registered devices
 *
 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
 * protected pointer. The reason for the same is that the opp pointer which is
@@ -331,7 +349,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
{
	struct device_opp *dev_opp;
	struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
	struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);

	if (!dev || !freq) {
		dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -340,7 +358,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)

	dev_opp = find_device_opp(dev);
	if (IS_ERR(dev_opp))
		return opp;
		return ERR_CAST(dev_opp);

	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
		if (temp_opp->available) {
@@ -356,6 +374,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)

	return opp;
}
EXPORT_SYMBOL(opp_find_freq_floor);

/**
 * opp_add()  - Add an OPP table from a table definitions
@@ -512,7 +531,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq,

	list_replace_rcu(&opp->node, &new_opp->node);
	mutex_unlock(&dev_opp_list_lock);
	synchronize_rcu();
	kfree_rcu(opp, head);

	/* Notify the change of the OPP availability */
	if (availability_req)
@@ -522,13 +541,10 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
		srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
					 new_opp);

	/* clean up old opp */
	new_opp = opp;
	goto out;
	return 0;

unlock:
	mutex_unlock(&dev_opp_list_lock);
out:
	kfree(new_opp);
	return r;
}
@@ -552,6 +568,7 @@ int opp_enable(struct device *dev, unsigned long freq)
{
	return opp_set_availability(dev, freq, true);
}
EXPORT_SYMBOL(opp_enable);

/**
 * opp_disable() - Disable a specific OPP
@@ -573,6 +590,7 @@ int opp_disable(struct device *dev, unsigned long freq)
{
	return opp_set_availability(dev, freq, false);
}
EXPORT_SYMBOL(opp_disable);

#ifdef CONFIG_CPU_FREQ
/**
+2 −2
Original line number Diff line number Diff line
@@ -656,14 +656,14 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
		opp = opp_find_freq_floor(dev, freq);

		/* If not available, use the closest opp */
		if (opp == ERR_PTR(-ENODEV))
		if (opp == ERR_PTR(-ERANGE))
			opp = opp_find_freq_ceil(dev, freq);
	} else {
		/* The freq is an lower bound. opp should be higher */
		opp = opp_find_freq_ceil(dev, freq);

		/* If not available, use the closest opp */
		if (opp == ERR_PTR(-ENODEV))
		if (opp == ERR_PTR(-ERANGE))
			opp = opp_find_freq_floor(dev, freq);
	}