PM / OPP: predictable fail results for opp_find* functions, v2
Currently the opp_find* functions return -ENODEV when: a) it cant find a device (e.g. request for an OPP search on device which was not registered) b) When it cant find a match for the search strategy used This makes life a little in-efficient for users such as devfreq to make reasonable judgement before switching search strategies. So, standardize the return results as following: -EINVAL for bad pointer parameters -ENODEV when device cannot be found -ERANGE when search fails This has the following benefit for devfreq implementation: The search fails when an unregistered device pointer is provided. This is a trigger to change the search direction and search for a better fit, however, if we cannot differentiate between a valid search range failure Vs an unregistered device, second search goes through the same fail return condition. This can be avoided by appropriate handling of error return code. With this change, we also fix devfreq for the improved search strategy with updated error code. Signed-off-by: Nishanth Menon <nm@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
80126ce7ae
commit
0779726cc2
|
@ -235,7 +235,10 @@ EXPORT_SYMBOL(opp_get_opp_count);
|
||||||
*
|
*
|
||||||
* Searches for exact match in the opp list and returns pointer to the matching
|
* 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
|
* 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
|
* 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
|
* match is for exact matching frequency and is available in the stored OPP
|
||||||
|
@ -254,7 +257,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
|
||||||
bool available)
|
bool available)
|
||||||
{
|
{
|
||||||
struct device_opp *dev_opp;
|
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);
|
dev_opp = find_device_opp(dev);
|
||||||
if (IS_ERR(dev_opp)) {
|
if (IS_ERR(dev_opp)) {
|
||||||
|
@ -284,7 +287,11 @@ EXPORT_SYMBOL(opp_find_freq_exact);
|
||||||
* for a device.
|
* for a device.
|
||||||
*
|
*
|
||||||
* Returns matching *opp and refreshes *freq accordingly, else returns
|
* 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
|
* 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
|
* protected pointer. The reason for the same is that the opp pointer which is
|
||||||
|
@ -295,7 +302,7 @@ EXPORT_SYMBOL(opp_find_freq_exact);
|
||||||
struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
|
struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
|
||||||
{
|
{
|
||||||
struct device_opp *dev_opp;
|
struct device_opp *dev_opp;
|
||||||
struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
|
struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
|
||||||
|
|
||||||
if (!dev || !freq) {
|
if (!dev || !freq) {
|
||||||
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
|
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
|
||||||
|
@ -304,7 +311,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
|
||||||
|
|
||||||
dev_opp = find_device_opp(dev);
|
dev_opp = find_device_opp(dev);
|
||||||
if (IS_ERR(dev_opp))
|
if (IS_ERR(dev_opp))
|
||||||
return opp;
|
return ERR_CAST(dev_opp);
|
||||||
|
|
||||||
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
|
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
|
||||||
if (temp_opp->available && temp_opp->rate >= *freq) {
|
if (temp_opp->available && temp_opp->rate >= *freq) {
|
||||||
|
@ -327,7 +334,11 @@ EXPORT_SYMBOL(opp_find_freq_ceil);
|
||||||
* for a device.
|
* for a device.
|
||||||
*
|
*
|
||||||
* Returns matching *opp and refreshes *freq accordingly, else returns
|
* 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
|
* 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
|
* protected pointer. The reason for the same is that the opp pointer which is
|
||||||
|
@ -338,7 +349,7 @@ EXPORT_SYMBOL(opp_find_freq_ceil);
|
||||||
struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
|
struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
|
||||||
{
|
{
|
||||||
struct device_opp *dev_opp;
|
struct device_opp *dev_opp;
|
||||||
struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
|
struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
|
||||||
|
|
||||||
if (!dev || !freq) {
|
if (!dev || !freq) {
|
||||||
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
|
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
|
||||||
|
@ -347,7 +358,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
|
||||||
|
|
||||||
dev_opp = find_device_opp(dev);
|
dev_opp = find_device_opp(dev);
|
||||||
if (IS_ERR(dev_opp))
|
if (IS_ERR(dev_opp))
|
||||||
return opp;
|
return ERR_CAST(dev_opp);
|
||||||
|
|
||||||
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
|
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
|
||||||
if (temp_opp->available) {
|
if (temp_opp->available) {
|
||||||
|
|
|
@ -656,14 +656,14 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
|
||||||
opp = opp_find_freq_floor(dev, freq);
|
opp = opp_find_freq_floor(dev, freq);
|
||||||
|
|
||||||
/* If not available, use the closest opp */
|
/* If not available, use the closest opp */
|
||||||
if (opp == ERR_PTR(-ENODEV))
|
if (opp == ERR_PTR(-ERANGE))
|
||||||
opp = opp_find_freq_ceil(dev, freq);
|
opp = opp_find_freq_ceil(dev, freq);
|
||||||
} else {
|
} else {
|
||||||
/* The freq is an lower bound. opp should be higher */
|
/* The freq is an lower bound. opp should be higher */
|
||||||
opp = opp_find_freq_ceil(dev, freq);
|
opp = opp_find_freq_ceil(dev, freq);
|
||||||
|
|
||||||
/* If not available, use the closest opp */
|
/* If not available, use the closest opp */
|
||||||
if (opp == ERR_PTR(-ENODEV))
|
if (opp == ERR_PTR(-ERANGE))
|
||||||
opp = opp_find_freq_floor(dev, freq);
|
opp = opp_find_freq_floor(dev, freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue