|
@@ -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);
|
|
|
}
|
|
|
|