cpufreq: arm_big_little_dt: Register driver only if DT has valid data
If arm_big_little_dt driver is enabled, then it will always try to register with big LITTLE cpufreq core driver. In case DT doesn't have relevant data for cpu nodes, i.e. operating points aren't present, then we should exit early and shouldn't register with big LITTLE cpufreq core driver. Otherwise we will fail continuously from the driver->init() routine. This patch fixes this issue. Reported-and-tested-by: Jon Medhurst <tixy@linaro.org> Reviewed-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
b5f14720a6
commit
92a9b5c291
1 changed files with 53 additions and 42 deletions
|
@ -19,6 +19,7 @@
|
|||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
|
@ -29,60 +30,63 @@
|
|||
#include <linux/types.h>
|
||||
#include "arm_big_little.h"
|
||||
|
||||
static int dt_init_opp_table(struct device *cpu_dev)
|
||||
/* get cpu node with valid operating-points */
|
||||
static struct device_node *get_cpu_node_with_valid_op(int cpu)
|
||||
{
|
||||
struct device_node *np, *parent;
|
||||
int count = 0, ret;
|
||||
|
||||
parent = of_find_node_by_path("/cpus");
|
||||
if (!parent) {
|
||||
pr_err("failed to find OF /cpus\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
for_each_child_of_node(parent, np) {
|
||||
if (count++ != cpu_dev->id)
|
||||
continue;
|
||||
if (!of_get_property(np, "operating-points", NULL)) {
|
||||
ret = -ENODATA;
|
||||
} else {
|
||||
cpu_dev->of_node = np;
|
||||
ret = of_init_opp_table(cpu_dev);
|
||||
}
|
||||
of_node_put(np);
|
||||
of_node_put(parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int dt_get_transition_latency(struct device *cpu_dev)
|
||||
{
|
||||
struct device_node *np, *parent;
|
||||
u32 transition_latency = CPUFREQ_ETERNAL;
|
||||
struct device_node *np = NULL, *parent;
|
||||
int count = 0;
|
||||
|
||||
parent = of_find_node_by_path("/cpus");
|
||||
if (!parent) {
|
||||
pr_info("Failed to find OF /cpus. Use CPUFREQ_ETERNAL transition latency\n");
|
||||
return CPUFREQ_ETERNAL;
|
||||
pr_err("failed to find OF /cpus\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for_each_child_of_node(parent, np) {
|
||||
if (count++ != cpu_dev->id)
|
||||
if (count++ != cpu)
|
||||
continue;
|
||||
if (!of_get_property(np, "operating-points", NULL)) {
|
||||
of_node_put(np);
|
||||
np = NULL;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "clock-latency", &transition_latency);
|
||||
of_node_put(np);
|
||||
of_node_put(parent);
|
||||
|
||||
return transition_latency;
|
||||
break;
|
||||
}
|
||||
|
||||
pr_info("clock-latency isn't found, use CPUFREQ_ETERNAL transition latency\n");
|
||||
return CPUFREQ_ETERNAL;
|
||||
of_node_put(parent);
|
||||
return np;
|
||||
}
|
||||
|
||||
static int dt_init_opp_table(struct device *cpu_dev)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
np = get_cpu_node_with_valid_op(cpu_dev->id);
|
||||
if (!np)
|
||||
return -ENODATA;
|
||||
|
||||
cpu_dev->of_node = np;
|
||||
ret = of_init_opp_table(cpu_dev);
|
||||
of_node_put(np);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dt_get_transition_latency(struct device *cpu_dev)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 transition_latency = CPUFREQ_ETERNAL;
|
||||
|
||||
np = get_cpu_node_with_valid_op(cpu_dev->id);
|
||||
if (!np)
|
||||
return CPUFREQ_ETERNAL;
|
||||
|
||||
of_property_read_u32(np, "clock-latency", &transition_latency);
|
||||
of_node_put(np);
|
||||
|
||||
pr_debug("%s: clock-latency: %d\n", __func__, transition_latency);
|
||||
return transition_latency;
|
||||
}
|
||||
|
||||
static struct cpufreq_arm_bL_ops dt_bL_ops = {
|
||||
|
@ -93,6 +97,13 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = {
|
|||
|
||||
static int generic_bL_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
np = get_cpu_node_with_valid_op(0);
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
of_node_put(np);
|
||||
return bL_cpufreq_register(&dt_bL_ops);
|
||||
}
|
||||
module_init(generic_bL_init);
|
||||
|
|
Loading…
Reference in a new issue