diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-08-25 09:34:12 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-08-25 09:34:12 -0400 |
commit | 4605ab653c1f9d7cc2dda8033de215c9cee325f4 (patch) | |
tree | 8f55aa3137973ce2a3ef0ed49c44304e148d50fe | |
parent | ef27bed1870dbd5fd363ff5ec51eebd5a695e277 (diff) |
PM / Domains: Use power.sybsys_data to reduce overhead
Currently pm_genpd_runtime_resume() has to walk the list of devices
from the device's PM domain to find the corresponding device list
object containing the need_restore field to check if the driver's
.runtime_resume() callback should be executed for the device.
This is suboptimal and can be simplified by using power.sybsys_data
to store device information used by the generic PM domains code.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r-- | arch/arm/mach-shmobile/pm-sh7372.c | 6 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 87 | ||||
-rw-r--r-- | include/linux/pm.h | 9 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 6 | ||||
-rw-r--r-- | include/linux/pm_runtime.h | 10 |
5 files changed, 51 insertions, 67 deletions
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index 54d4d86883c9..4aeca0adae56 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c | |||
@@ -114,11 +114,9 @@ void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, | |||
114 | { | 114 | { |
115 | struct device *dev = &pdev->dev; | 115 | struct device *dev = &pdev->dev; |
116 | 116 | ||
117 | if (!dev->power.subsys_data) { | ||
118 | pm_clk_create(dev); | ||
119 | pm_clk_add(dev, NULL); | ||
120 | } | ||
121 | pm_genpd_add_device(&sh7372_pd->genpd, dev); | 117 | pm_genpd_add_device(&sh7372_pd->genpd, dev); |
118 | if (pm_clk_no_clocks(dev)) | ||
119 | pm_clk_add(dev, NULL); | ||
122 | } | 120 | } |
123 | 121 | ||
124 | void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, | 122 | void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, |
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 1fc6cc9835ad..339eb2d9bdda 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -181,18 +181,18 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
181 | 181 | ||
182 | /** | 182 | /** |
183 | * __pm_genpd_save_device - Save the pre-suspend state of a device. | 183 | * __pm_genpd_save_device - Save the pre-suspend state of a device. |
184 | * @dle: Device list entry of the device to save the state of. | 184 | * @pdd: Domain data of the device to save the state of. |
185 | * @genpd: PM domain the device belongs to. | 185 | * @genpd: PM domain the device belongs to. |
186 | */ | 186 | */ |
187 | static int __pm_genpd_save_device(struct dev_list_entry *dle, | 187 | static int __pm_genpd_save_device(struct pm_domain_data *pdd, |
188 | struct generic_pm_domain *genpd) | 188 | struct generic_pm_domain *genpd) |
189 | __releases(&genpd->lock) __acquires(&genpd->lock) | 189 | __releases(&genpd->lock) __acquires(&genpd->lock) |
190 | { | 190 | { |
191 | struct device *dev = dle->dev; | 191 | struct device *dev = pdd->dev; |
192 | struct device_driver *drv = dev->driver; | 192 | struct device_driver *drv = dev->driver; |
193 | int ret = 0; | 193 | int ret = 0; |
194 | 194 | ||
195 | if (dle->need_restore) | 195 | if (pdd->need_restore) |
196 | return 0; | 196 | return 0; |
197 | 197 | ||
198 | mutex_unlock(&genpd->lock); | 198 | mutex_unlock(&genpd->lock); |
@@ -210,24 +210,24 @@ static int __pm_genpd_save_device(struct dev_list_entry *dle, | |||
210 | mutex_lock(&genpd->lock); | 210 | mutex_lock(&genpd->lock); |
211 | 211 | ||
212 | if (!ret) | 212 | if (!ret) |
213 | dle->need_restore = true; | 213 | pdd->need_restore = true; |
214 | 214 | ||
215 | return ret; | 215 | return ret; |
216 | } | 216 | } |
217 | 217 | ||
218 | /** | 218 | /** |
219 | * __pm_genpd_restore_device - Restore the pre-suspend state of a device. | 219 | * __pm_genpd_restore_device - Restore the pre-suspend state of a device. |
220 | * @dle: Device list entry of the device to restore the state of. | 220 | * @pdd: Domain data of the device to restore the state of. |
221 | * @genpd: PM domain the device belongs to. | 221 | * @genpd: PM domain the device belongs to. |
222 | */ | 222 | */ |
223 | static void __pm_genpd_restore_device(struct dev_list_entry *dle, | 223 | static void __pm_genpd_restore_device(struct pm_domain_data *pdd, |
224 | struct generic_pm_domain *genpd) | 224 | struct generic_pm_domain *genpd) |
225 | __releases(&genpd->lock) __acquires(&genpd->lock) | 225 | __releases(&genpd->lock) __acquires(&genpd->lock) |
226 | { | 226 | { |
227 | struct device *dev = dle->dev; | 227 | struct device *dev = pdd->dev; |
228 | struct device_driver *drv = dev->driver; | 228 | struct device_driver *drv = dev->driver; |
229 | 229 | ||
230 | if (!dle->need_restore) | 230 | if (!pdd->need_restore) |
231 | return; | 231 | return; |
232 | 232 | ||
233 | mutex_unlock(&genpd->lock); | 233 | mutex_unlock(&genpd->lock); |
@@ -244,7 +244,7 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle, | |||
244 | 244 | ||
245 | mutex_lock(&genpd->lock); | 245 | mutex_lock(&genpd->lock); |
246 | 246 | ||
247 | dle->need_restore = false; | 247 | pdd->need_restore = false; |
248 | } | 248 | } |
249 | 249 | ||
250 | /** | 250 | /** |
@@ -286,7 +286,7 @@ void genpd_queue_power_off_work(struct generic_pm_domain *genpd) | |||
286 | static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | 286 | static int pm_genpd_poweroff(struct generic_pm_domain *genpd) |
287 | __releases(&genpd->lock) __acquires(&genpd->lock) | 287 | __releases(&genpd->lock) __acquires(&genpd->lock) |
288 | { | 288 | { |
289 | struct dev_list_entry *dle; | 289 | struct pm_domain_data *pdd; |
290 | struct gpd_link *link; | 290 | struct gpd_link *link; |
291 | unsigned int not_suspended; | 291 | unsigned int not_suspended; |
292 | int ret = 0; | 292 | int ret = 0; |
@@ -308,8 +308,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
308 | return -EBUSY; | 308 | return -EBUSY; |
309 | 309 | ||
310 | not_suspended = 0; | 310 | not_suspended = 0; |
311 | list_for_each_entry(dle, &genpd->dev_list, node) | 311 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
312 | if (dle->dev->driver && !pm_runtime_suspended(dle->dev)) | 312 | if (pdd->dev->driver && !pm_runtime_suspended(pdd->dev)) |
313 | not_suspended++; | 313 | not_suspended++; |
314 | 314 | ||
315 | if (not_suspended > genpd->in_progress) | 315 | if (not_suspended > genpd->in_progress) |
@@ -332,9 +332,9 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
332 | genpd->status = GPD_STATE_BUSY; | 332 | genpd->status = GPD_STATE_BUSY; |
333 | genpd->poweroff_task = current; | 333 | genpd->poweroff_task = current; |
334 | 334 | ||
335 | list_for_each_entry_reverse(dle, &genpd->dev_list, node) { | 335 | list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) { |
336 | ret = atomic_read(&genpd->sd_count) == 0 ? | 336 | ret = atomic_read(&genpd->sd_count) == 0 ? |
337 | __pm_genpd_save_device(dle, genpd) : -EBUSY; | 337 | __pm_genpd_save_device(pdd, genpd) : -EBUSY; |
338 | 338 | ||
339 | if (genpd_abort_poweroff(genpd)) | 339 | if (genpd_abort_poweroff(genpd)) |
340 | goto out; | 340 | goto out; |
@@ -433,24 +433,6 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
433 | } | 433 | } |
434 | 434 | ||
435 | /** | 435 | /** |
436 | * __pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. | ||
437 | * @dev: Device to resume. | ||
438 | * @genpd: PM domain the device belongs to. | ||
439 | */ | ||
440 | static void __pm_genpd_runtime_resume(struct device *dev, | ||
441 | struct generic_pm_domain *genpd) | ||
442 | { | ||
443 | struct dev_list_entry *dle; | ||
444 | |||
445 | list_for_each_entry(dle, &genpd->dev_list, node) { | ||
446 | if (dle->dev == dev) { | ||
447 | __pm_genpd_restore_device(dle, genpd); | ||
448 | break; | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | |||
453 | /** | ||
454 | * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. | 436 | * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. |
455 | * @dev: Device to resume. | 437 | * @dev: Device to resume. |
456 | * | 438 | * |
@@ -495,7 +477,7 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
495 | mutex_lock(&genpd->lock); | 477 | mutex_lock(&genpd->lock); |
496 | } | 478 | } |
497 | finish_wait(&genpd->status_wait_queue, &wait); | 479 | finish_wait(&genpd->status_wait_queue, &wait); |
498 | __pm_genpd_runtime_resume(dev, genpd); | 480 | __pm_genpd_restore_device(&dev->power.subsys_data->domain_data, genpd); |
499 | genpd->resume_count--; | 481 | genpd->resume_count--; |
500 | genpd_set_active(genpd); | 482 | genpd_set_active(genpd); |
501 | wake_up_all(&genpd->status_wait_queue); | 483 | wake_up_all(&genpd->status_wait_queue); |
@@ -525,8 +507,6 @@ void pm_genpd_poweroff_unused(void) | |||
525 | #else | 507 | #else |
526 | 508 | ||
527 | static inline void genpd_power_off_work_fn(struct work_struct *work) {} | 509 | static inline void genpd_power_off_work_fn(struct work_struct *work) {} |
528 | static inline void __pm_genpd_runtime_resume(struct device *dev, | ||
529 | struct generic_pm_domain *genpd) {} | ||
530 | 510 | ||
531 | #define pm_genpd_runtime_suspend NULL | 511 | #define pm_genpd_runtime_suspend NULL |
532 | #define pm_genpd_runtime_resume NULL | 512 | #define pm_genpd_runtime_resume NULL |
@@ -1083,7 +1063,7 @@ static void pm_genpd_complete(struct device *dev) | |||
1083 | */ | 1063 | */ |
1084 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | 1064 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) |
1085 | { | 1065 | { |
1086 | struct dev_list_entry *dle; | 1066 | struct pm_domain_data *pdd; |
1087 | int ret = 0; | 1067 | int ret = 0; |
1088 | 1068 | ||
1089 | dev_dbg(dev, "%s()\n", __func__); | 1069 | dev_dbg(dev, "%s()\n", __func__); |
@@ -1103,26 +1083,20 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | |||
1103 | goto out; | 1083 | goto out; |
1104 | } | 1084 | } |
1105 | 1085 | ||
1106 | list_for_each_entry(dle, &genpd->dev_list, node) | 1086 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
1107 | if (dle->dev == dev) { | 1087 | if (pdd->dev == dev) { |
1108 | ret = -EINVAL; | 1088 | ret = -EINVAL; |
1109 | goto out; | 1089 | goto out; |
1110 | } | 1090 | } |
1111 | 1091 | ||
1112 | dle = kzalloc(sizeof(*dle), GFP_KERNEL); | ||
1113 | if (!dle) { | ||
1114 | ret = -ENOMEM; | ||
1115 | goto out; | ||
1116 | } | ||
1117 | |||
1118 | dle->dev = dev; | ||
1119 | dle->need_restore = false; | ||
1120 | list_add_tail(&dle->node, &genpd->dev_list); | ||
1121 | genpd->device_count++; | 1092 | genpd->device_count++; |
1122 | 1093 | ||
1123 | spin_lock_irq(&dev->power.lock); | ||
1124 | dev->pm_domain = &genpd->domain; | 1094 | dev->pm_domain = &genpd->domain; |
1125 | spin_unlock_irq(&dev->power.lock); | 1095 | dev_pm_get_subsys_data(dev); |
1096 | pdd = &dev->power.subsys_data->domain_data; | ||
1097 | pdd->dev = dev; | ||
1098 | pdd->need_restore = false; | ||
1099 | list_add_tail(&pdd->list_node, &genpd->dev_list); | ||
1126 | 1100 | ||
1127 | out: | 1101 | out: |
1128 | genpd_release_lock(genpd); | 1102 | genpd_release_lock(genpd); |
@@ -1138,7 +1112,7 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | |||
1138 | int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 1112 | int pm_genpd_remove_device(struct generic_pm_domain *genpd, |
1139 | struct device *dev) | 1113 | struct device *dev) |
1140 | { | 1114 | { |
1141 | struct dev_list_entry *dle; | 1115 | struct pm_domain_data *pdd; |
1142 | int ret = -EINVAL; | 1116 | int ret = -EINVAL; |
1143 | 1117 | ||
1144 | dev_dbg(dev, "%s()\n", __func__); | 1118 | dev_dbg(dev, "%s()\n", __func__); |
@@ -1153,17 +1127,16 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1153 | goto out; | 1127 | goto out; |
1154 | } | 1128 | } |
1155 | 1129 | ||
1156 | list_for_each_entry(dle, &genpd->dev_list, node) { | 1130 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { |
1157 | if (dle->dev != dev) | 1131 | if (pdd->dev != dev) |
1158 | continue; | 1132 | continue; |
1159 | 1133 | ||
1160 | spin_lock_irq(&dev->power.lock); | 1134 | list_del_init(&pdd->list_node); |
1135 | pdd->dev = NULL; | ||
1136 | dev_pm_put_subsys_data(dev); | ||
1161 | dev->pm_domain = NULL; | 1137 | dev->pm_domain = NULL; |
1162 | spin_unlock_irq(&dev->power.lock); | ||
1163 | 1138 | ||
1164 | genpd->device_count--; | 1139 | genpd->device_count--; |
1165 | list_del(&dle->node); | ||
1166 | kfree(dle); | ||
1167 | 1140 | ||
1168 | ret = 0; | 1141 | ret = 0; |
1169 | break; | 1142 | break; |
diff --git a/include/linux/pm.h b/include/linux/pm.h index c6b5a0a41ab3..ed10f24d5259 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
@@ -421,12 +421,21 @@ enum rpm_request { | |||
421 | 421 | ||
422 | struct wakeup_source; | 422 | struct wakeup_source; |
423 | 423 | ||
424 | struct pm_domain_data { | ||
425 | struct list_head list_node; | ||
426 | struct device *dev; | ||
427 | bool need_restore; | ||
428 | }; | ||
429 | |||
424 | struct pm_subsys_data { | 430 | struct pm_subsys_data { |
425 | spinlock_t lock; | 431 | spinlock_t lock; |
426 | unsigned int refcount; | 432 | unsigned int refcount; |
427 | #ifdef CONFIG_PM_CLK | 433 | #ifdef CONFIG_PM_CLK |
428 | struct list_head clock_list; | 434 | struct list_head clock_list; |
429 | #endif | 435 | #endif |
436 | #ifdef CONFIG_PM_GENERIC_DOMAINS | ||
437 | struct pm_domain_data domain_data; | ||
438 | #endif | ||
430 | }; | 439 | }; |
431 | 440 | ||
432 | struct dev_pm_info { | 441 | struct dev_pm_info { |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index bf679f59f9a8..5cce46c2d926 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
@@ -61,12 +61,6 @@ struct gpd_link { | |||
61 | struct list_head slave_node; | 61 | struct list_head slave_node; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | struct dev_list_entry { | ||
65 | struct list_head node; | ||
66 | struct device *dev; | ||
67 | bool need_restore; | ||
68 | }; | ||
69 | |||
70 | #ifdef CONFIG_PM_GENERIC_DOMAINS | 64 | #ifdef CONFIG_PM_GENERIC_DOMAINS |
71 | extern int pm_genpd_add_device(struct generic_pm_domain *genpd, | 65 | extern int pm_genpd_add_device(struct generic_pm_domain *genpd, |
72 | struct device *dev); | 66 | struct device *dev); |
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 6b90630e3c98..a5a41a850efb 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h | |||
@@ -258,6 +258,12 @@ struct pm_clk_notifier_block { | |||
258 | }; | 258 | }; |
259 | 259 | ||
260 | #ifdef CONFIG_PM_CLK | 260 | #ifdef CONFIG_PM_CLK |
261 | static inline bool pm_clk_no_clocks(struct device *dev) | ||
262 | { | ||
263 | return dev && dev->power.subsys_data | ||
264 | && list_empty(&dev->power.subsys_data->clock_list); | ||
265 | } | ||
266 | |||
261 | extern void pm_clk_init(struct device *dev); | 267 | extern void pm_clk_init(struct device *dev); |
262 | extern int pm_clk_create(struct device *dev); | 268 | extern int pm_clk_create(struct device *dev); |
263 | extern void pm_clk_destroy(struct device *dev); | 269 | extern void pm_clk_destroy(struct device *dev); |
@@ -266,6 +272,10 @@ extern void pm_clk_remove(struct device *dev, const char *con_id); | |||
266 | extern int pm_clk_suspend(struct device *dev); | 272 | extern int pm_clk_suspend(struct device *dev); |
267 | extern int pm_clk_resume(struct device *dev); | 273 | extern int pm_clk_resume(struct device *dev); |
268 | #else | 274 | #else |
275 | static inline bool pm_clk_no_clocks(struct device *dev) | ||
276 | { | ||
277 | return true; | ||
278 | } | ||
269 | static inline void pm_clk_init(struct device *dev) | 279 | static inline void pm_clk_init(struct device *dev) |
270 | { | 280 | { |
271 | } | 281 | } |