aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-08-08 17:43:14 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-08-25 09:33:43 -0400
commit3c07cbc488bfd1ad1abf64d09cc692339b5f8a83 (patch)
treed53a2a9a3635092f289b66dabcbac0fbcefe8d50 /drivers/base/power
parentc4bb3160c8823d3a1e581d7e05fb8b343097e7c8 (diff)
PM / Domains: Do not take parent locks to modify subdomain counters
After the subdomain counter in struct generic_pm_domain has been changed into an atomic_t field, it is possible to modify pm_genpd_poweron() and pm_genpd_poweroff() so that they don't take the parents locks. This requires pm_genpd_poweron() to increment the parent's subdomain counter before calling itself recursively for the parent and to decrement it if an error is to be returned. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/domain.c70
1 files changed, 31 insertions, 39 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 20e2b52d9c9..ef25b6f99f9 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -93,12 +93,7 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
93 int ret = 0; 93 int ret = 0;
94 94
95 start: 95 start:
96 if (parent) { 96 mutex_lock(&genpd->lock);
97 genpd_acquire_lock(parent);
98 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
99 } else {
100 mutex_lock(&genpd->lock);
101 }
102 97
103 if (genpd->status == GPD_STATE_ACTIVE 98 if (genpd->status == GPD_STATE_ACTIVE
104 || (genpd->prepared_count > 0 && genpd->suspend_power_off)) 99 || (genpd->prepared_count > 0 && genpd->suspend_power_off))
@@ -109,31 +104,33 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
109 goto out; 104 goto out;
110 } 105 }
111 106
112 if (parent && parent->status != GPD_STATE_ACTIVE) { 107 if (parent) {
108 genpd_sd_counter_inc(parent);
109
113 mutex_unlock(&genpd->lock); 110 mutex_unlock(&genpd->lock);
114 genpd_release_lock(parent);
115 111
116 ret = pm_genpd_poweron(parent); 112 ret = pm_genpd_poweron(parent);
117 if (ret) 113 if (ret) {
114 genpd_sd_counter_dec(parent);
118 return ret; 115 return ret;
116 }
119 117
118 parent = NULL;
120 goto start; 119 goto start;
121 } 120 }
122 121
123 if (genpd->power_on) { 122 if (genpd->power_on)
124 ret = genpd->power_on(genpd); 123 ret = genpd->power_on(genpd);
125 if (ret)
126 goto out;
127 }
128 124
129 genpd_set_active(genpd); 125 if (ret) {
130 if (parent) 126 if (genpd->parent)
131 genpd_sd_counter_inc(parent); 127 genpd_sd_counter_dec(genpd->parent);
128 } else {
129 genpd_set_active(genpd);
130 }
132 131
133 out: 132 out:
134 mutex_unlock(&genpd->lock); 133 mutex_unlock(&genpd->lock);
135 if (parent)
136 genpd_release_lock(parent);
137 134
138 return ret; 135 return ret;
139} 136}
@@ -293,7 +290,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
293 genpd->poweroff_task = current; 290 genpd->poweroff_task = current;
294 291
295 list_for_each_entry_reverse(dle, &genpd->dev_list, node) { 292 list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
296 ret = __pm_genpd_save_device(dle, genpd); 293 ret = atomic_read(&genpd->sd_count) == 0 ?
294 __pm_genpd_save_device(dle, genpd) : -EBUSY;
297 if (ret) { 295 if (ret) {
298 genpd_set_active(genpd); 296 genpd_set_active(genpd);
299 goto out; 297 goto out;
@@ -308,38 +306,32 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
308 } 306 }
309 } 307 }
310 308
311 parent = genpd->parent; 309 if (genpd->power_off) {
312 if (parent) { 310 if (atomic_read(&genpd->sd_count) > 0) {
313 mutex_unlock(&genpd->lock); 311 ret = -EBUSY;
314
315 genpd_acquire_lock(parent);
316 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
317
318 if (genpd_abort_poweroff(genpd)) {
319 genpd_release_lock(parent);
320 goto out; 312 goto out;
321 } 313 }
322 }
323 314
324 if (genpd->power_off) { 315 /*
316 * If sd_count > 0 at this point, one of the children hasn't
317 * managed to call pm_genpd_poweron() for the parent yet after
318 * incrementing it. In that case pm_genpd_poweron() will wait
319 * for us to drop the lock, so we can call .power_off() and let
320 * the pm_genpd_poweron() restore power for us (this shouldn't
321 * happen very often).
322 */
325 ret = genpd->power_off(genpd); 323 ret = genpd->power_off(genpd);
326 if (ret == -EBUSY) { 324 if (ret == -EBUSY) {
327 genpd_set_active(genpd); 325 genpd_set_active(genpd);
328 if (parent)
329 genpd_release_lock(parent);
330
331 goto out; 326 goto out;
332 } 327 }
333 } 328 }
334 329
335 genpd->status = GPD_STATE_POWER_OFF; 330 genpd->status = GPD_STATE_POWER_OFF;
336 331
337 if (parent) { 332 parent = genpd->parent;
338 if (genpd_sd_counter_dec(parent)) 333 if (parent && genpd_sd_counter_dec(parent))
339 genpd_queue_power_off_work(parent); 334 genpd_queue_power_off_work(parent);
340
341 genpd_release_lock(parent);
342 }
343 335
344 out: 336 out:
345 genpd->poweroff_task = NULL; 337 genpd->poweroff_task = NULL;