aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-12-09 18:58:18 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-01-02 18:29:48 -0500
commit4fa3061a6856cc72f3f984702145bb30f16ee40e (patch)
tree7f10e0e1c662becfe39f91e467a55f64488dda7e
parent9dbc64a5d5938b990a045509ff5356fc53e4abd4 (diff)
PM / core: Add helpers for subsystem callback selection
Add helper routines to find and return a suitable subsystem callback during the "noirq" phases of system suspend/resume (or analogous) transitions as well as during the "late" phase of system suspend and the "early" phase of system resume (or analogous) transitions. The helpers will be called from additional sites going forward. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
-rw-r--r--drivers/base/power/main.c188
1 files changed, 128 insertions, 60 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 6e8cc5de93fd..3c5fdf155c91 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -551,6 +551,35 @@ bool dev_pm_may_skip_resume(struct device *dev)
551 return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE; 551 return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE;
552} 552}
553 553
554static pm_callback_t dpm_subsys_resume_noirq_cb(struct device *dev,
555 pm_message_t state,
556 const char **info_p)
557{
558 pm_callback_t callback;
559 const char *info;
560
561 if (dev->pm_domain) {
562 info = "noirq power domain ";
563 callback = pm_noirq_op(&dev->pm_domain->ops, state);
564 } else if (dev->type && dev->type->pm) {
565 info = "noirq type ";
566 callback = pm_noirq_op(dev->type->pm, state);
567 } else if (dev->class && dev->class->pm) {
568 info = "noirq class ";
569 callback = pm_noirq_op(dev->class->pm, state);
570 } else if (dev->bus && dev->bus->pm) {
571 info = "noirq bus ";
572 callback = pm_noirq_op(dev->bus->pm, state);
573 } else {
574 return NULL;
575 }
576
577 if (info_p)
578 *info_p = info;
579
580 return callback;
581}
582
554/** 583/**
555 * device_resume_noirq - Execute a "noirq resume" callback for given device. 584 * device_resume_noirq - Execute a "noirq resume" callback for given device.
556 * @dev: Device to handle. 585 * @dev: Device to handle.
@@ -562,8 +591,8 @@ bool dev_pm_may_skip_resume(struct device *dev)
562 */ 591 */
563static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) 592static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
564{ 593{
565 pm_callback_t callback = NULL; 594 pm_callback_t callback;
566 const char *info = NULL; 595 const char *info;
567 int error = 0; 596 int error = 0;
568 597
569 TRACE_DEVICE(dev); 598 TRACE_DEVICE(dev);
@@ -577,19 +606,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
577 606
578 dpm_wait_for_superior(dev, async); 607 dpm_wait_for_superior(dev, async);
579 608
580 if (dev->pm_domain) { 609 callback = dpm_subsys_resume_noirq_cb(dev, state, &info);
581 info = "noirq power domain ";
582 callback = pm_noirq_op(&dev->pm_domain->ops, state);
583 } else if (dev->type && dev->type->pm) {
584 info = "noirq type ";
585 callback = pm_noirq_op(dev->type->pm, state);
586 } else if (dev->class && dev->class->pm) {
587 info = "noirq class ";
588 callback = pm_noirq_op(dev->class->pm, state);
589 } else if (dev->bus && dev->bus->pm) {
590 info = "noirq bus ";
591 callback = pm_noirq_op(dev->bus->pm, state);
592 }
593 610
594 if (!callback && dev->driver && dev->driver->pm) { 611 if (!callback && dev->driver && dev->driver->pm) {
595 info = "noirq driver "; 612 info = "noirq driver ";
@@ -704,6 +721,35 @@ void dpm_resume_noirq(pm_message_t state)
704 dpm_noirq_end(); 721 dpm_noirq_end();
705} 722}
706 723
724static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev,
725 pm_message_t state,
726 const char **info_p)
727{
728 pm_callback_t callback;
729 const char *info;
730
731 if (dev->pm_domain) {
732 info = "early power domain ";
733 callback = pm_late_early_op(&dev->pm_domain->ops, state);
734 } else if (dev->type && dev->type->pm) {
735 info = "early type ";
736 callback = pm_late_early_op(dev->type->pm, state);
737 } else if (dev->class && dev->class->pm) {
738 info = "early class ";
739 callback = pm_late_early_op(dev->class->pm, state);
740 } else if (dev->bus && dev->bus->pm) {
741 info = "early bus ";
742 callback = pm_late_early_op(dev->bus->pm, state);
743 } else {
744 return NULL;
745 }
746
747 if (info_p)
748 *info_p = info;
749
750 return callback;
751}
752
707/** 753/**
708 * device_resume_early - Execute an "early resume" callback for given device. 754 * device_resume_early - Execute an "early resume" callback for given device.
709 * @dev: Device to handle. 755 * @dev: Device to handle.
@@ -714,8 +760,8 @@ void dpm_resume_noirq(pm_message_t state)
714 */ 760 */
715static int device_resume_early(struct device *dev, pm_message_t state, bool async) 761static int device_resume_early(struct device *dev, pm_message_t state, bool async)
716{ 762{
717 pm_callback_t callback = NULL; 763 pm_callback_t callback;
718 const char *info = NULL; 764 const char *info;
719 int error = 0; 765 int error = 0;
720 766
721 TRACE_DEVICE(dev); 767 TRACE_DEVICE(dev);
@@ -729,19 +775,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
729 775
730 dpm_wait_for_superior(dev, async); 776 dpm_wait_for_superior(dev, async);
731 777
732 if (dev->pm_domain) { 778 callback = dpm_subsys_resume_early_cb(dev, state, &info);
733 info = "early power domain ";
734 callback = pm_late_early_op(&dev->pm_domain->ops, state);
735 } else if (dev->type && dev->type->pm) {
736 info = "early type ";
737 callback = pm_late_early_op(dev->type->pm, state);
738 } else if (dev->class && dev->class->pm) {
739 info = "early class ";
740 callback = pm_late_early_op(dev->class->pm, state);
741 } else if (dev->bus && dev->bus->pm) {
742 info = "early bus ";
743 callback = pm_late_early_op(dev->bus->pm, state);
744 }
745 779
746 if (!callback && dev->driver && dev->driver->pm) { 780 if (!callback && dev->driver && dev->driver->pm) {
747 info = "early driver "; 781 info = "early driver ";
@@ -1128,6 +1162,35 @@ static void dpm_superior_set_must_resume(struct device *dev)
1128 device_links_read_unlock(idx); 1162 device_links_read_unlock(idx);
1129} 1163}
1130 1164
1165static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev,
1166 pm_message_t state,
1167 const char **info_p)
1168{
1169 pm_callback_t callback;
1170 const char *info;
1171
1172 if (dev->pm_domain) {
1173 info = "noirq power domain ";
1174 callback = pm_noirq_op(&dev->pm_domain->ops, state);
1175 } else if (dev->type && dev->type->pm) {
1176 info = "noirq type ";
1177 callback = pm_noirq_op(dev->type->pm, state);
1178 } else if (dev->class && dev->class->pm) {
1179 info = "noirq class ";
1180 callback = pm_noirq_op(dev->class->pm, state);
1181 } else if (dev->bus && dev->bus->pm) {
1182 info = "noirq bus ";
1183 callback = pm_noirq_op(dev->bus->pm, state);
1184 } else {
1185 return NULL;
1186 }
1187
1188 if (info_p)
1189 *info_p = info;
1190
1191 return callback;
1192}
1193
1131/** 1194/**
1132 * __device_suspend_noirq - Execute a "noirq suspend" callback for given device. 1195 * __device_suspend_noirq - Execute a "noirq suspend" callback for given device.
1133 * @dev: Device to handle. 1196 * @dev: Device to handle.
@@ -1139,8 +1202,8 @@ static void dpm_superior_set_must_resume(struct device *dev)
1139 */ 1202 */
1140static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) 1203static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
1141{ 1204{
1142 pm_callback_t callback = NULL; 1205 pm_callback_t callback;
1143 const char *info = NULL; 1206 const char *info;
1144 int error = 0; 1207 int error = 0;
1145 1208
1146 TRACE_DEVICE(dev); 1209 TRACE_DEVICE(dev);
@@ -1159,19 +1222,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
1159 if (dev->power.syscore || dev->power.direct_complete) 1222 if (dev->power.syscore || dev->power.direct_complete)
1160 goto Complete; 1223 goto Complete;
1161 1224
1162 if (dev->pm_domain) { 1225 callback = dpm_subsys_suspend_noirq_cb(dev, state, &info);
1163 info = "noirq power domain ";
1164 callback = pm_noirq_op(&dev->pm_domain->ops, state);
1165 } else if (dev->type && dev->type->pm) {
1166 info = "noirq type ";
1167 callback = pm_noirq_op(dev->type->pm, state);
1168 } else if (dev->class && dev->class->pm) {
1169 info = "noirq class ";
1170 callback = pm_noirq_op(dev->class->pm, state);
1171 } else if (dev->bus && dev->bus->pm) {
1172 info = "noirq bus ";
1173 callback = pm_noirq_op(dev->bus->pm, state);
1174 }
1175 1226
1176 if (!callback && dev->driver && dev->driver->pm) { 1227 if (!callback && dev->driver && dev->driver->pm) {
1177 info = "noirq driver "; 1228 info = "noirq driver ";
@@ -1306,6 +1357,35 @@ int dpm_suspend_noirq(pm_message_t state)
1306 return ret; 1357 return ret;
1307} 1358}
1308 1359
1360static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev,
1361 pm_message_t state,
1362 const char **info_p)
1363{
1364 pm_callback_t callback;
1365 const char *info;
1366
1367 if (dev->pm_domain) {
1368 info = "late power domain ";
1369 callback = pm_late_early_op(&dev->pm_domain->ops, state);
1370 } else if (dev->type && dev->type->pm) {
1371 info = "late type ";
1372 callback = pm_late_early_op(dev->type->pm, state);
1373 } else if (dev->class && dev->class->pm) {
1374 info = "late class ";
1375 callback = pm_late_early_op(dev->class->pm, state);
1376 } else if (dev->bus && dev->bus->pm) {
1377 info = "late bus ";
1378 callback = pm_late_early_op(dev->bus->pm, state);
1379 } else {
1380 return NULL;
1381 }
1382
1383 if (info_p)
1384 *info_p = info;
1385
1386 return callback;
1387}
1388
1309/** 1389/**
1310 * __device_suspend_late - Execute a "late suspend" callback for given device. 1390 * __device_suspend_late - Execute a "late suspend" callback for given device.
1311 * @dev: Device to handle. 1391 * @dev: Device to handle.
@@ -1316,8 +1396,8 @@ int dpm_suspend_noirq(pm_message_t state)
1316 */ 1396 */
1317static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) 1397static int __device_suspend_late(struct device *dev, pm_message_t state, bool async)
1318{ 1398{
1319 pm_callback_t callback = NULL; 1399 pm_callback_t callback;
1320 const char *info = NULL; 1400 const char *info;
1321 int error = 0; 1401 int error = 0;
1322 1402
1323 TRACE_DEVICE(dev); 1403 TRACE_DEVICE(dev);
@@ -1338,19 +1418,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
1338 if (dev->power.syscore || dev->power.direct_complete) 1418 if (dev->power.syscore || dev->power.direct_complete)
1339 goto Complete; 1419 goto Complete;
1340 1420
1341 if (dev->pm_domain) { 1421 callback = dpm_subsys_suspend_late_cb(dev, state, &info);
1342 info = "late power domain ";
1343 callback = pm_late_early_op(&dev->pm_domain->ops, state);
1344 } else if (dev->type && dev->type->pm) {
1345 info = "late type ";
1346 callback = pm_late_early_op(dev->type->pm, state);
1347 } else if (dev->class && dev->class->pm) {
1348 info = "late class ";
1349 callback = pm_late_early_op(dev->class->pm, state);
1350 } else if (dev->bus && dev->bus->pm) {
1351 info = "late bus ";
1352 callback = pm_late_early_op(dev->bus->pm, state);
1353 }
1354 1422
1355 if (!callback && dev->driver && dev->driver->pm) { 1423 if (!callback && dev->driver && dev->driver->pm) {
1356 info = "late driver "; 1424 info = "late driver ";