All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] PM / Domains: Power off masters immediately
@ 2017-02-17  9:55 Ulf Hansson
  2017-02-17  9:55 ` [PATCH 1/3] PM / Domains: Move genpd_power_off() above genpd_power_on() Ulf Hansson
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Ulf Hansson @ 2017-02-17  9:55 UTC (permalink / raw)
  To: Rafael J. Wysocki, Ulf Hansson, linux-pm
  Cc: Len Brown, Pavel Machek, Kevin Hilman, Geert Uytterhoeven,
	Lina Iyer, Jon Hunter, Marek Szyprowski

Currently genpd queues a power off work for each of the subdomain's
corresponding masters, thus postponing the masters to be powered off to a later
point.

This series intends to improve that behaviour in genpd, by instead power off
the masters immediately, thus avoiding unnecessary works from being queued.

Ulf Hansson (3):
  PM / Domains: Move genpd_power_off() above genpd_power_on()
  PM / Domains: Rename is_async to one_dev_on for genpd_power_off()
  PM / Domains: Power off masters immediately in the power off sequence

 drivers/base/power/domain.c | 178 +++++++++++++++++++++++---------------------
 1 file changed, 93 insertions(+), 85 deletions(-)

-- 
1.9.1

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

* [PATCH 1/3] PM / Domains: Move genpd_power_off() above genpd_power_on()
  2017-02-17  9:55 [PATCH 0/3] PM / Domains: Power off masters immediately Ulf Hansson
@ 2017-02-17  9:55 ` Ulf Hansson
  2017-02-17  9:55 ` [PATCH 2/3] PM / Domains: Rename is_async to one_dev_on for genpd_power_off() Ulf Hansson
  2017-02-17  9:55 ` [PATCH 3/3] PM / Domains: Power off masters immediately in the power off sequence Ulf Hansson
  2 siblings, 0 replies; 5+ messages in thread
From: Ulf Hansson @ 2017-02-17  9:55 UTC (permalink / raw)
  To: Rafael J. Wysocki, Ulf Hansson, linux-pm
  Cc: Len Brown, Pavel Machek, Kevin Hilman, Geert Uytterhoeven,
	Lina Iyer, Jon Hunter, Marek Szyprowski

Following changes in genpd_power_on() makes it invoke genpd_power_off().
To enable these changes and avoiding to declare genpd_power_off(), let's
move its implementation above genpd_power_on(). In this way, following
changes should become easier to review.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/domain.c | 162 ++++++++++++++++++++++----------------------
 1 file changed, 81 insertions(+), 81 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3a75fb1..3dc44f2 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -274,6 +274,87 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
 }
 
 /**
+ * genpd_power_off - Remove power from a given PM domain.
+ * @genpd: PM domain to power down.
+ * @is_async: PM domain is powered down from a scheduled work
+ *
+ * If all of the @genpd's devices have been suspended and all of its subdomains
+ * have been powered down, remove power from @genpd.
+ */
+static int genpd_power_off(struct generic_pm_domain *genpd, bool is_async)
+{
+	struct pm_domain_data *pdd;
+	struct gpd_link *link;
+	unsigned int not_suspended = 0;
+
+	/*
+	 * 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.
+	 */
+	if (genpd->status == GPD_STATE_POWER_OFF
+	    || genpd->prepared_count > 0)
+		return 0;
+
+	if (atomic_read(&genpd->sd_count) > 0)
+		return -EBUSY;
+
+	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+		enum pm_qos_flags_status stat;
+
+		stat = dev_pm_qos_flags(pdd->dev,
+					PM_QOS_FLAG_NO_POWER_OFF
+						| PM_QOS_FLAG_REMOTE_WAKEUP);
+		if (stat > PM_QOS_FLAGS_NONE)
+			return -EBUSY;
+
+		/*
+		 * Do not allow PM domain to be powered off, when an IRQ safe
+		 * device is part of a non-IRQ safe domain.
+		 */
+		if (!pm_runtime_suspended(pdd->dev) ||
+			irq_safe_dev_in_no_sleep_domain(pdd->dev, genpd))
+			not_suspended++;
+	}
+
+	if (not_suspended > 1 || (not_suspended == 1 && is_async))
+		return -EBUSY;
+
+	if (genpd->gov && genpd->gov->power_down_ok) {
+		if (!genpd->gov->power_down_ok(&genpd->domain))
+			return -EAGAIN;
+	}
+
+	if (genpd->power_off) {
+		int ret;
+
+		if (atomic_read(&genpd->sd_count) > 0)
+			return -EBUSY;
+
+		/*
+		 * If sd_count > 0 at this point, one of the subdomains hasn't
+		 * managed to call genpd_power_on() for the master yet after
+		 * incrementing it.  In that case genpd_power_on() will wait
+		 * for us to drop the lock, so we can call .power_off() and let
+		 * the genpd_power_on() restore power for us (this shouldn't
+		 * happen very often).
+		 */
+		ret = _genpd_power_off(genpd, true);
+		if (ret)
+			return ret;
+	}
+
+	genpd->status = GPD_STATE_POWER_OFF;
+
+	list_for_each_entry(link, &genpd->slave_links, slave_node) {
+		genpd_sd_counter_dec(link->master);
+		genpd_queue_power_off_work(link->master);
+	}
+
+	return 0;
+}
+
+/**
  * genpd_power_on - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  * @depth: nesting count for lockdep.
@@ -368,87 +449,6 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 }
 
 /**
- * genpd_power_off - Remove power from a given PM domain.
- * @genpd: PM domain to power down.
- * @is_async: PM domain is powered down from a scheduled work
- *
- * If all of the @genpd's devices have been suspended and all of its subdomains
- * have been powered down, remove power from @genpd.
- */
-static int genpd_power_off(struct generic_pm_domain *genpd, bool is_async)
-{
-	struct pm_domain_data *pdd;
-	struct gpd_link *link;
-	unsigned int not_suspended = 0;
-
-	/*
-	 * 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.
-	 */
-	if (genpd->status == GPD_STATE_POWER_OFF
-	    || genpd->prepared_count > 0)
-		return 0;
-
-	if (atomic_read(&genpd->sd_count) > 0)
-		return -EBUSY;
-
-	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
-		enum pm_qos_flags_status stat;
-
-		stat = dev_pm_qos_flags(pdd->dev,
-					PM_QOS_FLAG_NO_POWER_OFF
-						| PM_QOS_FLAG_REMOTE_WAKEUP);
-		if (stat > PM_QOS_FLAGS_NONE)
-			return -EBUSY;
-
-		/*
-		 * Do not allow PM domain to be powered off, when an IRQ safe
-		 * device is part of a non-IRQ safe domain.
-		 */
-		if (!pm_runtime_suspended(pdd->dev) ||
-			irq_safe_dev_in_no_sleep_domain(pdd->dev, genpd))
-			not_suspended++;
-	}
-
-	if (not_suspended > 1 || (not_suspended == 1 && is_async))
-		return -EBUSY;
-
-	if (genpd->gov && genpd->gov->power_down_ok) {
-		if (!genpd->gov->power_down_ok(&genpd->domain))
-			return -EAGAIN;
-	}
-
-	if (genpd->power_off) {
-		int ret;
-
-		if (atomic_read(&genpd->sd_count) > 0)
-			return -EBUSY;
-
-		/*
-		 * If sd_count > 0 at this point, one of the subdomains hasn't
-		 * managed to call genpd_power_on() for the master yet after
-		 * incrementing it.  In that case genpd_power_on() will wait
-		 * for us to drop the lock, so we can call .power_off() and let
-		 * the genpd_power_on() restore power for us (this shouldn't
-		 * happen very often).
-		 */
-		ret = _genpd_power_off(genpd, true);
-		if (ret)
-			return ret;
-	}
-
-	genpd->status = GPD_STATE_POWER_OFF;
-
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		genpd_sd_counter_dec(link->master);
-		genpd_queue_power_off_work(link->master);
-	}
-
-	return 0;
-}
-
-/**
  * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0.
  * @work: Work structure used for scheduling the execution of this function.
  */
-- 
1.9.1

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

* [PATCH 2/3] PM / Domains: Rename is_async to one_dev_on for genpd_power_off()
  2017-02-17  9:55 [PATCH 0/3] PM / Domains: Power off masters immediately Ulf Hansson
  2017-02-17  9:55 ` [PATCH 1/3] PM / Domains: Move genpd_power_off() above genpd_power_on() Ulf Hansson
@ 2017-02-17  9:55 ` Ulf Hansson
  2017-02-17  9:55 ` [PATCH 3/3] PM / Domains: Power off masters immediately in the power off sequence Ulf Hansson
  2 siblings, 0 replies; 5+ messages in thread
From: Ulf Hansson @ 2017-02-17  9:55 UTC (permalink / raw)
  To: Rafael J. Wysocki, Ulf Hansson, linux-pm
  Cc: Len Brown, Pavel Machek, Kevin Hilman, Geert Uytterhoeven,
	Lina Iyer, Jon Hunter, Marek Szyprowski

The parameter name is_async, for genpd_power_off() gives a poor description
of its purpose. To clarify, let's rename it to one_dev_on and update the
documentation of it in the function header.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/domain.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3dc44f2..179bb26 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -276,12 +276,15 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
 /**
  * genpd_power_off - Remove power from a given PM domain.
  * @genpd: PM domain to power down.
- * @is_async: PM domain is powered down from a scheduled work
+ * @one_dev_on: If invoked from genpd's ->runtime_suspend|resume() callback, the
+ * RPM status of the releated device is in an intermediate state, not yet turned
+ * into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not
+ * be RPM_SUSPENDED, while it tries to power off the PM domain.
  *
  * If all of the @genpd's devices have been suspended and all of its subdomains
  * have been powered down, remove power from @genpd.
  */
-static int genpd_power_off(struct generic_pm_domain *genpd, bool is_async)
+static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on)
 {
 	struct pm_domain_data *pdd;
 	struct gpd_link *link;
@@ -317,7 +320,7 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool is_async)
 			not_suspended++;
 	}
 
-	if (not_suspended > 1 || (not_suspended == 1 && is_async))
+	if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on))
 		return -EBUSY;
 
 	if (genpd->gov && genpd->gov->power_down_ok) {
@@ -459,7 +462,7 @@ static void genpd_power_off_work_fn(struct work_struct *work)
 	genpd = container_of(work, struct generic_pm_domain, power_off_work);
 
 	genpd_lock(genpd);
-	genpd_power_off(genpd, true);
+	genpd_power_off(genpd, false);
 	genpd_unlock(genpd);
 }
 
@@ -578,7 +581,7 @@ static int genpd_runtime_suspend(struct device *dev)
 		return 0;
 
 	genpd_lock(genpd);
-	genpd_power_off(genpd, false);
+	genpd_power_off(genpd, true);
 	genpd_unlock(genpd);
 
 	return 0;
@@ -658,7 +661,7 @@ static int genpd_runtime_resume(struct device *dev)
 	if (!pm_runtime_is_irq_safe(dev) ||
 		(pm_runtime_is_irq_safe(dev) && genpd_is_irq_safe(genpd))) {
 		genpd_lock(genpd);
-		genpd_power_off(genpd, 0);
+		genpd_power_off(genpd, true);
 		genpd_unlock(genpd);
 	}
 
-- 
1.9.1

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

* [PATCH 3/3] PM / Domains: Power off masters immediately in the power off sequence
  2017-02-17  9:55 [PATCH 0/3] PM / Domains: Power off masters immediately Ulf Hansson
  2017-02-17  9:55 ` [PATCH 1/3] PM / Domains: Move genpd_power_off() above genpd_power_on() Ulf Hansson
  2017-02-17  9:55 ` [PATCH 2/3] PM / Domains: Rename is_async to one_dev_on for genpd_power_off() Ulf Hansson
@ 2017-02-17  9:55 ` Ulf Hansson
  2017-03-03 18:28   ` Lina Iyer
  2 siblings, 1 reply; 5+ messages in thread
From: Ulf Hansson @ 2017-02-17  9:55 UTC (permalink / raw)
  To: Rafael J. Wysocki, Ulf Hansson, linux-pm
  Cc: Len Brown, Pavel Machek, Kevin Hilman, Geert Uytterhoeven,
	Lina Iyer, Jon Hunter, Marek Szyprowski

Once a subdomain is powered off, genpd queues a power off work for each of
the subdomain's corresponding masters, thus postponing the masters to be
powered off to a later point.

When genpd used intermediate power off states, which was removed in
commit ba2bbfbf6307 ("PM / Domains: Remove intermediate states from the
power off sequence"), this behaviour made sense, but now it simply doesn't.

Genpd can easily try to power off the masters in the same context as the
subdomain, of course by acquiring/releasing the lock. Then, let's convert
to this behaviour, as it avoids unnecessary works from being queued.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/domain.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 179bb26..e697dec 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -284,7 +284,8 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
  * If all of the @genpd's devices have been suspended and all of its subdomains
  * have been powered down, remove power from @genpd.
  */
-static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on)
+static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
+			   unsigned int depth)
 {
 	struct pm_domain_data *pdd;
 	struct gpd_link *link;
@@ -351,7 +352,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on)
 
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
 		genpd_sd_counter_dec(link->master);
-		genpd_queue_power_off_work(link->master);
+		genpd_lock_nested(link->master, depth + 1);
+		genpd_power_off(link->master, false, depth + 1);
+		genpd_unlock(link->master);
 	}
 
 	return 0;
@@ -405,7 +408,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
 					&genpd->slave_links,
 					slave_node) {
 		genpd_sd_counter_dec(link->master);
-		genpd_queue_power_off_work(link->master);
+		genpd_lock_nested(link->master, depth + 1);
+		genpd_power_off(link->master, false, depth + 1);
+		genpd_unlock(link->master);
 	}
 
 	return ret;
@@ -462,7 +467,7 @@ static void genpd_power_off_work_fn(struct work_struct *work)
 	genpd = container_of(work, struct generic_pm_domain, power_off_work);
 
 	genpd_lock(genpd);
-	genpd_power_off(genpd, false);
+	genpd_power_off(genpd, false, 0);
 	genpd_unlock(genpd);
 }
 
@@ -581,7 +586,7 @@ static int genpd_runtime_suspend(struct device *dev)
 		return 0;
 
 	genpd_lock(genpd);
-	genpd_power_off(genpd, true);
+	genpd_power_off(genpd, true, 0);
 	genpd_unlock(genpd);
 
 	return 0;
@@ -661,7 +666,7 @@ static int genpd_runtime_resume(struct device *dev)
 	if (!pm_runtime_is_irq_safe(dev) ||
 		(pm_runtime_is_irq_safe(dev) && genpd_is_irq_safe(genpd))) {
 		genpd_lock(genpd);
-		genpd_power_off(genpd, true);
+		genpd_power_off(genpd, true, 0);
 		genpd_unlock(genpd);
 	}
 
-- 
1.9.1

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

* Re: [PATCH 3/3] PM / Domains: Power off masters immediately in the power off sequence
  2017-02-17  9:55 ` [PATCH 3/3] PM / Domains: Power off masters immediately in the power off sequence Ulf Hansson
@ 2017-03-03 18:28   ` Lina Iyer
  0 siblings, 0 replies; 5+ messages in thread
From: Lina Iyer @ 2017-03-03 18:28 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rafael J. Wysocki, linux-pm, Len Brown, Pavel Machek,
	Kevin Hilman, Geert Uytterhoeven, Jon Hunter, Marek Szyprowski

On Fri, Feb 17 2017 at 02:55 -0700, Ulf Hansson wrote:
>Once a subdomain is powered off, genpd queues a power off work for each of
>the subdomain's corresponding masters, thus postponing the masters to be
>powered off to a later point.
>
>When genpd used intermediate power off states, which was removed in
>commit ba2bbfbf6307 ("PM / Domains: Remove intermediate states from the
>power off sequence"), this behaviour made sense, but now it simply doesn't.
>
>Genpd can easily try to power off the masters in the same context as the
>subdomain, of course by acquiring/releasing the lock. Then, let's convert
>to this behaviour, as it avoids unnecessary works from being queued.
>
>Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Tested-by: Lina Iyer <lina.iyer@linaro.org>

Thanks,
Lina

>---
> drivers/base/power/domain.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
>diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>index 179bb26..e697dec 100644
>--- a/drivers/base/power/domain.c
>+++ b/drivers/base/power/domain.c
>@@ -284,7 +284,8 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
>  * If all of the @genpd's devices have been suspended and all of its subdomains
>  * have been powered down, remove power from @genpd.
>  */
>-static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on)
>+static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
>+			   unsigned int depth)
> {
> 	struct pm_domain_data *pdd;
> 	struct gpd_link *link;
>@@ -351,7 +352,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on)
>
> 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
> 		genpd_sd_counter_dec(link->master);
>-		genpd_queue_power_off_work(link->master);
>+		genpd_lock_nested(link->master, depth + 1);
>+		genpd_power_off(link->master, false, depth + 1);
>+		genpd_unlock(link->master);
> 	}
>
> 	return 0;
>@@ -405,7 +408,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
> 					&genpd->slave_links,
> 					slave_node) {
> 		genpd_sd_counter_dec(link->master);
>-		genpd_queue_power_off_work(link->master);
>+		genpd_lock_nested(link->master, depth + 1);
>+		genpd_power_off(link->master, false, depth + 1);
>+		genpd_unlock(link->master);
> 	}
>
> 	return ret;
>@@ -462,7 +467,7 @@ static void genpd_power_off_work_fn(struct work_struct *work)
> 	genpd = container_of(work, struct generic_pm_domain, power_off_work);
>
> 	genpd_lock(genpd);
>-	genpd_power_off(genpd, false);
>+	genpd_power_off(genpd, false, 0);
> 	genpd_unlock(genpd);
> }
>
>@@ -581,7 +586,7 @@ static int genpd_runtime_suspend(struct device *dev)
> 		return 0;
>
> 	genpd_lock(genpd);
>-	genpd_power_off(genpd, true);
>+	genpd_power_off(genpd, true, 0);
> 	genpd_unlock(genpd);
>
> 	return 0;
>@@ -661,7 +666,7 @@ static int genpd_runtime_resume(struct device *dev)
> 	if (!pm_runtime_is_irq_safe(dev) ||
> 		(pm_runtime_is_irq_safe(dev) && genpd_is_irq_safe(genpd))) {
> 		genpd_lock(genpd);
>-		genpd_power_off(genpd, true);
>+		genpd_power_off(genpd, true, 0);
> 		genpd_unlock(genpd);
> 	}
>
>-- 
>1.9.1
>

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

end of thread, other threads:[~2017-03-03 18:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-17  9:55 [PATCH 0/3] PM / Domains: Power off masters immediately Ulf Hansson
2017-02-17  9:55 ` [PATCH 1/3] PM / Domains: Move genpd_power_off() above genpd_power_on() Ulf Hansson
2017-02-17  9:55 ` [PATCH 2/3] PM / Domains: Rename is_async to one_dev_on for genpd_power_off() Ulf Hansson
2017-02-17  9:55 ` [PATCH 3/3] PM / Domains: Power off masters immediately in the power off sequence Ulf Hansson
2017-03-03 18:28   ` Lina Iyer

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.