linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/14] PM: domains: Various improvements for genpd
@ 2022-05-11 14:56 Ulf Hansson
  2022-05-11 14:56 ` [PATCH 01/14] PM: domains: Add GENPD_FLAG_RPM_ALWAYS_ON for the always-on governor Ulf Hansson
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

The main goal with this series is to improve the way genpd deals with its
governor(s). Especially it turns allocation of governor related data to be
dynamically allocated. It also improves the execution path for runtime-
suspend/resume of devices (attached to a genpd of course) and the similar is
also done for genpd's power-on/off path.

Note that, patch 1->3 have already been sent before in a separate series [1],
but for simplicity I have included them here again.

Tests/reviews are as usual highly appreciated!

Kind regards
Ulf Hansson

[1]
https://www.spinics.net/lists/kernel/msg4335838.html

Ulf Hansson (14):
  PM: domains: Add GENPD_FLAG_RPM_ALWAYS_ON for the always-on governor
  PM: domains: Drop redundant code for genpd always-on governor
  PM: domains: Don't check PM_QOS_FLAG_NO_POWER_OFF in genpd
  PM: domains: Rename irq_safe_dev_in_no_sleep_domain() in genpd
  PM: domains: Skip another warning in irq_safe_dev_in_sleep_domain()
  PM: domains: Allocate gpd_timing_data dynamically based on governor
  PM: domains: Move the next_wakeup variable into the struct
    gpd_timing_data
  PM: domains: Measure suspend/resume latencies in genpd based on
    governor
  PM: domains: Fixup QoS latency measurements for IRQ safe devices in
    genpd
  PM: domains: Fix initialization of genpd's next_wakeup
  PM: domains: Clean up some code in pm_genpd_init() and genpd_remove()
  PM: domains: Allocate governor data dynamically based on a genpd
    governor
  PM: domains: Measure power-on/off latencies in genpd based on a
    governor
  PM: domains: Trust domain-idle-states from DT to be correct by genpd

 drivers/base/power/domain.c          | 201 +++++++++++++++++----------
 drivers/base/power/domain_governor.c |  65 +++++----
 include/linux/pm_domain.h            |  18 ++-
 3 files changed, 173 insertions(+), 111 deletions(-)

-- 
2.25.1


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

* [PATCH 01/14] PM: domains: Add GENPD_FLAG_RPM_ALWAYS_ON for the always-on governor
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 02/14] PM: domains: Drop redundant code for genpd " Ulf Hansson
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

Rather than relying on the genpd provider to set the corresponding flag,
GENPD_FLAG_RPM_ALWAYS_ON, when the always-on governor is being used, let's
add it in pm_genpd_init(). In this way, it starts to benefits all genpd
providers immediately.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 18cd7965e5d6..262bda9b56ef 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2016,6 +2016,10 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
 		genpd->dev_ops.start = pm_clk_resume;
 	}
 
+	/* The always-on governor works better with the corresponding flag. */
+	if (gov == &pm_domain_always_on_gov)
+		genpd->flags |= GENPD_FLAG_RPM_ALWAYS_ON;
+
 	/* Always-on domains must be powered on at initialization. */
 	if ((genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd)) &&
 			!genpd_status_on(genpd))
-- 
2.25.1


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

* [PATCH 02/14] PM: domains: Drop redundant code for genpd always-on governor
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
  2022-05-11 14:56 ` [PATCH 01/14] PM: domains: Add GENPD_FLAG_RPM_ALWAYS_ON for the always-on governor Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 03/14] PM: domains: Don't check PM_QOS_FLAG_NO_POWER_OFF in genpd Ulf Hansson
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

Due to recent changes, the always-on governor is always used with a genpd
that has the GENPD_FLAG_RPM_ALWAYS_ON flag being set. This means genpd,
doesn't invoke the governor's ->power_down_ok() callback, which makes the
code in the governor redundant, so let's drop it.

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

diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index cd08c5885190..c13e44823f16 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -327,11 +327,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 	return _default_power_down_ok(pd, ktime_get());
 }
 
-static bool always_on_power_down_ok(struct dev_pm_domain *domain)
-{
-	return false;
-}
-
 #ifdef CONFIG_CPU_IDLE
 static bool cpu_power_down_ok(struct dev_pm_domain *pd)
 {
@@ -401,6 +396,5 @@ struct dev_power_governor simple_qos_governor = {
  * pm_genpd_gov_always_on - A governor implementing an always-on policy
  */
 struct dev_power_governor pm_domain_always_on_gov = {
-	.power_down_ok = always_on_power_down_ok,
 	.suspend_ok = default_suspend_ok,
 };
-- 
2.25.1


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

* [PATCH 03/14] PM: domains: Don't check PM_QOS_FLAG_NO_POWER_OFF in genpd
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
  2022-05-11 14:56 ` [PATCH 01/14] PM: domains: Add GENPD_FLAG_RPM_ALWAYS_ON for the always-on governor Ulf Hansson
  2022-05-11 14:56 ` [PATCH 02/14] PM: domains: Drop redundant code for genpd " Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 04/14] PM: domains: Rename irq_safe_dev_in_no_sleep_domain() " Ulf Hansson
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

Back in the days when genpd supported intermediate power states of its
devices, it made sense to check the PM_QOS_FLAG_NO_POWER_OFF in
genpd_power_off(). This because the attached devices were all being put
into low power state together when the PM domain was also being powered
off.

At this point, the flag PM_QOS_FLAG_NO_POWER_OFF is better checked by
drivers from their ->runtime_suspend() callbacks, like in the
usb_port_runtime_suspend(), for example. Or perhaps an even better option
is to set the QoS resume latency constraint for the device to zero, which
informs the runtime PM core to prevent the device from being runtime
suspended.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 262bda9b56ef..5059c5d2e64a 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -648,12 +648,6 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
 	}
 
 	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);
-		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.
-- 
2.25.1


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

* [PATCH 04/14] PM: domains: Rename irq_safe_dev_in_no_sleep_domain() in genpd
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (2 preceding siblings ...)
  2022-05-11 14:56 ` [PATCH 03/14] PM: domains: Don't check PM_QOS_FLAG_NO_POWER_OFF in genpd Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 05/14] PM: domains: Skip another warning in irq_safe_dev_in_sleep_domain() Ulf Hansson
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

The name "irq_safe_dev_in_no_sleep_domain", doesn't really match the
conditions that are being checked in the function, hence the code becomes a
bit confusing to read.

Let's clarify this by renaming it into "irq_safe_dev_in_sleep_domain" and
let's also take the opportunity to clarify a corresponding comment in the
code.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 5059c5d2e64a..269bfa3d2303 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -131,7 +131,7 @@ static const struct genpd_lock_ops genpd_spin_ops = {
 #define genpd_is_cpu_domain(genpd)	(genpd->flags & GENPD_FLAG_CPU_DOMAIN)
 #define genpd_is_rpm_always_on(genpd)	(genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)
 
-static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
+static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
 		const struct generic_pm_domain *genpd)
 {
 	bool ret;
@@ -139,9 +139,9 @@ static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
 	ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd);
 
 	/*
-	 * Warn once if an IRQ safe device is attached to a no sleep domain, as
-	 * to indicate a suboptimal configuration for PM. For an always on
-	 * domain this isn't case, thus don't warn.
+	 * Warn once if an IRQ safe device is attached to a domain, which
+	 * callbacks are allowed to sleep. This indicates a suboptimal
+	 * configuration for PM, but it doesn't matter for an always on domain.
 	 */
 	if (ret && !genpd_is_always_on(genpd))
 		dev_warn_once(dev, "PM domain %s will not be powered off\n",
@@ -653,7 +653,7 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
 		 * 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))
+			irq_safe_dev_in_sleep_domain(pdd->dev, genpd))
 			not_suspended++;
 	}
 
@@ -925,7 +925,7 @@ static int genpd_runtime_suspend(struct device *dev)
 	 * If power.irq_safe is set, this routine may be run with
 	 * IRQs disabled, so suspend only if the PM domain also is irq_safe.
 	 */
-	if (irq_safe_dev_in_no_sleep_domain(dev, genpd))
+	if (irq_safe_dev_in_sleep_domain(dev, genpd))
 		return 0;
 
 	genpd_lock(genpd);
@@ -965,7 +965,7 @@ static int genpd_runtime_resume(struct device *dev)
 	 * As we don't power off a non IRQ safe domain, which holds
 	 * an IRQ safe device, we don't need to restore power to it.
 	 */
-	if (irq_safe_dev_in_no_sleep_domain(dev, genpd)) {
+	if (irq_safe_dev_in_sleep_domain(dev, genpd)) {
 		timed = false;
 		goto out;
 	}
-- 
2.25.1


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

* [PATCH 05/14] PM: domains: Skip another warning in irq_safe_dev_in_sleep_domain()
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (3 preceding siblings ...)
  2022-05-11 14:56 ` [PATCH 04/14] PM: domains: Rename irq_safe_dev_in_no_sleep_domain() " Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 06/14] PM: domains: Allocate gpd_timing_data dynamically based on governor Ulf Hansson
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

In irq_safe_dev_in_sleep_domain() we correctly skip the dev_warn_once() if
the corresponding genpd for the device, has the GENPD_FLAG_ALWAYS_ON flag
being set. For the same reason (the genpd is always-on in runtime), let's
also skip the warning if the GENPD_FLAG_RPM_ALWAYS_ON flag is set for the
genpd.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 269bfa3d2303..a3e727c9a4fa 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -143,7 +143,10 @@ static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
 	 * callbacks are allowed to sleep. This indicates a suboptimal
 	 * configuration for PM, but it doesn't matter for an always on domain.
 	 */
-	if (ret && !genpd_is_always_on(genpd))
+	if (genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd))
+		return ret;
+
+	if (ret)
 		dev_warn_once(dev, "PM domain %s will not be powered off\n",
 				genpd->name);
 
-- 
2.25.1


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

* [PATCH 06/14] PM: domains: Allocate gpd_timing_data dynamically based on governor
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (4 preceding siblings ...)
  2022-05-11 14:56 ` [PATCH 05/14] PM: domains: Skip another warning in irq_safe_dev_in_sleep_domain() Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 07/14] PM: domains: Move the next_wakeup variable into the struct gpd_timing_data Ulf Hansson
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

If a genpd doesn't have an associated governor assigned, there's really no
point to allocate the per device gpd_timing_data, as the data isn't being
used by a governor anyway.

To avoid wasting memory, let's therefore convert the corresponding td
variable in the struct generic_pm_domain_data into a pointer and manage the
allocation of its data dynamically.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/domain.c          | 48 +++++++++++++++++++---------
 drivers/base/power/domain_governor.c |  9 ++++--
 include/linux/pm_domain.h            |  2 +-
 3 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index a3e727c9a4fa..ca86fb3db901 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -773,13 +773,16 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 	for (;;) {
 		struct generic_pm_domain *genpd;
 		struct pm_domain_data *pdd;
+		struct gpd_timing_data *td;
 
 		spin_lock_irq(&dev->power.lock);
 
 		pdd = dev->power.subsys_data ?
 				dev->power.subsys_data->domain_data : NULL;
 		if (pdd) {
-			to_gpd_data(pdd)->td.constraint_changed = true;
+			td = to_gpd_data(pdd)->td;
+			if (td)
+				td->constraint_changed = true;
 			genpd = dev_to_genpd(dev);
 		} else {
 			genpd = ERR_PTR(-ENODATA);
@@ -875,7 +878,7 @@ static int genpd_runtime_suspend(struct device *dev)
 	struct generic_pm_domain *genpd;
 	bool (*suspend_ok)(struct device *__dev);
 	struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
-	struct gpd_timing_data *td = &gpd_data->td;
+	struct gpd_timing_data *td = gpd_data->td;
 	bool runtime_pm = pm_runtime_enabled(dev);
 	ktime_t time_start;
 	s64 elapsed_ns;
@@ -915,7 +918,7 @@ static int genpd_runtime_suspend(struct device *dev)
 	/* Update suspend latency value if the measured time exceeds it. */
 	if (runtime_pm) {
 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-		if (elapsed_ns > td->suspend_latency_ns) {
+		if (td && (elapsed_ns > td->suspend_latency_ns)) {
 			td->suspend_latency_ns = elapsed_ns;
 			dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
 				elapsed_ns);
@@ -951,7 +954,7 @@ static int genpd_runtime_resume(struct device *dev)
 {
 	struct generic_pm_domain *genpd;
 	struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
-	struct gpd_timing_data *td = &gpd_data->td;
+	struct gpd_timing_data *td = gpd_data->td;
 	bool runtime_pm = pm_runtime_enabled(dev);
 	ktime_t time_start;
 	s64 elapsed_ns;
@@ -999,7 +1002,7 @@ static int genpd_runtime_resume(struct device *dev)
 	/* Update resume latency value if the measured time exceeds it. */
 	if (timed && runtime_pm) {
 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-		if (elapsed_ns > td->resume_latency_ns) {
+		if (td && (elapsed_ns > td->resume_latency_ns)) {
 			td->resume_latency_ns = elapsed_ns;
 			dev_dbg(dev, "resume latency exceeded, %lld ns\n",
 				elapsed_ns);
@@ -1496,9 +1499,11 @@ EXPORT_SYMBOL_GPL(dev_pm_genpd_resume);
 
 #endif /* CONFIG_PM_SLEEP */
 
-static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
+static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
+							   bool has_governor)
 {
 	struct generic_pm_domain_data *gpd_data;
+	struct gpd_timing_data *td;
 	int ret;
 
 	ret = dev_pm_get_subsys_data(dev);
@@ -1512,26 +1517,38 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
 	}
 
 	gpd_data->base.dev = dev;
-	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 	gpd_data->next_wakeup = KTIME_MAX;
 
-	spin_lock_irq(&dev->power.lock);
+	/* Allocate data used by a governor. */
+	if (has_governor) {
+		td = kzalloc(sizeof(*td), GFP_KERNEL);
+		if (!td) {
+			ret = -ENOMEM;
+			goto err_free;
+		}
 
-	if (dev->power.subsys_data->domain_data) {
-		ret = -EINVAL;
-		goto err_free;
+		td->constraint_changed = true;
+		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
+		gpd_data->td = td;
 	}
 
-	dev->power.subsys_data->domain_data = &gpd_data->base;
+	spin_lock_irq(&dev->power.lock);
+
+	if (dev->power.subsys_data->domain_data)
+		ret = -EINVAL;
+	else
+		dev->power.subsys_data->domain_data = &gpd_data->base;
 
 	spin_unlock_irq(&dev->power.lock);
 
+	if (ret)
+		goto err_free;
+
 	return gpd_data;
 
  err_free:
-	spin_unlock_irq(&dev->power.lock);
+	kfree(gpd_data->td);
 	kfree(gpd_data);
  err_put:
 	dev_pm_put_subsys_data(dev);
@@ -1547,6 +1564,7 @@ static void genpd_free_dev_data(struct device *dev,
 
 	spin_unlock_irq(&dev->power.lock);
 
+	kfree(gpd_data->td);
 	kfree(gpd_data);
 	dev_pm_put_subsys_data(dev);
 }
@@ -1611,7 +1629,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
 		return -EINVAL;
 
-	gpd_data = genpd_alloc_dev_data(dev);
+	gpd_data = genpd_alloc_dev_data(dev, genpd->gov);
 	if (IS_ERR(gpd_data))
 		return PTR_ERR(gpd_data);
 
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index c13e44823f16..62be9b3f8c90 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -18,6 +18,8 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
 	s64 constraint_ns;
 
 	if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
+		struct gpd_timing_data *td = dev_gpd_data(dev)->td;
+
 		/*
 		 * Only take suspend-time QoS constraints of devices into
 		 * account, because constraints updated after the device has
@@ -25,7 +27,8 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
 		 * anyway.  In order for them to take effect, the device has to
 		 * be resumed and suspended again.
 		 */
-		constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+		constraint_ns = td ? td->effective_constraint_ns :
+				PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 	} else {
 		/*
 		 * The child is not in a domain and there's no info on its
@@ -49,7 +52,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
  */
 static bool default_suspend_ok(struct device *dev)
 {
-	struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+	struct gpd_timing_data *td = dev_gpd_data(dev)->td;
 	unsigned long flags;
 	s64 constraint_ns;
 
@@ -215,7 +218,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
 		 * domain to turn off and on (that's how much time it will
 		 * have to wait worst case).
 		 */
-		td = &to_gpd_data(pdd)->td;
+		td = to_gpd_data(pdd)->td;
 		constraint_ns = td->effective_constraint_ns;
 		/*
 		 * Zero means "no suspend at all" and this runs only when all
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 043d48e4420a..126a4b9ab215 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -193,7 +193,7 @@ struct pm_domain_data {
 
 struct generic_pm_domain_data {
 	struct pm_domain_data base;
-	struct gpd_timing_data td;
+	struct gpd_timing_data *td;
 	struct notifier_block nb;
 	struct notifier_block *power_nb;
 	int cpu;
-- 
2.25.1


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

* [PATCH 07/14] PM: domains: Move the next_wakeup variable into the struct gpd_timing_data
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (5 preceding siblings ...)
  2022-05-11 14:56 ` [PATCH 06/14] PM: domains: Allocate gpd_timing_data dynamically based on governor Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 08/14] PM: domains: Measure suspend/resume latencies in genpd based on governor Ulf Hansson
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

If the corresponding genpd for the device doesn't use a governor, the
variable next_wakeup within the struct generic_pm_domain_data becomes
superfluous.

To avoid wasting memory, let's move it into the struct gpd_timing_data,
which is already being allocated based upon if there is governor assigned.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/domain.c          | 9 +++++----
 drivers/base/power/domain_governor.c | 2 +-
 include/linux/pm_domain.h            | 2 +-
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index ca86fb3db901..4c059a858957 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -478,15 +478,16 @@ EXPORT_SYMBOL_GPL(dev_pm_genpd_set_performance_state);
  */
 void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next)
 {
-	struct generic_pm_domain_data *gpd_data;
 	struct generic_pm_domain *genpd;
+	struct gpd_timing_data *td;
 
 	genpd = dev_to_genpd_safe(dev);
 	if (!genpd)
 		return;
 
-	gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
-	gpd_data->next_wakeup = next;
+	td = to_gpd_data(dev->power.subsys_data->domain_data)->td;
+	if (td)
+		td->next_wakeup = next;
 }
 EXPORT_SYMBOL_GPL(dev_pm_genpd_set_next_wakeup);
 
@@ -1518,7 +1519,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
 
 	gpd_data->base.dev = dev;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
-	gpd_data->next_wakeup = KTIME_MAX;
 
 	/* Allocate data used by a governor. */
 	if (has_governor) {
@@ -1530,6 +1530,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
 
 		td->constraint_changed = true;
 		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
+		td->next_wakeup = KTIME_MAX;
 		gpd_data->td = td;
 	}
 
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 62be9b3f8c90..599b3909821c 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -139,7 +139,7 @@ static void update_domain_next_wakeup(struct generic_pm_domain *genpd, ktime_t n
 	 * is able to enter its optimal idle state.
 	 */
 	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
-		next_wakeup = to_gpd_data(pdd)->next_wakeup;
+		next_wakeup = to_gpd_data(pdd)->td->next_wakeup;
 		if (next_wakeup != KTIME_MAX && !ktime_before(next_wakeup, now))
 			if (ktime_before(next_wakeup, domain_wakeup))
 				domain_wakeup = next_wakeup;
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 126a4b9ab215..1f370f074f30 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -182,6 +182,7 @@ struct gpd_timing_data {
 	s64 suspend_latency_ns;
 	s64 resume_latency_ns;
 	s64 effective_constraint_ns;
+	ktime_t	next_wakeup;
 	bool constraint_changed;
 	bool cached_suspend_ok;
 };
@@ -200,7 +201,6 @@ struct generic_pm_domain_data {
 	unsigned int performance_state;
 	unsigned int default_pstate;
 	unsigned int rpm_pstate;
-	ktime_t	next_wakeup;
 	void *data;
 };
 
-- 
2.25.1


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

* [PATCH 08/14] PM: domains: Measure suspend/resume latencies in genpd based on governor
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (6 preceding siblings ...)
  2022-05-11 14:56 ` [PATCH 07/14] PM: domains: Move the next_wakeup variable into the struct gpd_timing_data Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:56 ` [PATCH 09/14] PM: domains: Fixup QoS latency measurements for IRQ safe devices in genpd Ulf Hansson
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

The QoS latency measurements for devices in genpd_runtime_suspend|resume()
are superfluous, unless the corresponding genpd has a governor assigned to
it, which would make use of the data.

Therefore, let's improve the behaviour in genpd by making the measurements
conditional, based upon if there's a governor assigned.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 4c059a858957..2cdfbe48dde0 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -881,7 +881,7 @@ static int genpd_runtime_suspend(struct device *dev)
 	struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
 	struct gpd_timing_data *td = gpd_data->td;
 	bool runtime_pm = pm_runtime_enabled(dev);
-	ktime_t time_start;
+	ktime_t time_start = 0;
 	s64 elapsed_ns;
 	int ret;
 
@@ -902,8 +902,7 @@ static int genpd_runtime_suspend(struct device *dev)
 		return -EBUSY;
 
 	/* Measure suspend latency. */
-	time_start = 0;
-	if (runtime_pm)
+	if (td && runtime_pm)
 		time_start = ktime_get();
 
 	ret = __genpd_runtime_suspend(dev);
@@ -917,9 +916,9 @@ static int genpd_runtime_suspend(struct device *dev)
 	}
 
 	/* Update suspend latency value if the measured time exceeds it. */
-	if (runtime_pm) {
+	if (td && runtime_pm) {
 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-		if (td && (elapsed_ns > td->suspend_latency_ns)) {
+		if (elapsed_ns > td->suspend_latency_ns) {
 			td->suspend_latency_ns = elapsed_ns;
 			dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
 				elapsed_ns);
@@ -956,11 +955,10 @@ static int genpd_runtime_resume(struct device *dev)
 	struct generic_pm_domain *genpd;
 	struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
 	struct gpd_timing_data *td = gpd_data->td;
-	bool runtime_pm = pm_runtime_enabled(dev);
-	ktime_t time_start;
+	bool timed = td && pm_runtime_enabled(dev);
+	ktime_t time_start = 0;
 	s64 elapsed_ns;
 	int ret;
-	bool timed = true;
 
 	dev_dbg(dev, "%s()\n", __func__);
 
@@ -988,8 +986,7 @@ static int genpd_runtime_resume(struct device *dev)
 
  out:
 	/* Measure resume latency. */
-	time_start = 0;
-	if (timed && runtime_pm)
+	if (timed)
 		time_start = ktime_get();
 
 	ret = genpd_start_dev(genpd, dev);
@@ -1001,9 +998,9 @@ static int genpd_runtime_resume(struct device *dev)
 		goto err_stop;
 
 	/* Update resume latency value if the measured time exceeds it. */
-	if (timed && runtime_pm) {
+	if (timed) {
 		elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-		if (td && (elapsed_ns > td->resume_latency_ns)) {
+		if (elapsed_ns > td->resume_latency_ns) {
 			td->resume_latency_ns = elapsed_ns;
 			dev_dbg(dev, "resume latency exceeded, %lld ns\n",
 				elapsed_ns);
-- 
2.25.1


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

* [PATCH 09/14] PM: domains: Fixup QoS latency measurements for IRQ safe devices in genpd
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (7 preceding siblings ...)
  2022-05-11 14:56 ` [PATCH 08/14] PM: domains: Measure suspend/resume latencies in genpd based on governor Ulf Hansson
@ 2022-05-11 14:56 ` Ulf Hansson
  2022-05-11 14:57 ` [PATCH 10/14] PM: domains: Fix initialization of genpd's next_wakeup Ulf Hansson
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:56 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

When an IRQ safe device is attached to a non-IRQ safe PM domain, genpd
needs to prevent the PM domain from being powered off. However, genpd still
allows the device to be runtime suspended/resumed, hence it's also
reasonable to think that a governor may be used to validate the QoS latency
constraints.

Unfortunately, genpd_runtime_resume() treats the configuration above, as a
reason to skip measuring the QoS resume latency for the device. This is a
legacy behaviour that was earlier correct, but should have been changed
when genpd was transformed into its current behaviour around how it manages
IRQ safe devices. Luckily, there's no report about problems, so let's just
fixup the behaviour.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 2cdfbe48dde0..48101232fcb9 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -970,10 +970,8 @@ static int genpd_runtime_resume(struct device *dev)
 	 * As we don't power off a non IRQ safe domain, which holds
 	 * an IRQ safe device, we don't need to restore power to it.
 	 */
-	if (irq_safe_dev_in_sleep_domain(dev, genpd)) {
-		timed = false;
+	if (irq_safe_dev_in_sleep_domain(dev, genpd))
 		goto out;
-	}
 
 	genpd_lock(genpd);
 	ret = genpd_power_on(genpd, 0);
-- 
2.25.1


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

* [PATCH 10/14] PM: domains: Fix initialization of genpd's next_wakeup
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (8 preceding siblings ...)
  2022-05-11 14:56 ` [PATCH 09/14] PM: domains: Fixup QoS latency measurements for IRQ safe devices in genpd Ulf Hansson
@ 2022-05-11 14:57 ` Ulf Hansson
  2022-05-11 14:57 ` [PATCH 11/14] PM: domains: Clean up some code in pm_genpd_init() and genpd_remove() Ulf Hansson
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:57 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

In the genpd governor we walk the list of child-domains to take into
account their next_wakeup. If the child-domain itself, doesn't have a
governor assigned to it, we can end up using the next_wakeup value before
it has been properly initialized. To prevent a possible incorrect behaviour
in the governor, let's initialize next_wakeup to KTIME_MAX.

Fixes: c79aa080fb0f ("PM: domains: use device's next wakeup to determine domain idle state")
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/domain.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 48101232fcb9..9922fd763739 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2007,6 +2007,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
 	genpd->device_count = 0;
 	genpd->max_off_time_ns = -1;
 	genpd->max_off_time_changed = true;
+	genpd->next_wakeup = KTIME_MAX;
 	genpd->provider = NULL;
 	genpd->has_provider = false;
 	genpd->accounting_time = ktime_get_mono_fast_ns();
-- 
2.25.1


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

* [PATCH 11/14] PM: domains: Clean up some code in pm_genpd_init() and genpd_remove()
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (9 preceding siblings ...)
  2022-05-11 14:57 ` [PATCH 10/14] PM: domains: Fix initialization of genpd's next_wakeup Ulf Hansson
@ 2022-05-11 14:57 ` Ulf Hansson
  2022-05-11 14:57 ` [PATCH 12/14] PM: domains: Allocate governor data dynamically based on a genpd governor Ulf Hansson
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:57 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

To improve the readability of the code, let's move the parts that deals
with allocation/freeing of data, into two separate functions.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 9922fd763739..ac1eb7d2470b 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1968,6 +1968,37 @@ static int genpd_set_default_power_state(struct generic_pm_domain *genpd)
 	return 0;
 }
 
+static int genpd_alloc_data(struct generic_pm_domain *genpd)
+{
+	int ret;
+
+	if (genpd_is_cpu_domain(genpd) &&
+	    !zalloc_cpumask_var(&genpd->cpus, GFP_KERNEL))
+		return -ENOMEM;
+
+	/* Use only one "off" state if there were no states declared */
+	if (genpd->state_count == 0) {
+		ret = genpd_set_default_power_state(genpd);
+		if (ret)
+			goto free;
+	}
+
+	return 0;
+
+free:
+	if (genpd_is_cpu_domain(genpd))
+		free_cpumask_var(genpd->cpus);
+	return ret;
+}
+
+static void genpd_free_data(struct generic_pm_domain *genpd)
+{
+	if (genpd_is_cpu_domain(genpd))
+		free_cpumask_var(genpd->cpus);
+	if (genpd->free_states)
+		genpd->free_states(genpd->states, genpd->state_count);
+}
+
 static void genpd_lock_init(struct generic_pm_domain *genpd)
 {
 	if (genpd->flags & GENPD_FLAG_IRQ_SAFE) {
@@ -2037,21 +2068,13 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
 			!genpd_status_on(genpd))
 		return -EINVAL;
 
-	if (genpd_is_cpu_domain(genpd) &&
-	    !zalloc_cpumask_var(&genpd->cpus, GFP_KERNEL))
-		return -ENOMEM;
-
-	/* Use only one "off" state if there were no states declared */
-	if (genpd->state_count == 0) {
-		ret = genpd_set_default_power_state(genpd);
-		if (ret) {
-			if (genpd_is_cpu_domain(genpd))
-				free_cpumask_var(genpd->cpus);
-			return ret;
-		}
-	} else if (!gov && genpd->state_count > 1) {
+	/* Multiple states but no governor doesn't make sense. */
+	if (!gov && genpd->state_count > 1)
 		pr_warn("%s: no governor for states\n", genpd->name);
-	}
+
+	ret = genpd_alloc_data(genpd);
+	if (ret)
+		return ret;
 
 	device_initialize(&genpd->dev);
 	dev_set_name(&genpd->dev, "%s", genpd->name);
@@ -2096,10 +2119,7 @@ static int genpd_remove(struct generic_pm_domain *genpd)
 	genpd_unlock(genpd);
 	genpd_debug_remove(genpd);
 	cancel_work_sync(&genpd->power_off_work);
-	if (genpd_is_cpu_domain(genpd))
-		free_cpumask_var(genpd->cpus);
-	if (genpd->free_states)
-		genpd->free_states(genpd->states, genpd->state_count);
+	genpd_free_data(genpd);
 
 	pr_debug("%s: removed %s\n", __func__, genpd->name);
 
-- 
2.25.1


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

* [PATCH 12/14] PM: domains: Allocate governor data dynamically based on a genpd governor
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (10 preceding siblings ...)
  2022-05-11 14:57 ` [PATCH 11/14] PM: domains: Clean up some code in pm_genpd_init() and genpd_remove() Ulf Hansson
@ 2022-05-11 14:57 ` Ulf Hansson
  2022-05-11 14:57 ` [PATCH 13/14] PM: domains: Measure power-on/off latencies in genpd based on a governor Ulf Hansson
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:57 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

If a genpd doesn't have an associated governor assigned, several variables
in the struct generic_pm_domain becomes superfluous.

Rather than wasting memory in allocated genpds, let's move the variables
from the struct generic_pm_domain into a new separate struct. In this way,
we can instead dynamically decide when we need to allocate the
corresponding data for it.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/domain.c          | 49 +++++++++++++++++++---------
 drivers/base/power/domain_governor.c | 48 +++++++++++++++------------
 include/linux/pm_domain.h            | 14 +++++---
 3 files changed, 70 insertions(+), 41 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index ac1eb7d2470b..a7de5fb8f073 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -527,7 +527,8 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 		goto out;
 
 	genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
-	genpd->max_off_time_changed = true;
+	if (genpd->gd)
+		genpd->gd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "on", elapsed_ns);
 
@@ -576,7 +577,8 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 		goto out;
 
 	genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
-	genpd->max_off_time_changed = true;
+	if (genpd->gd)
+		genpd->gd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "off", elapsed_ns);
 
@@ -772,7 +774,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 	dev = gpd_data->base.dev;
 
 	for (;;) {
-		struct generic_pm_domain *genpd;
+		struct generic_pm_domain *genpd = ERR_PTR(-ENODATA);
 		struct pm_domain_data *pdd;
 		struct gpd_timing_data *td;
 
@@ -782,18 +784,17 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 				dev->power.subsys_data->domain_data : NULL;
 		if (pdd) {
 			td = to_gpd_data(pdd)->td;
-			if (td)
+			if (td) {
 				td->constraint_changed = true;
-			genpd = dev_to_genpd(dev);
-		} else {
-			genpd = ERR_PTR(-ENODATA);
+				genpd = dev_to_genpd(dev);
+			}
 		}
 
 		spin_unlock_irq(&dev->power.lock);
 
 		if (!IS_ERR(genpd)) {
 			genpd_lock(genpd);
-			genpd->max_off_time_changed = true;
+			genpd->gd->max_off_time_changed = true;
 			genpd_unlock(genpd);
 		}
 
@@ -922,7 +923,7 @@ static int genpd_runtime_suspend(struct device *dev)
 			td->suspend_latency_ns = elapsed_ns;
 			dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
 				elapsed_ns);
-			genpd->max_off_time_changed = true;
+			genpd->gd->max_off_time_changed = true;
 			td->constraint_changed = true;
 		}
 	}
@@ -1002,7 +1003,7 @@ static int genpd_runtime_resume(struct device *dev)
 			td->resume_latency_ns = elapsed_ns;
 			dev_dbg(dev, "resume latency exceeded, %lld ns\n",
 				elapsed_ns);
-			genpd->max_off_time_changed = true;
+			genpd->gd->max_off_time_changed = true;
 			td->constraint_changed = true;
 		}
 	}
@@ -1617,6 +1618,7 @@ static int genpd_get_cpu(struct generic_pm_domain *genpd, struct device *dev)
 static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 			    struct device *base_dev)
 {
+	struct genpd_governor_data *gd = genpd->gd;
 	struct generic_pm_domain_data *gpd_data;
 	int ret;
 
@@ -1625,7 +1627,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
 		return -EINVAL;
 
-	gpd_data = genpd_alloc_dev_data(dev, genpd->gov);
+	gpd_data = genpd_alloc_dev_data(dev, gd);
 	if (IS_ERR(gpd_data))
 		return PTR_ERR(gpd_data);
 
@@ -1641,7 +1643,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	dev_pm_domain_set(dev, &genpd->domain);
 
 	genpd->device_count++;
-	genpd->max_off_time_changed = true;
+	if (gd)
+		gd->max_off_time_changed = true;
 
 	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
 
@@ -1695,7 +1698,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 	}
 
 	genpd->device_count--;
-	genpd->max_off_time_changed = true;
+	if (genpd->gd)
+		genpd->gd->max_off_time_changed = true;
 
 	genpd_clear_cpumask(genpd, gpd_data->cpu);
 	dev_pm_domain_set(dev, NULL);
@@ -1970,12 +1974,25 @@ static int genpd_set_default_power_state(struct generic_pm_domain *genpd)
 
 static int genpd_alloc_data(struct generic_pm_domain *genpd)
 {
+	struct genpd_governor_data *gd = NULL;
 	int ret;
 
 	if (genpd_is_cpu_domain(genpd) &&
 	    !zalloc_cpumask_var(&genpd->cpus, GFP_KERNEL))
 		return -ENOMEM;
 
+	if (genpd->gov) {
+		gd = kzalloc(sizeof(*gd), GFP_KERNEL);
+		if (!gd) {
+			ret = -ENOMEM;
+			goto free;
+		}
+
+		gd->max_off_time_ns = -1;
+		gd->max_off_time_changed = true;
+		gd->next_wakeup = KTIME_MAX;
+	}
+
 	/* Use only one "off" state if there were no states declared */
 	if (genpd->state_count == 0) {
 		ret = genpd_set_default_power_state(genpd);
@@ -1983,11 +2000,13 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd)
 			goto free;
 	}
 
+	genpd->gd = gd;
 	return 0;
 
 free:
 	if (genpd_is_cpu_domain(genpd))
 		free_cpumask_var(genpd->cpus);
+	kfree(gd);
 	return ret;
 }
 
@@ -1997,6 +2016,7 @@ static void genpd_free_data(struct generic_pm_domain *genpd)
 		free_cpumask_var(genpd->cpus);
 	if (genpd->free_states)
 		genpd->free_states(genpd->states, genpd->state_count);
+	kfree(genpd->gd);
 }
 
 static void genpd_lock_init(struct generic_pm_domain *genpd)
@@ -2036,9 +2056,6 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
 	atomic_set(&genpd->sd_count, 0);
 	genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON;
 	genpd->device_count = 0;
-	genpd->max_off_time_ns = -1;
-	genpd->max_off_time_changed = true;
-	genpd->next_wakeup = KTIME_MAX;
 	genpd->provider = NULL;
 	genpd->has_provider = false;
 	genpd->accounting_time = ktime_get_mono_fast_ns();
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 599b3909821c..282a3a135827 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -146,19 +146,21 @@ static void update_domain_next_wakeup(struct generic_pm_domain *genpd, ktime_t n
 	}
 
 	list_for_each_entry(link, &genpd->parent_links, parent_node) {
-		next_wakeup = link->child->next_wakeup;
+		struct genpd_governor_data *cgd = link->child->gd;
+
+		next_wakeup = cgd ? cgd->next_wakeup : KTIME_MAX;
 		if (next_wakeup != KTIME_MAX && !ktime_before(next_wakeup, now))
 			if (ktime_before(next_wakeup, domain_wakeup))
 				domain_wakeup = next_wakeup;
 	}
 
-	genpd->next_wakeup = domain_wakeup;
+	genpd->gd->next_wakeup = domain_wakeup;
 }
 
 static bool next_wakeup_allows_state(struct generic_pm_domain *genpd,
 				     unsigned int state, ktime_t now)
 {
-	ktime_t domain_wakeup = genpd->next_wakeup;
+	ktime_t domain_wakeup = genpd->gd->next_wakeup;
 	s64 idle_time_ns, min_sleep_ns;
 
 	min_sleep_ns = genpd->states[state].power_off_latency_ns +
@@ -188,8 +190,9 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
 	 * All subdomains have been powered off already at this point.
 	 */
 	list_for_each_entry(link, &genpd->parent_links, parent_node) {
-		struct generic_pm_domain *sd = link->child;
-		s64 sd_max_off_ns = sd->max_off_time_ns;
+		struct genpd_governor_data *cgd = link->child->gd;
+
+		s64 sd_max_off_ns = cgd ? cgd->max_off_time_ns : -1;
 
 		if (sd_max_off_ns < 0)
 			continue;
@@ -247,7 +250,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
 	 * time and the time needed to turn the domain on is the maximum
 	 * theoretical time this domain can spend in the "off" state.
 	 */
-	genpd->max_off_time_ns = min_off_time_ns -
+	genpd->gd->max_off_time_ns = min_off_time_ns -
 		genpd->states[state].power_on_latency_ns;
 	return true;
 }
@@ -262,6 +265,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
 static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
 {
 	struct generic_pm_domain *genpd = pd_to_genpd(pd);
+	struct genpd_governor_data *gd = genpd->gd;
 	int state_idx = genpd->state_count - 1;
 	struct gpd_link *link;
 
@@ -272,11 +276,11 @@ static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
 	 * cannot be met.
 	 */
 	update_domain_next_wakeup(genpd, now);
-	if ((genpd->flags & GENPD_FLAG_MIN_RESIDENCY) && (genpd->next_wakeup != KTIME_MAX)) {
+	if ((genpd->flags & GENPD_FLAG_MIN_RESIDENCY) && (gd->next_wakeup != KTIME_MAX)) {
 		/* Let's find out the deepest domain idle state, the devices prefer */
 		while (state_idx >= 0) {
 			if (next_wakeup_allows_state(genpd, state_idx, now)) {
-				genpd->max_off_time_changed = true;
+				gd->max_off_time_changed = true;
 				break;
 			}
 			state_idx--;
@@ -284,14 +288,14 @@ static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
 
 		if (state_idx < 0) {
 			state_idx = 0;
-			genpd->cached_power_down_ok = false;
+			gd->cached_power_down_ok = false;
 			goto done;
 		}
 	}
 
-	if (!genpd->max_off_time_changed) {
-		genpd->state_idx = genpd->cached_power_down_state_idx;
-		return genpd->cached_power_down_ok;
+	if (!gd->max_off_time_changed) {
+		genpd->state_idx = gd->cached_power_down_state_idx;
+		return gd->cached_power_down_ok;
 	}
 
 	/*
@@ -300,12 +304,16 @@ static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
 	 * going to be called for any parent until this instance
 	 * returns.
 	 */
-	list_for_each_entry(link, &genpd->child_links, child_node)
-		link->parent->max_off_time_changed = true;
+	list_for_each_entry(link, &genpd->child_links, child_node) {
+		struct genpd_governor_data *pgd = link->parent->gd;
+
+		if (pgd)
+			pgd->max_off_time_changed = true;
+	}
 
-	genpd->max_off_time_ns = -1;
-	genpd->max_off_time_changed = false;
-	genpd->cached_power_down_ok = true;
+	gd->max_off_time_ns = -1;
+	gd->max_off_time_changed = false;
+	gd->cached_power_down_ok = true;
 
 	/*
 	 * Find a state to power down to, starting from the state
@@ -313,7 +321,7 @@ static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
 	 */
 	while (!__default_power_down_ok(pd, state_idx)) {
 		if (state_idx == 0) {
-			genpd->cached_power_down_ok = false;
+			gd->cached_power_down_ok = false;
 			break;
 		}
 		state_idx--;
@@ -321,8 +329,8 @@ static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
 
 done:
 	genpd->state_idx = state_idx;
-	genpd->cached_power_down_state_idx = genpd->state_idx;
-	return genpd->cached_power_down_ok;
+	gd->cached_power_down_state_idx = genpd->state_idx;
+	return gd->cached_power_down_ok;
 }
 
 static bool default_power_down_ok(struct dev_pm_domain *pd)
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 1f370f074f30..ebc351698090 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -91,6 +91,14 @@ struct gpd_dev_ops {
 	int (*stop)(struct device *dev);
 };
 
+struct genpd_governor_data {
+	s64 max_off_time_ns;
+	bool max_off_time_changed;
+	ktime_t next_wakeup;
+	bool cached_power_down_ok;
+	bool cached_power_down_state_idx;
+};
+
 struct genpd_power_state {
 	s64 power_off_latency_ns;
 	s64 power_on_latency_ns;
@@ -114,6 +122,7 @@ struct generic_pm_domain {
 	struct list_head child_links;	/* Links with PM domain as a child */
 	struct list_head dev_list;	/* List of devices */
 	struct dev_power_governor *gov;
+	struct genpd_governor_data *gd;	/* Data used by a genpd governor. */
 	struct work_struct power_off_work;
 	struct fwnode_handle *provider;	/* Identity of the domain provider */
 	bool has_provider;
@@ -134,11 +143,6 @@ struct generic_pm_domain {
 	int (*set_performance_state)(struct generic_pm_domain *genpd,
 				     unsigned int state);
 	struct gpd_dev_ops dev_ops;
-	s64 max_off_time_ns;	/* Maximum allowed "suspended" time. */
-	ktime_t next_wakeup;	/* Maintained by the domain governor */
-	bool max_off_time_changed;
-	bool cached_power_down_ok;
-	bool cached_power_down_state_idx;
 	int (*attach_dev)(struct generic_pm_domain *domain,
 			  struct device *dev);
 	void (*detach_dev)(struct generic_pm_domain *domain,
-- 
2.25.1


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

* [PATCH 13/14] PM: domains: Measure power-on/off latencies in genpd based on a governor
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (11 preceding siblings ...)
  2022-05-11 14:57 ` [PATCH 12/14] PM: domains: Allocate governor data dynamically based on a genpd governor Ulf Hansson
@ 2022-05-11 14:57 ` Ulf Hansson
  2022-05-11 14:57 ` [PATCH 14/14] PM: domains: Trust domain-idle-states from DT to be correct by genpd Ulf Hansson
  2022-05-19 18:37 ` [PATCH 00/14] PM: domains: Various improvements for genpd Rafael J. Wysocki
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:57 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

The measurements of the power-on|off latencies in genpd for a PM domain are
superfluous, unless the corresponding genpd has a governor assigned to it,
which would make use of the data.

Therefore, let's improve the behaviour in genpd by making the measurements
conditional, based upon if there's a governor assigned.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index a7de5fb8f073..83b073cdd0ed 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -509,6 +509,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 	if (!genpd->power_on)
 		goto out;
 
+	timed = timed && genpd->gd;
 	if (!timed) {
 		ret = genpd->power_on(genpd);
 		if (ret)
@@ -527,8 +528,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 		goto out;
 
 	genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
-	if (genpd->gd)
-		genpd->gd->max_off_time_changed = true;
+	genpd->gd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "on", elapsed_ns);
 
@@ -559,6 +559,7 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 	if (!genpd->power_off)
 		goto out;
 
+	timed = timed && genpd->gd;
 	if (!timed) {
 		ret = genpd->power_off(genpd);
 		if (ret)
@@ -577,8 +578,7 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 		goto out;
 
 	genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
-	if (genpd->gd)
-		genpd->gd->max_off_time_changed = true;
+	genpd->gd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "off", elapsed_ns);
 
-- 
2.25.1


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

* [PATCH 14/14] PM: domains: Trust domain-idle-states from DT to be correct by genpd
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (12 preceding siblings ...)
  2022-05-11 14:57 ` [PATCH 13/14] PM: domains: Measure power-on/off latencies in genpd based on a governor Ulf Hansson
@ 2022-05-11 14:57 ` Ulf Hansson
  2022-05-19 18:37 ` [PATCH 00/14] PM: domains: Various improvements for genpd Rafael J. Wysocki
  14 siblings, 0 replies; 16+ messages in thread
From: Ulf Hansson @ 2022-05-11 14:57 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-pm
  Cc: Rafael J . Wysocki, Geert Uytterhoeven, Maulik Shah,
	Gabriel Fernandez, Alexandre Torgue, Dmitry Osipenko,
	Kevin Hilman, Ulf Hansson, linux-arm-kernel, linux-kernel

If genpd has parsed the domain-idle-states from DT, it's reasonable to
believe that the parsed data should be correct for the HW in question.
Based upon this, it seem superfluous to let genpd measure the corresponding
power-on/off latencies for these states.

Therefore, let's improve the behaviour in genpd by avoiding the
measurements for the domain-idle-states that have been parsed from DT.

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

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 83b073cdd0ed..739e52cd4aba 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -509,7 +509,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 	if (!genpd->power_on)
 		goto out;
 
-	timed = timed && genpd->gd;
+	timed = timed && genpd->gd && !genpd->states[state_idx].fwnode;
 	if (!timed) {
 		ret = genpd->power_on(genpd);
 		if (ret)
@@ -559,7 +559,7 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 	if (!genpd->power_off)
 		goto out;
 
-	timed = timed && genpd->gd;
+	timed = timed && genpd->gd && !genpd->states[state_idx].fwnode;
 	if (!timed) {
 		ret = genpd->power_off(genpd);
 		if (ret)
-- 
2.25.1


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

* Re: [PATCH 00/14] PM: domains: Various improvements for genpd
  2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
                   ` (13 preceding siblings ...)
  2022-05-11 14:57 ` [PATCH 14/14] PM: domains: Trust domain-idle-states from DT to be correct by genpd Ulf Hansson
@ 2022-05-19 18:37 ` Rafael J. Wysocki
  14 siblings, 0 replies; 16+ messages in thread
From: Rafael J. Wysocki @ 2022-05-19 18:37 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rafael J . Wysocki, Linux PM, Rafael J . Wysocki,
	Geert Uytterhoeven, Maulik Shah, Gabriel Fernandez,
	Alexandre Torgue, Dmitry Osipenko, Kevin Hilman, Linux ARM,
	Linux Kernel Mailing List

On Wed, May 11, 2022 at 4:57 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> The main goal with this series is to improve the way genpd deals with its
> governor(s). Especially it turns allocation of governor related data to be
> dynamically allocated. It also improves the execution path for runtime-
> suspend/resume of devices (attached to a genpd of course) and the similar is
> also done for genpd's power-on/off path.
>
> Note that, patch 1->3 have already been sent before in a separate series [1],
> but for simplicity I have included them here again.
>
> Tests/reviews are as usual highly appreciated!
>
> Kind regards
> Ulf Hansson
>
> [1]
> https://www.spinics.net/lists/kernel/msg4335838.html
>
> Ulf Hansson (14):
>   PM: domains: Add GENPD_FLAG_RPM_ALWAYS_ON for the always-on governor
>   PM: domains: Drop redundant code for genpd always-on governor
>   PM: domains: Don't check PM_QOS_FLAG_NO_POWER_OFF in genpd
>   PM: domains: Rename irq_safe_dev_in_no_sleep_domain() in genpd
>   PM: domains: Skip another warning in irq_safe_dev_in_sleep_domain()
>   PM: domains: Allocate gpd_timing_data dynamically based on governor
>   PM: domains: Move the next_wakeup variable into the struct
>     gpd_timing_data
>   PM: domains: Measure suspend/resume latencies in genpd based on
>     governor
>   PM: domains: Fixup QoS latency measurements for IRQ safe devices in
>     genpd
>   PM: domains: Fix initialization of genpd's next_wakeup
>   PM: domains: Clean up some code in pm_genpd_init() and genpd_remove()
>   PM: domains: Allocate governor data dynamically based on a genpd
>     governor
>   PM: domains: Measure power-on/off latencies in genpd based on a
>     governor
>   PM: domains: Trust domain-idle-states from DT to be correct by genpd
>
>  drivers/base/power/domain.c          | 201 +++++++++++++++++----------
>  drivers/base/power/domain_governor.c |  65 +++++----
>  include/linux/pm_domain.h            |  18 ++-
>  3 files changed, 173 insertions(+), 111 deletions(-)
>
> --

All of the changes made by this series make sense to me, so I've
queued it for 5.19.

Thanks!

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

end of thread, other threads:[~2022-05-19 18:37 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-11 14:56 [PATCH 00/14] PM: domains: Various improvements for genpd Ulf Hansson
2022-05-11 14:56 ` [PATCH 01/14] PM: domains: Add GENPD_FLAG_RPM_ALWAYS_ON for the always-on governor Ulf Hansson
2022-05-11 14:56 ` [PATCH 02/14] PM: domains: Drop redundant code for genpd " Ulf Hansson
2022-05-11 14:56 ` [PATCH 03/14] PM: domains: Don't check PM_QOS_FLAG_NO_POWER_OFF in genpd Ulf Hansson
2022-05-11 14:56 ` [PATCH 04/14] PM: domains: Rename irq_safe_dev_in_no_sleep_domain() " Ulf Hansson
2022-05-11 14:56 ` [PATCH 05/14] PM: domains: Skip another warning in irq_safe_dev_in_sleep_domain() Ulf Hansson
2022-05-11 14:56 ` [PATCH 06/14] PM: domains: Allocate gpd_timing_data dynamically based on governor Ulf Hansson
2022-05-11 14:56 ` [PATCH 07/14] PM: domains: Move the next_wakeup variable into the struct gpd_timing_data Ulf Hansson
2022-05-11 14:56 ` [PATCH 08/14] PM: domains: Measure suspend/resume latencies in genpd based on governor Ulf Hansson
2022-05-11 14:56 ` [PATCH 09/14] PM: domains: Fixup QoS latency measurements for IRQ safe devices in genpd Ulf Hansson
2022-05-11 14:57 ` [PATCH 10/14] PM: domains: Fix initialization of genpd's next_wakeup Ulf Hansson
2022-05-11 14:57 ` [PATCH 11/14] PM: domains: Clean up some code in pm_genpd_init() and genpd_remove() Ulf Hansson
2022-05-11 14:57 ` [PATCH 12/14] PM: domains: Allocate governor data dynamically based on a genpd governor Ulf Hansson
2022-05-11 14:57 ` [PATCH 13/14] PM: domains: Measure power-on/off latencies in genpd based on a governor Ulf Hansson
2022-05-11 14:57 ` [PATCH 14/14] PM: domains: Trust domain-idle-states from DT to be correct by genpd Ulf Hansson
2022-05-19 18:37 ` [PATCH 00/14] PM: domains: Various improvements for genpd Rafael J. Wysocki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).