]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/opp/core.c
Merge tag 'printk-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek...
[linux.git] / drivers / opp / core.c
index b555121b878b1c0c234b02a1f7d74958d9549eb9..2c2df4e4fc14db27e6d2f5f938ff6300e43e9412 100644 (file)
@@ -318,7 +318,7 @@ int dev_pm_opp_get_opp_count(struct device *dev)
                count = PTR_ERR(opp_table);
                dev_dbg(dev, "%s: OPP table not found (%d)\n",
                        __func__, count);
-               return 0;
+               return count;
        }
 
        count = _get_opp_count(opp_table);
@@ -759,8 +759,8 @@ static void _remove_opp_dev(struct opp_device *opp_dev,
        kfree(opp_dev);
 }
 
-struct opp_device *_add_opp_dev(const struct device *dev,
-                               struct opp_table *opp_table)
+static struct opp_device *_add_opp_dev_unlocked(const struct device *dev,
+                                               struct opp_table *opp_table)
 {
        struct opp_device *opp_dev;
        int ret;
@@ -772,7 +772,6 @@ struct opp_device *_add_opp_dev(const struct device *dev,
        /* Initialize opp-dev */
        opp_dev->dev = dev;
 
-       mutex_lock(&opp_table->lock);
        list_add(&opp_dev->node, &opp_table->dev_list);
 
        /* Create debugfs entries for the opp_table */
@@ -780,6 +779,17 @@ struct opp_device *_add_opp_dev(const struct device *dev,
        if (ret)
                dev_err(dev, "%s: Failed to register opp debugfs (%d)\n",
                        __func__, ret);
+
+       return opp_dev;
+}
+
+struct opp_device *_add_opp_dev(const struct device *dev,
+                               struct opp_table *opp_table)
+{
+       struct opp_device *opp_dev;
+
+       mutex_lock(&opp_table->lock);
+       opp_dev = _add_opp_dev_unlocked(dev, opp_table);
        mutex_unlock(&opp_table->lock);
 
        return opp_dev;
@@ -844,6 +854,15 @@ static struct opp_table *_opp_get_opp_table(struct device *dev, int index)
        if (!IS_ERR(opp_table))
                goto unlock;
 
+       opp_table = _managed_opp(dev, index);
+       if (opp_table) {
+               if (!_add_opp_dev_unlocked(dev, opp_table)) {
+                       dev_pm_opp_put_opp_table(opp_table);
+                       opp_table = NULL;
+               }
+               goto unlock;
+       }
+
        opp_table = _allocate_opp_table(dev, index);
 
 unlock:
@@ -867,23 +886,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,44 +1778,7 @@ 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 or even the
- * dynamically added entries based on remove_all param.
- */
-void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev,
-                             bool remove_all)
-{
-       struct dev_pm_opp *opp, *tmp;
-
-       /* 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);
-
-               /* Free dynamic OPPs */
-               list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
-                       if (remove_all)
-                               dev_pm_opp_put(opp);
-               }
-
-               /*
-                * 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, bool remove_all)
+void _dev_pm_opp_find_and_remove_table(struct device *dev)
 {
        struct opp_table *opp_table;
 
@@ -1812,8 +1795,12 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
                return;
        }
 
-       _dev_pm_opp_remove_table(opp_table, dev, remove_all);
+       _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);
 }
 
@@ -1826,6 +1813,6 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
  */
 void dev_pm_opp_remove_table(struct device *dev)
 {
-       _dev_pm_opp_find_and_remove_table(dev, true);
+       _dev_pm_opp_find_and_remove_table(dev);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_remove_table);