aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-08-25 09:34:12 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-08-25 09:34:12 -0400
commit4605ab653c1f9d7cc2dda8033de215c9cee325f4 (patch)
tree8f55aa3137973ce2a3ef0ed49c44304e148d50fe
parentef27bed1870dbd5fd363ff5ec51eebd5a695e277 (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.c6
-rw-r--r--drivers/base/power/domain.c87
-rw-r--r--include/linux/pm.h9
-rw-r--r--include/linux/pm_domain.h6
-rw-r--r--include/linux/pm_runtime.h10
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
124void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, 122void 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 */
187static int __pm_genpd_save_device(struct dev_list_entry *dle, 187static 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 */
223static void __pm_genpd_restore_device(struct dev_list_entry *dle, 223static 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)
286static int pm_genpd_poweroff(struct generic_pm_domain *genpd) 286static 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 */
440static 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
527static inline void genpd_power_off_work_fn(struct work_struct *work) {} 509static inline void genpd_power_off_work_fn(struct work_struct *work) {}
528static 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 */
1084int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) 1064int 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)
1138int pm_genpd_remove_device(struct generic_pm_domain *genpd, 1112int 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
422struct wakeup_source; 422struct wakeup_source;
423 423
424struct pm_domain_data {
425 struct list_head list_node;
426 struct device *dev;
427 bool need_restore;
428};
429
424struct pm_subsys_data { 430struct 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
432struct dev_pm_info { 441struct 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
64struct 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
71extern int pm_genpd_add_device(struct generic_pm_domain *genpd, 65extern 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
261static 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
261extern void pm_clk_init(struct device *dev); 267extern void pm_clk_init(struct device *dev);
262extern int pm_clk_create(struct device *dev); 268extern int pm_clk_create(struct device *dev);
263extern void pm_clk_destroy(struct device *dev); 269extern void pm_clk_destroy(struct device *dev);
@@ -266,6 +272,10 @@ extern void pm_clk_remove(struct device *dev, const char *con_id);
266extern int pm_clk_suspend(struct device *dev); 272extern int pm_clk_suspend(struct device *dev);
267extern int pm_clk_resume(struct device *dev); 273extern int pm_clk_resume(struct device *dev);
268#else 274#else
275static inline bool pm_clk_no_clocks(struct device *dev)
276{
277 return true;
278}
269static inline void pm_clk_init(struct device *dev) 279static inline void pm_clk_init(struct device *dev)
270{ 280{
271} 281}