aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-08-08 17:43:04 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-08-25 09:33:43 -0400
commitc4bb3160c8823d3a1e581d7e05fb8b343097e7c8 (patch)
tree550ba22e33176d4e5116a50cb8789ababe6dd09d /drivers/base
parentff35336d3efd1ec4015b56f690191ed69730cbb0 (diff)
PM / Domains: Implement subdomain counters as atomic fields
Currently, pm_genpd_poweron() and pm_genpd_poweroff() need to take the parent PM domain's lock in order to modify the parent's counter of active subdomains in a nonracy way. This causes the locking to be considerably complex and in fact is not necessary, because the subdomain counters may be implemented as atomic fields and they won't have to be modified under a lock. Replace the unsigned in sd_count field in struct generic_pm_domain by an atomic_t one and modify the code in drivers/base/power/domain.c to take this change into account. This patch doesn't change the locking yet, that is going to be done in a separate subsequent patch. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/domain.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 1c374579407c..20e2b52d9c9c 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -29,10 +29,20 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
29 return pd_to_genpd(dev->pm_domain); 29 return pd_to_genpd(dev->pm_domain);
30} 30}
31 31
32static void genpd_sd_counter_dec(struct generic_pm_domain *genpd) 32static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
33{ 33{
34 if (!WARN_ON(genpd->sd_count == 0)) 34 bool ret = false;
35 genpd->sd_count--; 35
36 if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))
37 ret = !!atomic_dec_and_test(&genpd->sd_count);
38
39 return ret;
40}
41
42static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
43{
44 atomic_inc(&genpd->sd_count);
45 smp_mb__after_atomic_inc();
36} 46}
37 47
38static void genpd_acquire_lock(struct generic_pm_domain *genpd) 48static void genpd_acquire_lock(struct generic_pm_domain *genpd)
@@ -118,7 +128,7 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
118 128
119 genpd_set_active(genpd); 129 genpd_set_active(genpd);
120 if (parent) 130 if (parent)
121 parent->sd_count++; 131 genpd_sd_counter_inc(parent);
122 132
123 out: 133 out:
124 mutex_unlock(&genpd->lock); 134 mutex_unlock(&genpd->lock);
@@ -254,7 +264,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
254 || genpd->resume_count > 0) 264 || genpd->resume_count > 0)
255 return 0; 265 return 0;
256 266
257 if (genpd->sd_count > 0) 267 if (atomic_read(&genpd->sd_count) > 0)
258 return -EBUSY; 268 return -EBUSY;
259 269
260 not_suspended = 0; 270 not_suspended = 0;
@@ -325,8 +335,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
325 genpd->status = GPD_STATE_POWER_OFF; 335 genpd->status = GPD_STATE_POWER_OFF;
326 336
327 if (parent) { 337 if (parent) {
328 genpd_sd_counter_dec(parent); 338 if (genpd_sd_counter_dec(parent))
329 if (parent->sd_count == 0)
330 genpd_queue_power_off_work(parent); 339 genpd_queue_power_off_work(parent);
331 340
332 genpd_release_lock(parent); 341 genpd_release_lock(parent);
@@ -506,7 +515,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
506 if (genpd->status == GPD_STATE_POWER_OFF) 515 if (genpd->status == GPD_STATE_POWER_OFF)
507 return; 516 return;
508 517
509 if (genpd->suspended_count != genpd->device_count || genpd->sd_count > 0) 518 if (genpd->suspended_count != genpd->device_count
519 || atomic_read(&genpd->sd_count) > 0)
510 return; 520 return;
511 521
512 if (genpd->power_off) 522 if (genpd->power_off)
@@ -1167,7 +1177,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
1167 list_add_tail(&new_subdomain->sd_node, &genpd->sd_list); 1177 list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
1168 new_subdomain->parent = genpd; 1178 new_subdomain->parent = genpd;
1169 if (subdomain->status != GPD_STATE_POWER_OFF) 1179 if (subdomain->status != GPD_STATE_POWER_OFF)
1170 genpd->sd_count++; 1180 genpd_sd_counter_inc(genpd);
1171 1181
1172 out: 1182 out:
1173 mutex_unlock(&new_subdomain->lock); 1183 mutex_unlock(&new_subdomain->lock);
@@ -1242,7 +1252,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
1242 genpd->gov = gov; 1252 genpd->gov = gov;
1243 INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); 1253 INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
1244 genpd->in_progress = 0; 1254 genpd->in_progress = 0;
1245 genpd->sd_count = 0; 1255 atomic_set(&genpd->sd_count, 0);
1246 genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE; 1256 genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
1247 init_waitqueue_head(&genpd->status_wait_queue); 1257 init_waitqueue_head(&genpd->status_wait_queue);
1248 genpd->poweroff_task = NULL; 1258 genpd->poweroff_task = NULL;