diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-08-05 19:46:39 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-09-03 19:36:04 -0400 |
commit | dbf374142dd7a3c394ec124ebe7339a6c412d9b6 (patch) | |
tree | 593b26dff2da2f364ed1ad97e667d691487d7e69 /drivers/base | |
parent | 6fb28badf207a6d8a78906353772e1c3f560a977 (diff) |
PM / Domains: Move syscore flag from subsys data to struct device
The syscore device PM flag is used to mark the devices (belonging to
a PM domain) that should never be turned off, except for the system
core (syscore) suspend/hibernation and resume stages. That flag is
stored in the device's struct pm_subsys_data object whose address is
available from struct device. However, in some situations it may be
convenient to set that flag before the device is added to a PM
domain, so it is better to move it directly to the "power" member of
struct device. Then, it can be checked by the routines in
drivers/base/power/runtime.c and drivers/base/power/main.c, which is
more straightforward.
This also reduces the number of dev_gpd_data() invocations in the
generic PM domains framework, so the overhead related to the syscore
flag is slightly smaller.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Magnus Damm <damm@opensource.se>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/common.c | 15 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 37 | ||||
-rw-r--r-- | drivers/base/power/main.c | 28 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 2 |
4 files changed, 50 insertions, 32 deletions
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index 39c32529b833..cf7a85134730 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c | |||
@@ -83,3 +83,18 @@ int dev_pm_put_subsys_data(struct device *dev) | |||
83 | return ret; | 83 | return ret; |
84 | } | 84 | } |
85 | EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); | 85 | EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); |
86 | |||
87 | /** | ||
88 | * dev_pm_syscore_device - Set/unset the given device's power.syscore flag. | ||
89 | * @dev: Device whose flag is to be modified. | ||
90 | * @val: New value of the flag. | ||
91 | */ | ||
92 | void dev_pm_syscore_device(struct device *dev, bool val) | ||
93 | { | ||
94 | unsigned long flags; | ||
95 | |||
96 | spin_lock_irqsave(&dev->power.lock, flags); | ||
97 | dev->power.syscore = val; | ||
98 | spin_unlock_irqrestore(&dev->power.lock, flags); | ||
99 | } | ||
100 | EXPORT_SYMBOL_GPL(dev_pm_syscore_device); | ||
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 15234ecd7edb..52172754ff78 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -436,7 +436,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
436 | not_suspended = 0; | 436 | not_suspended = 0; |
437 | list_for_each_entry(pdd, &genpd->dev_list, list_node) | 437 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
438 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) | 438 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) |
439 | || pdd->dev->power.irq_safe || to_gpd_data(pdd)->syscore)) | 439 | || pdd->dev->power.irq_safe || pdd->dev->power.syscore)) |
440 | not_suspended++; | 440 | not_suspended++; |
441 | 441 | ||
442 | if (not_suspended > genpd->in_progress) | 442 | if (not_suspended > genpd->in_progress) |
@@ -578,9 +578,6 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
578 | 578 | ||
579 | might_sleep_if(!genpd->dev_irq_safe); | 579 | might_sleep_if(!genpd->dev_irq_safe); |
580 | 580 | ||
581 | if (dev_gpd_data(dev)->syscore) | ||
582 | return -EBUSY; | ||
583 | |||
584 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; | 581 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; |
585 | if (stop_ok && !stop_ok(dev)) | 582 | if (stop_ok && !stop_ok(dev)) |
586 | return -EBUSY; | 583 | return -EBUSY; |
@@ -983,7 +980,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
983 | if (IS_ERR(genpd)) | 980 | if (IS_ERR(genpd)) |
984 | return -EINVAL; | 981 | return -EINVAL; |
985 | 982 | ||
986 | if (genpd->suspend_power_off || dev_gpd_data(dev)->syscore | 983 | if (genpd->suspend_power_off |
987 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 984 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
988 | return 0; | 985 | return 0; |
989 | 986 | ||
@@ -1016,7 +1013,7 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
1016 | if (IS_ERR(genpd)) | 1013 | if (IS_ERR(genpd)) |
1017 | return -EINVAL; | 1014 | return -EINVAL; |
1018 | 1015 | ||
1019 | if (genpd->suspend_power_off || dev_gpd_data(dev)->syscore | 1016 | if (genpd->suspend_power_off |
1020 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 1017 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
1021 | return 0; | 1018 | return 0; |
1022 | 1019 | ||
@@ -1136,8 +1133,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
1136 | if (IS_ERR(genpd)) | 1133 | if (IS_ERR(genpd)) |
1137 | return -EINVAL; | 1134 | return -EINVAL; |
1138 | 1135 | ||
1139 | return genpd->suspend_power_off || dev_gpd_data(dev)->syscore ? | 1136 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); |
1140 | 0 : genpd_stop_dev(genpd, dev); | ||
1141 | } | 1137 | } |
1142 | 1138 | ||
1143 | /** | 1139 | /** |
@@ -1157,8 +1153,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
1157 | if (IS_ERR(genpd)) | 1153 | if (IS_ERR(genpd)) |
1158 | return -EINVAL; | 1154 | return -EINVAL; |
1159 | 1155 | ||
1160 | return genpd->suspend_power_off || dev_gpd_data(dev)->syscore ? | 1156 | return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); |
1161 | 0 : genpd_start_dev(genpd, dev); | ||
1162 | } | 1157 | } |
1163 | 1158 | ||
1164 | /** | 1159 | /** |
@@ -1253,7 +1248,7 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1253 | 1248 | ||
1254 | pm_genpd_sync_poweron(genpd); | 1249 | pm_genpd_sync_poweron(genpd); |
1255 | 1250 | ||
1256 | return dev_gpd_data(dev)->syscore ? 0 : genpd_start_dev(genpd, dev); | 1251 | return genpd_start_dev(genpd, dev); |
1257 | } | 1252 | } |
1258 | 1253 | ||
1259 | /** | 1254 | /** |
@@ -1526,26 +1521,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1526 | } | 1521 | } |
1527 | 1522 | ||
1528 | /** | 1523 | /** |
1529 | * pm_genpd_dev_syscore - Set/unset the "syscore" flag for a given device. | ||
1530 | * @dev: Device to set/unset the flag for. | ||
1531 | * @val: The new value of the device's "syscore" flag. | ||
1532 | */ | ||
1533 | void pm_genpd_dev_syscore(struct device *dev, bool val) | ||
1534 | { | ||
1535 | struct pm_subsys_data *psd; | ||
1536 | unsigned long flags; | ||
1537 | |||
1538 | spin_lock_irqsave(&dev->power.lock, flags); | ||
1539 | |||
1540 | psd = dev_to_psd(dev); | ||
1541 | if (psd && psd->domain_data) | ||
1542 | to_gpd_data(psd->domain_data)->syscore = val; | ||
1543 | |||
1544 | spin_unlock_irqrestore(&dev->power.lock, flags); | ||
1545 | } | ||
1546 | EXPORT_SYMBOL_GPL(pm_genpd_dev_syscore); | ||
1547 | |||
1548 | /** | ||
1549 | * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag. | 1524 | * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag. |
1550 | * @dev: Device to set/unset the flag for. | 1525 | * @dev: Device to set/unset the flag for. |
1551 | * @val: The new value of the device's "need restore" flag. | 1526 | * @val: The new value of the device's "need restore" flag. |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 7bd1fe400549..57f5814c2732 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -405,6 +405,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) | |||
405 | TRACE_DEVICE(dev); | 405 | TRACE_DEVICE(dev); |
406 | TRACE_RESUME(0); | 406 | TRACE_RESUME(0); |
407 | 407 | ||
408 | if (dev->power.syscore) | ||
409 | goto Out; | ||
410 | |||
408 | if (dev->pm_domain) { | 411 | if (dev->pm_domain) { |
409 | info = "noirq power domain "; | 412 | info = "noirq power domain "; |
410 | callback = pm_noirq_op(&dev->pm_domain->ops, state); | 413 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
@@ -426,6 +429,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) | |||
426 | 429 | ||
427 | error = dpm_run_callback(callback, dev, state, info); | 430 | error = dpm_run_callback(callback, dev, state, info); |
428 | 431 | ||
432 | Out: | ||
429 | TRACE_RESUME(error); | 433 | TRACE_RESUME(error); |
430 | return error; | 434 | return error; |
431 | } | 435 | } |
@@ -483,6 +487,9 @@ static int device_resume_early(struct device *dev, pm_message_t state) | |||
483 | TRACE_DEVICE(dev); | 487 | TRACE_DEVICE(dev); |
484 | TRACE_RESUME(0); | 488 | TRACE_RESUME(0); |
485 | 489 | ||
490 | if (dev->power.syscore) | ||
491 | goto Out; | ||
492 | |||
486 | if (dev->pm_domain) { | 493 | if (dev->pm_domain) { |
487 | info = "early power domain "; | 494 | info = "early power domain "; |
488 | callback = pm_late_early_op(&dev->pm_domain->ops, state); | 495 | callback = pm_late_early_op(&dev->pm_domain->ops, state); |
@@ -504,6 +511,7 @@ static int device_resume_early(struct device *dev, pm_message_t state) | |||
504 | 511 | ||
505 | error = dpm_run_callback(callback, dev, state, info); | 512 | error = dpm_run_callback(callback, dev, state, info); |
506 | 513 | ||
514 | Out: | ||
507 | TRACE_RESUME(error); | 515 | TRACE_RESUME(error); |
508 | return error; | 516 | return error; |
509 | } | 517 | } |
@@ -567,6 +575,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
567 | TRACE_DEVICE(dev); | 575 | TRACE_DEVICE(dev); |
568 | TRACE_RESUME(0); | 576 | TRACE_RESUME(0); |
569 | 577 | ||
578 | if (dev->power.syscore) | ||
579 | goto Complete; | ||
580 | |||
570 | dpm_wait(dev->parent, async); | 581 | dpm_wait(dev->parent, async); |
571 | device_lock(dev); | 582 | device_lock(dev); |
572 | 583 | ||
@@ -629,6 +640,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
629 | 640 | ||
630 | Unlock: | 641 | Unlock: |
631 | device_unlock(dev); | 642 | device_unlock(dev); |
643 | |||
644 | Complete: | ||
632 | complete_all(&dev->power.completion); | 645 | complete_all(&dev->power.completion); |
633 | 646 | ||
634 | TRACE_RESUME(error); | 647 | TRACE_RESUME(error); |
@@ -719,6 +732,9 @@ static void device_complete(struct device *dev, pm_message_t state) | |||
719 | void (*callback)(struct device *) = NULL; | 732 | void (*callback)(struct device *) = NULL; |
720 | char *info = NULL; | 733 | char *info = NULL; |
721 | 734 | ||
735 | if (dev->power.syscore) | ||
736 | return; | ||
737 | |||
722 | device_lock(dev); | 738 | device_lock(dev); |
723 | 739 | ||
724 | if (dev->pm_domain) { | 740 | if (dev->pm_domain) { |
@@ -831,6 +847,9 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) | |||
831 | pm_callback_t callback = NULL; | 847 | pm_callback_t callback = NULL; |
832 | char *info = NULL; | 848 | char *info = NULL; |
833 | 849 | ||
850 | if (dev->power.syscore) | ||
851 | return 0; | ||
852 | |||
834 | if (dev->pm_domain) { | 853 | if (dev->pm_domain) { |
835 | info = "noirq power domain "; | 854 | info = "noirq power domain "; |
836 | callback = pm_noirq_op(&dev->pm_domain->ops, state); | 855 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
@@ -914,6 +933,9 @@ static int device_suspend_late(struct device *dev, pm_message_t state) | |||
914 | pm_callback_t callback = NULL; | 933 | pm_callback_t callback = NULL; |
915 | char *info = NULL; | 934 | char *info = NULL; |
916 | 935 | ||
936 | if (dev->power.syscore) | ||
937 | return 0; | ||
938 | |||
917 | if (dev->pm_domain) { | 939 | if (dev->pm_domain) { |
918 | info = "late power domain "; | 940 | info = "late power domain "; |
919 | callback = pm_late_early_op(&dev->pm_domain->ops, state); | 941 | callback = pm_late_early_op(&dev->pm_domain->ops, state); |
@@ -1050,6 +1072,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1050 | goto Complete; | 1072 | goto Complete; |
1051 | } | 1073 | } |
1052 | 1074 | ||
1075 | if (dev->power.syscore) | ||
1076 | goto Complete; | ||
1077 | |||
1053 | device_lock(dev); | 1078 | device_lock(dev); |
1054 | 1079 | ||
1055 | if (dev->pm_domain) { | 1080 | if (dev->pm_domain) { |
@@ -1206,6 +1231,9 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
1206 | char *info = NULL; | 1231 | char *info = NULL; |
1207 | int error = 0; | 1232 | int error = 0; |
1208 | 1233 | ||
1234 | if (dev->power.syscore) | ||
1235 | return 0; | ||
1236 | |||
1209 | device_lock(dev); | 1237 | device_lock(dev); |
1210 | 1238 | ||
1211 | dev->power.wakeup_path = device_may_wakeup(dev); | 1239 | dev->power.wakeup_path = device_may_wakeup(dev); |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 7d9c1cb1c39a..bd1de3980919 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -134,7 +134,7 @@ static int rpm_check_suspend_allowed(struct device *dev) | |||
134 | 134 | ||
135 | if (dev->power.runtime_error) | 135 | if (dev->power.runtime_error) |
136 | retval = -EINVAL; | 136 | retval = -EINVAL; |
137 | else if (dev->power.disable_depth > 0) | 137 | else if (dev->power.disable_depth > 0 || dev->power.syscore) |
138 | retval = -EACCES; | 138 | retval = -EACCES; |
139 | else if (atomic_read(&dev->power.usage_count) > 0) | 139 | else if (atomic_read(&dev->power.usage_count) > 0) |
140 | retval = -EAGAIN; | 140 | retval = -EAGAIN; |