From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: Linux PM list <linux-pm@vger.kernel.org>
Cc: LKML <linux-kernel@vger.kernel.org>,
Linux-sh list <linux-sh@vger.kernel.org>,
Magnus Damm <magnus.damm@gmail.com>,
Guennadi Liakhovetski <g.liakhovetski@gmx.de>,
Kevin Hilman <khilman@ti.com>,
jean.pihet@newoldbits.com
Subject: [Update 2x][PATCH 6/7] PM / Domains: Add default power off governor function (v4)
Date: Sat, 19 Nov 2011 14:01:56 +0000 [thread overview]
Message-ID: <201111191501.56519.rjw@sisk.pl> (raw)
In-Reply-To: <201111191456.40453.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Add a function deciding whether or not a given PM domain should
be powered off on the basis of the PM QoS constraints of devices
belonging to it and their PM QoS timing data.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/domain.c | 12 +++
drivers/base/power/domain_governor.c | 110 +++++++++++++++++++++++++++++++++++
include/linux/pm_domain.h | 7 ++
3 files changed, 129 insertions(+)
Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -57,8 +57,13 @@ struct generic_pm_domain {
bool suspend_power_off; /* Power status before system suspend */
bool dev_irq_safe; /* Device callbacks are IRQ-safe */
int (*power_off)(struct generic_pm_domain *domain);
+ s64 power_off_latency_ns;
int (*power_on)(struct generic_pm_domain *domain);
+ s64 power_on_latency_ns;
struct gpd_dev_ops dev_ops;
+ s64 break_even_ns; /* Power break even for the entire domain. */
+ s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
+ ktime_t power_off_time;
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -76,6 +81,8 @@ struct gpd_link {
struct gpd_timing_data {
s64 stop_latency_ns;
s64 start_latency_ns;
+ s64 save_state_latency_ns;
+ s64 restore_state_latency_ns;
s64 break_even_ns;
};
Index: linux/drivers/base/power/domain_governor.c
=================================--- linux.orig/drivers/base/power/domain_governor.c
+++ linux/drivers/base/power/domain_governor.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
/**
* default_stop_ok - Default PM domain governor routine for stopping devices.
@@ -28,6 +29,115 @@ bool default_stop_ok(struct device *dev)
&& td->break_even_ns < dev->power.max_time_suspended_ns;
}
+/**
+ * default_power_down_ok - Default generic PM domain power off governor routine.
+ * @pd: PM domain to check.
+ *
+ * This routine must be executed under the PM domain's lock.
+ */
+static bool default_power_down_ok(struct dev_pm_domain *pd)
+{
+ struct generic_pm_domain *genpd = pd_to_genpd(pd);
+ struct gpd_link *link;
+ struct pm_domain_data *pdd;
+ s64 min_dev_off_time_ns;
+ s64 off_on_time_ns;
+ ktime_t time_now = ktime_get();
+
+ off_on_time_ns = genpd->power_off_latency_ns +
+ genpd->power_on_latency_ns;
+ /*
+ * It doesn't make sense to remove power from the domain if saving
+ * the state of all devices in it and the power off/power on operations
+ * take too much time.
+ *
+ * All devices in this domain have been stopped already at this point.
+ */
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ if (pdd->dev->driver)
+ off_on_time_ns ++ to_gpd_data(pdd)->td.save_state_latency_ns;
+ }
+
+ /*
+ * Check if subdomains can be off for enough time.
+ *
+ * All subdomains have been powered off already at this point.
+ */
+ list_for_each_entry(link, &genpd->master_links, master_node) {
+ struct generic_pm_domain *sd = link->slave;
+ s64 sd_max_off_ns = sd->max_off_time_ns;
+
+ if (sd_max_off_ns < 0)
+ continue;
+
+ sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
+ sd->power_off_time));
+ /*
+ * Check if the subdomain is allowed to be off long enough for
+ * the current domain to turn off and on (that's how much time
+ * it will have to wait worst case).
+ */
+ if (sd_max_off_ns <= off_on_time_ns)
+ return false;
+ }
+
+ /*
+ * Check if the devices in the domain can be off enough time.
+ */
+ min_dev_off_time_ns = -1;
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ struct gpd_timing_data *td;
+ struct device *dev = pdd->dev;
+ s64 dev_off_time_ns;
+
+ if (!dev->driver || dev->power.max_time_suspended_ns < 0)
+ continue;
+
+ td = &to_gpd_data(pdd)->td;
+ dev_off_time_ns = dev->power.max_time_suspended_ns -
+ (td->start_latency_ns + td->restore_state_latency_ns +
+ ktime_to_ns(ktime_sub(time_now,
+ dev->power.suspend_time)));
+ if (dev_off_time_ns <= off_on_time_ns)
+ return false;
+
+ if (min_dev_off_time_ns > dev_off_time_ns
+ || min_dev_off_time_ns < 0)
+ min_dev_off_time_ns = dev_off_time_ns;
+ }
+
+ if (min_dev_off_time_ns < 0) {
+ /*
+ * There are no latency constraints, so the domain can spend
+ * arbitrary time in the "off" state.
+ */
+ genpd->max_off_time_ns = -1;
+ return true;
+ }
+
+ /*
+ * The difference between the computed minimum delta and the time needed
+ * to turn the domain on is the maximum theoretical time this domain can
+ * spend in the "off" state.
+ */
+ min_dev_off_time_ns -= genpd->power_on_latency_ns;
+
+ /*
+ * If the difference between the computed minimum delta and the time
+ * needed to turn the domain off and back on on is smaller than the
+ * domain's power break even time, removing power from the domain is not
+ * worth it.
+ */
+ if (genpd->break_even_ns >
+ min_dev_off_time_ns - genpd->power_off_latency_ns)
+ return false;
+
+ genpd->max_off_time_ns = min_dev_off_time_ns;
+ return true;
+}
+
struct dev_power_governor simple_qos_governor = {
.stop_ok = default_stop_ok,
+ .power_down_ok = default_power_down_ok,
};
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -398,6 +398,17 @@ static int pm_genpd_poweroff(struct gene
}
genpd->status = GPD_STATE_POWER_OFF;
+ genpd->power_off_time = ktime_get();
+
+ /* Update PM QoS information for devices in the domain. */
+ list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
+ struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
+
+ pm_runtime_update_max_time_suspended(pdd->dev,
+ td->start_latency_ns +
+ td->restore_state_latency_ns +
+ genpd->power_on_latency_ns);
+ }
list_for_each_entry(link, &genpd->slave_links, slave_node) {
genpd_sd_counter_dec(link->master);
@@ -1417,6 +1428,7 @@ void pm_genpd_init(struct generic_pm_dom
genpd->resume_count = 0;
genpd->device_count = 0;
genpd->suspended_count = 0;
+ genpd->max_off_time_ns = -1;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
WARNING: multiple messages have this Message-ID (diff)
From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: Linux PM list <linux-pm@vger.kernel.org>
Cc: LKML <linux-kernel@vger.kernel.org>,
"Linux-sh list" <linux-sh@vger.kernel.org>,
Magnus Damm <magnus.damm@gmail.com>,
Guennadi Liakhovetski <g.liakhovetski@gmx.de>,
Kevin Hilman <khilman@ti.com>,
jean.pihet@newoldbits.com
Subject: [Update 2x][PATCH 6/7] PM / Domains: Add default power off governor function (v4)
Date: Sat, 19 Nov 2011 15:01:56 +0100 [thread overview]
Message-ID: <201111191501.56519.rjw@sisk.pl> (raw)
In-Reply-To: <201111191456.40453.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Add a function deciding whether or not a given PM domain should
be powered off on the basis of the PM QoS constraints of devices
belonging to it and their PM QoS timing data.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/domain.c | 12 +++
drivers/base/power/domain_governor.c | 110 +++++++++++++++++++++++++++++++++++
include/linux/pm_domain.h | 7 ++
3 files changed, 129 insertions(+)
Index: linux/include/linux/pm_domain.h
===================================================================
--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -57,8 +57,13 @@ struct generic_pm_domain {
bool suspend_power_off; /* Power status before system suspend */
bool dev_irq_safe; /* Device callbacks are IRQ-safe */
int (*power_off)(struct generic_pm_domain *domain);
+ s64 power_off_latency_ns;
int (*power_on)(struct generic_pm_domain *domain);
+ s64 power_on_latency_ns;
struct gpd_dev_ops dev_ops;
+ s64 break_even_ns; /* Power break even for the entire domain. */
+ s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
+ ktime_t power_off_time;
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -76,6 +81,8 @@ struct gpd_link {
struct gpd_timing_data {
s64 stop_latency_ns;
s64 start_latency_ns;
+ s64 save_state_latency_ns;
+ s64 restore_state_latency_ns;
s64 break_even_ns;
};
Index: linux/drivers/base/power/domain_governor.c
===================================================================
--- linux.orig/drivers/base/power/domain_governor.c
+++ linux/drivers/base/power/domain_governor.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
/**
* default_stop_ok - Default PM domain governor routine for stopping devices.
@@ -28,6 +29,115 @@ bool default_stop_ok(struct device *dev)
&& td->break_even_ns < dev->power.max_time_suspended_ns;
}
+/**
+ * default_power_down_ok - Default generic PM domain power off governor routine.
+ * @pd: PM domain to check.
+ *
+ * This routine must be executed under the PM domain's lock.
+ */
+static bool default_power_down_ok(struct dev_pm_domain *pd)
+{
+ struct generic_pm_domain *genpd = pd_to_genpd(pd);
+ struct gpd_link *link;
+ struct pm_domain_data *pdd;
+ s64 min_dev_off_time_ns;
+ s64 off_on_time_ns;
+ ktime_t time_now = ktime_get();
+
+ off_on_time_ns = genpd->power_off_latency_ns +
+ genpd->power_on_latency_ns;
+ /*
+ * It doesn't make sense to remove power from the domain if saving
+ * the state of all devices in it and the power off/power on operations
+ * take too much time.
+ *
+ * All devices in this domain have been stopped already at this point.
+ */
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ if (pdd->dev->driver)
+ off_on_time_ns +=
+ to_gpd_data(pdd)->td.save_state_latency_ns;
+ }
+
+ /*
+ * Check if subdomains can be off for enough time.
+ *
+ * All subdomains have been powered off already at this point.
+ */
+ list_for_each_entry(link, &genpd->master_links, master_node) {
+ struct generic_pm_domain *sd = link->slave;
+ s64 sd_max_off_ns = sd->max_off_time_ns;
+
+ if (sd_max_off_ns < 0)
+ continue;
+
+ sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
+ sd->power_off_time));
+ /*
+ * Check if the subdomain is allowed to be off long enough for
+ * the current domain to turn off and on (that's how much time
+ * it will have to wait worst case).
+ */
+ if (sd_max_off_ns <= off_on_time_ns)
+ return false;
+ }
+
+ /*
+ * Check if the devices in the domain can be off enough time.
+ */
+ min_dev_off_time_ns = -1;
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ struct gpd_timing_data *td;
+ struct device *dev = pdd->dev;
+ s64 dev_off_time_ns;
+
+ if (!dev->driver || dev->power.max_time_suspended_ns < 0)
+ continue;
+
+ td = &to_gpd_data(pdd)->td;
+ dev_off_time_ns = dev->power.max_time_suspended_ns -
+ (td->start_latency_ns + td->restore_state_latency_ns +
+ ktime_to_ns(ktime_sub(time_now,
+ dev->power.suspend_time)));
+ if (dev_off_time_ns <= off_on_time_ns)
+ return false;
+
+ if (min_dev_off_time_ns > dev_off_time_ns
+ || min_dev_off_time_ns < 0)
+ min_dev_off_time_ns = dev_off_time_ns;
+ }
+
+ if (min_dev_off_time_ns < 0) {
+ /*
+ * There are no latency constraints, so the domain can spend
+ * arbitrary time in the "off" state.
+ */
+ genpd->max_off_time_ns = -1;
+ return true;
+ }
+
+ /*
+ * The difference between the computed minimum delta and the time needed
+ * to turn the domain on is the maximum theoretical time this domain can
+ * spend in the "off" state.
+ */
+ min_dev_off_time_ns -= genpd->power_on_latency_ns;
+
+ /*
+ * If the difference between the computed minimum delta and the time
+ * needed to turn the domain off and back on on is smaller than the
+ * domain's power break even time, removing power from the domain is not
+ * worth it.
+ */
+ if (genpd->break_even_ns >
+ min_dev_off_time_ns - genpd->power_off_latency_ns)
+ return false;
+
+ genpd->max_off_time_ns = min_dev_off_time_ns;
+ return true;
+}
+
struct dev_power_governor simple_qos_governor = {
.stop_ok = default_stop_ok,
+ .power_down_ok = default_power_down_ok,
};
Index: linux/drivers/base/power/domain.c
===================================================================
--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -398,6 +398,17 @@ static int pm_genpd_poweroff(struct gene
}
genpd->status = GPD_STATE_POWER_OFF;
+ genpd->power_off_time = ktime_get();
+
+ /* Update PM QoS information for devices in the domain. */
+ list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
+ struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
+
+ pm_runtime_update_max_time_suspended(pdd->dev,
+ td->start_latency_ns +
+ td->restore_state_latency_ns +
+ genpd->power_on_latency_ns);
+ }
list_for_each_entry(link, &genpd->slave_links, slave_node) {
genpd_sd_counter_dec(link->master);
@@ -1417,6 +1428,7 @@ void pm_genpd_init(struct generic_pm_dom
genpd->resume_count = 0;
genpd->device_count = 0;
genpd->suspended_count = 0;
+ genpd->max_off_time_ns = -1;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
next prev parent reply other threads:[~2011-11-19 14:01 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-07 0:01 [PATCH 0/7] PM / Domains: Per-device callbacks and PM QoS Rafael J. Wysocki
2011-11-07 0:01 ` Rafael J. Wysocki
2011-11-07 0:06 ` [PATCH 1/7] PM / Domains: Make it possible to use per-device start/stop routines Rafael J. Wysocki
2011-11-07 0:06 ` Rafael J. Wysocki
2011-11-08 9:30 ` [PATCH 1/7] PM / Domains: Make it possible to use per-device Guennadi Liakhovetski
2011-11-08 9:30 ` [PATCH 1/7] PM / Domains: Make it possible to use per-device start/stop routines Guennadi Liakhovetski
2011-11-08 20:38 ` Rafael J. Wysocki
2011-11-08 20:38 ` Rafael J. Wysocki
2011-11-07 0:06 ` [PATCH 2/7] PM / Domains: Make it possible to use per-device .active_wakeup() Rafael J. Wysocki
2011-11-07 0:06 ` Rafael J. Wysocki
2011-11-08 10:27 ` [PATCH 2/7] PM / Domains: Make it possible to use per-device Guennadi Liakhovetski
2011-11-08 10:27 ` [PATCH 2/7] PM / Domains: Make it possible to use per-device .active_wakeup() Guennadi Liakhovetski
2011-11-08 20:40 ` Rafael J. Wysocki
2011-11-08 20:40 ` Rafael J. Wysocki
2011-11-09 8:52 ` [PATCH 2/7] PM / Domains: Make it possible to use per-device Guennadi Liakhovetski
2011-11-09 8:52 ` [PATCH 2/7] PM / Domains: Make it possible to use per-device .active_wakeup() Guennadi Liakhovetski
2011-11-09 22:40 ` Rafael J. Wysocki
2011-11-09 22:40 ` Rafael J. Wysocki
2011-11-09 23:02 ` [PATCH 2/7] PM / Domains: Make it possible to use per-device Guennadi Liakhovetski
2011-11-09 23:02 ` [PATCH 2/7] PM / Domains: Make it possible to use per-device .active_wakeup() Guennadi Liakhovetski
2011-11-07 0:07 ` [PATCH 3/7] PM / Domains: Introduce "save/restore state" device callbacks Rafael J. Wysocki
2011-11-07 0:07 ` Rafael J. Wysocki
2011-11-07 0:08 ` [PATCH 4/7] PM / Domains: Rework system suspend callback routines Rafael J. Wysocki
2011-11-07 0:08 ` Rafael J. Wysocki
2012-02-17 19:29 ` Pavel Machek
2012-02-17 19:29 ` Pavel Machek
2012-02-17 20:57 ` Rafael J. Wysocki
2012-02-17 21:01 ` Rafael J. Wysocki
2011-11-07 0:08 ` [PATCH 5/7] PM / Domains: Add device stop governor function (v3) Rafael J. Wysocki
2011-11-07 0:08 ` Rafael J. Wysocki
2011-11-07 0:09 ` [PATCH 6/7] PM / Domains: Add default power off " Rafael J. Wysocki
2011-11-07 0:09 ` Rafael J. Wysocki
2011-11-07 0:10 ` [PATCH 7/7] PM / Domains: Automatically update overoptimistic latency information Rafael J. Wysocki
2011-11-07 0:10 ` Rafael J. Wysocki
2011-11-14 0:22 ` [update][PATCH 0/7] PM / Domains: Per-device callbacks and PM QoS Rafael J. Wysocki
2011-11-14 0:22 ` Rafael J. Wysocki
2011-11-14 0:23 ` [update][PATCH 1/7] PM / Domains: Make it possible to use per-device domain callbacks Rafael J. Wysocki
2011-11-14 0:23 ` Rafael J. Wysocki
2011-11-14 0:24 ` [update][PATCH 2/7] PM / Domains: Introduce "save/restore state" device callbacks Rafael J. Wysocki
2011-11-14 0:24 ` Rafael J. Wysocki
2011-11-14 0:25 ` [update][PATCH 3/7] PM / Domains: Rework system suspend callback routines Rafael J. Wysocki
2011-11-14 0:25 ` Rafael J. Wysocki
2011-11-14 0:26 ` [update][PATCH 4/7] PM / Runtime: Use device PM QoS constraints Rafael J. Wysocki
2011-11-14 0:26 ` Rafael J. Wysocki
2011-11-14 0:27 ` [update][PATCH 5/7] PM / Domains: Add device stop governor function (v4) Rafael J. Wysocki
2011-11-14 0:27 ` Rafael J. Wysocki
2011-11-14 0:27 ` [update][PATCH 6/7] PM / Domains: Add default power off " Rafael J. Wysocki
2011-11-14 0:27 ` Rafael J. Wysocki
2011-11-14 0:28 ` [update][PATCH 7/7] PM / Domains: Automatically update overoptimistic latency information Rafael J. Wysocki
2011-11-14 0:28 ` Rafael J. Wysocki
2011-11-19 13:56 ` [Update 2x][PATCH 0/7] PM / Domains: Per-device callbacks and PM QoS Rafael J. Wysocki
2011-11-19 13:56 ` Rafael J. Wysocki
2011-11-19 13:58 ` [Update 2x][PATCH 1/7] PM / Domains: Make it possible to use per-device domain callbacks Rafael J. Wysocki
2011-11-19 13:58 ` Rafael J. Wysocki
2011-11-19 13:59 ` [Update 2x][PATCH 2/7] PM / Domains: Introduce "save/restore state" device callbacks Rafael J. Wysocki
2011-11-19 13:59 ` Rafael J. Wysocki
2011-11-19 13:59 ` [Update 2x][PATCH 3/7] PM / Domains: Rework system suspend callback routines Rafael J. Wysocki
2011-11-19 13:59 ` Rafael J. Wysocki
2011-11-24 0:20 ` [Update 3x][PATCH 3/7] PM / Domains: Rework system suspend callback routines (v2) Rafael J. Wysocki
2011-11-24 0:20 ` Rafael J. Wysocki
2011-11-19 14:00 ` [Update 2x][PATCH 4/7] PM / Runtime: Use device PM QoS constraints Rafael J. Wysocki
2011-11-19 14:00 ` Rafael J. Wysocki
2011-11-30 23:20 ` [Update 3x][PATCH 4/7] PM / Runtime: Use device PM QoS constraints (v2) Rafael J. Wysocki
2011-11-30 23:20 ` Rafael J. Wysocki
2011-11-19 14:01 ` [Update 2x][PATCH 5/7] PM / Domains: Add device stop governor function (v4) Rafael J. Wysocki
2011-11-19 14:01 ` Rafael J. Wysocki
2011-11-19 14:01 ` Rafael J. Wysocki [this message]
2011-11-19 14:01 ` [Update 2x][PATCH 6/7] PM / Domains: Add default power off " Rafael J. Wysocki
2011-11-19 14:02 ` [Update 2x][PATCH 7/7] PM / Domains: Automatically update overoptimistic latency information Rafael J. Wysocki
2011-11-19 14:02 ` Rafael J. Wysocki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201111191501.56519.rjw@sisk.pl \
--to=rjw@sisk.pl \
--cc=g.liakhovetski@gmx.de \
--cc=jean.pihet@newoldbits.com \
--cc=khilman@ti.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-sh@vger.kernel.org \
--cc=magnus.damm@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.