diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index cf62a1f64dd7..7fe52fcddcf1 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -487,6 +487,8 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = arm_bL_ops->get_transition_latency(cpu_dev); + dev_pm_opp_of_register_em(policy->cpus); + if (is_bL_switching_enabled()) per_cpu(cpu_last_req_freq, policy->cpu) = clk_get_cpu_rate(policy->cpu); diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 1aefaa1b0ca2..bde28878725b 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -278,6 +278,8 @@ static int cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = transition_latency; policy->dvfs_possible_from_any_cpu = true; + dev_pm_opp_of_register_em(policy->cpus); + return 0; out_free_cpufreq_table: diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index ca955713e070..a4ff09f91c8f 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -198,6 +198,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy) policy->clk = clks[ARM].clk; ret = cpufreq_generic_init(policy, freq_table, transition_latency); policy->suspend_freq = max_freq; + dev_pm_opp_of_register_em(policy->cpus); return ret; } diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index 4229fcc31310..48e9829274c6 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -456,6 +456,8 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) policy->driver_data = info; policy->clk = info->cpu_clk; + dev_pm_opp_of_register_em(policy->cpus); + return 0; } diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 71e81bbf031b..68052b74d28f 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -133,8 +133,10 @@ static int omap_cpu_init(struct cpufreq_policy *policy) /* FIXME: what's the actual transition time? */ result = cpufreq_generic_init(policy, freq_table, 300 * 1000); - if (!result) + if (!result) { + dev_pm_opp_of_register_em(policy->cpus); return 0; + } freq_table_free(); fail: diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index c47182fc64ea..e6182c89df79 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -101,13 +102,42 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) return 0; } +static int __maybe_unused +scmi_get_cpu_power(unsigned long *power, unsigned long *KHz, int cpu) +{ + struct device *cpu_dev = get_cpu_device(cpu); + unsigned long Hz; + int ret, domain; + + if (!cpu_dev) { + pr_err("failed to get cpu%d device\n", cpu); + return -ENODEV; + } + + domain = handle->perf_ops->device_domain_id(cpu_dev); + if (domain < 0) + return domain; + + /* Get the power cost of the performance domain. */ + Hz = *KHz * 1000; + ret = handle->perf_ops->est_power_get(handle, domain, &Hz, power); + if (ret) + return ret; + + /* The EM framework specifies the frequency in KHz. */ + *KHz = Hz / 1000; + + return 0; +} + static int scmi_cpufreq_init(struct cpufreq_policy *policy) { - int ret; + int ret, nr_opp; unsigned int latency; struct device *cpu_dev; struct scmi_data *priv; struct cpufreq_frequency_table *freq_table; + struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power); cpu_dev = get_cpu_device(policy->cpu); if (!cpu_dev) { @@ -134,8 +164,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) return ret; } - ret = dev_pm_opp_get_opp_count(cpu_dev); - if (ret <= 0) { + nr_opp = dev_pm_opp_get_opp_count(cpu_dev); + if (nr_opp <= 0) { dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); ret = -EPROBE_DEFER; goto out_free_opp; @@ -169,6 +199,9 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = latency; policy->fast_switch_possible = true; + + em_register_perf_domain(policy->cpus, nr_opp, &em_cb); + return 0; out_free_priv: diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index 1db2f6927e13..3f49427766b8 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -168,6 +168,9 @@ static int scpi_cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = latency; policy->fast_switch_possible = false; + + dev_pm_opp_of_register_em(policy->cpus); + return 0; out_free_cpufreq_table: diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 4e00301060cf..410892d54bc4 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -792,7 +792,6 @@ static struct opp_device *_add_opp_dev_unlocked(const struct device *dev, struct opp_table *opp_table) { struct opp_device *opp_dev; - int ret; opp_dev = kzalloc(sizeof(*opp_dev), GFP_KERNEL); if (!opp_dev) @@ -804,10 +803,7 @@ static struct opp_device *_add_opp_dev_unlocked(const struct device *dev, list_add(&opp_dev->node, &opp_table->dev_list); /* Create debugfs entries for the opp_table */ - ret = opp_debug_register(opp_dev, opp_table); - if (ret) - dev_err(dev, "%s: Failed to register opp debugfs (%d)\n", - __func__, ret); + opp_debug_register(opp_dev, opp_table); return opp_dev; } @@ -1228,10 +1224,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, new_opp->opp_table = opp_table; kref_init(&new_opp->kref); - ret = opp_debug_create_one(new_opp, opp_table); - if (ret) - dev_err(dev, "%s: Failed to register opp to debugfs (%d)\n", - __func__, ret); + opp_debug_create_one(new_opp, opp_table); if (!_opp_supported_by_regulators(new_opp, opp_table)) { new_opp->available = false; diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c index e6828e5f81b0..a1c57fe14de4 100644 --- a/drivers/opp/debugfs.c +++ b/drivers/opp/debugfs.c @@ -35,7 +35,7 @@ void opp_debug_remove_one(struct dev_pm_opp *opp) debugfs_remove_recursive(opp->dentry); } -static bool opp_debug_create_supplies(struct dev_pm_opp *opp, +static void opp_debug_create_supplies(struct dev_pm_opp *opp, struct opp_table *opp_table, struct dentry *pdentry) { @@ -50,30 +50,21 @@ static bool opp_debug_create_supplies(struct dev_pm_opp *opp, /* Create per-opp directory */ d = debugfs_create_dir(name, pdentry); - if (!d) - return false; + debugfs_create_ulong("u_volt_target", S_IRUGO, d, + &opp->supplies[i].u_volt); - if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, - &opp->supplies[i].u_volt)) - return false; + debugfs_create_ulong("u_volt_min", S_IRUGO, d, + &opp->supplies[i].u_volt_min); - if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, - &opp->supplies[i].u_volt_min)) - return false; + debugfs_create_ulong("u_volt_max", S_IRUGO, d, + &opp->supplies[i].u_volt_max); - if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, - &opp->supplies[i].u_volt_max)) - return false; - - if (!debugfs_create_ulong("u_amp", S_IRUGO, d, - &opp->supplies[i].u_amp)) - return false; + debugfs_create_ulong("u_amp", S_IRUGO, d, + &opp->supplies[i].u_amp); } - - return true; } -int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) +void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) { struct dentry *pdentry = opp_table->dentry; struct dentry *d; @@ -95,40 +86,23 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) /* Create per-opp directory */ d = debugfs_create_dir(name, pdentry); - if (!d) - return -ENOMEM; - if (!debugfs_create_bool("available", S_IRUGO, d, &opp->available)) - return -ENOMEM; + debugfs_create_bool("available", S_IRUGO, d, &opp->available); + debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic); + debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo); + debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend); + debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate); + debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate); + debugfs_create_ulong("clock_latency_ns", S_IRUGO, d, + &opp->clock_latency_ns); - if (!debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic)) - return -ENOMEM; - - if (!debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo)) - return -ENOMEM; - - if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend)) - return -ENOMEM; - - if (!debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate)) - return -ENOMEM; - - if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate)) - return -ENOMEM; - - if (!opp_debug_create_supplies(opp, opp_table, d)) - return -ENOMEM; - - if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d, - &opp->clock_latency_ns)) - return -ENOMEM; + opp_debug_create_supplies(opp, opp_table, d); opp->dentry = d; - return 0; } -static int opp_list_debug_create_dir(struct opp_device *opp_dev, - struct opp_table *opp_table) +static void opp_list_debug_create_dir(struct opp_device *opp_dev, + struct opp_table *opp_table) { const struct device *dev = opp_dev->dev; struct dentry *d; @@ -137,36 +111,21 @@ static int opp_list_debug_create_dir(struct opp_device *opp_dev, /* Create device specific directory */ d = debugfs_create_dir(opp_table->dentry_name, rootdir); - if (!d) { - dev_err(dev, "%s: Failed to create debugfs dir\n", __func__); - return -ENOMEM; - } opp_dev->dentry = d; opp_table->dentry = d; - - return 0; } -static int opp_list_debug_create_link(struct opp_device *opp_dev, - struct opp_table *opp_table) +static void opp_list_debug_create_link(struct opp_device *opp_dev, + struct opp_table *opp_table) { - const struct device *dev = opp_dev->dev; char name[NAME_MAX]; - struct dentry *d; opp_set_dev_name(opp_dev->dev, name); /* Create device specific directory link */ - d = debugfs_create_symlink(name, rootdir, opp_table->dentry_name); - if (!d) { - dev_err(dev, "%s: Failed to create link\n", __func__); - return -ENOMEM; - } - - opp_dev->dentry = d; - - return 0; + opp_dev->dentry = debugfs_create_symlink(name, rootdir, + opp_table->dentry_name); } /** @@ -177,20 +136,13 @@ static int opp_list_debug_create_link(struct opp_device *opp_dev, * Dynamically adds device specific directory in debugfs 'opp' directory. If the * device-opp is shared with other devices, then links will be created for all * devices except the first. - * - * Return: 0 on success, otherwise negative error. */ -int opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table) +void opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table) { - if (!rootdir) { - pr_debug("%s: Uninitialized rootdir\n", __func__); - return -EINVAL; - } - if (opp_table->dentry) - return opp_list_debug_create_link(opp_dev, opp_table); - - return opp_list_debug_create_dir(opp_dev, opp_table); + opp_list_debug_create_link(opp_dev, opp_table); + else + opp_list_debug_create_dir(opp_dev, opp_table); } static void opp_migrate_dentry(struct opp_device *opp_dev, @@ -252,10 +204,6 @@ static int __init opp_debug_init(void) { /* Create /sys/kernel/debug/opp directory */ rootdir = debugfs_create_dir("opp", NULL); - if (!rootdir) { - pr_err("%s: Failed to create root directory\n", __func__); - return -ENOMEM; - } return 0; } diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index e24d81497375..810a85b9a66d 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -236,18 +236,17 @@ static inline void _of_opp_free_required_opps(struct opp_table *opp_table, #ifdef CONFIG_DEBUG_FS void opp_debug_remove_one(struct dev_pm_opp *opp); -int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table); -int opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table); +void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table); +void opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table); void opp_debug_unregister(struct opp_device *opp_dev, struct opp_table *opp_table); #else static inline void opp_debug_remove_one(struct dev_pm_opp *opp) {} -static inline int opp_debug_create_one(struct dev_pm_opp *opp, - struct opp_table *opp_table) -{ return 0; } -static inline int opp_debug_register(struct opp_device *opp_dev, - struct opp_table *opp_table) -{ return 0; } +static inline void opp_debug_create_one(struct dev_pm_opp *opp, + struct opp_table *opp_table) { } + +static inline void opp_debug_register(struct opp_device *opp_dev, + struct opp_table *opp_table) { } static inline void opp_debug_unregister(struct opp_device *opp_dev, struct opp_table *opp_table)