aboutsummaryrefslogtreecommitdiff
path: root/drivers/opp/core.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2018-09-12 12:35:19 +0530
committerViresh Kumar <viresh.kumar@linaro.org>2018-09-19 14:56:46 -0700
commitcdd6ed90cdb6c2fd982909501f0a109274147fb4 (patch)
tree353be38edd20f6a6045244801cd6597ceb5caf87 /drivers/opp/core.c
parent2a4eb7358aba6beff7fa23f028c733310756e525 (diff)
OPP: Use a single mechanism to free the OPP table
Currently there are two separate ways to free the OPP table based on how it is created in the first place. We call _dev_pm_opp_remove_table() to free the static and/or dynamic OPP, OPP list devices, etc. This is done for the case where the OPP table is added while initializing the OPPs, like via the path dev_pm_opp_of_add_table(). We also call dev_pm_opp_put_opp_table() in some cases which eventually frees the OPP table structure once the reference count reaches 0. This is used by the first case as well as other cases like dev_pm_opp_set_regulators() where the OPPs aren't necessarily initialized at this point. This whole thing is a bit unclear and messy and obstruct any further cleanup/fixup of OPP core. This patch tries to streamline this by keeping a single path for OPP table destruction, i.e. dev_pm_opp_put_opp_table(). All the cleanup happens in _opp_table_kref_release() now after the reference count reaches 0. _dev_pm_opp_remove_table() is removed as it isn't required anymore. We don't drop the reference to the OPP table after creating it from _of_add_opp_table_v{1|2}() anymore and the same is dropped only when we try to remove them. Tested-by: Niklas Cassel <niklas.cassel@linaro.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Diffstat (limited to 'drivers/opp/core.c')
-rw-r--r--drivers/opp/core.c54
1 files changed, 16 insertions, 38 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 2319ad4a0177..d3e33fd32694 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -867,23 +867,24 @@ struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev,
static void _opp_table_kref_release(struct kref *kref)
{
struct opp_table *opp_table = container_of(kref, struct opp_table, kref);
- struct opp_device *opp_dev;
+ struct opp_device *opp_dev, *temp;
/* Release clk */
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
- /*
- * No need to take opp_table->lock here as we are guaranteed that no
- * references to the OPP table are taken at this point.
- */
- opp_dev = list_first_entry(&opp_table->dev_list, struct opp_device,
- node);
+ WARN_ON(!list_empty(&opp_table->opp_list));
- _remove_opp_dev(opp_dev, opp_table);
+ list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node) {
+ /*
+ * The OPP table is getting removed, drop the performance state
+ * constraints.
+ */
+ if (opp_table->genpd_performance_state)
+ dev_pm_genpd_set_performance_state((struct device *)(opp_dev->dev), 0);
- /* dev_list must be empty now */
- WARN_ON(!list_empty(&opp_table->dev_list));
+ _remove_opp_dev(opp_dev, opp_table);
+ }
mutex_destroy(&opp_table->lock);
list_del(&opp_table->node);
@@ -1758,33 +1759,6 @@ int dev_pm_opp_unregister_notifier(struct device *dev,
}
EXPORT_SYMBOL(dev_pm_opp_unregister_notifier);
-/*
- * Free OPPs either created using static entries present in DT.
- */
-void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev)
-{
- /* Protect dev_list */
- mutex_lock(&opp_table->lock);
-
- /* Find if opp_table manages a single device */
- if (list_is_singular(&opp_table->dev_list)) {
- /* Free static OPPs */
- _put_opp_list_kref(opp_table);
-
- /*
- * The OPP table is getting removed, drop the performance state
- * constraints.
- */
- if (opp_table->genpd_performance_state)
- dev_pm_genpd_set_performance_state(dev, 0);
- } else {
- _put_opp_list_kref(opp_table);
- _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
- }
-
- mutex_unlock(&opp_table->lock);
-}
-
void _dev_pm_opp_find_and_remove_table(struct device *dev)
{
struct opp_table *opp_table;
@@ -1802,8 +1776,12 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev)
return;
}
- _dev_pm_opp_remove_table(opp_table, dev);
+ _put_opp_list_kref(opp_table);
+
+ /* Drop reference taken by _find_opp_table() */
+ dev_pm_opp_put_opp_table(opp_table);
+ /* Drop reference taken while the OPP table was added */
dev_pm_opp_put_opp_table(opp_table);
}