All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] PM / Domains: Allow generic PM domains to have multiple parents
@ 2011-07-31 17:46 ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:46 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

Hi,

This patchset modifies the generic PM domains code so that it's possible
for a PM domain to have multiple parent domains (i.e. domains it depends on).
This makes the framework applicable to more use cases and allows us to
address one issue one a system already using it.

Patch [1/9] is for 3.1, patches [2-9/9] are 3.2 material, if there are no
objections.

[1/9] - Fix genpd_power_on().
[2/9] - Make subdomain counts be atomic.
[3/9] - Don't acquire parent locks in genpd_power_on() and genpd_power_off().
[4/9] - Make genpd_power_on() always survive parent removal.
[5/9] - Add PM domain status value GPD_STATE_WAIT_PARENT.
[6/9] - Allow generic PM domains to have multiple parents.
[7/9] - Rename GPD_STATE_WAIT_PARENT to GPD_STATE_WAIT_MASTER.
[8/9] - Rename the second argument of pm_genpd_add_subdomain().
[9/9] - Make A3RV be a subdomain of A4LC on SH7372.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 0/9] PM / Domains: Allow generic PM domains to have multiple parents
@ 2011-07-31 17:46 ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:46 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

Hi,

This patchset modifies the generic PM domains code so that it's possible
for a PM domain to have multiple parent domains (i.e. domains it depends on).
This makes the framework applicable to more use cases and allows us to
address one issue one a system already using it.

Patch [1/9] is for 3.1, patches [2-9/9] are 3.2 material, if there are no
objections.

[1/9] - Fix genpd_power_on().
[2/9] - Make subdomain counts be atomic.
[3/9] - Don't acquire parent locks in genpd_power_on() and genpd_power_off().
[4/9] - Make genpd_power_on() always survive parent removal.
[5/9] - Add PM domain status value GPD_STATE_WAIT_PARENT.
[6/9] - Allow generic PM domains to have multiple parents.
[7/9] - Rename GPD_STATE_WAIT_PARENT to GPD_STATE_WAIT_MASTER.
[8/9] - Rename the second argument of pm_genpd_add_subdomain().
[9/9] - Make A3RV be a subdomain of A4LC on SH7372.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/9] PM / Domains: Fix pm_genpd_poweron()
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:47   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:47 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

The local variable ret is defined twice in pm_genpd_poweron(), which
causes this function to always return 0, even if the PM domain's
.power_on() callback fails, in which case an error code should be
returned.

Remove the wrong second definition of ret and additionally remove an
unnecessary definition of wait from pm_genpd_poweron().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -80,7 +80,6 @@ static void genpd_set_active(struct gene
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
 	struct generic_pm_domain *parent = genpd->parent;
-	DEFINE_WAIT(wait);
 	int ret = 0;
 
  start:
@@ -112,7 +111,7 @@ int pm_genpd_poweron(struct generic_pm_d
 	}
 
 	if (genpd->power_on) {
-		int ret = genpd->power_on(genpd);
+		ret = genpd->power_on(genpd);
 		if (ret)
 			goto out;
 	}


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/9] PM / Domains: Fix pm_genpd_poweron()
@ 2011-07-31 17:47   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:47 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

The local variable ret is defined twice in pm_genpd_poweron(), which
causes this function to always return 0, even if the PM domain's
.power_on() callback fails, in which case an error code should be
returned.

Remove the wrong second definition of ret and additionally remove an
unnecessary definition of wait from pm_genpd_poweron().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -80,7 +80,6 @@ static void genpd_set_active(struct gene
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
 	struct generic_pm_domain *parent = genpd->parent;
-	DEFINE_WAIT(wait);
 	int ret = 0;
 
  start:
@@ -112,7 +111,7 @@ int pm_genpd_poweron(struct generic_pm_d
 	}
 
 	if (genpd->power_on) {
-		int ret = genpd->power_on(genpd);
+		ret = genpd->power_on(genpd);
 		if (ret)
 			goto out;
 	}


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/9] PM / Domains: Fix pm_genpd_poweron()
  2011-07-31 17:46 ` Rafael J. Wysocki
  (?)
@ 2011-07-31 17:47 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:47 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

The local variable ret is defined twice in pm_genpd_poweron(), which
causes this function to always return 0, even if the PM domain's
.power_on() callback fails, in which case an error code should be
returned.

Remove the wrong second definition of ret and additionally remove an
unnecessary definition of wait from pm_genpd_poweron().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -80,7 +80,6 @@ static void genpd_set_active(struct gene
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
 	struct generic_pm_domain *parent = genpd->parent;
-	DEFINE_WAIT(wait);
 	int ret = 0;
 
  start:
@@ -112,7 +111,7 @@ int pm_genpd_poweron(struct generic_pm_d
 	}
 
 	if (genpd->power_on) {
-		int ret = genpd->power_on(genpd);
+		ret = genpd->power_on(genpd);
 		if (ret)
 			goto out;
 	}

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 2/9] PM / Domains: Implement subdomain counters as atomic fields
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:47   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:47 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

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>
---
 drivers/base/power/domain.c |   30 ++++++++++++++++++++----------
 include/linux/pm_domain.h   |    2 +-
 2 files changed, 21 insertions(+), 11 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -29,10 +29,20 @@ static struct generic_pm_domain *dev_to_
 	return pd_to_genpd(dev->pm_domain);
 }
 
-static void genpd_sd_counter_dec(struct generic_pm_domain *genpd)
+static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
 {
-	if (!WARN_ON(genpd->sd_count = 0))
-			genpd->sd_count--;
+	bool ret = false;
+
+	if (!WARN_ON(atomic_read(&genpd->sd_count) = 0))
+		ret = !!atomic_dec_and_test(&genpd->sd_count);
+
+	return ret;
+}
+
+static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
+{
+	atomic_inc(&genpd->sd_count);
+	smp_mb__after_atomic_inc();
 }
 
 static void genpd_acquire_lock(struct generic_pm_domain *genpd)
@@ -118,7 +128,7 @@ int pm_genpd_poweron(struct generic_pm_d
 
 	genpd_set_active(genpd);
 	if (parent)
-		parent->sd_count++;
+		genpd_sd_counter_inc(parent);
 
  out:
 	mutex_unlock(&genpd->lock);
@@ -254,7 +264,7 @@ static int pm_genpd_poweroff(struct gene
 	    || genpd->resume_count > 0)
 		return 0;
 
-	if (genpd->sd_count > 0)
+	if (atomic_read(&genpd->sd_count) > 0)
 		return -EBUSY;
 
 	not_suspended = 0;
@@ -325,8 +335,7 @@ static int pm_genpd_poweroff(struct gene
 	genpd->status = GPD_STATE_POWER_OFF;
 
 	if (parent) {
-		genpd_sd_counter_dec(parent);
-		if (parent->sd_count = 0)
+		if (genpd_sd_counter_dec(parent))
 			genpd_queue_power_off_work(parent);
 
 		genpd_release_lock(parent);
@@ -491,7 +500,8 @@ static void pm_genpd_sync_poweroff(struc
 	if (genpd->status = GPD_STATE_POWER_OFF)
 		return;
 
-	if (genpd->suspended_count != genpd->device_count || genpd->sd_count > 0)
+	if (genpd->suspended_count != genpd->device_count
+	    || atomic_read(&genpd->sd_count) > 0)
 		return;
 
 	if (genpd->power_off)
@@ -1152,7 +1162,7 @@ int pm_genpd_add_subdomain(struct generi
 	list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
 	new_subdomain->parent = genpd;
 	if (subdomain->status != GPD_STATE_POWER_OFF)
-		genpd->sd_count++;
+		genpd_sd_counter_inc(genpd);
 
  out:
 	mutex_unlock(&new_subdomain->lock);
@@ -1227,7 +1237,7 @@ void pm_genpd_init(struct generic_pm_dom
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
 	genpd->in_progress = 0;
-	genpd->sd_count = 0;
+	atomic_set(&genpd->sd_count, 0);
 	genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
 	init_waitqueue_head(&genpd->status_wait_queue);
 	genpd->poweroff_task = NULL;
Index: linux-2.6/include/linux/pm_domain.h
=================================--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -33,7 +33,7 @@ struct generic_pm_domain {
 	struct dev_power_governor *gov;
 	struct work_struct power_off_work;
 	unsigned int in_progress;	/* Number of devices being suspended now */
-	unsigned int sd_count;	/* Number of subdomains with power "on" */
+	atomic_t sd_count;	/* Number of subdomains with power "on" */
 	enum gpd_status status;	/* Current state of the domain */
 	wait_queue_head_t status_wait_queue;
 	struct task_struct *poweroff_task;	/* Powering off task */


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 2/9] PM / Domains: Implement subdomain counters as atomic fields
@ 2011-07-31 17:47   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:47 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

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>
---
 drivers/base/power/domain.c |   30 ++++++++++++++++++++----------
 include/linux/pm_domain.h   |    2 +-
 2 files changed, 21 insertions(+), 11 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -29,10 +29,20 @@ static struct generic_pm_domain *dev_to_
 	return pd_to_genpd(dev->pm_domain);
 }
 
-static void genpd_sd_counter_dec(struct generic_pm_domain *genpd)
+static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
 {
-	if (!WARN_ON(genpd->sd_count == 0))
-			genpd->sd_count--;
+	bool ret = false;
+
+	if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))
+		ret = !!atomic_dec_and_test(&genpd->sd_count);
+
+	return ret;
+}
+
+static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
+{
+	atomic_inc(&genpd->sd_count);
+	smp_mb__after_atomic_inc();
 }
 
 static void genpd_acquire_lock(struct generic_pm_domain *genpd)
@@ -118,7 +128,7 @@ int pm_genpd_poweron(struct generic_pm_d
 
 	genpd_set_active(genpd);
 	if (parent)
-		parent->sd_count++;
+		genpd_sd_counter_inc(parent);
 
  out:
 	mutex_unlock(&genpd->lock);
@@ -254,7 +264,7 @@ static int pm_genpd_poweroff(struct gene
 	    || genpd->resume_count > 0)
 		return 0;
 
-	if (genpd->sd_count > 0)
+	if (atomic_read(&genpd->sd_count) > 0)
 		return -EBUSY;
 
 	not_suspended = 0;
@@ -325,8 +335,7 @@ static int pm_genpd_poweroff(struct gene
 	genpd->status = GPD_STATE_POWER_OFF;
 
 	if (parent) {
-		genpd_sd_counter_dec(parent);
-		if (parent->sd_count == 0)
+		if (genpd_sd_counter_dec(parent))
 			genpd_queue_power_off_work(parent);
 
 		genpd_release_lock(parent);
@@ -491,7 +500,8 @@ static void pm_genpd_sync_poweroff(struc
 	if (genpd->status == GPD_STATE_POWER_OFF)
 		return;
 
-	if (genpd->suspended_count != genpd->device_count || genpd->sd_count > 0)
+	if (genpd->suspended_count != genpd->device_count
+	    || atomic_read(&genpd->sd_count) > 0)
 		return;
 
 	if (genpd->power_off)
@@ -1152,7 +1162,7 @@ int pm_genpd_add_subdomain(struct generi
 	list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
 	new_subdomain->parent = genpd;
 	if (subdomain->status != GPD_STATE_POWER_OFF)
-		genpd->sd_count++;
+		genpd_sd_counter_inc(genpd);
 
  out:
 	mutex_unlock(&new_subdomain->lock);
@@ -1227,7 +1237,7 @@ void pm_genpd_init(struct generic_pm_dom
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
 	genpd->in_progress = 0;
-	genpd->sd_count = 0;
+	atomic_set(&genpd->sd_count, 0);
 	genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
 	init_waitqueue_head(&genpd->status_wait_queue);
 	genpd->poweroff_task = NULL;
Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -33,7 +33,7 @@ struct generic_pm_domain {
 	struct dev_power_governor *gov;
 	struct work_struct power_off_work;
 	unsigned int in_progress;	/* Number of devices being suspended now */
-	unsigned int sd_count;	/* Number of subdomains with power "on" */
+	atomic_t sd_count;	/* Number of subdomains with power "on" */
 	enum gpd_status status;	/* Current state of the domain */
 	wait_queue_head_t status_wait_queue;
 	struct task_struct *poweroff_task;	/* Powering off task */


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 2/9] PM / Domains: Implement subdomain counters as atomic fields
  2011-07-31 17:46 ` Rafael J. Wysocki
                   ` (3 preceding siblings ...)
  (?)
@ 2011-07-31 17:47 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:47 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

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>
---
 drivers/base/power/domain.c |   30 ++++++++++++++++++++----------
 include/linux/pm_domain.h   |    2 +-
 2 files changed, 21 insertions(+), 11 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -29,10 +29,20 @@ static struct generic_pm_domain *dev_to_
 	return pd_to_genpd(dev->pm_domain);
 }
 
-static void genpd_sd_counter_dec(struct generic_pm_domain *genpd)
+static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
 {
-	if (!WARN_ON(genpd->sd_count == 0))
-			genpd->sd_count--;
+	bool ret = false;
+
+	if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))
+		ret = !!atomic_dec_and_test(&genpd->sd_count);
+
+	return ret;
+}
+
+static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
+{
+	atomic_inc(&genpd->sd_count);
+	smp_mb__after_atomic_inc();
 }
 
 static void genpd_acquire_lock(struct generic_pm_domain *genpd)
@@ -118,7 +128,7 @@ int pm_genpd_poweron(struct generic_pm_d
 
 	genpd_set_active(genpd);
 	if (parent)
-		parent->sd_count++;
+		genpd_sd_counter_inc(parent);
 
  out:
 	mutex_unlock(&genpd->lock);
@@ -254,7 +264,7 @@ static int pm_genpd_poweroff(struct gene
 	    || genpd->resume_count > 0)
 		return 0;
 
-	if (genpd->sd_count > 0)
+	if (atomic_read(&genpd->sd_count) > 0)
 		return -EBUSY;
 
 	not_suspended = 0;
@@ -325,8 +335,7 @@ static int pm_genpd_poweroff(struct gene
 	genpd->status = GPD_STATE_POWER_OFF;
 
 	if (parent) {
-		genpd_sd_counter_dec(parent);
-		if (parent->sd_count == 0)
+		if (genpd_sd_counter_dec(parent))
 			genpd_queue_power_off_work(parent);
 
 		genpd_release_lock(parent);
@@ -491,7 +500,8 @@ static void pm_genpd_sync_poweroff(struc
 	if (genpd->status == GPD_STATE_POWER_OFF)
 		return;
 
-	if (genpd->suspended_count != genpd->device_count || genpd->sd_count > 0)
+	if (genpd->suspended_count != genpd->device_count
+	    || atomic_read(&genpd->sd_count) > 0)
 		return;
 
 	if (genpd->power_off)
@@ -1152,7 +1162,7 @@ int pm_genpd_add_subdomain(struct generi
 	list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
 	new_subdomain->parent = genpd;
 	if (subdomain->status != GPD_STATE_POWER_OFF)
-		genpd->sd_count++;
+		genpd_sd_counter_inc(genpd);
 
  out:
 	mutex_unlock(&new_subdomain->lock);
@@ -1227,7 +1237,7 @@ void pm_genpd_init(struct generic_pm_dom
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
 	genpd->in_progress = 0;
-	genpd->sd_count = 0;
+	atomic_set(&genpd->sd_count, 0);
 	genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
 	init_waitqueue_head(&genpd->status_wait_queue);
 	genpd->poweroff_task = NULL;
Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -33,7 +33,7 @@ struct generic_pm_domain {
 	struct dev_power_governor *gov;
 	struct work_struct power_off_work;
 	unsigned int in_progress;	/* Number of devices being suspended now */
-	unsigned int sd_count;	/* Number of subdomains with power "on" */
+	atomic_t sd_count;	/* Number of subdomains with power "on" */
 	enum gpd_status status;	/* Current state of the domain */
 	wait_queue_head_t status_wait_queue;
 	struct task_struct *poweroff_task;	/* Powering off task */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 3/9] PM / Domains: Do not take parent locks to modify subdomain counters
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:48   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:48 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

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>
---
 drivers/base/power/domain.c |   70 +++++++++++++++++++-------------------------
 1 file changed, 31 insertions(+), 39 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -93,12 +93,7 @@ int pm_genpd_poweron(struct generic_pm_d
 	int ret = 0;
 
  start:
-	if (parent) {
-		genpd_acquire_lock(parent);
-		mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-	} else {
-		mutex_lock(&genpd->lock);
-	}
+	mutex_lock(&genpd->lock);
 
 	if (genpd->status = GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
@@ -109,31 +104,33 @@ int pm_genpd_poweron(struct generic_pm_d
 		goto out;
 	}
 
-	if (parent && parent->status != GPD_STATE_ACTIVE) {
+	if (parent) {
+		genpd_sd_counter_inc(parent);
+
 		mutex_unlock(&genpd->lock);
-		genpd_release_lock(parent);
 
 		ret = pm_genpd_poweron(parent);
-		if (ret)
+		if (ret) {
+			genpd_sd_counter_dec(parent);
 			return ret;
+		}
 
+		parent = NULL;
 		goto start;
 	}
 
-	if (genpd->power_on) {
+	if (genpd->power_on)
 		ret = genpd->power_on(genpd);
-		if (ret)
-			goto out;
-	}
 
-	genpd_set_active(genpd);
-	if (parent)
-		genpd_sd_counter_inc(parent);
+	if (ret) {
+		if (genpd->parent)
+			genpd_sd_counter_dec(genpd->parent);
+	} else {
+		genpd_set_active(genpd);
+	}
 
  out:
 	mutex_unlock(&genpd->lock);
-	if (parent)
-		genpd_release_lock(parent);
 
 	return ret;
 }
@@ -293,7 +290,8 @@ static int pm_genpd_poweroff(struct gene
 	genpd->poweroff_task = current;
 
 	list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
-		ret = __pm_genpd_save_device(dle, genpd);
+		ret = atomic_read(&genpd->sd_count) = 0 ?
+			__pm_genpd_save_device(dle, genpd) : -EBUSY;
 		if (ret) {
 			genpd_set_active(genpd);
 			goto out;
@@ -308,38 +306,32 @@ static int pm_genpd_poweroff(struct gene
 		}
 	}
 
-	parent = genpd->parent;
-	if (parent) {
-		mutex_unlock(&genpd->lock);
-
-		genpd_acquire_lock(parent);
-		mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-
-		if (genpd_abort_poweroff(genpd)) {
-			genpd_release_lock(parent);
+	if (genpd->power_off) {
+		if (atomic_read(&genpd->sd_count) > 0) {
+			ret = -EBUSY;
 			goto out;
 		}
-	}
 
-	if (genpd->power_off) {
+		/*
+		 * If sd_count > 0 at this point, one of the children hasn't
+		 * managed to call pm_genpd_poweron() for the parent yet after
+		 * incrementing it.  In that case pm_genpd_poweron() will wait
+		 * for us to drop the lock, so we can call .power_off() and let
+		 * the pm_genpd_poweron() restore power for us (this shouldn't
+		 * happen very often).
+		 */
 		ret = genpd->power_off(genpd);
 		if (ret = -EBUSY) {
 			genpd_set_active(genpd);
-			if (parent)
-				genpd_release_lock(parent);
-
 			goto out;
 		}
 	}
 
 	genpd->status = GPD_STATE_POWER_OFF;
 
-	if (parent) {
-		if (genpd_sd_counter_dec(parent))
-			genpd_queue_power_off_work(parent);
-
-		genpd_release_lock(parent);
-	}
+	parent = genpd->parent;
+	if (parent && genpd_sd_counter_dec(parent))
+		genpd_queue_power_off_work(parent);
 
  out:
 	genpd->poweroff_task = NULL;


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 3/9] PM / Domains: Do not take parent locks to modify subdomain counters
@ 2011-07-31 17:48   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:48 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

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>
---
 drivers/base/power/domain.c |   70 +++++++++++++++++++-------------------------
 1 file changed, 31 insertions(+), 39 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -93,12 +93,7 @@ int pm_genpd_poweron(struct generic_pm_d
 	int ret = 0;
 
  start:
-	if (parent) {
-		genpd_acquire_lock(parent);
-		mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-	} else {
-		mutex_lock(&genpd->lock);
-	}
+	mutex_lock(&genpd->lock);
 
 	if (genpd->status == GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
@@ -109,31 +104,33 @@ int pm_genpd_poweron(struct generic_pm_d
 		goto out;
 	}
 
-	if (parent && parent->status != GPD_STATE_ACTIVE) {
+	if (parent) {
+		genpd_sd_counter_inc(parent);
+
 		mutex_unlock(&genpd->lock);
-		genpd_release_lock(parent);
 
 		ret = pm_genpd_poweron(parent);
-		if (ret)
+		if (ret) {
+			genpd_sd_counter_dec(parent);
 			return ret;
+		}
 
+		parent = NULL;
 		goto start;
 	}
 
-	if (genpd->power_on) {
+	if (genpd->power_on)
 		ret = genpd->power_on(genpd);
-		if (ret)
-			goto out;
-	}
 
-	genpd_set_active(genpd);
-	if (parent)
-		genpd_sd_counter_inc(parent);
+	if (ret) {
+		if (genpd->parent)
+			genpd_sd_counter_dec(genpd->parent);
+	} else {
+		genpd_set_active(genpd);
+	}
 
  out:
 	mutex_unlock(&genpd->lock);
-	if (parent)
-		genpd_release_lock(parent);
 
 	return ret;
 }
@@ -293,7 +290,8 @@ static int pm_genpd_poweroff(struct gene
 	genpd->poweroff_task = current;
 
 	list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
-		ret = __pm_genpd_save_device(dle, genpd);
+		ret = atomic_read(&genpd->sd_count) == 0 ?
+			__pm_genpd_save_device(dle, genpd) : -EBUSY;
 		if (ret) {
 			genpd_set_active(genpd);
 			goto out;
@@ -308,38 +306,32 @@ static int pm_genpd_poweroff(struct gene
 		}
 	}
 
-	parent = genpd->parent;
-	if (parent) {
-		mutex_unlock(&genpd->lock);
-
-		genpd_acquire_lock(parent);
-		mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-
-		if (genpd_abort_poweroff(genpd)) {
-			genpd_release_lock(parent);
+	if (genpd->power_off) {
+		if (atomic_read(&genpd->sd_count) > 0) {
+			ret = -EBUSY;
 			goto out;
 		}
-	}
 
-	if (genpd->power_off) {
+		/*
+		 * If sd_count > 0 at this point, one of the children hasn't
+		 * managed to call pm_genpd_poweron() for the parent yet after
+		 * incrementing it.  In that case pm_genpd_poweron() will wait
+		 * for us to drop the lock, so we can call .power_off() and let
+		 * the pm_genpd_poweron() restore power for us (this shouldn't
+		 * happen very often).
+		 */
 		ret = genpd->power_off(genpd);
 		if (ret == -EBUSY) {
 			genpd_set_active(genpd);
-			if (parent)
-				genpd_release_lock(parent);
-
 			goto out;
 		}
 	}
 
 	genpd->status = GPD_STATE_POWER_OFF;
 
-	if (parent) {
-		if (genpd_sd_counter_dec(parent))
-			genpd_queue_power_off_work(parent);
-
-		genpd_release_lock(parent);
-	}
+	parent = genpd->parent;
+	if (parent && genpd_sd_counter_dec(parent))
+		genpd_queue_power_off_work(parent);
 
  out:
 	genpd->poweroff_task = NULL;


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 3/9] PM / Domains: Do not take parent locks to modify subdomain counters
  2011-07-31 17:46 ` Rafael J. Wysocki
                   ` (5 preceding siblings ...)
  (?)
@ 2011-07-31 17:48 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:48 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

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>
---
 drivers/base/power/domain.c |   70 +++++++++++++++++++-------------------------
 1 file changed, 31 insertions(+), 39 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -93,12 +93,7 @@ int pm_genpd_poweron(struct generic_pm_d
 	int ret = 0;
 
  start:
-	if (parent) {
-		genpd_acquire_lock(parent);
-		mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-	} else {
-		mutex_lock(&genpd->lock);
-	}
+	mutex_lock(&genpd->lock);
 
 	if (genpd->status == GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
@@ -109,31 +104,33 @@ int pm_genpd_poweron(struct generic_pm_d
 		goto out;
 	}
 
-	if (parent && parent->status != GPD_STATE_ACTIVE) {
+	if (parent) {
+		genpd_sd_counter_inc(parent);
+
 		mutex_unlock(&genpd->lock);
-		genpd_release_lock(parent);
 
 		ret = pm_genpd_poweron(parent);
-		if (ret)
+		if (ret) {
+			genpd_sd_counter_dec(parent);
 			return ret;
+		}
 
+		parent = NULL;
 		goto start;
 	}
 
-	if (genpd->power_on) {
+	if (genpd->power_on)
 		ret = genpd->power_on(genpd);
-		if (ret)
-			goto out;
-	}
 
-	genpd_set_active(genpd);
-	if (parent)
-		genpd_sd_counter_inc(parent);
+	if (ret) {
+		if (genpd->parent)
+			genpd_sd_counter_dec(genpd->parent);
+	} else {
+		genpd_set_active(genpd);
+	}
 
  out:
 	mutex_unlock(&genpd->lock);
-	if (parent)
-		genpd_release_lock(parent);
 
 	return ret;
 }
@@ -293,7 +290,8 @@ static int pm_genpd_poweroff(struct gene
 	genpd->poweroff_task = current;
 
 	list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
-		ret = __pm_genpd_save_device(dle, genpd);
+		ret = atomic_read(&genpd->sd_count) == 0 ?
+			__pm_genpd_save_device(dle, genpd) : -EBUSY;
 		if (ret) {
 			genpd_set_active(genpd);
 			goto out;
@@ -308,38 +306,32 @@ static int pm_genpd_poweroff(struct gene
 		}
 	}
 
-	parent = genpd->parent;
-	if (parent) {
-		mutex_unlock(&genpd->lock);
-
-		genpd_acquire_lock(parent);
-		mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-
-		if (genpd_abort_poweroff(genpd)) {
-			genpd_release_lock(parent);
+	if (genpd->power_off) {
+		if (atomic_read(&genpd->sd_count) > 0) {
+			ret = -EBUSY;
 			goto out;
 		}
-	}
 
-	if (genpd->power_off) {
+		/*
+		 * If sd_count > 0 at this point, one of the children hasn't
+		 * managed to call pm_genpd_poweron() for the parent yet after
+		 * incrementing it.  In that case pm_genpd_poweron() will wait
+		 * for us to drop the lock, so we can call .power_off() and let
+		 * the pm_genpd_poweron() restore power for us (this shouldn't
+		 * happen very often).
+		 */
 		ret = genpd->power_off(genpd);
 		if (ret == -EBUSY) {
 			genpd_set_active(genpd);
-			if (parent)
-				genpd_release_lock(parent);
-
 			goto out;
 		}
 	}
 
 	genpd->status = GPD_STATE_POWER_OFF;
 
-	if (parent) {
-		if (genpd_sd_counter_dec(parent))
-			genpd_queue_power_off_work(parent);
-
-		genpd_release_lock(parent);
-	}
+	parent = genpd->parent;
+	if (parent && genpd_sd_counter_dec(parent))
+		genpd_queue_power_off_work(parent);
 
  out:
 	genpd->poweroff_task = NULL;

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 4/9] PM / Domains: Make pm_genpd_poweron() always survive parent removal
  2011-07-31 17:46 ` Rafael J. Wysocki
  (?)
@ 2011-07-31 17:49   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:49 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

If pm_genpd_remove_subdomain() is called to remove a PM domain's
subdomain and pm_genpd_poweron() is called for that subdomain at
the same time, and the pm_genpd_poweron() called by it recursively
for the parent returns an error, the first pm_genpd_poweron()'s
error code path will attempt to decrement the subdomain counter of
a PM domain that it's not a subdomain of any more.

Rearrange the code in pm_genpd_poweron() to prevent this from
happening.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -89,12 +89,14 @@ static void genpd_set_active(struct gene
  */
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
-	struct generic_pm_domain *parent = genpd->parent;
+	struct generic_pm_domain *parent;
 	int ret = 0;
 
- start:
 	mutex_lock(&genpd->lock);
 
+	parent = genpd->parent;
+
+ start:
 	if (genpd->status = GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
 		goto out;
@@ -110,29 +112,34 @@ int pm_genpd_poweron(struct generic_pm_d
 		mutex_unlock(&genpd->lock);
 
 		ret = pm_genpd_poweron(parent);
-		if (ret) {
-			genpd_sd_counter_dec(parent);
-			return ret;
-		}
+
+		mutex_lock(&genpd->lock);
+
+		if (ret)
+			goto err;
 
 		parent = NULL;
 		goto start;
 	}
 
-	if (genpd->power_on)
+	if (genpd->power_on) {
 		ret = genpd->power_on(genpd);
-
-	if (ret) {
-		if (genpd->parent)
-			genpd_sd_counter_dec(genpd->parent);
-	} else {
-		genpd_set_active(genpd);
+		if (ret)
+			goto err;
 	}
 
+	genpd_set_active(genpd);
+
  out:
 	mutex_unlock(&genpd->lock);
 
 	return ret;
+
+ err:
+	if (genpd->parent)
+		genpd_sd_counter_dec(genpd->parent);
+
+	goto out;
 }
 
 #endif /* CONFIG_PM */


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 4/9] PM / Domains: Make pm_genpd_poweron() always survive parent removal
@ 2011-07-31 17:49   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:49 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

If pm_genpd_remove_subdomain() is called to remove a PM domain's
subdomain and pm_genpd_poweron() is called for that subdomain at
the same time, and the pm_genpd_poweron() called by it recursively
for the parent returns an error, the first pm_genpd_poweron()'s
error code path will attempt to decrement the subdomain counter of
a PM domain that it's not a subdomain of any more.

Rearrange the code in pm_genpd_poweron() to prevent this from
happening.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -89,12 +89,14 @@ static void genpd_set_active(struct gene
  */
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
-	struct generic_pm_domain *parent = genpd->parent;
+	struct generic_pm_domain *parent;
 	int ret = 0;
 
- start:
 	mutex_lock(&genpd->lock);
 
+	parent = genpd->parent;
+
+ start:
 	if (genpd->status == GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
 		goto out;
@@ -110,29 +112,34 @@ int pm_genpd_poweron(struct generic_pm_d
 		mutex_unlock(&genpd->lock);
 
 		ret = pm_genpd_poweron(parent);
-		if (ret) {
-			genpd_sd_counter_dec(parent);
-			return ret;
-		}
+
+		mutex_lock(&genpd->lock);
+
+		if (ret)
+			goto err;
 
 		parent = NULL;
 		goto start;
 	}
 
-	if (genpd->power_on)
+	if (genpd->power_on) {
 		ret = genpd->power_on(genpd);
-
-	if (ret) {
-		if (genpd->parent)
-			genpd_sd_counter_dec(genpd->parent);
-	} else {
-		genpd_set_active(genpd);
+		if (ret)
+			goto err;
 	}
 
+	genpd_set_active(genpd);
+
  out:
 	mutex_unlock(&genpd->lock);
 
 	return ret;
+
+ err:
+	if (genpd->parent)
+		genpd_sd_counter_dec(genpd->parent);
+
+	goto out;
 }
 
 #endif /* CONFIG_PM */


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 4/9] PM / Domains: Make pm_genpd_poweron() always survive parent removal
@ 2011-07-31 17:49   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:49 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

If pm_genpd_remove_subdomain() is called to remove a PM domain's
subdomain and pm_genpd_poweron() is called for that subdomain at
the same time, and the pm_genpd_poweron() called by it recursively
for the parent returns an error, the first pm_genpd_poweron()'s
error code path will attempt to decrement the subdomain counter of
a PM domain that it's not a subdomain of any more.

Rearrange the code in pm_genpd_poweron() to prevent this from
happening.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -89,12 +89,14 @@ static void genpd_set_active(struct gene
  */
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
-	struct generic_pm_domain *parent = genpd->parent;
+	struct generic_pm_domain *parent;
 	int ret = 0;
 
- start:
 	mutex_lock(&genpd->lock);
 
+	parent = genpd->parent;
+
+ start:
 	if (genpd->status == GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
 		goto out;
@@ -110,29 +112,34 @@ int pm_genpd_poweron(struct generic_pm_d
 		mutex_unlock(&genpd->lock);
 
 		ret = pm_genpd_poweron(parent);
-		if (ret) {
-			genpd_sd_counter_dec(parent);
-			return ret;
-		}
+
+		mutex_lock(&genpd->lock);
+
+		if (ret)
+			goto err;
 
 		parent = NULL;
 		goto start;
 	}
 
-	if (genpd->power_on)
+	if (genpd->power_on) {
 		ret = genpd->power_on(genpd);
-
-	if (ret) {
-		if (genpd->parent)
-			genpd_sd_counter_dec(genpd->parent);
-	} else {
-		genpd_set_active(genpd);
+		if (ret)
+			goto err;
 	}
 
+	genpd_set_active(genpd);
+
  out:
 	mutex_unlock(&genpd->lock);
 
 	return ret;
+
+ err:
+	if (genpd->parent)
+		genpd_sd_counter_dec(genpd->parent);
+
+	goto out;
 }
 
 #endif /* CONFIG_PM */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 5/9] PM / Domains: Add "wait for parent" status for generic PM domains
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:49   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:49 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

The next patch will make it possible for a generic PM domain to have
multiple parents (i.e. multiple PM domains it depends on).  To
prepare for that change it is necessary to change pm_genpd_poweron()
so that it doesn't jump to the start label after running itself
recursively for the parent domain.  For this purpose, introduce a new
PM domain status value GPD_STATE_WAIT_PARENT that will be set by
pm_genpd_poweron() before calling itself recursively for the parent
domain and modify the code in drivers/base/power/domain.c so that
the GPD_STATE_WAIT_PARENT status is guaranteed to be preserved during
the execution of pm_genpd_poweron() for the parent.

This change also causes pm_genpd_add_subdomain() and
pm_genpd_remove_subdomain() to wait for started pm_genpd_poweron() to
complete and allows pm_genpd_runtime_resume() to avoid dropping the
lock after powering on the PM domain.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   90 +++++++++++++++++++++++++++++---------------
 include/linux/pm_domain.h   |    1 
 2 files changed, 61 insertions(+), 30 deletions(-)

Index: linux-2.6/include/linux/pm_domain.h
=================================--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -13,6 +13,7 @@
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
+	GPD_STATE_WAIT_PARENT,	/* PM domain's parent is being waited for */
 	GPD_STATE_BUSY,		/* Something is happening to the PM domain */
 	GPD_STATE_REPEAT,	/* Power off in progress, to be repeated */
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -81,45 +81,59 @@ static void genpd_set_active(struct gene
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its parents.
  * @genpd: PM domain to power up.
  *
  * Restore power to @genpd and all of its parents so that it is possible to
  * resume a device belonging to it.
  */
-int pm_genpd_poweron(struct generic_pm_domain *genpd)
+int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
-	struct generic_pm_domain *parent;
+	DEFINE_WAIT(wait);
 	int ret = 0;
 
-	mutex_lock(&genpd->lock);
+	/* If the domain's parent is being waited for, we have to wait too. */
+	for (;;) {
+		prepare_to_wait(&genpd->status_wait_queue, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (genpd->status != GPD_STATE_WAIT_PARENT)
+			break;
+		mutex_unlock(&genpd->lock);
 
-	parent = genpd->parent;
+		schedule();
+
+		mutex_lock(&genpd->lock);
+	}
+	finish_wait(&genpd->status_wait_queue, &wait);
 
- start:
 	if (genpd->status = GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
-		goto out;
+		return 0;
 
 	if (genpd->status != GPD_STATE_POWER_OFF) {
 		genpd_set_active(genpd);
-		goto out;
+		return 0;
 	}
 
-	if (parent) {
-		genpd_sd_counter_inc(parent);
+	if (genpd->parent) {
+		genpd_sd_counter_inc(genpd->parent);
+		genpd->status = GPD_STATE_WAIT_PARENT;
 
 		mutex_unlock(&genpd->lock);
 
-		ret = pm_genpd_poweron(parent);
+		ret = pm_genpd_poweron(genpd->parent);
 
 		mutex_lock(&genpd->lock);
 
+		/*
+		 * The "wait for parent" status is guaranteed not to change
+		 * while the parent is powering on.
+		 */
+		genpd->status = GPD_STATE_POWER_OFF;
+		wake_up_all(&genpd->status_wait_queue);
 		if (ret)
 			goto err;
-
-		parent = NULL;
-		goto start;
 	}
 
 	if (genpd->power_on) {
@@ -130,16 +144,27 @@ int pm_genpd_poweron(struct generic_pm_d
 
 	genpd_set_active(genpd);
 
- out:
-	mutex_unlock(&genpd->lock);
-
-	return ret;
+	return 0;
 
  err:
 	if (genpd->parent)
 		genpd_sd_counter_dec(genpd->parent);
 
-	goto out;
+	return ret;
+}
+
+/**
+ * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * @genpd: PM domain to power up.
+ */
+int pm_genpd_poweron(struct generic_pm_domain *genpd)
+{
+	int ret;
+
+	mutex_lock(&genpd->lock);
+	ret = __pm_genpd_poweron(genpd);
+	mutex_unlock(&genpd->lock);
+	return ret;
 }
 
 #endif /* CONFIG_PM */
@@ -225,7 +250,8 @@ static void __pm_genpd_restore_device(st
  */
 static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
 {
-	return genpd->status = GPD_STATE_ACTIVE || genpd->resume_count > 0;
+	return genpd->status = GPD_STATE_WAIT_PARENT
+		|| genpd->status = GPD_STATE_ACTIVE || genpd->resume_count > 0;
 }
 
 /**
@@ -261,11 +287,13 @@ static int pm_genpd_poweroff(struct gene
 	/*
 	 * Do not try to power off the domain in the following situations:
 	 * (1) The domain is already in the "power off" state.
-	 * (2) System suspend is in progress.
+	 * (2) The domain is waiting for its parent to power up.
 	 * (3) One of the domain's devices is being resumed right now.
+	 * (4) System suspend is in progress.
 	 */
-	if (genpd->status = GPD_STATE_POWER_OFF || genpd->prepared_count > 0
-	    || genpd->resume_count > 0)
+	if (genpd->status = GPD_STATE_POWER_OFF
+	    || genpd->status = GPD_STATE_WAIT_PARENT
+	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
 		return 0;
 
 	if (atomic_read(&genpd->sd_count) > 0)
@@ -299,14 +327,15 @@ static int pm_genpd_poweroff(struct gene
 	list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
 		ret = atomic_read(&genpd->sd_count) = 0 ?
 			__pm_genpd_save_device(dle, genpd) : -EBUSY;
+
+		if (genpd_abort_poweroff(genpd))
+			goto out;
+
 		if (ret) {
 			genpd_set_active(genpd);
 			goto out;
 		}
 
-		if (genpd_abort_poweroff(genpd))
-			goto out;
-
 		if (genpd->status = GPD_STATE_REPEAT) {
 			genpd->poweroff_task = NULL;
 			goto start;
@@ -432,11 +461,12 @@ static int pm_genpd_runtime_resume(struc
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	ret = pm_genpd_poweron(genpd);
-	if (ret)
-		return ret;
-
 	mutex_lock(&genpd->lock);
+	ret = __pm_genpd_poweron(genpd);
+	if (ret) {
+		mutex_unlock(&genpd->lock);
+		return ret;
+	}
 	genpd->status = GPD_STATE_BUSY;
 	genpd->resume_count++;
 	for (;;) {


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 5/9] PM / Domains: Add "wait for parent" status for generic PM domains
@ 2011-07-31 17:49   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:49 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

The next patch will make it possible for a generic PM domain to have
multiple parents (i.e. multiple PM domains it depends on).  To
prepare for that change it is necessary to change pm_genpd_poweron()
so that it doesn't jump to the start label after running itself
recursively for the parent domain.  For this purpose, introduce a new
PM domain status value GPD_STATE_WAIT_PARENT that will be set by
pm_genpd_poweron() before calling itself recursively for the parent
domain and modify the code in drivers/base/power/domain.c so that
the GPD_STATE_WAIT_PARENT status is guaranteed to be preserved during
the execution of pm_genpd_poweron() for the parent.

This change also causes pm_genpd_add_subdomain() and
pm_genpd_remove_subdomain() to wait for started pm_genpd_poweron() to
complete and allows pm_genpd_runtime_resume() to avoid dropping the
lock after powering on the PM domain.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   90 +++++++++++++++++++++++++++++---------------
 include/linux/pm_domain.h   |    1 
 2 files changed, 61 insertions(+), 30 deletions(-)

Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -13,6 +13,7 @@
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
+	GPD_STATE_WAIT_PARENT,	/* PM domain's parent is being waited for */
 	GPD_STATE_BUSY,		/* Something is happening to the PM domain */
 	GPD_STATE_REPEAT,	/* Power off in progress, to be repeated */
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -81,45 +81,59 @@ static void genpd_set_active(struct gene
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its parents.
  * @genpd: PM domain to power up.
  *
  * Restore power to @genpd and all of its parents so that it is possible to
  * resume a device belonging to it.
  */
-int pm_genpd_poweron(struct generic_pm_domain *genpd)
+int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
-	struct generic_pm_domain *parent;
+	DEFINE_WAIT(wait);
 	int ret = 0;
 
-	mutex_lock(&genpd->lock);
+	/* If the domain's parent is being waited for, we have to wait too. */
+	for (;;) {
+		prepare_to_wait(&genpd->status_wait_queue, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (genpd->status != GPD_STATE_WAIT_PARENT)
+			break;
+		mutex_unlock(&genpd->lock);
 
-	parent = genpd->parent;
+		schedule();
+
+		mutex_lock(&genpd->lock);
+	}
+	finish_wait(&genpd->status_wait_queue, &wait);
 
- start:
 	if (genpd->status == GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
-		goto out;
+		return 0;
 
 	if (genpd->status != GPD_STATE_POWER_OFF) {
 		genpd_set_active(genpd);
-		goto out;
+		return 0;
 	}
 
-	if (parent) {
-		genpd_sd_counter_inc(parent);
+	if (genpd->parent) {
+		genpd_sd_counter_inc(genpd->parent);
+		genpd->status = GPD_STATE_WAIT_PARENT;
 
 		mutex_unlock(&genpd->lock);
 
-		ret = pm_genpd_poweron(parent);
+		ret = pm_genpd_poweron(genpd->parent);
 
 		mutex_lock(&genpd->lock);
 
+		/*
+		 * The "wait for parent" status is guaranteed not to change
+		 * while the parent is powering on.
+		 */
+		genpd->status = GPD_STATE_POWER_OFF;
+		wake_up_all(&genpd->status_wait_queue);
 		if (ret)
 			goto err;
-
-		parent = NULL;
-		goto start;
 	}
 
 	if (genpd->power_on) {
@@ -130,16 +144,27 @@ int pm_genpd_poweron(struct generic_pm_d
 
 	genpd_set_active(genpd);
 
- out:
-	mutex_unlock(&genpd->lock);
-
-	return ret;
+	return 0;
 
  err:
 	if (genpd->parent)
 		genpd_sd_counter_dec(genpd->parent);
 
-	goto out;
+	return ret;
+}
+
+/**
+ * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * @genpd: PM domain to power up.
+ */
+int pm_genpd_poweron(struct generic_pm_domain *genpd)
+{
+	int ret;
+
+	mutex_lock(&genpd->lock);
+	ret = __pm_genpd_poweron(genpd);
+	mutex_unlock(&genpd->lock);
+	return ret;
 }
 
 #endif /* CONFIG_PM */
@@ -225,7 +250,8 @@ static void __pm_genpd_restore_device(st
  */
 static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
 {
-	return genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
+	return genpd->status == GPD_STATE_WAIT_PARENT
+		|| genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
 }
 
 /**
@@ -261,11 +287,13 @@ static int pm_genpd_poweroff(struct gene
 	/*
 	 * Do not try to power off the domain in the following situations:
 	 * (1) The domain is already in the "power off" state.
-	 * (2) System suspend is in progress.
+	 * (2) The domain is waiting for its parent to power up.
 	 * (3) One of the domain's devices is being resumed right now.
+	 * (4) System suspend is in progress.
 	 */
-	if (genpd->status == GPD_STATE_POWER_OFF || genpd->prepared_count > 0
-	    || genpd->resume_count > 0)
+	if (genpd->status == GPD_STATE_POWER_OFF
+	    || genpd->status == GPD_STATE_WAIT_PARENT
+	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
 		return 0;
 
 	if (atomic_read(&genpd->sd_count) > 0)
@@ -299,14 +327,15 @@ static int pm_genpd_poweroff(struct gene
 	list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
 		ret = atomic_read(&genpd->sd_count) == 0 ?
 			__pm_genpd_save_device(dle, genpd) : -EBUSY;
+
+		if (genpd_abort_poweroff(genpd))
+			goto out;
+
 		if (ret) {
 			genpd_set_active(genpd);
 			goto out;
 		}
 
-		if (genpd_abort_poweroff(genpd))
-			goto out;
-
 		if (genpd->status == GPD_STATE_REPEAT) {
 			genpd->poweroff_task = NULL;
 			goto start;
@@ -432,11 +461,12 @@ static int pm_genpd_runtime_resume(struc
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	ret = pm_genpd_poweron(genpd);
-	if (ret)
-		return ret;
-
 	mutex_lock(&genpd->lock);
+	ret = __pm_genpd_poweron(genpd);
+	if (ret) {
+		mutex_unlock(&genpd->lock);
+		return ret;
+	}
 	genpd->status = GPD_STATE_BUSY;
 	genpd->resume_count++;
 	for (;;) {


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 5/9] PM / Domains: Add "wait for parent" status for generic PM domains
  2011-07-31 17:46 ` Rafael J. Wysocki
                   ` (8 preceding siblings ...)
  (?)
@ 2011-07-31 17:49 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:49 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

The next patch will make it possible for a generic PM domain to have
multiple parents (i.e. multiple PM domains it depends on).  To
prepare for that change it is necessary to change pm_genpd_poweron()
so that it doesn't jump to the start label after running itself
recursively for the parent domain.  For this purpose, introduce a new
PM domain status value GPD_STATE_WAIT_PARENT that will be set by
pm_genpd_poweron() before calling itself recursively for the parent
domain and modify the code in drivers/base/power/domain.c so that
the GPD_STATE_WAIT_PARENT status is guaranteed to be preserved during
the execution of pm_genpd_poweron() for the parent.

This change also causes pm_genpd_add_subdomain() and
pm_genpd_remove_subdomain() to wait for started pm_genpd_poweron() to
complete and allows pm_genpd_runtime_resume() to avoid dropping the
lock after powering on the PM domain.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   90 +++++++++++++++++++++++++++++---------------
 include/linux/pm_domain.h   |    1 
 2 files changed, 61 insertions(+), 30 deletions(-)

Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -13,6 +13,7 @@
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
+	GPD_STATE_WAIT_PARENT,	/* PM domain's parent is being waited for */
 	GPD_STATE_BUSY,		/* Something is happening to the PM domain */
 	GPD_STATE_REPEAT,	/* Power off in progress, to be repeated */
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -81,45 +81,59 @@ static void genpd_set_active(struct gene
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its parents.
  * @genpd: PM domain to power up.
  *
  * Restore power to @genpd and all of its parents so that it is possible to
  * resume a device belonging to it.
  */
-int pm_genpd_poweron(struct generic_pm_domain *genpd)
+int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
-	struct generic_pm_domain *parent;
+	DEFINE_WAIT(wait);
 	int ret = 0;
 
-	mutex_lock(&genpd->lock);
+	/* If the domain's parent is being waited for, we have to wait too. */
+	for (;;) {
+		prepare_to_wait(&genpd->status_wait_queue, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (genpd->status != GPD_STATE_WAIT_PARENT)
+			break;
+		mutex_unlock(&genpd->lock);
 
-	parent = genpd->parent;
+		schedule();
+
+		mutex_lock(&genpd->lock);
+	}
+	finish_wait(&genpd->status_wait_queue, &wait);
 
- start:
 	if (genpd->status == GPD_STATE_ACTIVE
 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
-		goto out;
+		return 0;
 
 	if (genpd->status != GPD_STATE_POWER_OFF) {
 		genpd_set_active(genpd);
-		goto out;
+		return 0;
 	}
 
-	if (parent) {
-		genpd_sd_counter_inc(parent);
+	if (genpd->parent) {
+		genpd_sd_counter_inc(genpd->parent);
+		genpd->status = GPD_STATE_WAIT_PARENT;
 
 		mutex_unlock(&genpd->lock);
 
-		ret = pm_genpd_poweron(parent);
+		ret = pm_genpd_poweron(genpd->parent);
 
 		mutex_lock(&genpd->lock);
 
+		/*
+		 * The "wait for parent" status is guaranteed not to change
+		 * while the parent is powering on.
+		 */
+		genpd->status = GPD_STATE_POWER_OFF;
+		wake_up_all(&genpd->status_wait_queue);
 		if (ret)
 			goto err;
-
-		parent = NULL;
-		goto start;
 	}
 
 	if (genpd->power_on) {
@@ -130,16 +144,27 @@ int pm_genpd_poweron(struct generic_pm_d
 
 	genpd_set_active(genpd);
 
- out:
-	mutex_unlock(&genpd->lock);
-
-	return ret;
+	return 0;
 
  err:
 	if (genpd->parent)
 		genpd_sd_counter_dec(genpd->parent);
 
-	goto out;
+	return ret;
+}
+
+/**
+ * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * @genpd: PM domain to power up.
+ */
+int pm_genpd_poweron(struct generic_pm_domain *genpd)
+{
+	int ret;
+
+	mutex_lock(&genpd->lock);
+	ret = __pm_genpd_poweron(genpd);
+	mutex_unlock(&genpd->lock);
+	return ret;
 }
 
 #endif /* CONFIG_PM */
@@ -225,7 +250,8 @@ static void __pm_genpd_restore_device(st
  */
 static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
 {
-	return genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
+	return genpd->status == GPD_STATE_WAIT_PARENT
+		|| genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
 }
 
 /**
@@ -261,11 +287,13 @@ static int pm_genpd_poweroff(struct gene
 	/*
 	 * Do not try to power off the domain in the following situations:
 	 * (1) The domain is already in the "power off" state.
-	 * (2) System suspend is in progress.
+	 * (2) The domain is waiting for its parent to power up.
 	 * (3) One of the domain's devices is being resumed right now.
+	 * (4) System suspend is in progress.
 	 */
-	if (genpd->status == GPD_STATE_POWER_OFF || genpd->prepared_count > 0
-	    || genpd->resume_count > 0)
+	if (genpd->status == GPD_STATE_POWER_OFF
+	    || genpd->status == GPD_STATE_WAIT_PARENT
+	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
 		return 0;
 
 	if (atomic_read(&genpd->sd_count) > 0)
@@ -299,14 +327,15 @@ static int pm_genpd_poweroff(struct gene
 	list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
 		ret = atomic_read(&genpd->sd_count) == 0 ?
 			__pm_genpd_save_device(dle, genpd) : -EBUSY;
+
+		if (genpd_abort_poweroff(genpd))
+			goto out;
+
 		if (ret) {
 			genpd_set_active(genpd);
 			goto out;
 		}
 
-		if (genpd_abort_poweroff(genpd))
-			goto out;
-
 		if (genpd->status == GPD_STATE_REPEAT) {
 			genpd->poweroff_task = NULL;
 			goto start;
@@ -432,11 +461,12 @@ static int pm_genpd_runtime_resume(struc
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	ret = pm_genpd_poweron(genpd);
-	if (ret)
-		return ret;
-
 	mutex_lock(&genpd->lock);
+	ret = __pm_genpd_poweron(genpd);
+	if (ret) {
+		mutex_unlock(&genpd->lock);
+		return ret;
+	}
 	genpd->status = GPD_STATE_BUSY;
 	genpd->resume_count++;
 	for (;;) {

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 6/9] PM / Domains: Allow generic PM domains to have multiple masters
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:50   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:50 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Currently, for a given generic PM domain there may be only one parent
domain (i.e. a PM domain it depends on).  However, there is at least
one real-life case in which there should be two parents (masters) for
one PM domain (the A3RV domain on SH7372 turns out to depend on the
A4LC domain and it depends on the A4R domain and the same time). For
this reason, allow a PM domain to have multiple parents (masters) by
introducing objects representing links between PM domains.

The (logical) links between PM domains represent relationships in
which one domain is a master (i.e. it is depended on) and another
domain is a slave (i.e. it depends on the master) with the rule that
the slave cannot be powered on if the master is not powered on and
the master cannot be powered off if the slave is not powered off.
Each struct generic_pm_domain object representing a PM domain has
two lists of links, a list of links in which it is a master and
a list of links in which it is a slave.  The first of these lists
replaces the list of subdomains and the second one is used in place
of the parent pointer.

Each link is represented by struct gpd_link object containing
pointers to the master and the slave and two struct list_head
members allowing it to hook into two lists (the master's list
of "master" links and the slave's list of "slave" links).  This
allows the code to get to the link from each side (either from
the master or from the slave) and follow it in each direction.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   99 +++++++++++++++++++++++++-------------------
 include/linux/pm_domain.h   |   12 ++++-
 2 files changed, 67 insertions(+), 44 deletions(-)

Index: linux-2.6/include/linux/pm_domain.h
=================================--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -26,9 +26,8 @@ struct dev_power_governor {
 struct generic_pm_domain {
 	struct dev_pm_domain domain;	/* PM domain operations */
 	struct list_head gpd_list_node;	/* Node in the global PM domains list */
-	struct list_head sd_node;	/* Node in the parent's subdomain list */
-	struct generic_pm_domain *parent;	/* Parent PM domain */
-	struct list_head sd_list;	/* List of dubdomains */
+	struct list_head master_links;	/* Links with PM domain as a master */
+	struct list_head slave_links;	/* Links with PM domain as a slave */
 	struct list_head dev_list;	/* List of devices */
 	struct mutex lock;
 	struct dev_power_governor *gov;
@@ -55,6 +54,13 @@ static inline struct generic_pm_domain *
 	return container_of(pd, struct generic_pm_domain, domain);
 }
 
+struct gpd_link {
+	struct generic_pm_domain *master;
+	struct list_head master_node;
+	struct generic_pm_domain *slave;
+	struct list_head slave_node;
+};
+
 struct dev_list_entry {
 	struct list_head node;
 	struct device *dev;
Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -81,19 +81,20 @@ static void genpd_set_active(struct gene
 }
 
 /**
- * __pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  *
- * Restore power to @genpd and all of its parents so that it is possible to
+ * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
 int __pm_genpd_poweron(struct generic_pm_domain *genpd)
 	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
+	struct gpd_link *link;
 	DEFINE_WAIT(wait);
 	int ret = 0;
 
-	/* If the domain's parent is being waited for, we have to wait too. */
+	/* If the domain's master is being waited for, we have to wait too. */
 	for (;;) {
 		prepare_to_wait(&genpd->status_wait_queue, &wait,
 				TASK_UNINTERRUPTIBLE);
@@ -116,24 +117,31 @@ int __pm_genpd_poweron(struct generic_pm
 		return 0;
 	}
 
-	if (genpd->parent) {
-		genpd_sd_counter_inc(genpd->parent);
+	/*
+	 * The list is guaranteed not to change while the loop below is being
+	 * executed, unless one of the masters' .power_on() callbacks fiddles
+	 * with it.
+	 */
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_inc(link->master);
 		genpd->status = GPD_STATE_WAIT_PARENT;
 
 		mutex_unlock(&genpd->lock);
 
-		ret = pm_genpd_poweron(genpd->parent);
+		ret = pm_genpd_poweron(link->master);
 
 		mutex_lock(&genpd->lock);
 
 		/*
 		 * The "wait for parent" status is guaranteed not to change
-		 * while the parent is powering on.
+		 * while the master is powering on.
 		 */
 		genpd->status = GPD_STATE_POWER_OFF;
 		wake_up_all(&genpd->status_wait_queue);
-		if (ret)
+		if (ret) {
+			genpd_sd_counter_dec(link->master);
 			goto err;
+		}
 	}
 
 	if (genpd->power_on) {
@@ -147,14 +155,14 @@ int __pm_genpd_poweron(struct generic_pm
 	return 0;
 
  err:
-	if (genpd->parent)
-		genpd_sd_counter_dec(genpd->parent);
+	list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node)
+		genpd_sd_counter_dec(link->master);
 
 	return ret;
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  */
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
@@ -278,8 +286,8 @@ void genpd_queue_power_off_work(struct g
 static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
 	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
-	struct generic_pm_domain *parent;
 	struct dev_list_entry *dle;
+	struct gpd_link *link;
 	unsigned int not_suspended;
 	int ret = 0;
 
@@ -287,7 +295,7 @@ static int pm_genpd_poweroff(struct gene
 	/*
 	 * Do not try to power off the domain in the following situations:
 	 * (1) The domain is already in the "power off" state.
-	 * (2) The domain is waiting for its parent to power up.
+	 * (2) The domain is waiting for its master to power up.
 	 * (3) One of the domain's devices is being resumed right now.
 	 * (4) System suspend is in progress.
 	 */
@@ -349,8 +357,8 @@ static int pm_genpd_poweroff(struct gene
 		}
 
 		/*
-		 * If sd_count > 0 at this point, one of the children hasn't
-		 * managed to call pm_genpd_poweron() for the parent yet after
+		 * If sd_count > 0 at this point, one of the subdomains hasn't
+		 * managed to call pm_genpd_poweron() for the master yet after
 		 * incrementing it.  In that case pm_genpd_poweron() will wait
 		 * for us to drop the lock, so we can call .power_off() and let
 		 * the pm_genpd_poweron() restore power for us (this shouldn't
@@ -365,9 +373,10 @@ static int pm_genpd_poweroff(struct gene
 
 	genpd->status = GPD_STATE_POWER_OFF;
 
-	parent = genpd->parent;
-	if (parent && genpd_sd_counter_dec(parent))
-		genpd_queue_power_off_work(parent);
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_dec(link->master);
+		genpd_queue_power_off_work(link->master);
+	}
 
  out:
 	genpd->poweroff_task = NULL;
@@ -512,11 +521,11 @@ static inline void __pm_genpd_runtime_re
 #ifdef CONFIG_PM_SLEEP
 
 /**
- * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its parents.
+ * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
  * @genpd: PM domain to power off, if possible.
  *
  * Check if the given PM domain can be powered off (during system suspend or
- * hibernation) and do that if so.  Also, in that case propagate to its parent.
+ * hibernation) and do that if so.  Also, in that case propagate to its masters.
  *
  * This function is only called in "noirq" stages of system power transitions,
  * so it need not acquire locks (all of the "noirq" callbacks are executed
@@ -524,7 +533,7 @@ static inline void __pm_genpd_runtime_re
  */
 static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
 {
-	struct generic_pm_domain *parent = genpd->parent;
+	struct gpd_link *link;
 
 	if (genpd->status = GPD_STATE_POWER_OFF)
 		return;
@@ -537,9 +546,10 @@ static void pm_genpd_sync_poweroff(struc
 		genpd->power_off(genpd);
 
 	genpd->status = GPD_STATE_POWER_OFF;
-	if (parent) {
-		genpd_sd_counter_dec(parent);
-		pm_genpd_sync_poweroff(parent);
+
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_dec(link->master);
+		pm_genpd_sync_poweroff(link->master);
 	}
 }
 
@@ -1158,7 +1168,7 @@ int pm_genpd_remove_device(struct generi
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 			   struct generic_pm_domain *new_subdomain)
 {
-	struct generic_pm_domain *subdomain;
+	struct gpd_link *link;
 	int ret = 0;
 
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
@@ -1181,16 +1191,23 @@ int pm_genpd_add_subdomain(struct generi
 		goto out;
 	}
 
-	list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-		if (subdomain = new_subdomain) {
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		if (link->slave = new_subdomain && link->master = genpd) {
 			ret = -EINVAL;
 			goto out;
 		}
 	}
 
-	list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
-	new_subdomain->parent = genpd;
-	if (subdomain->status != GPD_STATE_POWER_OFF)
+	link = kzalloc(sizeof(*link), GFP_KERNEL);
+	if (!link) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	link->master = genpd;
+	list_add_tail(&link->master_node, &genpd->master_links);
+	link->slave = new_subdomain;
+	list_add_tail(&link->slave_node, &new_subdomain->slave_links);
+	if (new_subdomain->status != GPD_STATE_POWER_OFF)
 		genpd_sd_counter_inc(genpd);
 
  out:
@@ -1203,22 +1220,22 @@ int pm_genpd_add_subdomain(struct generi
 /**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
  * @genpd: Master PM domain to remove the subdomain from.
- * @target: Subdomain to be removed.
+ * @subdomain: Subdomain to be removed.
  */
 int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
-			      struct generic_pm_domain *target)
+			      struct generic_pm_domain *subdomain)
 {
-	struct generic_pm_domain *subdomain;
+	struct gpd_link *link;
 	int ret = -EINVAL;
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
  start:
 	genpd_acquire_lock(genpd);
 
-	list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-		if (subdomain != target)
+	list_for_each_entry(link, &genpd->master_links, master_node) {
+		if (link->slave != subdomain)
 			continue;
 
 		mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
@@ -1230,8 +1247,9 @@ int pm_genpd_remove_subdomain(struct gen
 			goto start;
 		}
 
-		list_del(&subdomain->sd_node);
-		subdomain->parent = NULL;
+		list_del(&link->master_node);
+		list_del(&link->slave_node);
+		kfree(link);
 		if (subdomain->status != GPD_STATE_POWER_OFF)
 			genpd_sd_counter_dec(genpd);
 
@@ -1258,10 +1276,9 @@ void pm_genpd_init(struct generic_pm_dom
 	if (IS_ERR_OR_NULL(genpd))
 		return;
 
-	INIT_LIST_HEAD(&genpd->sd_node);
-	genpd->parent = NULL;
+	INIT_LIST_HEAD(&genpd->master_links);
+	INIT_LIST_HEAD(&genpd->slave_links);
 	INIT_LIST_HEAD(&genpd->dev_list);
-	INIT_LIST_HEAD(&genpd->sd_list);
 	mutex_init(&genpd->lock);
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 6/9] PM / Domains: Allow generic PM domains to have multiple masters
@ 2011-07-31 17:50   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:50 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Currently, for a given generic PM domain there may be only one parent
domain (i.e. a PM domain it depends on).  However, there is at least
one real-life case in which there should be two parents (masters) for
one PM domain (the A3RV domain on SH7372 turns out to depend on the
A4LC domain and it depends on the A4R domain and the same time). For
this reason, allow a PM domain to have multiple parents (masters) by
introducing objects representing links between PM domains.

The (logical) links between PM domains represent relationships in
which one domain is a master (i.e. it is depended on) and another
domain is a slave (i.e. it depends on the master) with the rule that
the slave cannot be powered on if the master is not powered on and
the master cannot be powered off if the slave is not powered off.
Each struct generic_pm_domain object representing a PM domain has
two lists of links, a list of links in which it is a master and
a list of links in which it is a slave.  The first of these lists
replaces the list of subdomains and the second one is used in place
of the parent pointer.

Each link is represented by struct gpd_link object containing
pointers to the master and the slave and two struct list_head
members allowing it to hook into two lists (the master's list
of "master" links and the slave's list of "slave" links).  This
allows the code to get to the link from each side (either from
the master or from the slave) and follow it in each direction.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   99 +++++++++++++++++++++++++-------------------
 include/linux/pm_domain.h   |   12 ++++-
 2 files changed, 67 insertions(+), 44 deletions(-)

Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -26,9 +26,8 @@ struct dev_power_governor {
 struct generic_pm_domain {
 	struct dev_pm_domain domain;	/* PM domain operations */
 	struct list_head gpd_list_node;	/* Node in the global PM domains list */
-	struct list_head sd_node;	/* Node in the parent's subdomain list */
-	struct generic_pm_domain *parent;	/* Parent PM domain */
-	struct list_head sd_list;	/* List of dubdomains */
+	struct list_head master_links;	/* Links with PM domain as a master */
+	struct list_head slave_links;	/* Links with PM domain as a slave */
 	struct list_head dev_list;	/* List of devices */
 	struct mutex lock;
 	struct dev_power_governor *gov;
@@ -55,6 +54,13 @@ static inline struct generic_pm_domain *
 	return container_of(pd, struct generic_pm_domain, domain);
 }
 
+struct gpd_link {
+	struct generic_pm_domain *master;
+	struct list_head master_node;
+	struct generic_pm_domain *slave;
+	struct list_head slave_node;
+};
+
 struct dev_list_entry {
 	struct list_head node;
 	struct device *dev;
Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -81,19 +81,20 @@ static void genpd_set_active(struct gene
 }
 
 /**
- * __pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  *
- * Restore power to @genpd and all of its parents so that it is possible to
+ * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
 int __pm_genpd_poweron(struct generic_pm_domain *genpd)
 	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
+	struct gpd_link *link;
 	DEFINE_WAIT(wait);
 	int ret = 0;
 
-	/* If the domain's parent is being waited for, we have to wait too. */
+	/* If the domain's master is being waited for, we have to wait too. */
 	for (;;) {
 		prepare_to_wait(&genpd->status_wait_queue, &wait,
 				TASK_UNINTERRUPTIBLE);
@@ -116,24 +117,31 @@ int __pm_genpd_poweron(struct generic_pm
 		return 0;
 	}
 
-	if (genpd->parent) {
-		genpd_sd_counter_inc(genpd->parent);
+	/*
+	 * The list is guaranteed not to change while the loop below is being
+	 * executed, unless one of the masters' .power_on() callbacks fiddles
+	 * with it.
+	 */
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_inc(link->master);
 		genpd->status = GPD_STATE_WAIT_PARENT;
 
 		mutex_unlock(&genpd->lock);
 
-		ret = pm_genpd_poweron(genpd->parent);
+		ret = pm_genpd_poweron(link->master);
 
 		mutex_lock(&genpd->lock);
 
 		/*
 		 * The "wait for parent" status is guaranteed not to change
-		 * while the parent is powering on.
+		 * while the master is powering on.
 		 */
 		genpd->status = GPD_STATE_POWER_OFF;
 		wake_up_all(&genpd->status_wait_queue);
-		if (ret)
+		if (ret) {
+			genpd_sd_counter_dec(link->master);
 			goto err;
+		}
 	}
 
 	if (genpd->power_on) {
@@ -147,14 +155,14 @@ int __pm_genpd_poweron(struct generic_pm
 	return 0;
 
  err:
-	if (genpd->parent)
-		genpd_sd_counter_dec(genpd->parent);
+	list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node)
+		genpd_sd_counter_dec(link->master);
 
 	return ret;
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  */
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
@@ -278,8 +286,8 @@ void genpd_queue_power_off_work(struct g
 static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
 	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
-	struct generic_pm_domain *parent;
 	struct dev_list_entry *dle;
+	struct gpd_link *link;
 	unsigned int not_suspended;
 	int ret = 0;
 
@@ -287,7 +295,7 @@ static int pm_genpd_poweroff(struct gene
 	/*
 	 * Do not try to power off the domain in the following situations:
 	 * (1) The domain is already in the "power off" state.
-	 * (2) The domain is waiting for its parent to power up.
+	 * (2) The domain is waiting for its master to power up.
 	 * (3) One of the domain's devices is being resumed right now.
 	 * (4) System suspend is in progress.
 	 */
@@ -349,8 +357,8 @@ static int pm_genpd_poweroff(struct gene
 		}
 
 		/*
-		 * If sd_count > 0 at this point, one of the children hasn't
-		 * managed to call pm_genpd_poweron() for the parent yet after
+		 * If sd_count > 0 at this point, one of the subdomains hasn't
+		 * managed to call pm_genpd_poweron() for the master yet after
 		 * incrementing it.  In that case pm_genpd_poweron() will wait
 		 * for us to drop the lock, so we can call .power_off() and let
 		 * the pm_genpd_poweron() restore power for us (this shouldn't
@@ -365,9 +373,10 @@ static int pm_genpd_poweroff(struct gene
 
 	genpd->status = GPD_STATE_POWER_OFF;
 
-	parent = genpd->parent;
-	if (parent && genpd_sd_counter_dec(parent))
-		genpd_queue_power_off_work(parent);
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_dec(link->master);
+		genpd_queue_power_off_work(link->master);
+	}
 
  out:
 	genpd->poweroff_task = NULL;
@@ -512,11 +521,11 @@ static inline void __pm_genpd_runtime_re
 #ifdef CONFIG_PM_SLEEP
 
 /**
- * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its parents.
+ * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
  * @genpd: PM domain to power off, if possible.
  *
  * Check if the given PM domain can be powered off (during system suspend or
- * hibernation) and do that if so.  Also, in that case propagate to its parent.
+ * hibernation) and do that if so.  Also, in that case propagate to its masters.
  *
  * This function is only called in "noirq" stages of system power transitions,
  * so it need not acquire locks (all of the "noirq" callbacks are executed
@@ -524,7 +533,7 @@ static inline void __pm_genpd_runtime_re
  */
 static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
 {
-	struct generic_pm_domain *parent = genpd->parent;
+	struct gpd_link *link;
 
 	if (genpd->status == GPD_STATE_POWER_OFF)
 		return;
@@ -537,9 +546,10 @@ static void pm_genpd_sync_poweroff(struc
 		genpd->power_off(genpd);
 
 	genpd->status = GPD_STATE_POWER_OFF;
-	if (parent) {
-		genpd_sd_counter_dec(parent);
-		pm_genpd_sync_poweroff(parent);
+
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_dec(link->master);
+		pm_genpd_sync_poweroff(link->master);
 	}
 }
 
@@ -1158,7 +1168,7 @@ int pm_genpd_remove_device(struct generi
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 			   struct generic_pm_domain *new_subdomain)
 {
-	struct generic_pm_domain *subdomain;
+	struct gpd_link *link;
 	int ret = 0;
 
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
@@ -1181,16 +1191,23 @@ int pm_genpd_add_subdomain(struct generi
 		goto out;
 	}
 
-	list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-		if (subdomain == new_subdomain) {
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		if (link->slave == new_subdomain && link->master == genpd) {
 			ret = -EINVAL;
 			goto out;
 		}
 	}
 
-	list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
-	new_subdomain->parent = genpd;
-	if (subdomain->status != GPD_STATE_POWER_OFF)
+	link = kzalloc(sizeof(*link), GFP_KERNEL);
+	if (!link) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	link->master = genpd;
+	list_add_tail(&link->master_node, &genpd->master_links);
+	link->slave = new_subdomain;
+	list_add_tail(&link->slave_node, &new_subdomain->slave_links);
+	if (new_subdomain->status != GPD_STATE_POWER_OFF)
 		genpd_sd_counter_inc(genpd);
 
  out:
@@ -1203,22 +1220,22 @@ int pm_genpd_add_subdomain(struct generi
 /**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
  * @genpd: Master PM domain to remove the subdomain from.
- * @target: Subdomain to be removed.
+ * @subdomain: Subdomain to be removed.
  */
 int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
-			      struct generic_pm_domain *target)
+			      struct generic_pm_domain *subdomain)
 {
-	struct generic_pm_domain *subdomain;
+	struct gpd_link *link;
 	int ret = -EINVAL;
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
  start:
 	genpd_acquire_lock(genpd);
 
-	list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-		if (subdomain != target)
+	list_for_each_entry(link, &genpd->master_links, master_node) {
+		if (link->slave != subdomain)
 			continue;
 
 		mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
@@ -1230,8 +1247,9 @@ int pm_genpd_remove_subdomain(struct gen
 			goto start;
 		}
 
-		list_del(&subdomain->sd_node);
-		subdomain->parent = NULL;
+		list_del(&link->master_node);
+		list_del(&link->slave_node);
+		kfree(link);
 		if (subdomain->status != GPD_STATE_POWER_OFF)
 			genpd_sd_counter_dec(genpd);
 
@@ -1258,10 +1276,9 @@ void pm_genpd_init(struct generic_pm_dom
 	if (IS_ERR_OR_NULL(genpd))
 		return;
 
-	INIT_LIST_HEAD(&genpd->sd_node);
-	genpd->parent = NULL;
+	INIT_LIST_HEAD(&genpd->master_links);
+	INIT_LIST_HEAD(&genpd->slave_links);
 	INIT_LIST_HEAD(&genpd->dev_list);
-	INIT_LIST_HEAD(&genpd->sd_list);
 	mutex_init(&genpd->lock);
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 6/9] PM / Domains: Allow generic PM domains to have multiple masters
  2011-07-31 17:46 ` Rafael J. Wysocki
                   ` (9 preceding siblings ...)
  (?)
@ 2011-07-31 17:50 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:50 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Currently, for a given generic PM domain there may be only one parent
domain (i.e. a PM domain it depends on).  However, there is at least
one real-life case in which there should be two parents (masters) for
one PM domain (the A3RV domain on SH7372 turns out to depend on the
A4LC domain and it depends on the A4R domain and the same time). For
this reason, allow a PM domain to have multiple parents (masters) by
introducing objects representing links between PM domains.

The (logical) links between PM domains represent relationships in
which one domain is a master (i.e. it is depended on) and another
domain is a slave (i.e. it depends on the master) with the rule that
the slave cannot be powered on if the master is not powered on and
the master cannot be powered off if the slave is not powered off.
Each struct generic_pm_domain object representing a PM domain has
two lists of links, a list of links in which it is a master and
a list of links in which it is a slave.  The first of these lists
replaces the list of subdomains and the second one is used in place
of the parent pointer.

Each link is represented by struct gpd_link object containing
pointers to the master and the slave and two struct list_head
members allowing it to hook into two lists (the master's list
of "master" links and the slave's list of "slave" links).  This
allows the code to get to the link from each side (either from
the master or from the slave) and follow it in each direction.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   99 +++++++++++++++++++++++++-------------------
 include/linux/pm_domain.h   |   12 ++++-
 2 files changed, 67 insertions(+), 44 deletions(-)

Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -26,9 +26,8 @@ struct dev_power_governor {
 struct generic_pm_domain {
 	struct dev_pm_domain domain;	/* PM domain operations */
 	struct list_head gpd_list_node;	/* Node in the global PM domains list */
-	struct list_head sd_node;	/* Node in the parent's subdomain list */
-	struct generic_pm_domain *parent;	/* Parent PM domain */
-	struct list_head sd_list;	/* List of dubdomains */
+	struct list_head master_links;	/* Links with PM domain as a master */
+	struct list_head slave_links;	/* Links with PM domain as a slave */
 	struct list_head dev_list;	/* List of devices */
 	struct mutex lock;
 	struct dev_power_governor *gov;
@@ -55,6 +54,13 @@ static inline struct generic_pm_domain *
 	return container_of(pd, struct generic_pm_domain, domain);
 }
 
+struct gpd_link {
+	struct generic_pm_domain *master;
+	struct list_head master_node;
+	struct generic_pm_domain *slave;
+	struct list_head slave_node;
+};
+
 struct dev_list_entry {
 	struct list_head node;
 	struct device *dev;
Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -81,19 +81,20 @@ static void genpd_set_active(struct gene
 }
 
 /**
- * __pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  *
- * Restore power to @genpd and all of its parents so that it is possible to
+ * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
 int __pm_genpd_poweron(struct generic_pm_domain *genpd)
 	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
+	struct gpd_link *link;
 	DEFINE_WAIT(wait);
 	int ret = 0;
 
-	/* If the domain's parent is being waited for, we have to wait too. */
+	/* If the domain's master is being waited for, we have to wait too. */
 	for (;;) {
 		prepare_to_wait(&genpd->status_wait_queue, &wait,
 				TASK_UNINTERRUPTIBLE);
@@ -116,24 +117,31 @@ int __pm_genpd_poweron(struct generic_pm
 		return 0;
 	}
 
-	if (genpd->parent) {
-		genpd_sd_counter_inc(genpd->parent);
+	/*
+	 * The list is guaranteed not to change while the loop below is being
+	 * executed, unless one of the masters' .power_on() callbacks fiddles
+	 * with it.
+	 */
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_inc(link->master);
 		genpd->status = GPD_STATE_WAIT_PARENT;
 
 		mutex_unlock(&genpd->lock);
 
-		ret = pm_genpd_poweron(genpd->parent);
+		ret = pm_genpd_poweron(link->master);
 
 		mutex_lock(&genpd->lock);
 
 		/*
 		 * The "wait for parent" status is guaranteed not to change
-		 * while the parent is powering on.
+		 * while the master is powering on.
 		 */
 		genpd->status = GPD_STATE_POWER_OFF;
 		wake_up_all(&genpd->status_wait_queue);
-		if (ret)
+		if (ret) {
+			genpd_sd_counter_dec(link->master);
 			goto err;
+		}
 	}
 
 	if (genpd->power_on) {
@@ -147,14 +155,14 @@ int __pm_genpd_poweron(struct generic_pm
 	return 0;
 
  err:
-	if (genpd->parent)
-		genpd_sd_counter_dec(genpd->parent);
+	list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node)
+		genpd_sd_counter_dec(link->master);
 
 	return ret;
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  */
 int pm_genpd_poweron(struct generic_pm_domain *genpd)
@@ -278,8 +286,8 @@ void genpd_queue_power_off_work(struct g
 static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
 	__releases(&genpd->lock) __acquires(&genpd->lock)
 {
-	struct generic_pm_domain *parent;
 	struct dev_list_entry *dle;
+	struct gpd_link *link;
 	unsigned int not_suspended;
 	int ret = 0;
 
@@ -287,7 +295,7 @@ static int pm_genpd_poweroff(struct gene
 	/*
 	 * Do not try to power off the domain in the following situations:
 	 * (1) The domain is already in the "power off" state.
-	 * (2) The domain is waiting for its parent to power up.
+	 * (2) The domain is waiting for its master to power up.
 	 * (3) One of the domain's devices is being resumed right now.
 	 * (4) System suspend is in progress.
 	 */
@@ -349,8 +357,8 @@ static int pm_genpd_poweroff(struct gene
 		}
 
 		/*
-		 * If sd_count > 0 at this point, one of the children hasn't
-		 * managed to call pm_genpd_poweron() for the parent yet after
+		 * If sd_count > 0 at this point, one of the subdomains hasn't
+		 * managed to call pm_genpd_poweron() for the master yet after
 		 * incrementing it.  In that case pm_genpd_poweron() will wait
 		 * for us to drop the lock, so we can call .power_off() and let
 		 * the pm_genpd_poweron() restore power for us (this shouldn't
@@ -365,9 +373,10 @@ static int pm_genpd_poweroff(struct gene
 
 	genpd->status = GPD_STATE_POWER_OFF;
 
-	parent = genpd->parent;
-	if (parent && genpd_sd_counter_dec(parent))
-		genpd_queue_power_off_work(parent);
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_dec(link->master);
+		genpd_queue_power_off_work(link->master);
+	}
 
  out:
 	genpd->poweroff_task = NULL;
@@ -512,11 +521,11 @@ static inline void __pm_genpd_runtime_re
 #ifdef CONFIG_PM_SLEEP
 
 /**
- * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its parents.
+ * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
  * @genpd: PM domain to power off, if possible.
  *
  * Check if the given PM domain can be powered off (during system suspend or
- * hibernation) and do that if so.  Also, in that case propagate to its parent.
+ * hibernation) and do that if so.  Also, in that case propagate to its masters.
  *
  * This function is only called in "noirq" stages of system power transitions,
  * so it need not acquire locks (all of the "noirq" callbacks are executed
@@ -524,7 +533,7 @@ static inline void __pm_genpd_runtime_re
  */
 static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
 {
-	struct generic_pm_domain *parent = genpd->parent;
+	struct gpd_link *link;
 
 	if (genpd->status == GPD_STATE_POWER_OFF)
 		return;
@@ -537,9 +546,10 @@ static void pm_genpd_sync_poweroff(struc
 		genpd->power_off(genpd);
 
 	genpd->status = GPD_STATE_POWER_OFF;
-	if (parent) {
-		genpd_sd_counter_dec(parent);
-		pm_genpd_sync_poweroff(parent);
+
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_dec(link->master);
+		pm_genpd_sync_poweroff(link->master);
 	}
 }
 
@@ -1158,7 +1168,7 @@ int pm_genpd_remove_device(struct generi
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 			   struct generic_pm_domain *new_subdomain)
 {
-	struct generic_pm_domain *subdomain;
+	struct gpd_link *link;
 	int ret = 0;
 
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
@@ -1181,16 +1191,23 @@ int pm_genpd_add_subdomain(struct generi
 		goto out;
 	}
 
-	list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-		if (subdomain == new_subdomain) {
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		if (link->slave == new_subdomain && link->master == genpd) {
 			ret = -EINVAL;
 			goto out;
 		}
 	}
 
-	list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
-	new_subdomain->parent = genpd;
-	if (subdomain->status != GPD_STATE_POWER_OFF)
+	link = kzalloc(sizeof(*link), GFP_KERNEL);
+	if (!link) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	link->master = genpd;
+	list_add_tail(&link->master_node, &genpd->master_links);
+	link->slave = new_subdomain;
+	list_add_tail(&link->slave_node, &new_subdomain->slave_links);
+	if (new_subdomain->status != GPD_STATE_POWER_OFF)
 		genpd_sd_counter_inc(genpd);
 
  out:
@@ -1203,22 +1220,22 @@ int pm_genpd_add_subdomain(struct generi
 /**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
  * @genpd: Master PM domain to remove the subdomain from.
- * @target: Subdomain to be removed.
+ * @subdomain: Subdomain to be removed.
  */
 int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
-			      struct generic_pm_domain *target)
+			      struct generic_pm_domain *subdomain)
 {
-	struct generic_pm_domain *subdomain;
+	struct gpd_link *link;
 	int ret = -EINVAL;
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
  start:
 	genpd_acquire_lock(genpd);
 
-	list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-		if (subdomain != target)
+	list_for_each_entry(link, &genpd->master_links, master_node) {
+		if (link->slave != subdomain)
 			continue;
 
 		mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
@@ -1230,8 +1247,9 @@ int pm_genpd_remove_subdomain(struct gen
 			goto start;
 		}
 
-		list_del(&subdomain->sd_node);
-		subdomain->parent = NULL;
+		list_del(&link->master_node);
+		list_del(&link->slave_node);
+		kfree(link);
 		if (subdomain->status != GPD_STATE_POWER_OFF)
 			genpd_sd_counter_dec(genpd);
 
@@ -1258,10 +1276,9 @@ void pm_genpd_init(struct generic_pm_dom
 	if (IS_ERR_OR_NULL(genpd))
 		return;
 
-	INIT_LIST_HEAD(&genpd->sd_node);
-	genpd->parent = NULL;
+	INIT_LIST_HEAD(&genpd->master_links);
+	INIT_LIST_HEAD(&genpd->slave_links);
 	INIT_LIST_HEAD(&genpd->dev_list);
-	INIT_LIST_HEAD(&genpd->sd_list);
 	mutex_init(&genpd->lock);
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 7/9] PM / Domains: Rename GPD_STATE_WAIT_PARENT to GPD_STATE_WAIT_MASTER
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:51   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:51 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Since it is now possible for a PM domain to have multiple masters
instead of one parent, rename the "wait for parent" status to reflect
the new situation.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   34 +++++++++++++++++-----------------
 include/linux/pm_domain.h   |    2 +-
 2 files changed, 18 insertions(+), 18 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -98,7 +98,7 @@ int __pm_genpd_poweron(struct generic_pm
 	for (;;) {
 		prepare_to_wait(&genpd->status_wait_queue, &wait,
 				TASK_UNINTERRUPTIBLE);
-		if (genpd->status != GPD_STATE_WAIT_PARENT)
+		if (genpd->status != GPD_STATE_WAIT_MASTER)
 			break;
 		mutex_unlock(&genpd->lock);
 
@@ -124,7 +124,7 @@ int __pm_genpd_poweron(struct generic_pm
 	 */
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
 		genpd_sd_counter_inc(link->master);
-		genpd->status = GPD_STATE_WAIT_PARENT;
+		genpd->status = GPD_STATE_WAIT_MASTER;
 
 		mutex_unlock(&genpd->lock);
 
@@ -258,7 +258,7 @@ static void __pm_genpd_restore_device(st
  */
 static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
 {
-	return genpd->status = GPD_STATE_WAIT_PARENT
+	return genpd->status = GPD_STATE_WAIT_MASTER
 		|| genpd->status = GPD_STATE_ACTIVE || genpd->resume_count > 0;
 }
 
@@ -300,7 +300,7 @@ static int pm_genpd_poweroff(struct gene
 	 * (4) System suspend is in progress.
 	 */
 	if (genpd->status = GPD_STATE_POWER_OFF
-	    || genpd->status = GPD_STATE_WAIT_PARENT
+	    || genpd->status = GPD_STATE_WAIT_MASTER
 	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
 		return 0;
 
Index: linux-2.6/include/linux/pm_domain.h
=================================--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -13,7 +13,7 @@
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
-	GPD_STATE_WAIT_PARENT,	/* PM domain's parent is being waited for */
+	GPD_STATE_WAIT_MASTER,	/* PM domain's master is being waited for */
 	GPD_STATE_BUSY,		/* Something is happening to the PM domain */
 	GPD_STATE_REPEAT,	/* Power off in progress, to be repeated */
 	GPD_STATE_POWER_OFF,	/* PM domain is off */


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 7/9] PM / Domains: Rename GPD_STATE_WAIT_PARENT to GPD_STATE_WAIT_MASTER
@ 2011-07-31 17:51   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:51 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Since it is now possible for a PM domain to have multiple masters
instead of one parent, rename the "wait for parent" status to reflect
the new situation.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   34 +++++++++++++++++-----------------
 include/linux/pm_domain.h   |    2 +-
 2 files changed, 18 insertions(+), 18 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -98,7 +98,7 @@ int __pm_genpd_poweron(struct generic_pm
 	for (;;) {
 		prepare_to_wait(&genpd->status_wait_queue, &wait,
 				TASK_UNINTERRUPTIBLE);
-		if (genpd->status != GPD_STATE_WAIT_PARENT)
+		if (genpd->status != GPD_STATE_WAIT_MASTER)
 			break;
 		mutex_unlock(&genpd->lock);
 
@@ -124,7 +124,7 @@ int __pm_genpd_poweron(struct generic_pm
 	 */
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
 		genpd_sd_counter_inc(link->master);
-		genpd->status = GPD_STATE_WAIT_PARENT;
+		genpd->status = GPD_STATE_WAIT_MASTER;
 
 		mutex_unlock(&genpd->lock);
 
@@ -258,7 +258,7 @@ static void __pm_genpd_restore_device(st
  */
 static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
 {
-	return genpd->status == GPD_STATE_WAIT_PARENT
+	return genpd->status == GPD_STATE_WAIT_MASTER
 		|| genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
 }
 
@@ -300,7 +300,7 @@ static int pm_genpd_poweroff(struct gene
 	 * (4) System suspend is in progress.
 	 */
 	if (genpd->status == GPD_STATE_POWER_OFF
-	    || genpd->status == GPD_STATE_WAIT_PARENT
+	    || genpd->status == GPD_STATE_WAIT_MASTER
 	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
 		return 0;
 
Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -13,7 +13,7 @@
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
-	GPD_STATE_WAIT_PARENT,	/* PM domain's parent is being waited for */
+	GPD_STATE_WAIT_MASTER,	/* PM domain's master is being waited for */
 	GPD_STATE_BUSY,		/* Something is happening to the PM domain */
 	GPD_STATE_REPEAT,	/* Power off in progress, to be repeated */
 	GPD_STATE_POWER_OFF,	/* PM domain is off */


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 7/9] PM / Domains: Rename GPD_STATE_WAIT_PARENT to GPD_STATE_WAIT_MASTER
  2011-07-31 17:46 ` Rafael J. Wysocki
                   ` (12 preceding siblings ...)
  (?)
@ 2011-07-31 17:51 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:51 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Since it is now possible for a PM domain to have multiple masters
instead of one parent, rename the "wait for parent" status to reflect
the new situation.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   34 +++++++++++++++++-----------------
 include/linux/pm_domain.h   |    2 +-
 2 files changed, 18 insertions(+), 18 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -98,7 +98,7 @@ int __pm_genpd_poweron(struct generic_pm
 	for (;;) {
 		prepare_to_wait(&genpd->status_wait_queue, &wait,
 				TASK_UNINTERRUPTIBLE);
-		if (genpd->status != GPD_STATE_WAIT_PARENT)
+		if (genpd->status != GPD_STATE_WAIT_MASTER)
 			break;
 		mutex_unlock(&genpd->lock);
 
@@ -124,7 +124,7 @@ int __pm_genpd_poweron(struct generic_pm
 	 */
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
 		genpd_sd_counter_inc(link->master);
-		genpd->status = GPD_STATE_WAIT_PARENT;
+		genpd->status = GPD_STATE_WAIT_MASTER;
 
 		mutex_unlock(&genpd->lock);
 
@@ -258,7 +258,7 @@ static void __pm_genpd_restore_device(st
  */
 static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
 {
-	return genpd->status == GPD_STATE_WAIT_PARENT
+	return genpd->status == GPD_STATE_WAIT_MASTER
 		|| genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
 }
 
@@ -300,7 +300,7 @@ static int pm_genpd_poweroff(struct gene
 	 * (4) System suspend is in progress.
 	 */
 	if (genpd->status == GPD_STATE_POWER_OFF
-	    || genpd->status == GPD_STATE_WAIT_PARENT
+	    || genpd->status == GPD_STATE_WAIT_MASTER
 	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
 		return 0;
 
Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -13,7 +13,7 @@
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
-	GPD_STATE_WAIT_PARENT,	/* PM domain's parent is being waited for */
+	GPD_STATE_WAIT_MASTER,	/* PM domain's master is being waited for */
 	GPD_STATE_BUSY,		/* Something is happening to the PM domain */
 	GPD_STATE_REPEAT,	/* Power off in progress, to be repeated */
 	GPD_STATE_POWER_OFF,	/* PM domain is off */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 8/9] PM / Domains: Rename second argument of pm_genpd_add_subdomain()
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:52   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:52 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Change the name of the second argument of pm_genpd_add_subdomain()
so that it is (a) shorter and (b) in agreement with the name of
the second argument of pm_genpd_add_subdomain().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
=================================--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -1163,36 +1163,36 @@ int pm_genpd_remove_device(struct generi
 /**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
  * @genpd: Master PM domain to add the subdomain to.
- * @new_subdomain: Subdomain to be added.
+ * @subdomain: Subdomain to be added.
  */
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
-			   struct generic_pm_domain *new_subdomain)
+			   struct generic_pm_domain *subdomain)
 {
 	struct gpd_link *link;
 	int ret = 0;
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
  start:
 	genpd_acquire_lock(genpd);
-	mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING);
+	mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
 
-	if (new_subdomain->status != GPD_STATE_POWER_OFF
-	    && new_subdomain->status != GPD_STATE_ACTIVE) {
-		mutex_unlock(&new_subdomain->lock);
+	if (subdomain->status != GPD_STATE_POWER_OFF
+	    && subdomain->status != GPD_STATE_ACTIVE) {
+		mutex_unlock(&subdomain->lock);
 		genpd_release_lock(genpd);
 		goto start;
 	}
 
 	if (genpd->status = GPD_STATE_POWER_OFF
-	    &&  new_subdomain->status != GPD_STATE_POWER_OFF) {
+	    &&  subdomain->status != GPD_STATE_POWER_OFF) {
 		ret = -EINVAL;
 		goto out;
 	}
 
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		if (link->slave = new_subdomain && link->master = genpd) {
+		if (link->slave = subdomain && link->master = genpd) {
 			ret = -EINVAL;
 			goto out;
 		}
@@ -1205,13 +1205,13 @@ int pm_genpd_add_subdomain(struct generi
 	}
 	link->master = genpd;
 	list_add_tail(&link->master_node, &genpd->master_links);
-	link->slave = new_subdomain;
-	list_add_tail(&link->slave_node, &new_subdomain->slave_links);
-	if (new_subdomain->status != GPD_STATE_POWER_OFF)
+	link->slave = subdomain;
+	list_add_tail(&link->slave_node, &subdomain->slave_links);
+	if (subdomain->status != GPD_STATE_POWER_OFF)
 		genpd_sd_counter_inc(genpd);
 
  out:
-	mutex_unlock(&new_subdomain->lock);
+	mutex_unlock(&subdomain->lock);
 	genpd_release_lock(genpd);
 
 	return ret;


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 8/9] PM / Domains: Rename second argument of pm_genpd_add_subdomain()
@ 2011-07-31 17:52   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:52 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Change the name of the second argument of pm_genpd_add_subdomain()
so that it is (a) shorter and (b) in agreement with the name of
the second argument of pm_genpd_add_subdomain().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -1163,36 +1163,36 @@ int pm_genpd_remove_device(struct generi
 /**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
  * @genpd: Master PM domain to add the subdomain to.
- * @new_subdomain: Subdomain to be added.
+ * @subdomain: Subdomain to be added.
  */
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
-			   struct generic_pm_domain *new_subdomain)
+			   struct generic_pm_domain *subdomain)
 {
 	struct gpd_link *link;
 	int ret = 0;
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
  start:
 	genpd_acquire_lock(genpd);
-	mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING);
+	mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
 
-	if (new_subdomain->status != GPD_STATE_POWER_OFF
-	    && new_subdomain->status != GPD_STATE_ACTIVE) {
-		mutex_unlock(&new_subdomain->lock);
+	if (subdomain->status != GPD_STATE_POWER_OFF
+	    && subdomain->status != GPD_STATE_ACTIVE) {
+		mutex_unlock(&subdomain->lock);
 		genpd_release_lock(genpd);
 		goto start;
 	}
 
 	if (genpd->status == GPD_STATE_POWER_OFF
-	    &&  new_subdomain->status != GPD_STATE_POWER_OFF) {
+	    &&  subdomain->status != GPD_STATE_POWER_OFF) {
 		ret = -EINVAL;
 		goto out;
 	}
 
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		if (link->slave == new_subdomain && link->master == genpd) {
+		if (link->slave == subdomain && link->master == genpd) {
 			ret = -EINVAL;
 			goto out;
 		}
@@ -1205,13 +1205,13 @@ int pm_genpd_add_subdomain(struct generi
 	}
 	link->master = genpd;
 	list_add_tail(&link->master_node, &genpd->master_links);
-	link->slave = new_subdomain;
-	list_add_tail(&link->slave_node, &new_subdomain->slave_links);
-	if (new_subdomain->status != GPD_STATE_POWER_OFF)
+	link->slave = subdomain;
+	list_add_tail(&link->slave_node, &subdomain->slave_links);
+	if (subdomain->status != GPD_STATE_POWER_OFF)
 		genpd_sd_counter_inc(genpd);
 
  out:
-	mutex_unlock(&new_subdomain->lock);
+	mutex_unlock(&subdomain->lock);
 	genpd_release_lock(genpd);
 
 	return ret;


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 8/9] PM / Domains: Rename second argument of pm_genpd_add_subdomain()
  2011-07-31 17:46 ` Rafael J. Wysocki
                   ` (13 preceding siblings ...)
  (?)
@ 2011-07-31 17:52 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:52 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Change the name of the second argument of pm_genpd_add_subdomain()
so that it is (a) shorter and (b) in agreement with the name of
the second argument of pm_genpd_add_subdomain().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |   26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -1163,36 +1163,36 @@ int pm_genpd_remove_device(struct generi
 /**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
  * @genpd: Master PM domain to add the subdomain to.
- * @new_subdomain: Subdomain to be added.
+ * @subdomain: Subdomain to be added.
  */
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
-			   struct generic_pm_domain *new_subdomain)
+			   struct generic_pm_domain *subdomain)
 {
 	struct gpd_link *link;
 	int ret = 0;
 
-	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
+	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
  start:
 	genpd_acquire_lock(genpd);
-	mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING);
+	mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
 
-	if (new_subdomain->status != GPD_STATE_POWER_OFF
-	    && new_subdomain->status != GPD_STATE_ACTIVE) {
-		mutex_unlock(&new_subdomain->lock);
+	if (subdomain->status != GPD_STATE_POWER_OFF
+	    && subdomain->status != GPD_STATE_ACTIVE) {
+		mutex_unlock(&subdomain->lock);
 		genpd_release_lock(genpd);
 		goto start;
 	}
 
 	if (genpd->status == GPD_STATE_POWER_OFF
-	    &&  new_subdomain->status != GPD_STATE_POWER_OFF) {
+	    &&  subdomain->status != GPD_STATE_POWER_OFF) {
 		ret = -EINVAL;
 		goto out;
 	}
 
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		if (link->slave == new_subdomain && link->master == genpd) {
+		if (link->slave == subdomain && link->master == genpd) {
 			ret = -EINVAL;
 			goto out;
 		}
@@ -1205,13 +1205,13 @@ int pm_genpd_add_subdomain(struct generi
 	}
 	link->master = genpd;
 	list_add_tail(&link->master_node, &genpd->master_links);
-	link->slave = new_subdomain;
-	list_add_tail(&link->slave_node, &new_subdomain->slave_links);
-	if (new_subdomain->status != GPD_STATE_POWER_OFF)
+	link->slave = subdomain;
+	list_add_tail(&link->slave_node, &subdomain->slave_links);
+	if (subdomain->status != GPD_STATE_POWER_OFF)
 		genpd_sd_counter_inc(genpd);
 
  out:
-	mutex_unlock(&new_subdomain->lock);
+	mutex_unlock(&subdomain->lock);
 	genpd_release_lock(genpd);
 
 	return ret;

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
  2011-07-31 17:46 ` Rafael J. Wysocki
@ 2011-07-31 17:52   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:52 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/mach-shmobile/pm-sh7372.c    |   42 +---------------------------------
 arch/arm/mach-shmobile/setup-sh7372.c |    3 ++
 2 files changed, 5 insertions(+), 40 deletions(-)

Index: linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux-2.6.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd = &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd = &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
Index: linux-2.6/arch/arm/mach-shmobile/setup-sh7372.c
=================================--- linux-2.6.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux-2.6/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	pm_genpd_add_subdomain(&sh7372_a4lc.genpd, &sh7372_a3sg.genpd);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
@ 2011-07-31 17:52   ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:52 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/mach-shmobile/pm-sh7372.c    |   42 +---------------------------------
 arch/arm/mach-shmobile/setup-sh7372.c |    3 ++
 2 files changed, 5 insertions(+), 40 deletions(-)

Index: linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd == &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd == &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
Index: linux-2.6/arch/arm/mach-shmobile/setup-sh7372.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux-2.6/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	pm_genpd_add_subdomain(&sh7372_a4lc.genpd, &sh7372_a3sg.genpd);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
  2011-07-31 17:46 ` Rafael J. Wysocki
                   ` (15 preceding siblings ...)
  (?)
@ 2011-07-31 17:52 ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:52 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/mach-shmobile/pm-sh7372.c    |   42 +---------------------------------
 arch/arm/mach-shmobile/setup-sh7372.c |    3 ++
 2 files changed, 5 insertions(+), 40 deletions(-)

Index: linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd == &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd == &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
Index: linux-2.6/arch/arm/mach-shmobile/setup-sh7372.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux-2.6/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	pm_genpd_add_subdomain(&sh7372_a4lc.genpd, &sh7372_a3sg.genpd);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [Update][PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
  2011-07-31 17:52   ` Rafael J. Wysocki
@ 2011-08-13 19:43     ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-08-13 19:43 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---

Well, the patch should actually do what's advertised in the changelog
(ie. make A3RV, _not_ A3SG, a subdomain of A4LC).

---
 arch/arm/mach-shmobile/pm-sh7372.c    |   42 +---------------------------------
 arch/arm/mach-shmobile/setup-sh7372.c |    3 ++
 2 files changed, 5 insertions(+), 40 deletions(-)

Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd = &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd = &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	pm_genpd_add_subdomain(&sh7372_a4lc.genpd, &sh7372_a3rv.genpd);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [Update][PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
@ 2011-08-13 19:43     ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-08-13 19:43 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---

Well, the patch should actually do what's advertised in the changelog
(ie. make A3RV, _not_ A3SG, a subdomain of A4LC).

---
 arch/arm/mach-shmobile/pm-sh7372.c    |   42 +---------------------------------
 arch/arm/mach-shmobile/setup-sh7372.c |    3 ++
 2 files changed, 5 insertions(+), 40 deletions(-)

Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd == &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd == &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	pm_genpd_add_subdomain(&sh7372_a4lc.genpd, &sh7372_a3rv.genpd);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [Update][PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
  2011-07-31 17:52   ` Rafael J. Wysocki
  (?)
  (?)
@ 2011-08-13 19:43   ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-08-13 19:43 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---

Well, the patch should actually do what's advertised in the changelog
(ie. make A3RV, _not_ A3SG, a subdomain of A4LC).

---
 arch/arm/mach-shmobile/pm-sh7372.c    |   42 +---------------------------------
 arch/arm/mach-shmobile/setup-sh7372.c |    3 ++
 2 files changed, 5 insertions(+), 40 deletions(-)

Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd == &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd == &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	pm_genpd_add_subdomain(&sh7372_a4lc.genpd, &sh7372_a3rv.genpd);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [Update x2][PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
  2011-08-13 19:43     ` Rafael J. Wysocki
@ 2011-08-14 14:07       ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-08-14 14:07 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---

It also needs to build for CONFIG_PM unset.

Thanks,
Rafael

---
 arch/arm/mach-shmobile/include/mach/sh7372.h |    3 +
 arch/arm/mach-shmobile/pm-sh7372.c           |   48 ++++-----------------------
 arch/arm/mach-shmobile/setup-sh7372.c        |    3 +
 3 files changed, 14 insertions(+), 40 deletions(-)

Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd = &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd = &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
@@ -159,6 +121,12 @@ void sh7372_add_device_to_domain(struct
 	pm_genpd_add_device(&sh7372_pd->genpd, dev);
 }
 
+void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+			     struct sh7372_pm_domain *sh7372_sd)
+{
+	pm_genpd_add_subdomain(&sh7372_pd->genpd, &sh7372_sd->genpd);
+}
+
 struct sh7372_pm_domain sh7372_a4lc = {
 	.bit_shift = 1,
 };
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 
Index: linux/arch/arm/mach-shmobile/include/mach/sh7372.h
=================================--- linux.orig/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ linux/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -494,9 +494,12 @@ extern struct sh7372_pm_domain sh7372_a3
 extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
 extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
 					struct platform_device *pdev);
+extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+				    struct sh7372_pm_domain *sh7372_sd);
 #else
 #define sh7372_init_pm_domain(pd) do { } while(0)
 #define sh7372_add_device_to_domain(pd, pdev) do { } while(0)
+#define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_SH7372_H__ */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [Update x2][PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
@ 2011-08-14 14:07       ` Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-08-14 14:07 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---

It also needs to build for CONFIG_PM unset.

Thanks,
Rafael

---
 arch/arm/mach-shmobile/include/mach/sh7372.h |    3 +
 arch/arm/mach-shmobile/pm-sh7372.c           |   48 ++++-----------------------
 arch/arm/mach-shmobile/setup-sh7372.c        |    3 +
 3 files changed, 14 insertions(+), 40 deletions(-)

Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd == &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd == &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
@@ -159,6 +121,12 @@ void sh7372_add_device_to_domain(struct
 	pm_genpd_add_device(&sh7372_pd->genpd, dev);
 }
 
+void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+			     struct sh7372_pm_domain *sh7372_sd)
+{
+	pm_genpd_add_subdomain(&sh7372_pd->genpd, &sh7372_sd->genpd);
+}
+
 struct sh7372_pm_domain sh7372_a4lc = {
 	.bit_shift = 1,
 };
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 
Index: linux/arch/arm/mach-shmobile/include/mach/sh7372.h
===================================================================
--- linux.orig/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ linux/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -494,9 +494,12 @@ extern struct sh7372_pm_domain sh7372_a3
 extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
 extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
 					struct platform_device *pdev);
+extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+				    struct sh7372_pm_domain *sh7372_sd);
 #else
 #define sh7372_init_pm_domain(pd) do { } while(0)
 #define sh7372_add_device_to_domain(pd, pdev) do { } while(0)
+#define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_SH7372_H__ */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [Update x2][PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372
  2011-08-13 19:43     ` Rafael J. Wysocki
  (?)
  (?)
@ 2011-08-14 14:07     ` Rafael J. Wysocki
  -1 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-08-14 14:07 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372

Instead of coding the undocumented dependencies between power domains
A3RV and A4LC on SH7372 directly into the low-level power up/down
routines, make A3RV be a subdomain of A4LC, which will cause the
same dependecies to hold.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---

It also needs to build for CONFIG_PM unset.

Thanks,
Rafael

---
 arch/arm/mach-shmobile/include/mach/sh7372.h |    3 +
 arch/arm/mach-shmobile/pm-sh7372.c           |   48 ++++-----------------------
 arch/arm/mach-shmobile/setup-sh7372.c        |    3 +
 3 files changed, 14 insertions(+), 40 deletions(-)

Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -91,35 +91,6 @@ static int pd_power_up(struct generic_pm
 	return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_up(genpd);
-
-	/* force A4LC on after A3RV has been requested on */
-	pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-	int ret = pd_power_down(genpd);
-
-	/* try to power down A4LC after A3RV is requested off */
-	genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-	return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-	/* only power down A4LC if A3RV is off */
-	if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-		return pd_power_down(genpd);
-
-	return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -133,17 +104,8 @@ void sh7372_init_pm_domain(struct sh7372
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->active_wakeup = pd_active_wakeup;
-
-	if (sh7372_pd == &sh7372_a4lc) {
-		genpd->power_off = pd_power_down_a4lc;
-		genpd->power_on = pd_power_up;
-	} else if (sh7372_pd == &sh7372_a3rv) {
-		genpd->power_off = pd_power_down_a3rv;
-		genpd->power_on = pd_power_up_a3rv;
-	} else {
-		genpd->power_off = pd_power_down;
-		genpd->power_on = pd_power_up;
-	}
+	genpd->power_off = pd_power_down;
+	genpd->power_on = pd_power_up;
 	genpd->power_on(&sh7372_pd->genpd);
 }
 
@@ -159,6 +121,12 @@ void sh7372_add_device_to_domain(struct
 	pm_genpd_add_device(&sh7372_pd->genpd, dev);
 }
 
+void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+			     struct sh7372_pm_domain *sh7372_sd)
+{
+	pm_genpd_add_subdomain(&sh7372_pd->genpd, &sh7372_sd->genpd);
+}
+
 struct sh7372_pm_domain sh7372_a4lc = {
 	.bit_shift = 1,
 };
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
===================================================================
--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -848,6 +849,8 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 
+	sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
+
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
 
Index: linux/arch/arm/mach-shmobile/include/mach/sh7372.h
===================================================================
--- linux.orig/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ linux/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -494,9 +494,12 @@ extern struct sh7372_pm_domain sh7372_a3
 extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
 extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
 					struct platform_device *pdev);
+extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+				    struct sh7372_pm_domain *sh7372_sd);
 #else
 #define sh7372_init_pm_domain(pd) do { } while(0)
 #define sh7372_add_device_to_domain(pd, pdev) do { } while(0)
+#define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_SH7372_H__ */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 0/9] PM / Domains: Allow generic PM domains to have multiple parents
@ 2011-07-31 17:46 Rafael J. Wysocki
  0 siblings, 0 replies; 36+ messages in thread
From: Rafael J. Wysocki @ 2011-07-31 17:46 UTC (permalink / raw)
  To: Linux PM mailing list; +Cc: LKML, linux-sh

Hi,

This patchset modifies the generic PM domains code so that it's possible
for a PM domain to have multiple parent domains (i.e. domains it depends on).
This makes the framework applicable to more use cases and allows us to
address one issue one a system already using it.

Patch [1/9] is for 3.1, patches [2-9/9] are 3.2 material, if there are no
objections.

[1/9] - Fix genpd_power_on().
[2/9] - Make subdomain counts be atomic.
[3/9] - Don't acquire parent locks in genpd_power_on() and genpd_power_off().
[4/9] - Make genpd_power_on() always survive parent removal.
[5/9] - Add PM domain status value GPD_STATE_WAIT_PARENT.
[6/9] - Allow generic PM domains to have multiple parents.
[7/9] - Rename GPD_STATE_WAIT_PARENT to GPD_STATE_WAIT_MASTER.
[8/9] - Rename the second argument of pm_genpd_add_subdomain().
[9/9] - Make A3RV be a subdomain of A4LC on SH7372.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2011-08-14 14:07 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-31 17:46 [PATCH 0/9] PM / Domains: Allow generic PM domains to have multiple parents Rafael J. Wysocki
2011-07-31 17:46 ` Rafael J. Wysocki
2011-07-31 17:47 ` [PATCH 1/9] PM / Domains: Fix pm_genpd_poweron() Rafael J. Wysocki
2011-07-31 17:47 ` Rafael J. Wysocki
2011-07-31 17:47   ` Rafael J. Wysocki
2011-07-31 17:47 ` [PATCH 2/9] PM / Domains: Implement subdomain counters as atomic fields Rafael J. Wysocki
2011-07-31 17:47   ` Rafael J. Wysocki
2011-07-31 17:47 ` Rafael J. Wysocki
2011-07-31 17:48 ` [PATCH 3/9] PM / Domains: Do not take parent locks to modify subdomain counters Rafael J. Wysocki
2011-07-31 17:48   ` Rafael J. Wysocki
2011-07-31 17:48 ` Rafael J. Wysocki
2011-07-31 17:49 ` [PATCH 4/9] PM / Domains: Make pm_genpd_poweron() always survive parent removal Rafael J. Wysocki
2011-07-31 17:49   ` Rafael J. Wysocki
2011-07-31 17:49   ` Rafael J. Wysocki
2011-07-31 17:49 ` [PATCH 5/9] PM / Domains: Add "wait for parent" status for generic PM domains Rafael J. Wysocki
2011-07-31 17:49   ` Rafael J. Wysocki
2011-07-31 17:49 ` Rafael J. Wysocki
2011-07-31 17:50 ` [PATCH 6/9] PM / Domains: Allow generic PM domains to have multiple masters Rafael J. Wysocki
2011-07-31 17:50 ` Rafael J. Wysocki
2011-07-31 17:50   ` Rafael J. Wysocki
2011-07-31 17:51 ` [PATCH 7/9] PM / Domains: Rename GPD_STATE_WAIT_PARENT to GPD_STATE_WAIT_MASTER Rafael J. Wysocki
2011-07-31 17:51   ` Rafael J. Wysocki
2011-07-31 17:51 ` Rafael J. Wysocki
2011-07-31 17:52 ` [PATCH 8/9] PM / Domains: Rename second argument of pm_genpd_add_subdomain() Rafael J. Wysocki
2011-07-31 17:52 ` Rafael J. Wysocki
2011-07-31 17:52   ` Rafael J. Wysocki
2011-07-31 17:52 ` [PATCH 9/9] ARM / shmobile: Make A3RV be a subdomain of A4LC on SH7372 Rafael J. Wysocki
2011-07-31 17:52 ` Rafael J. Wysocki
2011-07-31 17:52   ` Rafael J. Wysocki
2011-08-13 19:43   ` [Update][PATCH " Rafael J. Wysocki
2011-08-13 19:43     ` Rafael J. Wysocki
2011-08-14 14:07     ` [Update x2][PATCH " Rafael J. Wysocki
2011-08-14 14:07       ` Rafael J. Wysocki
2011-08-14 14:07     ` Rafael J. Wysocki
2011-08-13 19:43   ` [Update][PATCH " Rafael J. Wysocki
  -- strict thread matches above, loose matches on Subject: below --
2011-07-31 17:46 [PATCH 0/9] PM / Domains: Allow generic PM domains to have multiple parents Rafael J. Wysocki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.