Hi Viresh,

On Thu, 27 Aug 2020 15:16:51 +0530 Viresh Kumar <[email protected]> wrote:
>
> On 27-08-20, 15:04, Naresh Kamboju wrote:
> > While boot testing arm x15 devices the Kernel warning noticed with linux 
> > next
> > tag 20200825.
> > 
> > BAD:  next-20200825
> > GOOD:  next-20200824
> > 
> > metadata:
> >   git branch: master
> >   git repo: 
> > https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
> >   git commit: 3a00d3dfd4b68b208ecd5405e676d06c8ad6bb63
> >   git describe: next-20200825
> >   make_kernelversion: 5.9.0-rc2
> >   kernel-config:
> > https://builds.tuxbuild.com/LDTu4GFMmvkJspza5LJIjQ/kernel.config
> > 
> > We are working on git bisect and boot testing on x15 and get back to you.  
> 
> Was this working earlier ? But considering that multiple things
> related to OPP broke recently, it may be a OPP core bug as well. Not
> sure though.
> 
> Can you give me delta between both the next branches for drivers/opp/
> path ? I didn't get these tags after fetching linux-next.

Yeah, you need to explicitly fetch the tags as only the latest tag is
part of the branches in the tree.

$ git diff next-20200824..next-20200825 drivers/opp
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 6978b9218c6e..8b3c3986f589 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -779,29 +779,39 @@ static int _set_opp_custom(const struct opp_table 
*opp_table,
        return opp_table->set_opp(data);
 }
 
+static int _set_required_opp(struct device *dev, struct device *pd_dev,
+                            struct dev_pm_opp *opp, int i)
+{
+       unsigned int pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
+       int ret;
+
+       if (!pd_dev)
+               return 0;
+
+       ret = dev_pm_genpd_set_performance_state(pd_dev, pstate);
+       if (ret) {
+               dev_err(dev, "Failed to set performance rate of %s: %d (%d)\n",
+                       dev_name(pd_dev), pstate, ret);
+       }
+
+       return ret;
+}
+
 /* This is only called for PM domain for now */
 static int _set_required_opps(struct device *dev,
                              struct opp_table *opp_table,
-                             struct dev_pm_opp *opp)
+                             struct dev_pm_opp *opp, bool up)
 {
        struct opp_table **required_opp_tables = opp_table->required_opp_tables;
        struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
-       unsigned int pstate;
        int i, ret = 0;
 
        if (!required_opp_tables)
                return 0;
 
        /* Single genpd case */
-       if (!genpd_virt_devs) {
-               pstate = likely(opp) ? opp->required_opps[0]->pstate : 0;
-               ret = dev_pm_genpd_set_performance_state(dev, pstate);
-               if (ret) {
-                       dev_err(dev, "Failed to set performance state of %s: %d 
(%d)\n",
-                               dev_name(dev), pstate, ret);
-               }
-               return ret;
-       }
+       if (!genpd_virt_devs)
+               return _set_required_opp(dev, dev, opp, 0);
 
        /* Multiple genpd case */
 
@@ -811,19 +821,21 @@ static int _set_required_opps(struct device *dev,
         */
        mutex_lock(&opp_table->genpd_virt_dev_lock);
 
-       for (i = 0; i < opp_table->required_opp_count; i++) {
-               pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
-
-               if (!genpd_virt_devs[i])
-                       continue;
-
-               ret = dev_pm_genpd_set_performance_state(genpd_virt_devs[i], 
pstate);
-               if (ret) {
-                       dev_err(dev, "Failed to set performance rate of %s: %d 
(%d)\n",
-                               dev_name(genpd_virt_devs[i]), pstate, ret);
-                       break;
+       /* Scaling up? Set required OPPs in normal order, else reverse */
+       if (up) {
+               for (i = 0; i < opp_table->required_opp_count; i++) {
+                       ret = _set_required_opp(dev, genpd_virt_devs[i], opp, 
i);
+                       if (ret)
+                               break;
+               }
+       } else {
+               for (i = opp_table->required_opp_count - 1; i >= 0; i--) {
+                       ret = _set_required_opp(dev, genpd_virt_devs[i], opp, 
i);
+                       if (ret)
+                               break;
                }
        }
+
        mutex_unlock(&opp_table->genpd_virt_dev_lock);
 
        return ret;
@@ -882,7 +894,7 @@ static int _opp_set_rate_zero(struct device *dev, struct 
opp_table *opp_table)
        if (opp_table->regulators)
                regulator_disable(opp_table->regulators[0]);
 
-       ret = _set_required_opps(dev, opp_table, NULL);
+       ret = _set_required_opps(dev, opp_table, NULL, false);
 
        opp_table->enabled = false;
        return ret;
@@ -973,7 +985,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long 
target_freq)
 
        /* Scaling up? Configure required OPPs before frequency */
        if (freq >= old_freq) {
-               ret = _set_required_opps(dev, opp_table, opp);
+               ret = _set_required_opps(dev, opp_table, opp, true);
                if (ret)
                        goto put_opp;
        }
@@ -993,7 +1005,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long 
target_freq)
 
        /* Scaling down? Configure required OPPs after frequency */
        if (!ret && freq < old_freq) {
-               ret = _set_required_opps(dev, opp_table, opp);
+               ret = _set_required_opps(dev, opp_table, opp, false);
                if (ret)
                        dev_err(dev, "Failed to set required opps: %d\n", ret);
        }
@@ -1068,7 +1080,7 @@ static struct opp_table *_allocate_opp_table(struct 
device *dev, int index)
         */
        opp_table = kzalloc(sizeof(*opp_table), GFP_KERNEL);
        if (!opp_table)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        mutex_init(&opp_table->lock);
        mutex_init(&opp_table->genpd_virt_dev_lock);
@@ -1079,8 +1091,8 @@ static struct opp_table *_allocate_opp_table(struct 
device *dev, int index)
 
        opp_dev = _add_opp_dev(dev, opp_table);
        if (!opp_dev) {
-               kfree(opp_table);
-               return NULL;
+               ret = -ENOMEM;
+               goto err;
        }
 
        _of_init_opp_table(opp_table, dev, index);
@@ -1089,16 +1101,21 @@ static struct opp_table *_allocate_opp_table(struct 
device *dev, int index)
        opp_table->clk = clk_get(dev, NULL);
        if (IS_ERR(opp_table->clk)) {
                ret = PTR_ERR(opp_table->clk);
-               if (ret != -EPROBE_DEFER)
-                       dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__,
-                               ret);
+               if (ret == -EPROBE_DEFER)
+                       goto err;
+
+               dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
        }
 
        /* Find interconnect path(s) for the device */
        ret = dev_pm_opp_of_find_icc_paths(dev, opp_table);
-       if (ret)
+       if (ret) {
+               if (ret == -EPROBE_DEFER)
+                       goto err;
+
                dev_warn(dev, "%s: Error finding interconnect paths: %d\n",
                         __func__, ret);
+       }
 
        BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
        INIT_LIST_HEAD(&opp_table->opp_list);
@@ -1107,6 +1124,10 @@ static struct opp_table *_allocate_opp_table(struct 
device *dev, int index)
        /* Secure the device table modification */
        list_add(&opp_table->node, &opp_tables);
        return opp_table;
+
+err:
+       kfree(opp_table);
+       return ERR_PTR(ret);
 }
 
 void _get_opp_table_kref(struct opp_table *opp_table)
@@ -1129,7 +1150,7 @@ static struct opp_table *_opp_get_opp_table(struct device 
*dev, int index)
        if (opp_table) {
                if (!_add_opp_dev_unlocked(dev, opp_table)) {
                        dev_pm_opp_put_opp_table(opp_table);
-                       opp_table = NULL;
+                       opp_table = ERR_PTR(-ENOMEM);
                }
                goto unlock;
        }
@@ -1573,8 +1594,8 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct 
device *dev,
        struct opp_table *opp_table;
 
        opp_table = dev_pm_opp_get_opp_table(dev);
-       if (!opp_table)
-               return ERR_PTR(-ENOMEM);
+       if (IS_ERR(opp_table))
+               return opp_table;
 
        /* Make sure there are no concurrent readers while updating opp_table */
        WARN_ON(!list_empty(&opp_table->opp_list));
@@ -1632,8 +1653,8 @@ struct opp_table *dev_pm_opp_set_prop_name(struct device 
*dev, const char *name)
        struct opp_table *opp_table;
 
        opp_table = dev_pm_opp_get_opp_table(dev);
-       if (!opp_table)
-               return ERR_PTR(-ENOMEM);
+       if (IS_ERR(opp_table))
+               return opp_table;
 
        /* Make sure there are no concurrent readers while updating opp_table */
        WARN_ON(!list_empty(&opp_table->opp_list));
@@ -1725,8 +1746,8 @@ struct opp_table *dev_pm_opp_set_regulators(struct device 
*dev,
        int ret, i;
 
        opp_table = dev_pm_opp_get_opp_table(dev);
-       if (!opp_table)
-               return ERR_PTR(-ENOMEM);
+       if (IS_ERR(opp_table))
+               return opp_table;
 
        /* This should be called before OPPs are initialized */
        if (WARN_ON(!list_empty(&opp_table->opp_list))) {
@@ -1833,8 +1854,8 @@ struct opp_table *dev_pm_opp_set_clkname(struct device 
*dev, const char *name)
        int ret;
 
        opp_table = dev_pm_opp_get_opp_table(dev);
-       if (!opp_table)
-               return ERR_PTR(-ENOMEM);
+       if (IS_ERR(opp_table))
+               return opp_table;
 
        /* This should be called before OPPs are initialized */
        if (WARN_ON(!list_empty(&opp_table->opp_list))) {
@@ -1901,8 +1922,8 @@ struct opp_table 
*dev_pm_opp_register_set_opp_helper(struct device *dev,
                return ERR_PTR(-EINVAL);
 
        opp_table = dev_pm_opp_get_opp_table(dev);
-       if (!opp_table)
-               return ERR_PTR(-ENOMEM);
+       if (!IS_ERR(opp_table))
+               return opp_table;
 
        /* This should be called before OPPs are initialized */
        if (WARN_ON(!list_empty(&opp_table->opp_list))) {
@@ -1982,8 +2003,8 @@ struct opp_table *dev_pm_opp_attach_genpd(struct device 
*dev,
        const char **name = names;
 
        opp_table = dev_pm_opp_get_opp_table(dev);
-       if (!opp_table)
-               return ERR_PTR(-ENOMEM);
+       if (IS_ERR(opp_table))
+               return opp_table;
 
        /*
         * If the genpd's OPP table isn't already initialized, parsing of the
@@ -2153,8 +2174,8 @@ int dev_pm_opp_add(struct device *dev, unsigned long 
freq, unsigned long u_volt)
        int ret;
 
        opp_table = dev_pm_opp_get_opp_table(dev);
-       if (!opp_table)
-               return -ENOMEM;
+       if (IS_ERR(opp_table))
+               return PTR_ERR(opp_table);
 
        /* Fix regulator count for dynamic OPPs */
        opp_table->regulator_count = 1;
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 7d9d4455a59e..e39ddcc779af 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -947,8 +947,8 @@ int dev_pm_opp_of_add_table(struct device *dev)
        int ret;
 
        opp_table = dev_pm_opp_get_opp_table_indexed(dev, 0);
-       if (!opp_table)
-               return -ENOMEM;
+       if (IS_ERR(opp_table))
+               return PTR_ERR(opp_table);
 
        /*
         * OPPs have two version of bindings now. Also try the old (v1)
@@ -1002,8 +1002,8 @@ int dev_pm_opp_of_add_table_indexed(struct device *dev, 
int index)
        }
 
        opp_table = dev_pm_opp_get_opp_table_indexed(dev, index);
-       if (!opp_table)
-               return -ENOMEM;
+       if (IS_ERR(opp_table))
+               return PTR_ERR(opp_table);
 
        ret = _of_add_opp_table_v2(dev, opp_table);
        if (ret)

-- 
Cheers,
Stephen Rothwell

Attachment: pgphchJbcm5AC.pgp
Description: OpenPGP digital signature

Reply via email to