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 | |
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>
-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 | ||||
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 2 | ||||
-rw-r--r-- | drivers/clocksource/sh_mtu2.c | 2 | ||||
-rw-r--r-- | drivers/clocksource/sh_tmu.c | 2 | ||||
-rw-r--r-- | include/linux/pm.h | 5 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 3 |
9 files changed, 58 insertions, 38 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; |
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index c6fbb9f71911..a515605bf8f5 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
@@ -717,7 +717,7 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev) | |||
717 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 717 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
718 | 718 | ||
719 | if (cfg->clocksource_rating || cfg->clockevent_rating) | 719 | if (cfg->clocksource_rating || cfg->clockevent_rating) |
720 | pm_genpd_dev_syscore(&pdev->dev, true); | 720 | dev_pm_syscore_device(&pdev->dev, true); |
721 | } | 721 | } |
722 | 722 | ||
723 | if (p) { | 723 | if (p) { |
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 278c18abb2ae..1a95cad96819 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c | |||
@@ -323,7 +323,7 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev) | |||
323 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 323 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
324 | 324 | ||
325 | if (cfg->clockevent_rating) | 325 | if (cfg->clockevent_rating) |
326 | pm_genpd_dev_syscore(&pdev->dev, true); | 326 | dev_pm_syscore_device(&pdev->dev, true); |
327 | } | 327 | } |
328 | 328 | ||
329 | if (p) { | 329 | if (p) { |
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 5319689c579c..81b0239718ee 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c | |||
@@ -453,7 +453,7 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev) | |||
453 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 453 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
454 | 454 | ||
455 | if (cfg->clocksource_rating || cfg->clockevent_rating) | 455 | if (cfg->clocksource_rating || cfg->clockevent_rating) |
456 | pm_genpd_dev_syscore(&pdev->dev, true); | 456 | dev_pm_syscore_device(&pdev->dev, true); |
457 | } | 457 | } |
458 | 458 | ||
459 | if (p) { | 459 | if (p) { |
diff --git a/include/linux/pm.h b/include/linux/pm.h index 716517af1543..b79a0dd3bc6d 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
@@ -43,8 +43,12 @@ struct device; | |||
43 | 43 | ||
44 | #ifdef CONFIG_PM | 44 | #ifdef CONFIG_PM |
45 | extern const char power_group_name[]; /* = "power" */ | 45 | extern const char power_group_name[]; /* = "power" */ |
46 | |||
47 | extern void dev_pm_syscore_device(struct device *dev, bool val); | ||
46 | #else | 48 | #else |
47 | #define power_group_name NULL | 49 | #define power_group_name NULL |
50 | |||
51 | static inline void dev_pm_syscore_device(struct device *dev, bool val) {} | ||
48 | #endif | 52 | #endif |
49 | 53 | ||
50 | typedef struct pm_message { | 54 | typedef struct pm_message { |
@@ -511,6 +515,7 @@ struct dev_pm_info { | |||
511 | bool is_suspended:1; /* Ditto */ | 515 | bool is_suspended:1; /* Ditto */ |
512 | bool ignore_children:1; | 516 | bool ignore_children:1; |
513 | bool early_init:1; /* Owned by the PM core */ | 517 | bool early_init:1; /* Owned by the PM core */ |
518 | bool syscore:1; | ||
514 | spinlock_t lock; | 519 | spinlock_t lock; |
515 | #ifdef CONFIG_PM_SLEEP | 520 | #ifdef CONFIG_PM_SLEEP |
516 | struct list_head entry; | 521 | struct list_head entry; |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index dab0938603fa..08adf8e5a80e 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
@@ -114,7 +114,6 @@ struct generic_pm_domain_data { | |||
114 | struct mutex lock; | 114 | struct mutex lock; |
115 | unsigned int refcount; | 115 | unsigned int refcount; |
116 | bool need_restore; | 116 | bool need_restore; |
117 | bool syscore; | ||
118 | }; | 117 | }; |
119 | 118 | ||
120 | #ifdef CONFIG_PM_GENERIC_DOMAINS | 119 | #ifdef CONFIG_PM_GENERIC_DOMAINS |
@@ -153,7 +152,6 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node, | |||
153 | 152 | ||
154 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 153 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, |
155 | struct device *dev); | 154 | struct device *dev); |
156 | extern void pm_genpd_dev_syscore(struct device *dev, bool val); | ||
157 | extern void pm_genpd_dev_need_restore(struct device *dev, bool val); | 155 | extern void pm_genpd_dev_need_restore(struct device *dev, bool val); |
158 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 156 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
159 | struct generic_pm_domain *new_subdomain); | 157 | struct generic_pm_domain *new_subdomain); |
@@ -199,7 +197,6 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
199 | { | 197 | { |
200 | return -ENOSYS; | 198 | return -ENOSYS; |
201 | } | 199 | } |
202 | static inline void pm_genpd_dev_syscore(struct device *dev, bool val) {} | ||
203 | static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {} | 200 | static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {} |
204 | static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 201 | static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
205 | struct generic_pm_domain *new_sd) | 202 | struct generic_pm_domain *new_sd) |