Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

OPP: Make dev_pm_opp_set_regulators() accept NULL terminated list

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>

+40 -32
+4 -5
drivers/cpufreq/cpufreq-dt.c
··· 193 193 struct private_data *priv; 194 194 struct device *cpu_dev; 195 195 bool fallback = false; 196 - const char *reg_name; 196 + const char *reg_name[] = { NULL, NULL }; 197 197 int ret; 198 198 199 199 /* Check if this CPU is already covered by some other policy */ ··· 218 218 * OPP layer will be taking care of regulators now, but it needs to know 219 219 * the name of the regulator first. 220 220 */ 221 - reg_name = find_supply_name(cpu_dev); 222 - if (reg_name) { 223 - priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, &reg_name, 224 - 1); 221 + reg_name[0] = find_supply_name(cpu_dev); 222 + if (reg_name[0]) { 223 + priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, reg_name); 225 224 if (IS_ERR(priv->opp_table)) { 226 225 ret = PTR_ERR(priv->opp_table); 227 226 if (ret != -EPROBE_DEFER)
+3 -4
drivers/cpufreq/ti-cpufreq.c
··· 173 173 * seems to always read as 0). 174 174 */ 175 175 176 - static const char * const omap3_reg_names[] = {"cpu0", "vbb"}; 176 + static const char * const omap3_reg_names[] = {"cpu0", "vbb", NULL}; 177 177 178 178 static struct ti_cpufreq_soc_data omap36xx_soc_data = { 179 179 .reg_names = omap3_reg_names, ··· 326 326 const struct of_device_id *match; 327 327 struct opp_table *ti_opp_table; 328 328 struct ti_cpufreq_data *opp_data; 329 - const char * const default_reg_names[] = {"vdd", "vbb"}; 329 + const char * const default_reg_names[] = {"vdd", "vbb", NULL}; 330 330 int ret; 331 331 332 332 match = dev_get_platdata(&pdev->dev); ··· 387 387 if (opp_data->soc_data->reg_names) 388 388 reg_names = opp_data->soc_data->reg_names; 389 389 ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev, 390 - reg_names, 391 - ARRAY_SIZE(default_reg_names)); 390 + reg_names); 392 391 if (IS_ERR(ti_opp_table)) { 393 392 dev_pm_opp_put_supported_hw(opp_data->opp_table); 394 393 ret = PTR_ERR(ti_opp_table);
+2 -2
drivers/devfreq/exynos-bus.c
··· 180 180 { 181 181 struct device *dev = bus->dev; 182 182 struct opp_table *opp_table; 183 - const char *vdd = "vdd"; 183 + const char *supplies[] = { "vdd", NULL }; 184 184 int i, ret, count, size; 185 185 186 - opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1); 186 + opp_table = dev_pm_opp_set_regulators(dev, supplies); 187 187 if (IS_ERR(opp_table)) { 188 188 ret = PTR_ERR(opp_table); 189 189 dev_err(dev, "failed to set regulators %d\n", ret);
+2 -1
drivers/gpu/drm/lima/lima_devfreq.c
··· 111 111 struct dev_pm_opp *opp; 112 112 unsigned long cur_freq; 113 113 int ret; 114 + const char *regulator_names[] = { "mali", NULL }; 114 115 115 116 if (!device_property_present(dev, "operating-points-v2")) 116 117 /* Optional, continue without devfreq */ ··· 123 122 if (ret) 124 123 return ret; 125 124 126 - ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1); 125 + ret = devm_pm_opp_set_regulators(dev, regulator_names); 127 126 if (ret) { 128 127 /* Continue if the optional regulator is missing */ 129 128 if (ret != -ENODEV)
+1 -2
drivers/gpu/drm/panfrost/panfrost_devfreq.c
··· 101 101 return 0; 102 102 } 103 103 104 - ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names, 105 - pfdev->comp->num_supplies); 104 + ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names); 106 105 if (ret) { 107 106 /* Continue if the optional regulator is missing */ 108 107 if (ret != -ENODEV) {
+10 -5
drivers/gpu/drm/panfrost/panfrost_drv.c
··· 625 625 return 0; 626 626 } 627 627 628 - static const char * const default_supplies[] = { "mali" }; 628 + /* 629 + * The OPP core wants the supply names to be NULL terminated, but we need the 630 + * correct num_supplies value for regulator core. Hence, we NULL terminate here 631 + * and then initialize num_supplies with ARRAY_SIZE - 1. 632 + */ 633 + static const char * const default_supplies[] = { "mali", NULL }; 629 634 static const struct panfrost_compatible default_data = { 630 - .num_supplies = ARRAY_SIZE(default_supplies), 635 + .num_supplies = ARRAY_SIZE(default_supplies) - 1, 631 636 .supply_names = default_supplies, 632 637 .num_pm_domains = 1, /* optional */ 633 638 .pm_domain_names = NULL, 634 639 }; 635 640 636 641 static const struct panfrost_compatible amlogic_data = { 637 - .num_supplies = ARRAY_SIZE(default_supplies), 642 + .num_supplies = ARRAY_SIZE(default_supplies) - 1, 638 643 .supply_names = default_supplies, 639 644 .vendor_quirk = panfrost_gpu_amlogic_quirk, 640 645 }; 641 646 642 - static const char * const mediatek_mt8183_supplies[] = { "mali", "sram" }; 647 + static const char * const mediatek_mt8183_supplies[] = { "mali", "sram", NULL }; 643 648 static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" }; 644 649 static const struct panfrost_compatible mediatek_mt8183_data = { 645 - .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies), 650 + .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies) - 1, 646 651 .supply_names = mediatek_mt8183_supplies, 647 652 .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains), 648 653 .pm_domain_names = mediatek_mt8183_pm_domains,
+12 -6
drivers/opp/core.c
··· 2105 2105 * This must be called before any OPPs are initialized for the device. 2106 2106 */ 2107 2107 struct opp_table *dev_pm_opp_set_regulators(struct device *dev, 2108 - const char * const names[], 2109 - unsigned int count) 2108 + const char * const names[]) 2110 2109 { 2111 2110 struct dev_pm_opp_supply *supplies; 2111 + const char * const *temp = names; 2112 2112 struct opp_table *opp_table; 2113 2113 struct regulator *reg; 2114 - int ret, i; 2114 + int count = 0, ret, i; 2115 + 2116 + /* Count number of regulators */ 2117 + while (*temp++) 2118 + count++; 2119 + 2120 + if (!count) 2121 + return ERR_PTR(-EINVAL); 2115 2122 2116 2123 opp_table = _add_opp_table(dev, false); 2117 2124 if (IS_ERR(opp_table)) ··· 2243 2236 * Return: 0 on success and errorno otherwise. 2244 2237 */ 2245 2238 int devm_pm_opp_set_regulators(struct device *dev, 2246 - const char * const names[], 2247 - unsigned int count) 2239 + const char * const names[]) 2248 2240 { 2249 2241 struct opp_table *opp_table; 2250 2242 2251 - opp_table = dev_pm_opp_set_regulators(dev, names, count); 2243 + opp_table = dev_pm_opp_set_regulators(dev, names); 2252 2244 if (IS_ERR(opp_table)) 2253 2245 return PTR_ERR(opp_table); 2254 2246
+2 -2
drivers/soc/tegra/pmc.c
··· 1384 1384 static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) 1385 1385 { 1386 1386 struct generic_pm_domain *genpd; 1387 - const char *rname = "core"; 1387 + const char *rname[] = { "core", NULL}; 1388 1388 int err; 1389 1389 1390 1390 genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL); ··· 1395 1395 genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; 1396 1396 genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; 1397 1397 1398 - err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1); 1398 + err = devm_pm_opp_set_regulators(pmc->dev, rname); 1399 1399 if (err) 1400 1400 return dev_err_probe(pmc->dev, err, 1401 1401 "failed to set core OPP regulator\n");
+4 -5
include/linux/pm_opp.h
··· 159 159 int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count); 160 160 struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name); 161 161 void dev_pm_opp_put_prop_name(struct opp_table *opp_table); 162 - struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count); 162 + struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[]); 163 163 void dev_pm_opp_put_regulators(struct opp_table *opp_table); 164 - int devm_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count); 164 + int devm_pm_opp_set_regulators(struct device *dev, const char * const names[]); 165 165 struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name); 166 166 void dev_pm_opp_put_clkname(struct opp_table *opp_table); 167 167 int devm_pm_opp_set_clkname(struct device *dev, const char *name); ··· 379 379 380 380 static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {} 381 381 382 - static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count) 382 + static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[]) 383 383 { 384 384 return ERR_PTR(-EOPNOTSUPP); 385 385 } ··· 387 387 static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {} 388 388 389 389 static inline int devm_pm_opp_set_regulators(struct device *dev, 390 - const char * const names[], 391 - unsigned int count) 390 + const char * const names[]) 392 391 { 393 392 return -EOPNOTSUPP; 394 393 }