Skip to content

Commit 91a12e9

Browse files
vireshkrafaeljw
authored andcommitted
cpufreq: Allow light-weight tear down and bring up of CPUs
The cpufreq core doesn't remove the cpufreq policy anymore on CPU offline operation, rather that happens when the CPU device gets unregistered from the kernel. This allows faster recovery when the CPU comes back online. This is also very useful during system wide suspend/resume where we offline all non-boot CPUs during suspend and then bring them back on resume. This commit takes the same idea a step ahead to allow drivers to do light weight tear-down and bring-up during CPU offline and online operations. A new set of callbacks is introduced, online/offline(). online() gets called when the first CPU of an inactive policy is brought up and offline() gets called when all the CPUs of a policy are offlined. The existing init/exit() callback get called on policy creation/destruction. They also get called instead of online/offline() callbacks if the online/offline() callbacks aren't provided. This also moves around some code to get executed only for the new-policy case going forward. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 9795607 commit 91a12e9

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

drivers/cpufreq/cpufreq.c

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,28 +1201,39 @@ static int cpufreq_online(unsigned int cpu)
12011201
return -ENOMEM;
12021202
}
12031203

1204-
cpumask_copy(policy->cpus, cpumask_of(cpu));
1204+
if (!new_policy && cpufreq_driver->online) {
1205+
ret = cpufreq_driver->online(policy);
1206+
if (ret) {
1207+
pr_debug("%s: %d: initialization failed\n", __func__,
1208+
__LINE__);
1209+
goto out_exit_policy;
1210+
}
12051211

1206-
/* call driver. From then on the cpufreq must be able
1207-
* to accept all calls to ->verify and ->setpolicy for this CPU
1208-
*/
1209-
ret = cpufreq_driver->init(policy);
1210-
if (ret) {
1211-
pr_debug("initialization failed\n");
1212-
goto out_free_policy;
1213-
}
1212+
/* Recover policy->cpus using related_cpus */
1213+
cpumask_copy(policy->cpus, policy->related_cpus);
1214+
} else {
1215+
cpumask_copy(policy->cpus, cpumask_of(cpu));
12141216

1215-
ret = cpufreq_table_validate_and_sort(policy);
1216-
if (ret)
1217-
goto out_exit_policy;
1217+
/*
1218+
* Call driver. From then on the cpufreq must be able
1219+
* to accept all calls to ->verify and ->setpolicy for this CPU.
1220+
*/
1221+
ret = cpufreq_driver->init(policy);
1222+
if (ret) {
1223+
pr_debug("%s: %d: initialization failed\n", __func__,
1224+
__LINE__);
1225+
goto out_free_policy;
1226+
}
12181227

1219-
down_write(&policy->rwsem);
1228+
ret = cpufreq_table_validate_and_sort(policy);
1229+
if (ret)
1230+
goto out_exit_policy;
12201231

1221-
if (new_policy) {
12221232
/* related_cpus should at least include policy->cpus. */
12231233
cpumask_copy(policy->related_cpus, policy->cpus);
12241234
}
12251235

1236+
down_write(&policy->rwsem);
12261237
/*
12271238
* affected cpus must always be the one, which are online. We aren't
12281239
* managing offline cpus here.
@@ -1421,11 +1432,12 @@ static int cpufreq_offline(unsigned int cpu)
14211432
cpufreq_exit_governor(policy);
14221433

14231434
/*
1424-
* Perform the ->exit() even during light-weight tear-down,
1425-
* since this is a core component, and is essential for the
1426-
* subsequent light-weight ->init() to succeed.
1435+
* Perform the ->offline() during light-weight tear-down, as
1436+
* that allows fast recovery when the CPU comes back.
14271437
*/
1428-
if (cpufreq_driver->exit) {
1438+
if (cpufreq_driver->offline) {
1439+
cpufreq_driver->offline(policy);
1440+
} else if (cpufreq_driver->exit) {
14291441
cpufreq_driver->exit(policy);
14301442
policy->freq_table = NULL;
14311443
}
@@ -1454,8 +1466,13 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
14541466
cpumask_clear_cpu(cpu, policy->real_cpus);
14551467
remove_cpu_dev_symlink(policy, dev);
14561468

1457-
if (cpumask_empty(policy->real_cpus))
1469+
if (cpumask_empty(policy->real_cpus)) {
1470+
/* We did light-weight exit earlier, do full tear down now */
1471+
if (cpufreq_driver->offline)
1472+
cpufreq_driver->exit(policy);
1473+
14581474
cpufreq_policy_free(policy);
1475+
}
14591476
}
14601477

14611478
/**
@@ -2488,7 +2505,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
24882505
driver_data->target) ||
24892506
(driver_data->setpolicy && (driver_data->target_index ||
24902507
driver_data->target)) ||
2491-
(!!driver_data->get_intermediate != !!driver_data->target_intermediate))
2508+
(!!driver_data->get_intermediate != !!driver_data->target_intermediate) ||
2509+
(!driver_data->online != !driver_data->offline))
24922510
return -EINVAL;
24932511

24942512
pr_debug("trying to register driver %s\n", driver_data->name);

include/linux/cpufreq.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ struct cpufreq_driver {
325325
/* optional */
326326
int (*bios_limit)(int cpu, unsigned int *limit);
327327

328+
int (*online)(struct cpufreq_policy *policy);
329+
int (*offline)(struct cpufreq_policy *policy);
328330
int (*exit)(struct cpufreq_policy *policy);
329331
void (*stop_cpu)(struct cpufreq_policy *policy);
330332
int (*suspend)(struct cpufreq_policy *policy);

0 commit comments

Comments
 (0)