aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-03-23 17:16:32 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-03-23 17:16:32 -0400
commite00e56dfd3cf1d209ce630a2b440c91e4a30bbd3 (patch)
tree4d1329036e250db15411b21b15a158f9042945bd /drivers/cpufreq
parentfb3600cc50302c9577b76838fcac1ee78828007d (diff)
cpufreq: Use syscore_ops for boot CPU suspend/resume (v2)
The cpufreq subsystem uses sysdev suspend and resume for executing cpufreq_suspend() and cpufreq_resume(), respectively, during system suspend, after interrupts have been switched off on the boot CPU, and during system resume, while interrupts are still off on the boot CPU. In both cases the other CPUs are off-line at the relevant point (either they have been switched off via CPU hotplug during suspend, or they haven't been switched on yet during resume). For this reason, although it may seem that cpufreq_suspend() and cpufreq_resume() are executed for all CPUs in the system, they are only called for the boot CPU in fact, which is quite confusing. To remove the confusion and to prepare for elimiating sysdev suspend and resume operations from the kernel enirely, convernt cpufreq to using a struct syscore_ops object for the boot CPU suspend and resume and rename the callbacks so that their names reflect their purpose. In addition, put some explanatory remarks into their kerneldoc comments. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq.c66
1 files changed, 26 insertions, 40 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 0f17ad8585d7..b03771d4787c 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -28,6 +28,7 @@
28#include <linux/cpu.h> 28#include <linux/cpu.h>
29#include <linux/completion.h> 29#include <linux/completion.h>
30#include <linux/mutex.h> 30#include <linux/mutex.h>
31#include <linux/syscore_ops.h>
31 32
32#include <trace/events/power.h> 33#include <trace/events/power.h>
33 34
@@ -1340,35 +1341,31 @@ out:
1340} 1341}
1341EXPORT_SYMBOL(cpufreq_get); 1342EXPORT_SYMBOL(cpufreq_get);
1342 1343
1344static struct sysdev_driver cpufreq_sysdev_driver = {
1345 .add = cpufreq_add_dev,
1346 .remove = cpufreq_remove_dev,
1347};
1348
1343 1349
1344/** 1350/**
1345 * cpufreq_suspend - let the low level driver prepare for suspend 1351 * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
1352 *
1353 * This function is only executed for the boot processor. The other CPUs
1354 * have been put offline by means of CPU hotplug.
1346 */ 1355 */
1347 1356static int cpufreq_bp_suspend(void)
1348static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
1349{ 1357{
1350 int ret = 0; 1358 int ret = 0;
1351 1359
1352 int cpu = sysdev->id; 1360 int cpu = smp_processor_id();
1353 struct cpufreq_policy *cpu_policy; 1361 struct cpufreq_policy *cpu_policy;
1354 1362
1355 dprintk("suspending cpu %u\n", cpu); 1363 dprintk("suspending cpu %u\n", cpu);
1356 1364
1357 if (!cpu_online(cpu)) 1365 /* If there's no policy for the boot CPU, we have nothing to do. */
1358 return 0;
1359
1360 /* we may be lax here as interrupts are off. Nonetheless
1361 * we need to grab the correct cpu policy, as to check
1362 * whether we really run on this CPU.
1363 */
1364
1365 cpu_policy = cpufreq_cpu_get(cpu); 1366 cpu_policy = cpufreq_cpu_get(cpu);
1366 if (!cpu_policy) 1367 if (!cpu_policy)
1367 return -EINVAL; 1368 return 0;
1368
1369 /* only handle each CPU group once */
1370 if (unlikely(cpu_policy->cpu != cpu))
1371 goto out;
1372 1369
1373 if (cpufreq_driver->suspend) { 1370 if (cpufreq_driver->suspend) {
1374 ret = cpufreq_driver->suspend(cpu_policy); 1371 ret = cpufreq_driver->suspend(cpu_policy);
@@ -1377,13 +1374,12 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
1377 "step on CPU %u\n", cpu_policy->cpu); 1374 "step on CPU %u\n", cpu_policy->cpu);
1378 } 1375 }
1379 1376
1380out:
1381 cpufreq_cpu_put(cpu_policy); 1377 cpufreq_cpu_put(cpu_policy);
1382 return ret; 1378 return ret;
1383} 1379}
1384 1380
1385/** 1381/**
1386 * cpufreq_resume - restore proper CPU frequency handling after resume 1382 * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
1387 * 1383 *
1388 * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) 1384 * 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
1389 * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are 1385 * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are
@@ -1391,31 +1387,23 @@ out:
1391 * what we believe it to be. This is a bit later than when it 1387 * what we believe it to be. This is a bit later than when it
1392 * should be, but nonethteless it's better than calling 1388 * should be, but nonethteless it's better than calling
1393 * cpufreq_driver->get() here which might re-enable interrupts... 1389 * cpufreq_driver->get() here which might re-enable interrupts...
1390 *
1391 * This function is only executed for the boot CPU. The other CPUs have not
1392 * been turned on yet.
1394 */ 1393 */
1395static int cpufreq_resume(struct sys_device *sysdev) 1394static void cpufreq_bp_resume(void)
1396{ 1395{
1397 int ret = 0; 1396 int ret = 0;
1398 1397
1399 int cpu = sysdev->id; 1398 int cpu = smp_processor_id();
1400 struct cpufreq_policy *cpu_policy; 1399 struct cpufreq_policy *cpu_policy;
1401 1400
1402 dprintk("resuming cpu %u\n", cpu); 1401 dprintk("resuming cpu %u\n", cpu);
1403 1402
1404 if (!cpu_online(cpu)) 1403 /* If there's no policy for the boot CPU, we have nothing to do. */
1405 return 0;
1406
1407 /* we may be lax here as interrupts are off. Nonetheless
1408 * we need to grab the correct cpu policy, as to check
1409 * whether we really run on this CPU.
1410 */
1411
1412 cpu_policy = cpufreq_cpu_get(cpu); 1404 cpu_policy = cpufreq_cpu_get(cpu);
1413 if (!cpu_policy) 1405 if (!cpu_policy)
1414 return -EINVAL; 1406 return;
1415
1416 /* only handle each CPU group once */
1417 if (unlikely(cpu_policy->cpu != cpu))
1418 goto fail;
1419 1407
1420 if (cpufreq_driver->resume) { 1408 if (cpufreq_driver->resume) {
1421 ret = cpufreq_driver->resume(cpu_policy); 1409 ret = cpufreq_driver->resume(cpu_policy);
@@ -1430,14 +1418,11 @@ static int cpufreq_resume(struct sys_device *sysdev)
1430 1418
1431fail: 1419fail:
1432 cpufreq_cpu_put(cpu_policy); 1420 cpufreq_cpu_put(cpu_policy);
1433 return ret;
1434} 1421}
1435 1422
1436static struct sysdev_driver cpufreq_sysdev_driver = { 1423static struct syscore_ops cpufreq_syscore_ops = {
1437 .add = cpufreq_add_dev, 1424 .suspend = cpufreq_bp_suspend,
1438 .remove = cpufreq_remove_dev, 1425 .resume = cpufreq_bp_resume,
1439 .suspend = cpufreq_suspend,
1440 .resume = cpufreq_resume,
1441}; 1426};
1442 1427
1443 1428
@@ -2002,6 +1987,7 @@ static int __init cpufreq_core_init(void)
2002 cpufreq_global_kobject = kobject_create_and_add("cpufreq", 1987 cpufreq_global_kobject = kobject_create_and_add("cpufreq",
2003 &cpu_sysdev_class.kset.kobj); 1988 &cpu_sysdev_class.kset.kobj);
2004 BUG_ON(!cpufreq_global_kobject); 1989 BUG_ON(!cpufreq_global_kobject);
1990 register_syscore_ops(&cpufreq_syscore_ops);
2005 1991
2006 return 0; 1992 return 0;
2007} 1993}