[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20210112111717.5ds446w2kroxzvhr@vireshk-i7>
Date: Tue, 12 Jan 2021 16:47:17 +0530
From: Viresh Kumar <viresh.kumar@...aro.org>
To: Nicola Mazzucato <nicola.mazzucato@....com>
Cc: linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
linux-pm@...r.kernel.org, sudeep.holla@....com, rjw@...ysocki.net,
vireshk@...nel.org, cristian.marussi@....com,
morten.rasmussen@....com, chris.redpath@....com
Subject: Re: [PATCH v6 2/4] scmi-cpufreq: Move CPU initialisation to probe
On 11-01-21, 15:45, Nicola Mazzucato wrote:
> diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c
> +static int scmi_init_cpudata(void)
> +{
> + int cpu;
> + unsigned int ncpus = num_possible_cpus();
> +
> + cpudata_table = kzalloc(sizeof(*cpudata_table) * ncpus, GFP_KERNEL);
> + if (!cpudata_table)
> + return -ENOMEM;
This could have been done with a per-cpu variable instead.
> + for_each_possible_cpu(cpu) {
> + if (!zalloc_cpumask_var(&cpudata_table[cpu].scmi_shared_cpus,
> + GFP_KERNEL))
> + goto out;
> + }
You are making a copy of the struct for each CPU and so for a 16 CPUs
sharing their clock lines, you will have 16 copies of the exact same
stuff.
An optimal approach would be to have a linked-list of this structure
and that will only have 1 node per cpufreq policy.
> + return 0;
> +
> +out:
> + kfree(cpudata_table);
> + return -ENOMEM;
> +}
> +
> +static int scmi_init_device(const struct scmi_handle *handle, int cpu)
> +{
> + struct device *cpu_dev;
> + int ret, nr_opp;
> + struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
> + bool power_scale_mw;
> + cpumask_var_t scmi_cpus;
> +
> + if (!zalloc_cpumask_var(&scmi_cpus, GFP_KERNEL))
> + return -ENOMEM;
> +
> + cpumask_set_cpu(cpu, scmi_cpus);
> +
> + cpu_dev = get_cpu_device(cpu);
> +
> + ret = scmi_get_sharing_cpus(cpu_dev, scmi_cpus);
Where do you expect the sharing information to come from in this case
? DT ?
> + if (ret) {
> + dev_warn(cpu_dev, "failed to get sharing cpumask\n");
> + goto free_cpumask;
> + }
> +
> + /*
> + * We get here for each CPU. Add OPPs only on those CPUs for which we
> + * haven't already done so, or set their OPPs as shared.
> + */
> + nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
> + if (nr_opp <= 0) {
> + ret = handle->perf_ops->device_opps_add(handle, cpu_dev);
> + if (ret) {
> + dev_warn(cpu_dev, "failed to add opps to the device\n");
> + goto free_cpumask;
> + }
> +
> + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, scmi_cpus);
> + if (ret) {
> + dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
> + __func__, ret);
> + goto free_cpumask;
> + }
> +
> + nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
Shouldn't you do this just after adding the OPPs ?
> + if (nr_opp <= 0) {
> + dev_err(cpu_dev, "%s: No OPPs for this device: %d\n",
> + __func__, ret);
> +
> + ret = -ENODEV;
> + goto free_cpumask;
> + }
> +
> + power_scale_mw = handle->perf_ops->power_scale_mw_get(handle);
> + em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, scmi_cpus,
> + power_scale_mw);
> + }
> +
> + ret = dev_pm_opp_init_cpufreq_table(cpu_dev,
> + &cpudata_table[cpu].freq_table);
> + if (ret) {
> + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
> + goto free_cpumask;
> + }
> +
> + cpumask_copy(cpudata_table[cpu].scmi_shared_cpus, scmi_cpus);
> +
> +free_cpumask:
> + free_cpumask_var(scmi_cpus);
> + return ret;
> +}
> +
> static int scmi_cpufreq_probe(struct scmi_device *sdev)
> {
> int ret;
> struct device *dev = &sdev->dev;
> + int cpu;
> + struct device *cpu_dev;
Please keep the list of local variable in decreasing order of their
length, many people including me prefer it that way.
>
> handle = sdev->handle;
>
> @@ -247,6 +305,24 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev)
> devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL);
> #endif
>
> + ret = scmi_init_cpudata();
> + if (ret) {
> + pr_err("%s: init cpu data failed\n", __func__);
> + return ret;
> + }
> +
> + for_each_possible_cpu(cpu) {
> + cpu_dev = get_cpu_device(cpu);
> +
> + ret = scmi_init_device(handle, cpu);
> + if (ret) {
> + dev_err(cpu_dev, "%s: init device failed\n",
> + __func__);
> +
> + return ret;
You missed undoing scmi_init_cpudata().
> + }
> + }
> +
> ret = cpufreq_register_driver(&scmi_cpufreq_driver);
> if (ret) {
> dev_err(dev, "%s: registering cpufreq failed, err: %d\n",
> @@ -258,6 +334,20 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev)
>
> static void scmi_cpufreq_remove(struct scmi_device *sdev)
> {
> + int cpu;
> + struct device *cpu_dev;
> +
> + for_each_possible_cpu(cpu) {
> + cpu_dev = get_cpu_device(cpu);
> +
> + dev_pm_opp_free_cpufreq_table(cpu_dev,
> + &cpudata_table[cpu].freq_table);
> +
> + free_cpumask_var(cpudata_table[cpu].scmi_shared_cpus);
> + }
> +
> + kfree(cpudata_table);
> +
> cpufreq_unregister_driver(&scmi_cpufreq_driver);
> }
>
> --
> 2.27.0
--
viresh
Powered by blists - more mailing lists