mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	PM / OPP: Take kref from _find_opp_table()
Take reference of the OPP table from within _find_opp_table(). Also update the callers of _find_opp_table() to call dev_pm_opp_put_opp_table() after they have used the OPP table. Note that _find_opp_table() increments the reference under the opp_table_lock. Now that the OPP table wouldn't get freed until the callers of _find_opp_table() call dev_pm_opp_put_opp_table(), there is no need to take the opp_table_lock or rcu_read_lock() around it. Drop them. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
		
							parent
							
								
									8a31d9d942
								
							
						
					
					
						commit
						5b650b3888
					
				
					 2 changed files with 95 additions and 122 deletions
				
			
		| 
						 | 
					@ -54,6 +54,21 @@ static struct opp_device *_find_opp_dev(const struct device *dev,
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct opp_table *_find_opp_table_unlocked(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(opp_table, &opp_tables, node) {
 | 
				
			||||||
 | 
							if (_find_opp_dev(dev, opp_table)) {
 | 
				
			||||||
 | 
								_get_opp_table_kref(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return opp_table;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ERR_PTR(-ENODEV);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * _find_opp_table() - find opp_table struct using device pointer
 | 
					 * _find_opp_table() - find opp_table struct using device pointer
 | 
				
			||||||
 * @dev:	device pointer used to lookup OPP table
 | 
					 * @dev:	device pointer used to lookup OPP table
 | 
				
			||||||
| 
						 | 
					@ -64,28 +79,22 @@ static struct opp_device *_find_opp_dev(const struct device *dev,
 | 
				
			||||||
 * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or
 | 
					 * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or
 | 
				
			||||||
 * -EINVAL based on type of error.
 | 
					 * -EINVAL based on type of error.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Locking: For readers, this function must be called under rcu_read_lock().
 | 
					 * The callers must call dev_pm_opp_put_opp_table() after the table is used.
 | 
				
			||||||
 * opp_table is a RCU protected pointer, which means that opp_table is valid
 | 
					 | 
				
			||||||
 * as long as we are under RCU lock.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * For Writers, this function must be called with opp_table_lock held.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct opp_table *_find_opp_table(struct device *dev)
 | 
					struct opp_table *_find_opp_table(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opp_rcu_lockdep_assert();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (IS_ERR_OR_NULL(dev)) {
 | 
						if (IS_ERR_OR_NULL(dev)) {
 | 
				
			||||||
		pr_err("%s: Invalid parameters\n", __func__);
 | 
							pr_err("%s: Invalid parameters\n", __func__);
 | 
				
			||||||
		return ERR_PTR(-EINVAL);
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry_rcu(opp_table, &opp_tables, node)
 | 
						mutex_lock(&opp_table_lock);
 | 
				
			||||||
		if (_find_opp_dev(dev, opp_table))
 | 
						opp_table = _find_opp_table_unlocked(dev);
 | 
				
			||||||
			return opp_table;
 | 
						mutex_unlock(&opp_table_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ERR_PTR(-ENODEV);
 | 
						return opp_table;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -175,23 +184,20 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo);
 | 
				
			||||||
 * @dev:	device for which we do this operation
 | 
					 * @dev:	device for which we do this operation
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Return: This function returns the max clock latency in nanoseconds.
 | 
					 * Return: This function returns the max clock latency in nanoseconds.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Locking: This function takes rcu_read_lock().
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
 | 
					unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	unsigned long clock_latency_ns;
 | 
						unsigned long clock_latency_ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table))
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		clock_latency_ns = 0;
 | 
							return 0;
 | 
				
			||||||
	else
 | 
					
 | 
				
			||||||
	clock_latency_ns = opp_table->clock_latency_ns_max;
 | 
						clock_latency_ns = opp_table->clock_latency_ns_max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_unlock();
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return clock_latency_ns;
 | 
						return clock_latency_ns;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
 | 
					EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
 | 
				
			||||||
| 
						 | 
					@ -201,15 +207,13 @@ static int _get_regulator_count(struct device *dev)
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	int count;
 | 
						int count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (!IS_ERR(opp_table))
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		count = opp_table->regulator_count;
 | 
							return 0;
 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		count = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_unlock();
 | 
						count = opp_table->regulator_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return count;
 | 
						return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -248,13 +252,11 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
 | 
				
			||||||
	if (!uV)
 | 
						if (!uV)
 | 
				
			||||||
		goto free_regulators;
 | 
							goto free_regulators;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		rcu_read_unlock();
 | 
					 | 
				
			||||||
		goto free_uV;
 | 
							goto free_uV;
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));
 | 
						memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -274,6 +276,7 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The caller needs to ensure that opp_table (and hence the regulator)
 | 
						 * The caller needs to ensure that opp_table (and hence the regulator)
 | 
				
			||||||
| 
						 | 
					@ -323,17 +326,15 @@ unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	unsigned long freq = 0;
 | 
						unsigned long freq = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table) || !opp_table->suspend_opp ||
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
	    !opp_table->suspend_opp->available)
 | 
							return 0;
 | 
				
			||||||
		goto unlock;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opp_table->suspend_opp && opp_table->suspend_opp->available)
 | 
				
			||||||
		freq = dev_pm_opp_get_freq(opp_table->suspend_opp);
 | 
							freq = dev_pm_opp_get_freq(opp_table->suspend_opp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unlock:
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
	rcu_read_unlock();
 | 
					
 | 
				
			||||||
	return freq;
 | 
						return freq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
 | 
					EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
 | 
				
			||||||
| 
						 | 
					@ -353,23 +354,24 @@ int dev_pm_opp_get_opp_count(struct device *dev)
 | 
				
			||||||
	struct dev_pm_opp *temp_opp;
 | 
						struct dev_pm_opp *temp_opp;
 | 
				
			||||||
	int count = 0;
 | 
						int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table)) {
 | 
				
			||||||
		count = PTR_ERR(opp_table);
 | 
							count = PTR_ERR(opp_table);
 | 
				
			||||||
		dev_err(dev, "%s: OPP table not found (%d)\n",
 | 
							dev_err(dev, "%s: OPP table not found (%d)\n",
 | 
				
			||||||
			__func__, count);
 | 
								__func__, count);
 | 
				
			||||||
		goto out_unlock;
 | 
							return count;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
 | 
						list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
 | 
				
			||||||
		if (temp_opp->available)
 | 
							if (temp_opp->available)
 | 
				
			||||||
			count++;
 | 
								count++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_unlock:
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return count;
 | 
						return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
 | 
					EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
 | 
				
			||||||
| 
						 | 
					@ -404,17 +406,16 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 | 
						struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table)) {
 | 
				
			||||||
		int r = PTR_ERR(opp_table);
 | 
							int r = PTR_ERR(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
 | 
							dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
 | 
				
			||||||
		rcu_read_unlock();
 | 
					 | 
				
			||||||
		return ERR_PTR(r);
 | 
							return ERR_PTR(r);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
 | 
						list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
 | 
				
			||||||
		if (temp_opp->available == available &&
 | 
							if (temp_opp->available == available &&
 | 
				
			||||||
				temp_opp->rate == freq) {
 | 
									temp_opp->rate == freq) {
 | 
				
			||||||
| 
						 | 
					@ -427,6 +428,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return opp;
 | 
						return opp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -480,17 +482,16 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
 | 
				
			||||||
		return ERR_PTR(-EINVAL);
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		rcu_read_unlock();
 | 
					 | 
				
			||||||
		return ERR_CAST(opp_table);
 | 
							return ERR_CAST(opp_table);
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opp = _find_freq_ceil(opp_table, freq);
 | 
						opp = _find_freq_ceil(opp_table, freq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return opp;
 | 
						return opp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -525,13 +526,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
 | 
				
			||||||
		return ERR_PTR(-EINVAL);
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		rcu_read_unlock();
 | 
					 | 
				
			||||||
		return ERR_CAST(opp_table);
 | 
							return ERR_CAST(opp_table);
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
 | 
						list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
 | 
				
			||||||
		if (temp_opp->available) {
 | 
							if (temp_opp->available) {
 | 
				
			||||||
| 
						 | 
					@ -547,6 +546,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
 | 
				
			||||||
	if (!IS_ERR(opp))
 | 
						if (!IS_ERR(opp))
 | 
				
			||||||
		dev_pm_opp_get(opp);
 | 
							dev_pm_opp_get(opp);
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!IS_ERR(opp))
 | 
						if (!IS_ERR(opp))
 | 
				
			||||||
		*freq = opp->rate;
 | 
							*freq = opp->rate;
 | 
				
			||||||
| 
						 | 
					@ -564,22 +564,18 @@ static struct clk *_get_opp_clk(struct device *dev)
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	struct clk *clk;
 | 
						struct clk *clk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table)) {
 | 
				
			||||||
		dev_err(dev, "%s: device opp doesn't exist\n", __func__);
 | 
							dev_err(dev, "%s: device opp doesn't exist\n", __func__);
 | 
				
			||||||
		clk = ERR_CAST(opp_table);
 | 
							return ERR_CAST(opp_table);
 | 
				
			||||||
		goto unlock;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clk = opp_table->clk;
 | 
						clk = opp_table->clk;
 | 
				
			||||||
	if (IS_ERR(clk))
 | 
						if (IS_ERR(clk))
 | 
				
			||||||
		dev_err(dev, "%s: No clock available for the device\n",
 | 
							dev_err(dev, "%s: No clock available for the device\n",
 | 
				
			||||||
			__func__);
 | 
								__func__);
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unlock:
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
					 | 
				
			||||||
	return clk;
 | 
						return clk;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -715,15 +711,14 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table)) {
 | 
				
			||||||
		dev_err(dev, "%s: device opp doesn't exist\n", __func__);
 | 
							dev_err(dev, "%s: device opp doesn't exist\n", __func__);
 | 
				
			||||||
		rcu_read_unlock();
 | 
					 | 
				
			||||||
		return PTR_ERR(opp_table);
 | 
							return PTR_ERR(opp_table);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	old_opp = _find_freq_ceil(opp_table, &old_freq);
 | 
						old_opp = _find_freq_ceil(opp_table, &old_freq);
 | 
				
			||||||
	if (IS_ERR(old_opp)) {
 | 
						if (IS_ERR(old_opp)) {
 | 
				
			||||||
		dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n",
 | 
							dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n",
 | 
				
			||||||
| 
						 | 
					@ -738,6 +733,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 | 
				
			||||||
		if (!IS_ERR(old_opp))
 | 
							if (!IS_ERR(old_opp))
 | 
				
			||||||
			dev_pm_opp_put(old_opp);
 | 
								dev_pm_opp_put(old_opp);
 | 
				
			||||||
		rcu_read_unlock();
 | 
							rcu_read_unlock();
 | 
				
			||||||
 | 
							dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -752,6 +748,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 | 
				
			||||||
		if (!IS_ERR(old_opp))
 | 
							if (!IS_ERR(old_opp))
 | 
				
			||||||
			dev_pm_opp_put(old_opp);
 | 
								dev_pm_opp_put(old_opp);
 | 
				
			||||||
		rcu_read_unlock();
 | 
							rcu_read_unlock();
 | 
				
			||||||
 | 
							dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
		return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
 | 
							return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -780,6 +777,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 | 
				
			||||||
	if (!IS_ERR(old_opp))
 | 
						if (!IS_ERR(old_opp))
 | 
				
			||||||
		dev_pm_opp_put(old_opp);
 | 
							dev_pm_opp_put(old_opp);
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return set_opp(data);
 | 
						return set_opp(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -893,11 +891,9 @@ struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
 | 
				
			||||||
	/* Hold our table modification lock here */
 | 
						/* Hold our table modification lock here */
 | 
				
			||||||
	mutex_lock(&opp_table_lock);
 | 
						mutex_lock(&opp_table_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table_unlocked(dev);
 | 
				
			||||||
	if (!IS_ERR(opp_table)) {
 | 
						if (!IS_ERR(opp_table))
 | 
				
			||||||
		_get_opp_table_kref(opp_table);
 | 
					 | 
				
			||||||
		goto unlock;
 | 
							goto unlock;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opp_table = _allocate_opp_table(dev);
 | 
						opp_table = _allocate_opp_table(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1004,12 +1000,9 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	bool found = false;
 | 
						bool found = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Hold our table modification lock here */
 | 
					 | 
				
			||||||
	mutex_lock(&opp_table_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table))
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		goto unlock;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opp_table->lock);
 | 
						mutex_lock(&opp_table->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1022,15 +1015,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&opp_table->lock);
 | 
						mutex_unlock(&opp_table->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!found) {
 | 
						if (found) {
 | 
				
			||||||
 | 
							dev_pm_opp_put(opp);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
 | 
							dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
 | 
				
			||||||
			 __func__, freq);
 | 
								 __func__, freq);
 | 
				
			||||||
		goto unlock;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_pm_opp_put(opp);
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
unlock:
 | 
					 | 
				
			||||||
	mutex_unlock(&opp_table_lock);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
 | 
					EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1648,14 +1640,12 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
 | 
				
			||||||
	if (!new_opp)
 | 
						if (!new_opp)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opp_table_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Find the opp_table */
 | 
						/* Find the opp_table */
 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table)) {
 | 
				
			||||||
		r = PTR_ERR(opp_table);
 | 
							r = PTR_ERR(opp_table);
 | 
				
			||||||
		dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
 | 
							dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
 | 
				
			||||||
		goto unlock;
 | 
							goto free_opp;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opp_table->lock);
 | 
						mutex_lock(&opp_table->lock);
 | 
				
			||||||
| 
						 | 
					@ -1668,8 +1658,6 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&opp_table->lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (IS_ERR(opp)) {
 | 
						if (IS_ERR(opp)) {
 | 
				
			||||||
		r = PTR_ERR(opp);
 | 
							r = PTR_ERR(opp);
 | 
				
			||||||
		goto unlock;
 | 
							goto unlock;
 | 
				
			||||||
| 
						 | 
					@ -1685,7 +1673,6 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
 | 
				
			||||||
	new_opp->available = availability_req;
 | 
						new_opp->available = availability_req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_replace_rcu(&opp->node, &new_opp->node);
 | 
						list_replace_rcu(&opp->node, &new_opp->node);
 | 
				
			||||||
	mutex_unlock(&opp_table_lock);
 | 
					 | 
				
			||||||
	call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
 | 
						call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Notify the change of the OPP availability */
 | 
						/* Notify the change of the OPP availability */
 | 
				
			||||||
| 
						 | 
					@ -1696,10 +1683,14 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
 | 
				
			||||||
		srcu_notifier_call_chain(&opp_table->srcu_head,
 | 
							srcu_notifier_call_chain(&opp_table->srcu_head,
 | 
				
			||||||
					 OPP_EVENT_DISABLE, new_opp);
 | 
										 OPP_EVENT_DISABLE, new_opp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&opp_table->lock);
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unlock:
 | 
					unlock:
 | 
				
			||||||
	mutex_unlock(&opp_table_lock);
 | 
						mutex_unlock(&opp_table->lock);
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					free_opp:
 | 
				
			||||||
	kfree(new_opp);
 | 
						kfree(new_opp);
 | 
				
			||||||
	return r;
 | 
						return r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1767,18 +1758,16 @@ int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		ret = PTR_ERR(opp_table);
 | 
							return PTR_ERR(opp_table);
 | 
				
			||||||
		goto unlock;
 | 
					
 | 
				
			||||||
	}
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = srcu_notifier_chain_register(&opp_table->srcu_head, nb);
 | 
						ret = srcu_notifier_chain_register(&opp_table->srcu_head, nb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unlock:
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1797,18 +1786,14 @@ int dev_pm_opp_unregister_notifier(struct device *dev,
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		ret = PTR_ERR(opp_table);
 | 
							return PTR_ERR(opp_table);
 | 
				
			||||||
		goto unlock;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = srcu_notifier_chain_unregister(&opp_table->srcu_head, nb);
 | 
						ret = srcu_notifier_chain_unregister(&opp_table->srcu_head, nb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unlock:
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1839,9 +1824,6 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Hold our table modification lock here */
 | 
					 | 
				
			||||||
	mutex_lock(&opp_table_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check for existing table for 'dev' */
 | 
						/* Check for existing table for 'dev' */
 | 
				
			||||||
	opp_table = _find_opp_table(dev);
 | 
						opp_table = _find_opp_table(dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table)) {
 | 
				
			||||||
| 
						 | 
					@ -1852,13 +1834,12 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
 | 
				
			||||||
			     IS_ERR_OR_NULL(dev) ?
 | 
								     IS_ERR_OR_NULL(dev) ?
 | 
				
			||||||
					"Invalid device" : dev_name(dev),
 | 
										"Invalid device" : dev_name(dev),
 | 
				
			||||||
			     error);
 | 
								     error);
 | 
				
			||||||
		goto unlock;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_dev_pm_opp_remove_table(opp_table, dev, remove_all);
 | 
						_dev_pm_opp_remove_table(opp_table, dev, remove_all);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unlock:
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
	mutex_unlock(&opp_table_lock);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -174,13 +174,9 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
 | 
				
			||||||
	struct device *dev;
 | 
						struct device *dev;
 | 
				
			||||||
	int cpu, ret = 0;
 | 
						int cpu, ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opp_table_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(cpu_dev);
 | 
						opp_table = _find_opp_table(cpu_dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		ret = PTR_ERR(opp_table);
 | 
							return PTR_ERR(opp_table);
 | 
				
			||||||
		goto unlock;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_cpu(cpu, cpumask) {
 | 
						for_each_cpu(cpu, cpumask) {
 | 
				
			||||||
		if (cpu == cpu_dev->id)
 | 
							if (cpu == cpu_dev->id)
 | 
				
			||||||
| 
						 | 
					@ -203,8 +199,8 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
 | 
				
			||||||
		/* Mark opp-table as multiple CPUs are sharing it now */
 | 
							/* Mark opp-table as multiple CPUs are sharing it now */
 | 
				
			||||||
		opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
 | 
							opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
unlock:
 | 
					
 | 
				
			||||||
	mutex_unlock(&opp_table_lock);
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -232,17 +228,13 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
 | 
				
			||||||
	struct opp_table *opp_table;
 | 
						struct opp_table *opp_table;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opp_table_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opp_table = _find_opp_table(cpu_dev);
 | 
						opp_table = _find_opp_table(cpu_dev);
 | 
				
			||||||
	if (IS_ERR(opp_table)) {
 | 
						if (IS_ERR(opp_table))
 | 
				
			||||||
		ret = PTR_ERR(opp_table);
 | 
							return PTR_ERR(opp_table);
 | 
				
			||||||
		goto unlock;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
 | 
						if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
 | 
				
			||||||
		ret = -EINVAL;
 | 
							ret = -EINVAL;
 | 
				
			||||||
		goto unlock;
 | 
							goto put_opp_table;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cpumask_clear(cpumask);
 | 
						cpumask_clear(cpumask);
 | 
				
			||||||
| 
						 | 
					@ -254,8 +246,8 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
 | 
				
			||||||
		cpumask_set_cpu(cpu_dev->id, cpumask);
 | 
							cpumask_set_cpu(cpu_dev->id, cpumask);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unlock:
 | 
					put_opp_table:
 | 
				
			||||||
	mutex_unlock(&opp_table_lock);
 | 
						dev_pm_opp_put_opp_table(opp_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue