Commit 76279291 authored by Waldemar Rymarkiewicz's avatar Waldemar Rymarkiewicz Committed by Rafael J. Wysocki

PM / OPP: Fix get sharing CPUs when hotplug is used

We fail dev_pm_opp_of_get_sharing_cpus() when possible CPU device does
not exist. This can happen on platforms where not all possible CPUs
are available at start up ie. hotplugged out.  The CPU device is not
registered in the system so we are not able to check struct device to
set the sharing CPUs bitmask properly.

Example (real use case):
2 physical MIPS cores, 4 VPE, cpu0/2 run Linux and cpu1/3 are not
available for Linux at boot up. cpufreq-dt driver + OPP v2 fail to
register opp_table due to the fact there is no struct device for
cpu1 (remains offline at
bootup).

To solve the bug, stop using device struct to check device_node.
Instead get CPU device_node directly from device tree with
of_get_cpu_node().
Signed-off-by: default avatarWaldemar Rymarkiewicz <waldemarx.rymarkiewicz@intel.com>
Acked-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: default avatarStephen Boyd <sboyd@codeaurora.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 5b60697c
...@@ -248,15 +248,22 @@ void dev_pm_opp_of_remove_table(struct device *dev) ...@@ -248,15 +248,22 @@ void dev_pm_opp_of_remove_table(struct device *dev)
} }
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
/* Returns opp descriptor node for a device, caller must do of_node_put() */ /* Returns opp descriptor node for a device node, caller must
struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) * do of_node_put() */
static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np)
{ {
/* /*
* There should be only ONE phandle present in "operating-points-v2" * There should be only ONE phandle present in "operating-points-v2"
* property. * property.
*/ */
return of_parse_phandle(dev->of_node, "operating-points-v2", 0); return of_parse_phandle(np, "operating-points-v2", 0);
}
/* Returns opp descriptor node for a device, caller must do of_node_put() */
struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
{
return _opp_of_get_opp_desc_node(dev->of_node);
} }
EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
...@@ -576,8 +583,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table); ...@@ -576,8 +583,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
struct cpumask *cpumask) struct cpumask *cpumask)
{ {
struct device_node *np, *tmp_np; struct device_node *np, *tmp_np, *cpu_np;
struct device *tcpu_dev;
int cpu, ret = 0; int cpu, ret = 0;
/* Get OPP descriptor node */ /* Get OPP descriptor node */
...@@ -597,19 +603,18 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, ...@@ -597,19 +603,18 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
if (cpu == cpu_dev->id) if (cpu == cpu_dev->id)
continue; continue;
tcpu_dev = get_cpu_device(cpu); cpu_np = of_get_cpu_node(cpu, NULL);
if (!tcpu_dev) { if (!cpu_np) {
dev_err(cpu_dev, "%s: failed to get cpu%d device\n", dev_err(cpu_dev, "%s: failed to get cpu%d node\n",
__func__, cpu); __func__, cpu);
ret = -ENODEV; ret = -ENOENT;
goto put_cpu_node; goto put_cpu_node;
} }
/* Get OPP descriptor node */ /* Get OPP descriptor node */
tmp_np = dev_pm_opp_of_get_opp_desc_node(tcpu_dev); tmp_np = _opp_of_get_opp_desc_node(cpu_np);
if (!tmp_np) { if (!tmp_np) {
dev_err(tcpu_dev, "%s: Couldn't find opp node.\n", pr_err("%pOF: Couldn't find opp node\n", cpu_np);
__func__);
ret = -ENOENT; ret = -ENOENT;
goto put_cpu_node; goto put_cpu_node;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment