lkml.org 
[lkml]   [2020]   [Aug]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: WARNING: at drivers/opp/core.c:678 dev_pm_opp_set_rate+0x4cc/0x5d4 - on arm x15
Hi Viresh,

On Thu, 27 Aug 2020 15:16:51 +0530 Viresh Kumar <viresh.kumar@linaro.org> 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
[unhandled content-type:application/pgp-signature]
\
 
 \ /
  Last update: 2020-08-27 17:21    [W:0.079 / U:1.344 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site