Re: [PATCH V2 3/9] OPP: Populate required opp tables from "required-opps" property

2018-10-12 Thread Ulf Hansson
On 12 October 2018 at 13:11, Viresh Kumar  wrote:
> The current implementation works only for the case where a single
> phandle is present in the "required-opps" property, while DT allows
> multiple phandles to be present there.
>
> This patch adds new infrastructure to parse all the phandles present in
> "required-opps" property and save pointers of the required OPP's OPP
> tables. These will be used by later commits.
>
> Signed-off-by: Viresh Kumar 

Reviewed-by: Ulf Hansson 

> ---
>  drivers/opp/core.c |   2 +
>  drivers/opp/of.c   | 147 +
>  drivers/opp/opp.h  |   8 +++
>  3 files changed, 157 insertions(+)
>
> diff --git a/drivers/opp/core.c b/drivers/opp/core.c
> index ebb3b648e0fd..85174a5c4850 100644
> --- a/drivers/opp/core.c
> +++ b/drivers/opp/core.c
> @@ -901,6 +901,8 @@ 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, *temp;
>
> +   _of_clear_opp_table(opp_table);
> +
> /* Release clk */
> if (!IS_ERR(opp_table->clk))
> clk_put(opp_table->clk);
> diff --git a/drivers/opp/of.c b/drivers/opp/of.c
> index 5f114cd3d88c..b5605196122a 100644
> --- a/drivers/opp/of.c
> +++ b/drivers/opp/of.c
> @@ -73,6 +73,147 @@ struct opp_table *_managed_opp(struct device *dev, int 
> index)
> return managed_table;
>  }
>
> +/* The caller must call dev_pm_opp_put() after the OPP is used */
> +static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table,
> + struct device_node *opp_np)
> +{
> +   struct dev_pm_opp *opp;
> +
> +   lockdep_assert_held(&opp_table_lock);
> +
> +   mutex_lock(&opp_table->lock);
> +
> +   list_for_each_entry(opp, &opp_table->opp_list, node) {
> +   if (opp->np == opp_np) {
> +   dev_pm_opp_get(opp);
> +   mutex_unlock(&opp_table->lock);
> +   return opp;
> +   }
> +   }
> +
> +   mutex_unlock(&opp_table->lock);
> +
> +   return NULL;
> +}
> +
> +static struct device_node *of_parse_required_opp(struct device_node *np,
> +int index)
> +{
> +   struct device_node *required_np;
> +
> +   required_np = of_parse_phandle(np, "required-opps", index);
> +   if (unlikely(!required_np)) {
> +   pr_err("%s: Unable to parse required-opps: %pOF, index: %d\n",
> +  __func__, np, index);
> +   }
> +
> +   return required_np;
> +}
> +
> +/* The caller must call dev_pm_opp_put_opp_table() after the table is used */
> +static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
> +{
> +   struct opp_table *opp_table;
> +   struct dev_pm_opp *opp;
> +
> +   lockdep_assert_held(&opp_table_lock);
> +
> +   list_for_each_entry(opp_table, &opp_tables, node) {
> +   opp = _find_opp_of_np(opp_table, opp_np);
> +   if (opp) {
> +   dev_pm_opp_put(opp);
> +   _get_opp_table_kref(opp_table);
> +   return opp_table;
> +   }
> +   }
> +
> +   return ERR_PTR(-ENODEV);
> +}
> +
> +/* Free resources previously acquired by _opp_table_alloc_required_tables() 
> */
> +static void _opp_table_free_required_tables(struct opp_table *opp_table)
> +{
> +   struct opp_table **required_opp_tables = 
> opp_table->required_opp_tables;
> +   int i;
> +
> +   if (!required_opp_tables)
> +   return;
> +
> +   for (i = 0; i < opp_table->required_opp_count; i++) {
> +   if (IS_ERR_OR_NULL(required_opp_tables[i]))
> +   break;
> +
> +   dev_pm_opp_put_opp_table(required_opp_tables[i]);
> +   }
> +
> +   kfree(required_opp_tables);
> +
> +   opp_table->required_opp_count = 0;
> +   opp_table->required_opp_tables = NULL;
> +}
> +
> +/*
> + * Populate all devices and opp tables which are part of "required-opps" 
> list.
> + * Checking only the first OPP node should be enough.
> + */
> +static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
> +struct device *dev,
> +struct device_node *opp_np)
> +{
> +   struct opp_table **required_opp_tables;
> +   struct device_node *required_np, *np;
> +   int count, i;
> +
> +   /* Traversing the first OPP node is all we need */
> +   np = of_get_next_available_child(opp_np, NULL);
> +   if (!np) {
> +   dev_err(dev, "Empty OPP table\n");
> +   return;
> +   }
> +
> +   count = of_count_phandle_with_args(np, "required-opps", NULL);
> +   if (!count)
> +   goto put_np;
> +
> +   required_opp_tables = kcalloc(count, sizeof(*required_opp_ta

[PATCH V2 3/9] OPP: Populate required opp tables from "required-opps" property

2018-10-12 Thread Viresh Kumar
The current implementation works only for the case where a single
phandle is present in the "required-opps" property, while DT allows
multiple phandles to be present there.

This patch adds new infrastructure to parse all the phandles present in
"required-opps" property and save pointers of the required OPP's OPP
tables. These will be used by later commits.

Signed-off-by: Viresh Kumar 
---
 drivers/opp/core.c |   2 +
 drivers/opp/of.c   | 147 +
 drivers/opp/opp.h  |   8 +++
 3 files changed, 157 insertions(+)

diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index ebb3b648e0fd..85174a5c4850 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -901,6 +901,8 @@ 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, *temp;
 
+   _of_clear_opp_table(opp_table);
+
/* Release clk */
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 5f114cd3d88c..b5605196122a 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -73,6 +73,147 @@ struct opp_table *_managed_opp(struct device *dev, int 
index)
return managed_table;
 }
 
+/* The caller must call dev_pm_opp_put() after the OPP is used */
+static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table,
+ struct device_node *opp_np)
+{
+   struct dev_pm_opp *opp;
+
+   lockdep_assert_held(&opp_table_lock);
+
+   mutex_lock(&opp_table->lock);
+
+   list_for_each_entry(opp, &opp_table->opp_list, node) {
+   if (opp->np == opp_np) {
+   dev_pm_opp_get(opp);
+   mutex_unlock(&opp_table->lock);
+   return opp;
+   }
+   }
+
+   mutex_unlock(&opp_table->lock);
+
+   return NULL;
+}
+
+static struct device_node *of_parse_required_opp(struct device_node *np,
+int index)
+{
+   struct device_node *required_np;
+
+   required_np = of_parse_phandle(np, "required-opps", index);
+   if (unlikely(!required_np)) {
+   pr_err("%s: Unable to parse required-opps: %pOF, index: %d\n",
+  __func__, np, index);
+   }
+
+   return required_np;
+}
+
+/* The caller must call dev_pm_opp_put_opp_table() after the table is used */
+static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
+{
+   struct opp_table *opp_table;
+   struct dev_pm_opp *opp;
+
+   lockdep_assert_held(&opp_table_lock);
+
+   list_for_each_entry(opp_table, &opp_tables, node) {
+   opp = _find_opp_of_np(opp_table, opp_np);
+   if (opp) {
+   dev_pm_opp_put(opp);
+   _get_opp_table_kref(opp_table);
+   return opp_table;
+   }
+   }
+
+   return ERR_PTR(-ENODEV);
+}
+
+/* Free resources previously acquired by _opp_table_alloc_required_tables() */
+static void _opp_table_free_required_tables(struct opp_table *opp_table)
+{
+   struct opp_table **required_opp_tables = opp_table->required_opp_tables;
+   int i;
+
+   if (!required_opp_tables)
+   return;
+
+   for (i = 0; i < opp_table->required_opp_count; i++) {
+   if (IS_ERR_OR_NULL(required_opp_tables[i]))
+   break;
+
+   dev_pm_opp_put_opp_table(required_opp_tables[i]);
+   }
+
+   kfree(required_opp_tables);
+
+   opp_table->required_opp_count = 0;
+   opp_table->required_opp_tables = NULL;
+}
+
+/*
+ * Populate all devices and opp tables which are part of "required-opps" list.
+ * Checking only the first OPP node should be enough.
+ */
+static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
+struct device *dev,
+struct device_node *opp_np)
+{
+   struct opp_table **required_opp_tables;
+   struct device_node *required_np, *np;
+   int count, i;
+
+   /* Traversing the first OPP node is all we need */
+   np = of_get_next_available_child(opp_np, NULL);
+   if (!np) {
+   dev_err(dev, "Empty OPP table\n");
+   return;
+   }
+
+   count = of_count_phandle_with_args(np, "required-opps", NULL);
+   if (!count)
+   goto put_np;
+
+   required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
+ GFP_KERNEL);
+   if (!required_opp_tables)
+   goto put_np;
+
+   opp_table->required_opp_tables = required_opp_tables;
+   opp_table->required_opp_count = count;
+
+   for (i = 0; i < count; i++) {
+   required_np = of_parse_required_opp(np, i);
+   if (!required_