Skip to content

Commit f0f6dba

Browse files
committed
Merge branch 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm
Pull OPP (Operating Performance Points) updates for 5.11-rc1 from Viresh Kumar: "This contains the following updates: - Allow empty (node-less) OPP tables in DT for passing just the dependency related information (Nicola Mazzucato). - Fix a potential lockdep in OPP core and other OPP core cleanups (Viresh Kumar). - Don't abuse dev_pm_opp_get_opp_table() to create an OPP table, fix cpufreq-dt driver for the same (Viresh Kumar). - dev_pm_opp_put_regulators() accepts a NULL argument now, updates to all the users as well (Viresh Kumar)." * 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: opp: of: Allow empty opp-table with opp-shared dt-bindings: opp: Allow empty OPP tables media: venus: dev_pm_opp_put_*() accepts NULL argument drm/panfrost: dev_pm_opp_put_*() accepts NULL argument drm/lima: dev_pm_opp_put_*() accepts NULL argument PM / devfreq: exynos: dev_pm_opp_put_*() accepts NULL argument cpufreq: qcom-cpufreq-nvmem: dev_pm_opp_put_*() accepts NULL argument cpufreq: dt: dev_pm_opp_put_regulators() accepts NULL argument opp: Allow dev_pm_opp_put_*() APIs to accept NULL opp_table opp: Don't create an OPP table from dev_pm_opp_get_opp_table() cpufreq: dt: Don't (ab)use dev_pm_opp_get_opp_table() to create OPP table opp: Reduce the size of critical section in _opp_kref_release() opp: Don't return opp_dev from _find_opp_dev() opp: Allocate the OPP table outside of opp_table_lock opp: Always add entries in dev_list with opp_table->lock held
2 parents 0477e92 + 2c07b0f commit f0f6dba

12 files changed

Lines changed: 283 additions & 223 deletions

File tree

Documentation/devicetree/bindings/opp/opp.txt

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ Required properties:
6565

6666
- OPP nodes: One or more OPP nodes describing voltage-current-frequency
6767
combinations. Their name isn't significant but their phandle can be used to
68-
reference an OPP.
68+
reference an OPP. These are mandatory except for the case where the OPP table
69+
is present only to indicate dependency between devices using the opp-shared
70+
property.
6971

7072
Optional properties:
7173
- opp-shared: Indicates that device nodes using this OPP Table Node's phandle
@@ -568,3 +570,53 @@ Example 6: opp-microvolt-<name>, opp-microamp-<name>:
568570
};
569571
};
570572
};
573+
574+
Example 7: Single cluster Quad-core ARM cortex A53, OPP points from firmware,
575+
distinct clock controls but two sets of clock/voltage/current lines.
576+
577+
/ {
578+
cpus {
579+
#address-cells = <2>;
580+
#size-cells = <0>;
581+
582+
cpu@0 {
583+
compatible = "arm,cortex-a53";
584+
reg = <0x0 0x100>;
585+
next-level-cache = <&A53_L2>;
586+
clocks = <&dvfs_controller 0>;
587+
operating-points-v2 = <&cpu_opp0_table>;
588+
};
589+
cpu@1 {
590+
compatible = "arm,cortex-a53";
591+
reg = <0x0 0x101>;
592+
next-level-cache = <&A53_L2>;
593+
clocks = <&dvfs_controller 1>;
594+
operating-points-v2 = <&cpu_opp0_table>;
595+
};
596+
cpu@2 {
597+
compatible = "arm,cortex-a53";
598+
reg = <0x0 0x102>;
599+
next-level-cache = <&A53_L2>;
600+
clocks = <&dvfs_controller 2>;
601+
operating-points-v2 = <&cpu_opp1_table>;
602+
};
603+
cpu@3 {
604+
compatible = "arm,cortex-a53";
605+
reg = <0x0 0x103>;
606+
next-level-cache = <&A53_L2>;
607+
clocks = <&dvfs_controller 3>;
608+
operating-points-v2 = <&cpu_opp1_table>;
609+
};
610+
611+
};
612+
613+
cpu_opp0_table: opp0_table {
614+
compatible = "operating-points-v2";
615+
opp-shared;
616+
};
617+
618+
cpu_opp1_table: opp1_table {
619+
compatible = "operating-points-v2";
620+
opp-shared;
621+
};
622+
};

drivers/base/power/domain.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2249,7 +2249,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
22492249
* Save table for faster processing while setting
22502250
* performance state.
22512251
*/
2252-
genpd->opp_table = dev_pm_opp_get_opp_table_indexed(&genpd->dev, i);
2252+
genpd->opp_table = dev_pm_opp_get_opp_table(&genpd->dev);
22532253
WARN_ON(IS_ERR(genpd->opp_table));
22542254
}
22552255

drivers/cpufreq/cpufreq-dt.c

Lines changed: 66 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct private_data {
3030
cpumask_var_t cpus;
3131
struct device *cpu_dev;
3232
struct opp_table *opp_table;
33-
struct opp_table *reg_opp_table;
33+
struct cpufreq_frequency_table *freq_table;
3434
bool have_static_opps;
3535
};
3636

@@ -102,7 +102,6 @@ static const char *find_supply_name(struct device *dev)
102102

103103
static int cpufreq_init(struct cpufreq_policy *policy)
104104
{
105-
struct cpufreq_frequency_table *freq_table;
106105
struct private_data *priv;
107106
struct device *cpu_dev;
108107
struct clk *cpu_clk;
@@ -114,9 +113,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
114113
pr_err("failed to find data for cpu%d\n", policy->cpu);
115114
return -ENODEV;
116115
}
117-
118116
cpu_dev = priv->cpu_dev;
119-
cpumask_copy(policy->cpus, priv->cpus);
120117

121118
cpu_clk = clk_get(cpu_dev, NULL);
122119
if (IS_ERR(cpu_clk)) {
@@ -125,67 +122,32 @@ static int cpufreq_init(struct cpufreq_policy *policy)
125122
return ret;
126123
}
127124

128-
/*
129-
* Initialize OPP tables for all policy->cpus. They will be shared by
130-
* all CPUs which have marked their CPUs shared with OPP bindings.
131-
*
132-
* For platforms not using operating-points-v2 bindings, we do this
133-
* before updating policy->cpus. Otherwise, we will end up creating
134-
* duplicate OPPs for policy->cpus.
135-
*
136-
* OPPs might be populated at runtime, don't check for error here
137-
*/
138-
if (!dev_pm_opp_of_cpumask_add_table(policy->cpus))
139-
priv->have_static_opps = true;
140-
141-
/*
142-
* But we need OPP table to function so if it is not there let's
143-
* give platform code chance to provide it for us.
144-
*/
145-
ret = dev_pm_opp_get_opp_count(cpu_dev);
146-
if (ret <= 0) {
147-
dev_err(cpu_dev, "OPP table can't be empty\n");
148-
ret = -ENODEV;
149-
goto out_free_opp;
150-
}
151-
152-
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
153-
if (ret) {
154-
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
155-
goto out_free_opp;
156-
}
125+
transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
126+
if (!transition_latency)
127+
transition_latency = CPUFREQ_ETERNAL;
157128

129+
cpumask_copy(policy->cpus, priv->cpus);
158130
policy->driver_data = priv;
159131
policy->clk = cpu_clk;
160-
policy->freq_table = freq_table;
161-
132+
policy->freq_table = priv->freq_table;
162133
policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;
134+
policy->cpuinfo.transition_latency = transition_latency;
135+
policy->dvfs_possible_from_any_cpu = true;
163136

164137
/* Support turbo/boost mode */
165138
if (policy_has_boost_freq(policy)) {
166139
/* This gets disabled by core on driver unregister */
167140
ret = cpufreq_enable_boost_support();
168141
if (ret)
169-
goto out_free_cpufreq_table;
142+
goto out_clk_put;
170143
cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs;
171144
}
172145

173-
transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
174-
if (!transition_latency)
175-
transition_latency = CPUFREQ_ETERNAL;
176-
177-
policy->cpuinfo.transition_latency = transition_latency;
178-
policy->dvfs_possible_from_any_cpu = true;
179-
180146
dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
181147

182148
return 0;
183149

184-
out_free_cpufreq_table:
185-
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
186-
out_free_opp:
187-
if (priv->have_static_opps)
188-
dev_pm_opp_of_cpumask_remove_table(policy->cpus);
150+
out_clk_put:
189151
clk_put(cpu_clk);
190152

191153
return ret;
@@ -208,11 +170,6 @@ static int cpufreq_offline(struct cpufreq_policy *policy)
208170

209171
static int cpufreq_exit(struct cpufreq_policy *policy)
210172
{
211-
struct private_data *priv = policy->driver_data;
212-
213-
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
214-
if (priv->have_static_opps)
215-
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
216173
clk_put(policy->clk);
217174
return 0;
218175
}
@@ -236,6 +193,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
236193
{
237194
struct private_data *priv;
238195
struct device *cpu_dev;
196+
bool fallback = false;
239197
const char *reg_name;
240198
int ret;
241199

@@ -254,68 +212,86 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
254212
if (!alloc_cpumask_var(&priv->cpus, GFP_KERNEL))
255213
return -ENOMEM;
256214

215+
cpumask_set_cpu(cpu, priv->cpus);
257216
priv->cpu_dev = cpu_dev;
258217

259-
/* Try to get OPP table early to ensure resources are available */
260-
priv->opp_table = dev_pm_opp_get_opp_table(cpu_dev);
261-
if (IS_ERR(priv->opp_table)) {
262-
ret = PTR_ERR(priv->opp_table);
263-
if (ret != -EPROBE_DEFER)
264-
dev_err(cpu_dev, "failed to get OPP table: %d\n", ret);
265-
goto free_cpumask;
266-
}
267-
268218
/*
269219
* OPP layer will be taking care of regulators now, but it needs to know
270220
* the name of the regulator first.
271221
*/
272222
reg_name = find_supply_name(cpu_dev);
273223
if (reg_name) {
274-
priv->reg_opp_table = dev_pm_opp_set_regulators(cpu_dev,
275-
&reg_name, 1);
276-
if (IS_ERR(priv->reg_opp_table)) {
277-
ret = PTR_ERR(priv->reg_opp_table);
224+
priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, &reg_name,
225+
1);
226+
if (IS_ERR(priv->opp_table)) {
227+
ret = PTR_ERR(priv->opp_table);
278228
if (ret != -EPROBE_DEFER)
279229
dev_err(cpu_dev, "failed to set regulators: %d\n",
280230
ret);
281-
goto put_table;
231+
goto free_cpumask;
282232
}
283233
}
284234

285-
/* Find OPP sharing information so we can fill pri->cpus here */
286235
/* Get OPP-sharing information from "operating-points-v2" bindings */
287236
ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->cpus);
288237
if (ret) {
289238
if (ret != -ENOENT)
290-
goto put_reg;
239+
goto out;
291240

292241
/*
293242
* operating-points-v2 not supported, fallback to all CPUs share
294243
* OPP for backward compatibility if the platform hasn't set
295244
* sharing CPUs.
296245
*/
297-
if (dev_pm_opp_get_sharing_cpus(cpu_dev, priv->cpus)) {
298-
cpumask_setall(priv->cpus);
299-
300-
/*
301-
* OPP tables are initialized only for cpu, do it for
302-
* others as well.
303-
*/
304-
ret = dev_pm_opp_set_sharing_cpus(cpu_dev, priv->cpus);
305-
if (ret)
306-
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
307-
__func__, ret);
308-
}
246+
if (dev_pm_opp_get_sharing_cpus(cpu_dev, priv->cpus))
247+
fallback = true;
248+
}
249+
250+
/*
251+
* Initialize OPP tables for all priv->cpus. They will be shared by
252+
* all CPUs which have marked their CPUs shared with OPP bindings.
253+
*
254+
* For platforms not using operating-points-v2 bindings, we do this
255+
* before updating priv->cpus. Otherwise, we will end up creating
256+
* duplicate OPPs for the CPUs.
257+
*
258+
* OPPs might be populated at runtime, don't check for error here.
259+
*/
260+
if (!dev_pm_opp_of_cpumask_add_table(priv->cpus))
261+
priv->have_static_opps = true;
262+
263+
/*
264+
* The OPP table must be initialized, statically or dynamically, by this
265+
* point.
266+
*/
267+
ret = dev_pm_opp_get_opp_count(cpu_dev);
268+
if (ret <= 0) {
269+
dev_err(cpu_dev, "OPP table can't be empty\n");
270+
ret = -ENODEV;
271+
goto out;
272+
}
273+
274+
if (fallback) {
275+
cpumask_setall(priv->cpus);
276+
ret = dev_pm_opp_set_sharing_cpus(cpu_dev, priv->cpus);
277+
if (ret)
278+
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
279+
__func__, ret);
280+
}
281+
282+
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &priv->freq_table);
283+
if (ret) {
284+
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
285+
goto out;
309286
}
310287

311288
list_add(&priv->node, &priv_list);
312289
return 0;
313290

314-
put_reg:
315-
if (priv->reg_opp_table)
316-
dev_pm_opp_put_regulators(priv->reg_opp_table);
317-
put_table:
318-
dev_pm_opp_put_opp_table(priv->opp_table);
291+
out:
292+
if (priv->have_static_opps)
293+
dev_pm_opp_of_cpumask_remove_table(priv->cpus);
294+
dev_pm_opp_put_regulators(priv->opp_table);
319295
free_cpumask:
320296
free_cpumask_var(priv->cpus);
321297
return ret;
@@ -326,9 +302,10 @@ static void dt_cpufreq_release(void)
326302
struct private_data *priv, *tmp;
327303

328304
list_for_each_entry_safe(priv, tmp, &priv_list, node) {
329-
if (priv->reg_opp_table)
330-
dev_pm_opp_put_regulators(priv->reg_opp_table);
331-
dev_pm_opp_put_opp_table(priv->opp_table);
305+
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table);
306+
if (priv->have_static_opps)
307+
dev_pm_opp_of_cpumask_remove_table(priv->cpus);
308+
dev_pm_opp_put_regulators(priv->opp_table);
332309
free_cpumask_var(priv->cpus);
333310
list_del(&priv->node);
334311
}

drivers/cpufreq/qcom-cpufreq-nvmem.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -397,19 +397,19 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
397397

398398
free_genpd_opp:
399399
for_each_possible_cpu(cpu) {
400-
if (IS_ERR_OR_NULL(drv->genpd_opp_tables[cpu]))
400+
if (IS_ERR(drv->genpd_opp_tables[cpu]))
401401
break;
402402
dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
403403
}
404404
kfree(drv->genpd_opp_tables);
405405
free_opp:
406406
for_each_possible_cpu(cpu) {
407-
if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu]))
407+
if (IS_ERR(drv->names_opp_tables[cpu]))
408408
break;
409409
dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
410410
}
411411
for_each_possible_cpu(cpu) {
412-
if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu]))
412+
if (IS_ERR(drv->hw_opp_tables[cpu]))
413413
break;
414414
dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
415415
}
@@ -430,12 +430,9 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)
430430
platform_device_unregister(cpufreq_dt_pdev);
431431

432432
for_each_possible_cpu(cpu) {
433-
if (drv->names_opp_tables[cpu])
434-
dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
435-
if (drv->hw_opp_tables[cpu])
436-
dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
437-
if (drv->genpd_opp_tables[cpu])
438-
dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
433+
dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
434+
dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
435+
dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
439436
}
440437

441438
kfree(drv->names_opp_tables);

drivers/devfreq/exynos-bus.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,8 @@ static void exynos_bus_exit(struct device *dev)
158158

159159
dev_pm_opp_of_remove_table(dev);
160160
clk_disable_unprepare(bus->clk);
161-
if (bus->opp_table) {
162-
dev_pm_opp_put_regulators(bus->opp_table);
163-
bus->opp_table = NULL;
164-
}
161+
dev_pm_opp_put_regulators(bus->opp_table);
162+
bus->opp_table = NULL;
165163
}
166164

167165
static void exynos_bus_passive_exit(struct device *dev)
@@ -444,10 +442,8 @@ static int exynos_bus_probe(struct platform_device *pdev)
444442
dev_pm_opp_of_remove_table(dev);
445443
clk_disable_unprepare(bus->clk);
446444
err_reg:
447-
if (!passive) {
448-
dev_pm_opp_put_regulators(bus->opp_table);
449-
bus->opp_table = NULL;
450-
}
445+
dev_pm_opp_put_regulators(bus->opp_table);
446+
bus->opp_table = NULL;
451447

452448
return ret;
453449
}

0 commit comments

Comments
 (0)