Quoting Viresh Kumar (2018-12-04 22:16:00)
> On 05-12-18, 09:07, Taniya Das wrote:
> > Hello Stephen, Viresh
> > 
> > Thanks for the code and suggestions.
> > 
> > Having a NR_DOMAINS '2' makes the driver not scalable for re-use.
> 
> Sure, I didn't like it either and that wasn't really what I was suggesting in
> the first place. I didn't wanted to write the code myself and pass it on, but 
> I
> have it now anyway :)
> 
> It may have a bug or two in there, but compiles just fine and is rebased over
> your patch Taniya.

If we move the ioremap of registers to the cpufreq_driver::init path
then we need to unmap it on cpufreq_driver::exit. In fact, all the
devm_*() code in the init path needs to change to non-devm. Otherwise
it's a nice simplification!

> +static int qcom_cpufreq_hw_read_lut(struct device *dev,
> +                                   struct cpufreq_policy *policy,
> +                                   void __iomem *base)
>  {
>         u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq;
> -       unsigned int max_cores = cpumask_weight(&c->related_cpus);
> +       unsigned int max_cores = cpumask_weight(policy->cpus);
> +       struct cpufreq_frequency_table  *table;
>  
> -       c->table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1,
> -                               sizeof(*c->table), GFP_KERNEL);
> -       if (!c->table)
> +       table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1,
> +                               sizeof(*table), GFP_KERNEL);

This one.

> +       if (!table)
>                 return -ENOMEM;
>  
>         for (i = 0; i < LUT_MAX_ENTRIES; i++) {
> @@ -194,22 +154,29 @@ static void qcom_get_related_cpus(int index, struct 
> cpumask *m)
>         }
>  }
>  
> -static int qcom_cpu_resources_init(struct platform_device *pdev,
> -                                  unsigned int cpu, int index,
> -                                  unsigned long xo_rate,
> -                                  unsigned long cpu_hw_rate)
> +static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
>  {
> -       struct cpufreq_qcom *c;
> +       struct device *dev = &global_pdev->dev;
> +       struct of_phandle_args args;
> +       struct device_node *cpu_np;
>         struct resource *res;
> -       struct device *dev = &pdev->dev;
>         void __iomem *base;
> -       int ret, cpu_r;
> +       int ret, index;
>  
> -       c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
> -       if (!c)
> -               return -ENOMEM;
> +       cpu_np = of_cpu_device_node_get(policy->cpu);
> +       if (!cpu_np)
> +               return -EINVAL;
> +
> +       ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
> +                       "#freq-domain-cells", 0, &args);
> +       of_node_put(cpu_np);
>  
> -       res = platform_get_resource(pdev, IORESOURCE_MEM, index);
> +       if (ret)
> +               return ret;
> +
> +       index = args.args[0];
> +
> +       res = platform_get_resource(global_pdev, IORESOURCE_MEM, index);
>         base = devm_ioremap_resource(dev, res);

And this one.

>         if (IS_ERR(base))
>                 return PTR_ERR(base);

Here's a patch to squash in to fix those tiny problems. I left it as
devm_ioremap_resource() because that has all the nice features of
resource requesting inside and it didn't seem too bad to devm_iounmap()
on the exit path.

---------8<--------------

 drivers/cpufreq/qcom-cpufreq-hw.c | 37 ++++++++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c 
b/drivers/cpufreq/qcom-cpufreq-hw.c
index bcf9bb37298a..1e865e216839 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/slab.h>
 
 #define LUT_MAX_ENTRIES                        40U
 #define LUT_SRC                                GENMASK(31, 30)
@@ -77,8 +78,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
        unsigned int max_cores = cpumask_weight(policy->cpus);
        struct cpufreq_frequency_table  *table;
 
-       table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1,
-                               sizeof(*table), GFP_KERNEL);
+       table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL);
        if (!table)
                return -ENOMEM;
 
@@ -144,7 +144,7 @@ static void qcom_get_related_cpus(int index, struct cpumask 
*m)
 
                ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
                                                 "#freq-domain-cells", 0,
-                                                 &args);
+                                                &args);
                of_node_put(cpu_np);
                if (ret < 0)
                        continue;
@@ -170,7 +170,6 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy 
*policy)
        ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
                        "#freq-domain-cells", 0, &args);
        of_node_put(cpu_np);
-
        if (ret)
                return ret;
 
@@ -184,13 +183,15 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy 
*policy)
        /* HW should be in enabled state to proceed */
        if (!(readl_relaxed(base + REG_ENABLE) & 0x1)) {
                dev_err(dev, "Domain-%d cpufreq hardware not enabled\n", index);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto error;
        }
 
        qcom_get_related_cpus(index, policy->cpus);
        if (!cpumask_weight(policy->cpus)) {
                dev_err(dev, "Domain-%d failed to get related CPUs\n", index);
-               return -ENOENT;
+               ret = -ENOENT;
+               goto error;
        }
 
        policy->driver_data = base + REG_PERF_STATE;
@@ -198,11 +199,25 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy 
*policy)
        ret = qcom_cpufreq_hw_read_lut(dev, policy, base);
        if (ret) {
                dev_err(dev, "Domain-%d failed to read LUT\n", index);
-               return ret;
+               goto error;
        }
 
        policy->fast_switch_possible = true;
 
+       return 0;
+
+error:
+       devm_iounmap(dev, base);
+       return ret;
+}
+
+static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
+{
+       void __iomem *base = policy->driver_data - REG_PERF_STATE;
+
+       kfree(policy->freq_table);
+       devm_iounmap(&global_pdev->dev, base);
+
        return 0;
 }
 
@@ -219,6 +234,7 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
        .target_index   = qcom_cpufreq_hw_target_index,
        .get            = qcom_cpufreq_hw_get,
        .init           = qcom_cpufreq_hw_cpu_init,
+       .exit           = qcom_cpufreq_hw_cpu_exit,
        .fast_switch    = qcom_cpufreq_hw_fast_switch,
        .name           = "qcom-cpufreq-hw",
        .attr           = qcom_cpufreq_hw_attr,
@@ -248,12 +264,11 @@ static int qcom_cpufreq_hw_driver_probe(struct 
platform_device *pdev)
        ret = cpufreq_register_driver(&cpufreq_qcom_hw_driver);
        if (ret) {
                dev_err(&pdev->dev, "CPUFreq HW driver failed to register\n");
-               return ret;
+       } else {
+               dev_dbg(&pdev->dev, "QCOM CPUFreq HW driver initialized\n");
        }
 
-       dev_dbg(&pdev->dev, "QCOM CPUFreq HW driver initialized\n");
-
-       return 0;
+       return ret;
 }
 
 static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)

Reply via email to