OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list
authorViresh Kumar <viresh.kumar@linaro.org>
Mon, 4 Jul 2022 10:40:39 +0000 (16:10 +0530)
committerViresh Kumar <viresh.kumar@linaro.org>
Fri, 8 Jul 2022 05:56:44 +0000 (11:26 +0530)
Make dev_pm_opp_set_regulators() accept a NULL terminated list of names
instead of making the callers keep the two parameters in sync, which
creates an opportunity for bugs to get in.

Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Steven Price <steven.price@arm.com> # panfrost
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/ti-cpufreq.c
drivers/devfreq/exynos-bus.c
drivers/gpu/drm/lima/lima_devfreq.c
drivers/gpu/drm/panfrost/panfrost_devfreq.c
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/opp/core.c
drivers/soc/tegra/pmc.c
include/linux/pm_opp.h

index 8fcaba541539bb0e3cad224d64523841fe3faa56..be0c19b3ffa52427710d9e359c752ef6f79ee205 100644 (file)
@@ -193,7 +193,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
        struct private_data *priv;
        struct device *cpu_dev;
        bool fallback = false;
-       const char *reg_name;
+       const char *reg_name[] = { NULL, NULL };
        int ret;
 
        /* Check if this CPU is already covered by some other policy */
@@ -218,10 +218,9 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
         * OPP layer will be taking care of regulators now, but it needs to know
         * the name of the regulator first.
         */
-       reg_name = find_supply_name(cpu_dev);
-       if (reg_name) {
-               priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, &reg_name,
-                                                           1);
+       reg_name[0] = find_supply_name(cpu_dev);
+       if (reg_name[0]) {
+               priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, reg_name);
                if (IS_ERR(priv->opp_table)) {
                        ret = PTR_ERR(priv->opp_table);
                        if (ret != -EPROBE_DEFER)
index 8f9fdd864391a697daa33c74a8af118d1c0de4e0..560d67a6bef1e234d6723397c231b8ee27e90d3d 100644 (file)
@@ -173,7 +173,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {
  *    seems to always read as 0).
  */
 
-static const char * const omap3_reg_names[] = {"cpu0", "vbb"};
+static const char * const omap3_reg_names[] = {"cpu0", "vbb", NULL};
 
 static struct ti_cpufreq_soc_data omap36xx_soc_data = {
        .reg_names = omap3_reg_names,
@@ -326,7 +326,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        struct opp_table *ti_opp_table;
        struct ti_cpufreq_data *opp_data;
-       const char * const default_reg_names[] = {"vdd", "vbb"};
+       const char * const default_reg_names[] = {"vdd", "vbb", NULL};
        int ret;
 
        match = dev_get_platdata(&pdev->dev);
@@ -387,8 +387,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
                if (opp_data->soc_data->reg_names)
                        reg_names = opp_data->soc_data->reg_names;
                ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev,
-                                                        reg_names,
-                                                        ARRAY_SIZE(default_reg_names));
+                                                        reg_names);
                if (IS_ERR(ti_opp_table)) {
                        dev_pm_opp_put_supported_hw(opp_data->opp_table);
                        ret =  PTR_ERR(ti_opp_table);
index e689101abc93036c0b84a435e1489bdb1c41d1cf..541baff93ee88683776b5d76a0de0d0af1f5f729 100644 (file)
@@ -180,10 +180,10 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
 {
        struct device *dev = bus->dev;
        struct opp_table *opp_table;
-       const char *vdd = "vdd";
+       const char *supplies[] = { "vdd", NULL };
        int i, ret, count, size;
 
-       opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1);
+       opp_table = dev_pm_opp_set_regulators(dev, supplies);
        if (IS_ERR(opp_table)) {
                ret = PTR_ERR(opp_table);
                dev_err(dev, "failed to set regulators %d\n", ret);
index 8989e215dfc9d6076b06b68d2c093fb43fffa2cf..dc83c5421125ebb9dfaa668202f3fe2c65235f47 100644 (file)
@@ -111,6 +111,7 @@ int lima_devfreq_init(struct lima_device *ldev)
        struct dev_pm_opp *opp;
        unsigned long cur_freq;
        int ret;
+       const char *regulator_names[] = { "mali", NULL };
 
        if (!device_property_present(dev, "operating-points-v2"))
                /* Optional, continue without devfreq */
@@ -122,7 +123,7 @@ int lima_devfreq_init(struct lima_device *ldev)
        if (ret)
                return ret;
 
-       ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1);
+       ret = devm_pm_opp_set_regulators(dev, regulator_names);
        if (ret) {
                /* Continue if the optional regulator is missing */
                if (ret != -ENODEV)
index 194af7f607a6ed5308c6972229496d0f3d63a014..5110cd9b2425890d3e620cbfd49186b581abd626 100644 (file)
@@ -101,8 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
                return 0;
        }
 
-       ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
-                                        pfdev->comp->num_supplies);
+       ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names);
        if (ret) {
                /* Continue if the optional regulator is missing */
                if (ret != -ENODEV) {
index 7fcbc2a5b6cda8f31813b90685dbe4546319a59d..8a4bef65d38ccc1dbe67b6fa92155444f0184af2 100644 (file)
@@ -625,24 +625,29 @@ static int panfrost_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const char * const default_supplies[] = { "mali" };
+/*
+ * The OPP core wants the supply names to be NULL terminated, but we need the
+ * correct num_supplies value for regulator core. Hence, we NULL terminate here
+ * and then initialize num_supplies with ARRAY_SIZE - 1.
+ */
+static const char * const default_supplies[] = { "mali", NULL };
 static const struct panfrost_compatible default_data = {
-       .num_supplies = ARRAY_SIZE(default_supplies),
+       .num_supplies = ARRAY_SIZE(default_supplies) - 1,
        .supply_names = default_supplies,
        .num_pm_domains = 1, /* optional */
        .pm_domain_names = NULL,
 };
 
 static const struct panfrost_compatible amlogic_data = {
-       .num_supplies = ARRAY_SIZE(default_supplies),
+       .num_supplies = ARRAY_SIZE(default_supplies) - 1,
        .supply_names = default_supplies,
        .vendor_quirk = panfrost_gpu_amlogic_quirk,
 };
 
-static const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
+static const char * const mediatek_mt8183_supplies[] = { "mali", "sram", NULL };
 static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
 static const struct panfrost_compatible mediatek_mt8183_data = {
-       .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies),
+       .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies) - 1,
        .supply_names = mediatek_mt8183_supplies,
        .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
        .pm_domain_names = mediatek_mt8183_pm_domains,
index e166bfe5fc90c40134211ba87ab5ff112f7b996c..4e4593957ec54c73d7a18fd16706f3c2dfb78b1b 100644 (file)
@@ -2105,13 +2105,20 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
  * This must be called before any OPPs are initialized for the device.
  */
 struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
-                                           const char * const names[],
-                                           unsigned int count)
+                                           const char * const names[])
 {
        struct dev_pm_opp_supply *supplies;
+       const char * const *temp = names;
        struct opp_table *opp_table;
        struct regulator *reg;
-       int ret, i;
+       int count = 0, ret, i;
+
+       /* Count number of regulators */
+       while (*temp++)
+               count++;
+
+       if (!count)
+               return ERR_PTR(-EINVAL);
 
        opp_table = _add_opp_table(dev, false);
        if (IS_ERR(opp_table))
@@ -2236,12 +2243,11 @@ static void devm_pm_opp_regulators_release(void *data)
  * Return: 0 on success and errorno otherwise.
  */
 int devm_pm_opp_set_regulators(struct device *dev,
-                              const char * const names[],
-                              unsigned int count)
+                              const char * const names[])
 {
        struct opp_table *opp_table;
 
-       opp_table = dev_pm_opp_set_regulators(dev, names, count);
+       opp_table = dev_pm_opp_set_regulators(dev, names);
        if (IS_ERR(opp_table))
                return PTR_ERR(opp_table);
 
index 5611d14d3ba2adbaa9eb17aaed30855fdce52a8a..6a4b8f7e79480d8207d3f72dd711778bd1bde2eb 100644 (file)
@@ -1384,7 +1384,7 @@ tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
 static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
 {
        struct generic_pm_domain *genpd;
-       const char *rname = "core";
+       const char *rname[] = { "core", NULL};
        int err;
 
        genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
@@ -1395,7 +1395,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
        genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
        genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
 
-       err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
+       err = devm_pm_opp_set_regulators(pmc->dev, rname);
        if (err)
                return dev_err_probe(pmc->dev, err,
                                     "failed to set core OPP regulator\n");
index 6708b4ec244d40d535b99cb7917b14b2e83754c6..4c490865d5746c7a8b450e1eb295bd785d232cfb 100644 (file)
@@ -159,9 +159,9 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
 int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
 struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name);
 void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
-struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
+struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[]);
 void dev_pm_opp_put_regulators(struct opp_table *opp_table);
-int devm_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
+int devm_pm_opp_set_regulators(struct device *dev, const char * const names[]);
 struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name);
 void dev_pm_opp_put_clkname(struct opp_table *opp_table);
 int devm_pm_opp_set_clkname(struct device *dev, const char *name);
@@ -379,7 +379,7 @@ static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, con
 
 static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {}
 
-static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
+static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[])
 {
        return ERR_PTR(-EOPNOTSUPP);
 }
@@ -387,8 +387,7 @@ static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, co
 static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}
 
 static inline int devm_pm_opp_set_regulators(struct device *dev,
-                                            const char * const names[],
-                                            unsigned int count)
+                                            const char * const names[])
 {
        return -EOPNOTSUPP;
 }