Skip to content

Commit 7d62728

Browse files
committed
Merge branches 'pm-cpufreq' and 'pm-sleep'
* pm-cpufreq: cpufreq: cpufreq-dt: Restore default cpumask_setall(policy->cpus) cpufreq: cpufreq-dt: disable unsupported OPPs * pm-sleep: PM / Sleep: fix recovery during resuming from hibernation PM / Sleep: fix async suspend_late/freeze_late error handling
3 parents 76dfdc2 + c81407f + 94fb823 commit 7d62728

File tree

3 files changed

+51
-27
lines changed

3 files changed

+51
-27
lines changed

drivers/base/power/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,8 @@ int dpm_suspend_late(pm_message_t state)
12661266
}
12671267
mutex_unlock(&dpm_list_mtx);
12681268
async_synchronize_full();
1269+
if (!error)
1270+
error = async_error;
12691271
if (error) {
12701272
suspend_stats.failed_suspend_late++;
12711273
dpm_save_failed_step(SUSPEND_SUSPEND_LATE);

drivers/cpufreq/cpufreq-dt.c

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
187187
struct device *cpu_dev;
188188
struct regulator *cpu_reg;
189189
struct clk *cpu_clk;
190+
unsigned long min_uV = ~0, max_uV = 0;
190191
unsigned int transition_latency;
191192
int ret;
192193

@@ -206,16 +207,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
206207
/* OPPs might be populated at runtime, don't check for error here */
207208
of_init_opp_table(cpu_dev);
208209

209-
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
210-
if (ret) {
211-
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
212-
goto out_put_node;
213-
}
214-
215210
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
216211
if (!priv) {
217212
ret = -ENOMEM;
218-
goto out_free_table;
213+
goto out_put_node;
219214
}
220215

221216
of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
@@ -224,30 +219,51 @@ static int cpufreq_init(struct cpufreq_policy *policy)
224219
transition_latency = CPUFREQ_ETERNAL;
225220

226221
if (!IS_ERR(cpu_reg)) {
227-
struct dev_pm_opp *opp;
228-
unsigned long min_uV, max_uV;
229-
int i;
222+
unsigned long opp_freq = 0;
230223

231224
/*
232-
* OPP is maintained in order of increasing frequency, and
233-
* freq_table initialised from OPP is therefore sorted in the
234-
* same order.
225+
* Disable any OPPs where the connected regulator isn't able to
226+
* provide the specified voltage and record minimum and maximum
227+
* voltage levels.
235228
*/
236-
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
237-
;
238-
rcu_read_lock();
239-
opp = dev_pm_opp_find_freq_exact(cpu_dev,
240-
freq_table[0].frequency * 1000, true);
241-
min_uV = dev_pm_opp_get_voltage(opp);
242-
opp = dev_pm_opp_find_freq_exact(cpu_dev,
243-
freq_table[i-1].frequency * 1000, true);
244-
max_uV = dev_pm_opp_get_voltage(opp);
245-
rcu_read_unlock();
229+
while (1) {
230+
struct dev_pm_opp *opp;
231+
unsigned long opp_uV, tol_uV;
232+
233+
rcu_read_lock();
234+
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq);
235+
if (IS_ERR(opp)) {
236+
rcu_read_unlock();
237+
break;
238+
}
239+
opp_uV = dev_pm_opp_get_voltage(opp);
240+
rcu_read_unlock();
241+
242+
tol_uV = opp_uV * priv->voltage_tolerance / 100;
243+
if (regulator_is_supported_voltage(cpu_reg, opp_uV,
244+
opp_uV + tol_uV)) {
245+
if (opp_uV < min_uV)
246+
min_uV = opp_uV;
247+
if (opp_uV > max_uV)
248+
max_uV = opp_uV;
249+
} else {
250+
dev_pm_opp_disable(cpu_dev, opp_freq);
251+
}
252+
253+
opp_freq++;
254+
}
255+
246256
ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
247257
if (ret > 0)
248258
transition_latency += ret * 1000;
249259
}
250260

261+
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
262+
if (ret) {
263+
pr_err("failed to init cpufreq table: %d\n", ret);
264+
goto out_free_priv;
265+
}
266+
251267
/*
252268
* For now, just loading the cooling device;
253269
* thermal DT code takes care of matching them.
@@ -277,7 +293,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
277293
policy->cpuinfo.transition_latency = transition_latency;
278294

279295
pd = cpufreq_get_driver_data();
280-
if (pd && !pd->independent_clocks)
296+
if (!pd || !pd->independent_clocks)
281297
cpumask_setall(policy->cpus);
282298

283299
of_node_put(np);
@@ -286,9 +302,9 @@ static int cpufreq_init(struct cpufreq_policy *policy)
286302

287303
out_cooling_unregister:
288304
cpufreq_cooling_unregister(priv->cdev);
289-
kfree(priv);
290-
out_free_table:
291305
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
306+
out_free_priv:
307+
kfree(priv);
292308
out_put_node:
293309
of_node_put(np);
294310
out_put_reg_clk:

kernel/power/hibernate.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,14 @@ int hibernation_restore(int platform_mode)
502502
error = dpm_suspend_start(PMSG_QUIESCE);
503503
if (!error) {
504504
error = resume_target_kernel(platform_mode);
505-
dpm_resume_end(PMSG_RECOVER);
505+
/*
506+
* The above should either succeed and jump to the new kernel,
507+
* or return with an error. Otherwise things are just
508+
* undefined, so let's be paranoid.
509+
*/
510+
BUG_ON(!error);
506511
}
512+
dpm_resume_end(PMSG_RECOVER);
507513
pm_restore_gfp_mask();
508514
resume_console();
509515
pm_restore_console();

0 commit comments

Comments
 (0)