All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFT][PATCH 0/2] PM / QoS: Device resume latency framework fix
@ 2017-11-01 23:00 Rafael J. Wysocki
  2017-11-01 23:01 ` [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
                   ` (2 more replies)
  0 siblings, 3 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-01 23:00 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

Hi,

This series is a replacement for commit 0cc2b4e5a020 (PM / QoS: Fix device
resume latency PM QoS) that had to be reverted due to problems introduced by it.

This time the genpd PM QoS governor is first updated to be more consistent
and the PM QoS changes are made on top of that which simplifies the second
patch quite a bit.

This is based on the linux-next branch from linux-pm.git as of now (should
also apply to the current mainline just fine).

Please test if you can or let me know if you have any comments.

Thanks,
Rafael

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

* [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-01 23:00 [RFT][PATCH 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
@ 2017-11-01 23:01 ` Rafael J. Wysocki
  2017-11-03  7:05   ` Ramesh Thomas
  2017-11-01 23:03 ` [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
  2017-11-03 11:42 ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
  2 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-01 23:01 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The genpd governor currently uses negative PM QoS values to indicate
the "no suspend" condition and 0 as "no restriction", but it doesn't
use them consistently.  Moreover, it tries to refresh QoS values for
already suspended devices in a quite questionable way.

For the above reasons, rework it to be a bit more consistent.

First off, note that dev_pm_qos_read_value() in
dev_update_qos_constraint() and __default_power_down_ok() is
evaluated for devices in suspend.  Moreover, that only happens if the
effective_constraint_ns value for them is negative (meaning "no
suspend").  It is not evaluated in any other cases, so effectively
the QoS values are only updated for devices in suspend that should
not have been suspended in the first place.  In all of the other
cases, the QoS values taken into account are the effective ones from
the time before the device has been suspended, so generally devices
need to be resumed and suspended again for new QoS values to take
effect anyway.  Thus evaluating dev_update_qos_constraint() in
those two places doesn't make sense at all, so drop it.

Second, initialize effective_constraint_ns to 0 ("no constraint")
rather than to (-1) ("no suspend"), which makes more sense in
general and in case effective_constraint_ns is never updated
(the device is in suspend all the time or it is never suspended)
it doesn't affect the device's parent and so on.

Finally, rework default_suspend_ok() to explicitly handle the
"no restriction" and "no suspend" special cases.

Also add WARN_ON() around checks that should never trigger.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/base/power/domain.c          |    2 -
 drivers/base/power/domain_governor.c |   56 ++++++++++++++++++++---------------
 2 files changed, 33 insertions(+), 25 deletions(-)

Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = -1;
+	gpd_data->td.effective_constraint_ns = 0;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -14,22 +14,22 @@
 static int dev_update_qos_constraint(struct device *dev, void *data)
 {
 	s64 *constraint_ns_p = data;
-	s32 constraint_ns = -1;
-
-	if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
-		constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+	s64 constraint_ns;
 
-	if (constraint_ns < 0) {
-		constraint_ns = dev_pm_qos_read_value(dev);
-		constraint_ns *= NSEC_PER_USEC;
-	}
-	if (constraint_ns == 0)
+	if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
 		return 0;
 
 	/*
-	 * constraint_ns cannot be negative here, because the device has been
-	 * suspended.
+	 * Only take suspend-time QoS constraints of devices into account,
+	 * because constraints updated after the device has been suspended are
+	 * not guaranteed to be taken into account 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;
+	/* 0 means "no constraint" */
+	if (constraint_ns == 0)
+		return 0;
+
 	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
 		*constraint_ns_p = constraint_ns;
 
@@ -76,14 +76,26 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns > 0) {
+	if (constraint_ns == 0) {
+		/* "No restriction", so the device is allowed to suspend. */
+		td->effective_constraint_ns = 0;
+		td->cached_suspend_ok = true;
+	} else if (WARN_ON(constraint_ns < 0)) {
+		/*
+		 * effective_constraint_ns is negative already and
+		 * cached_suspend_ok is false, so return right away.
+		 */
+		return false;
+	} else {
 		constraint_ns -= td->suspend_latency_ns +
 				td->resume_latency_ns;
-		if (constraint_ns == 0)
+		/* Again, if negative or zero, returning right away is fine. */
+		if (constraint_ns <= 0)
 			return false;
+
+		td->effective_constraint_ns = constraint_ns;
+		td->cached_suspend_ok = true;
 	}
-	td->effective_constraint_ns = constraint_ns;
-	td->cached_suspend_ok = constraint_ns >= 0;
 
 	/*
 	 * The children have been suspended already, so we don't need to take
@@ -144,18 +156,14 @@ static bool __default_power_down_ok(stru
 		 */
 		td = &to_gpd_data(pdd)->td;
 		constraint_ns = td->effective_constraint_ns;
-		/* default_suspend_ok() need not be called before us. */
-		if (constraint_ns < 0) {
-			constraint_ns = dev_pm_qos_read_value(pdd->dev);
-			constraint_ns *= NSEC_PER_USEC;
-		}
+		/* Negative values mean "no suspend at all" */
+		if (WARN_ON(constraint_ns < 0))
+			return false;
+
+		/* 0 means "no constraint" */
 		if (constraint_ns == 0)
 			continue;
 
-		/*
-		 * constraint_ns cannot be negative here, because the device has
-		 * been suspended.
-		 */
 		if (constraint_ns <= off_on_time_ns)
 			return false;
 

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

* [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework
  2017-11-01 23:00 [RFT][PATCH 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
  2017-11-01 23:01 ` [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
@ 2017-11-01 23:03 ` Rafael J. Wysocki
  2017-11-03  7:43   ` Ramesh Thomas
  2017-11-03 11:42 ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
  2 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-01 23:03 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The special value of 0 for device resume latency PM QoS means
"no restriction", but there are two problems with that.

First, device resume latency PM QoS requests with 0 as the
value are always put in front of requests with positive
values in the priority lists used internally by the PM QoS
framework, causing 0 to be chosen as an effective constraint
value.  However, that 0 is then interpreted as "no restriction"
effectively overriding the other requests with specific
restrictions which is incorrect.

Second, the users of device resume latency PM QoS have no
way to specify that *any* resume latency at all should be
avoided, which is an artificial limitation in general.

To address these issues, modify device resume latency PM QoS to
use S32_MAX as the "no constraint" value and 0 as the "no
latency at all" one and rework its users (the cpuidle menu
governor, the genpd QoS governor and the runtime PM framework)
to follow these changes.

Also add a special "n/a" value to the corresponding user space I/F
to allow user space to indicate that it cannot accept any resume
latencies at all for the given device.

Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 Documentation/ABI/testing/sysfs-devices-power |    4 ++-
 drivers/base/cpu.c                            |    3 +-
 drivers/base/power/domain.c                   |    2 -
 drivers/base/power/domain_governor.c          |   27 ++++++++++++--------------
 drivers/base/power/qos.c                      |    5 +++-
 drivers/base/power/runtime.c                  |    2 -
 drivers/base/power/sysfs.c                    |   25 ++++++++++++++++++++----
 drivers/cpuidle/governors/menu.c              |    4 +--
 include/linux/pm_qos.h                        |   24 +++++++++++++++--------
 9 files changed, 63 insertions(+), 33 deletions(-)

Index: linux-pm/drivers/base/power/sysfs.c
===================================================================
--- linux-pm.orig/drivers/base/power/sysfs.c
+++ linux-pm/drivers/base/power/sysfs.c
@@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
 					  struct device_attribute *attr,
 					  char *buf)
 {
-	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
+	s32 value = dev_pm_qos_requested_resume_latency(dev);
+
+	if (value == 0)
+		return sprintf(buf, "n/a\n");
+	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+		value = 0;
+
+	return sprintf(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_resume_latency_store(struct device *dev,
@@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
 	s32 value;
 	int ret;
 
-	if (kstrtos32(buf, 0, &value))
-		return -EINVAL;
+	if (!kstrtos32(buf, 0, &value)) {
+		/*
+		 * Prevent users from writing negative or "no constraint" values
+		 * directly.
+		 */
+		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+			return -EINVAL;
 
-	if (value < 0)
+		if (value == 0)
+			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
+		value = 0;
+	} else {
 		return -EINVAL;
+	}
 
 	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
 					value);
Index: linux-pm/include/linux/pm_qos.h
===================================================================
--- linux-pm.orig/include/linux/pm_qos.h
+++ linux-pm/include/linux/pm_qos.h
@@ -27,16 +27,17 @@ enum pm_qos_flags_status {
 	PM_QOS_FLAGS_ALL,
 };
 
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_DEFAULT_VALUE	(-1)
+#define PM_QOS_LATENCY_ANY	S32_MAX
 
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
-#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
-#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
 
@@ -173,7 +174,8 @@ static inline s32 dev_pm_qos_requested_f
 static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
 {
 	return IS_ERR_OR_NULL(dev->power.qos) ?
-		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
+		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
+		pm_qos_read_value(&dev->power.qos->resume_latency);
 }
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -183,9 +185,9 @@ static inline enum pm_qos_flags_status d
 							s32 mask)
 			{ return PM_QOS_FLAGS_UNDEFINED; }
 static inline s32 __dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline s32 dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline int dev_pm_qos_add_request(struct device *dev,
 					 struct dev_pm_qos_request *req,
 					 enum dev_pm_qos_req_type type,
@@ -231,9 +233,15 @@ static inline int dev_pm_qos_expose_late
 			{ return 0; }
 static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
 
-static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 #endif
 
 #endif
Index: linux-pm/drivers/cpuidle/governors/menu.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/menu.c
+++ linux-pm/drivers/cpuidle/governors/menu.c
@@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
 		data->needs_update = 0;
 	}
 
-	/* resume_latency is 0 means no restriction */
-	if (resume_latency && resume_latency < latency_req)
+	if (resume_latency < latency_req &&
+	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		latency_req = resume_latency;
 
 	/* Special case when user has set very strict latency requirement */
Index: linux-pm/drivers/base/power/runtime.c
===================================================================
--- linux-pm.orig/drivers/base/power/runtime.c
+++ linux-pm/drivers/base/power/runtime.c
@@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
-	else if (__dev_pm_qos_read_value(dev) < 0)
+	else if (__dev_pm_qos_read_value(dev) == 0)
 		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
Index: linux-pm/drivers/base/cpu.c
===================================================================
--- linux-pm.orig/drivers/base/cpu.c
+++ linux-pm/drivers/base/cpu.c
@@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
 
 	per_cpu(cpu_sys_devices, num) = &cpu->dev;
 	register_cpu_under_node(num, cpu_to_node(num));
-	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
+	dev_pm_qos_expose_latency_limit(&cpu->dev,
+					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
 
 	return 0;
 }
Index: linux-pm/drivers/base/power/qos.c
===================================================================
--- linux-pm.orig/drivers/base/power/qos.c
+++ linux-pm/drivers/base/power/qos.c
@@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
 
 	switch(req->type) {
 	case DEV_PM_QOS_RESUME_LATENCY:
+		if (WARN_ON(value < 0))
+			value = 0;
+
 		ret = pm_qos_update_target(&qos->resume_latency,
 					   &req->data.pnode, action, value);
 		break;
@@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
 	plist_head_init(&c->list);
 	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
 	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
-	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 	c->type = PM_QOS_MIN;
 	c->notifiers = n;
 
Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
===================================================================
--- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
+++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
@@ -211,7 +211,9 @@ Description:
 		device, after it has been suspended at run time, from a resume
 		request to the moment the device will be ready to process I/O,
 		in microseconds.  If it is equal to 0, however, this means that
-		the PM QoS resume latency may be arbitrary.
+		the PM QoS resume latency may be arbitrary and the special value
+		"n/a" means that user space cannot accept any resume latency at
+		all for the given device.
 
 		Not all drivers support this attribute.  If it isn't supported,
 		it is not present.
Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = 0;
+	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -26,11 +26,11 @@ static int dev_update_qos_constraint(str
 	 * to take effect, the device has to be resumed and suspended again.
 	 */
 	constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
-	/* 0 means "no constraint" */
-	if (constraint_ns == 0)
+	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		return 0;
 
-	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+	if (constraint_ns < *constraint_ns_p ||
+	    *constraint_ns_p == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		*constraint_ns_p = constraint_ns;
 
 	return 0;
@@ -58,12 +58,12 @@ static bool default_suspend_ok(struct de
 	}
 	td->constraint_changed = false;
 	td->cached_suspend_ok = false;
-	td->effective_constraint_ns = -1;
+	td->effective_constraint_ns = 0;
 	constraint_ns = __dev_pm_qos_read_value(dev);
 
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
-	if (constraint_ns < 0)
+	if (constraint_ns == 0)
 		return false;
 
 	constraint_ns *= NSEC_PER_USEC;
@@ -76,14 +76,14 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns == 0) {
+	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) {
 		/* "No restriction", so the device is allowed to suspend. */
-		td->effective_constraint_ns = 0;
+		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 		td->cached_suspend_ok = true;
-	} else if (WARN_ON(constraint_ns < 0)) {
+	} else if (WARN_ON(constraint_ns == 0)) {
 		/*
-		 * effective_constraint_ns is negative already and
-		 * cached_suspend_ok is false, so return right away.
+		 * effective_constraint_ns is 0 already and cached_suspend_ok is
+		 * false, so return right away.
 		 */
 		return false;
 	} else {
@@ -156,12 +156,11 @@ static bool __default_power_down_ok(stru
 		 */
 		td = &to_gpd_data(pdd)->td;
 		constraint_ns = td->effective_constraint_ns;
-		/* Negative values mean "no suspend at all" */
-		if (WARN_ON(constraint_ns < 0))
+		/* 0 mean "no suspend at all" */
+		if (WARN_ON(constraint_ns == 0))
 			return false;
 
-		/* 0 means "no constraint" */
-		if (constraint_ns == 0)
+		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 			continue;
 
 		if (constraint_ns <= off_on_time_ns)

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

* Re: [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-01 23:01 ` [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
@ 2017-11-03  7:05   ` Ramesh Thomas
  2017-11-03  7:51     ` Rafael J. Wysocki
  0 siblings, 1 reply; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-03  7:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On 2017-11-02 at 00:01:50 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The genpd governor currently uses negative PM QoS values to indicate
> the "no suspend" condition and 0 as "no restriction", but it doesn't
> use them consistently.  Moreover, it tries to refresh QoS values for
> already suspended devices in a quite questionable way.
> 
> For the above reasons, rework it to be a bit more consistent.
> 
> First off, note that dev_pm_qos_read_value() in
> dev_update_qos_constraint() and __default_power_down_ok() is
> evaluated for devices in suspend.  Moreover, that only happens if the
> effective_constraint_ns value for them is negative (meaning "no
> suspend").  It is not evaluated in any other cases, so effectively
> the QoS values are only updated for devices in suspend that should
> not have been suspended in the first place.  In all of the other
> cases, the QoS values taken into account are the effective ones from
> the time before the device has been suspended, so generally devices
> need to be resumed and suspended again for new QoS values to take
> effect anyway.  Thus evaluating dev_update_qos_constraint() in
> those two places doesn't make sense at all, so drop it.
> 
> Second, initialize effective_constraint_ns to 0 ("no constraint")
> rather than to (-1) ("no suspend"), which makes more sense in
> general and in case effective_constraint_ns is never updated
> (the device is in suspend all the time or it is never suspended)
> it doesn't affect the device's parent and so on.
> 
> Finally, rework default_suspend_ok() to explicitly handle the
> "no restriction" and "no suspend" special cases.
> 
> Also add WARN_ON() around checks that should never trigger.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/base/power/domain.c          |    2 -
>  drivers/base/power/domain_governor.c |   56 ++++++++++++++++++++---------------
>  2 files changed, 33 insertions(+), 25 deletions(-)
> 
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>  
>  	gpd_data->base.dev = dev;
>  	gpd_data->td.constraint_changed = true;
> -	gpd_data->td.effective_constraint_ns = -1;
> +	gpd_data->td.effective_constraint_ns = 0;
>  	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>  
>  	spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -14,22 +14,22 @@
>  static int dev_update_qos_constraint(struct device *dev, void *data)
>  {
>  	s64 *constraint_ns_p = data;
> -	s32 constraint_ns = -1;
> -
> -	if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
> -		constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
> +	s64 constraint_ns;
>  
> -	if (constraint_ns < 0) {
> -		constraint_ns = dev_pm_qos_read_value(dev);
> -		constraint_ns *= NSEC_PER_USEC;
> -	}
> -	if (constraint_ns == 0)
> +	if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
>  		return 0;
>  
>  	/*
> -	 * constraint_ns cannot be negative here, because the device has been
> -	 * suspended.
> +	 * Only take suspend-time QoS constraints of devices into account,
> +	 * because constraints updated after the device has been suspended are
> +	 * not guaranteed to be taken into account 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;
> +	/* 0 means "no constraint" */
> +	if (constraint_ns == 0)
> +		return 0;
> +
>  	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>  		*constraint_ns_p = constraint_ns;
>  
> @@ -76,14 +76,26 @@ static bool default_suspend_ok(struct de
>  		device_for_each_child(dev, &constraint_ns,
>  				      dev_update_qos_constraint);
>  
> -	if (constraint_ns > 0) {
> +	if (constraint_ns == 0) {
> +		/* "No restriction", so the device is allowed to suspend. */
> +		td->effective_constraint_ns = 0;
> +		td->cached_suspend_ok = true;
> +	} else if (WARN_ON(constraint_ns < 0)) {

Should never comer here. Child should not have suspended.
Should be a fatal bug. This else block probably is not necessary.

> +		/*
> +		 * effective_constraint_ns is negative already and
> +		 * cached_suspend_ok is false, so return right away.
> +		 */
> +		return false;
> +	} else {
>  		constraint_ns -= td->suspend_latency_ns +
>  				td->resume_latency_ns;
> -		if (constraint_ns == 0)
> +		/* Again, if negative or zero, returning right away is fine. */
> +		if (constraint_ns <= 0)
>  			return false;
> +
> +		td->effective_constraint_ns = constraint_ns;
> +		td->cached_suspend_ok = true;
>  	}
> -	td->effective_constraint_ns = constraint_ns;
> -	td->cached_suspend_ok = constraint_ns >= 0;
>  
>  	/*
>  	 * The children have been suspended already, so we don't need to take
> @@ -144,18 +156,14 @@ static bool __default_power_down_ok(stru
>  		 */
>  		td = &to_gpd_data(pdd)->td;
>  		constraint_ns = td->effective_constraint_ns;
> -		/* default_suspend_ok() need not be called before us. */
> -		if (constraint_ns < 0) {
> -			constraint_ns = dev_pm_qos_read_value(pdd->dev);
> -			constraint_ns *= NSEC_PER_USEC;
> -		}
> +		/* Negative values mean "no suspend at all" */
> +		if (WARN_ON(constraint_ns < 0))
> +			return false;

Cannot come here if was not suspended. Looks like a redundant check.

> +
> +		/* 0 means "no constraint" */
>  		if (constraint_ns == 0)
>  			continue;
>  
> -		/*
> -		 * constraint_ns cannot be negative here, because the device has
> -		 * been suspended.
> -		 */
>  		if (constraint_ns <= off_on_time_ns)
>  			return false;
>  
> 

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

* Re: [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework
  2017-11-01 23:03 ` [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
@ 2017-11-03  7:43   ` Ramesh Thomas
  2017-11-03  7:58     ` Rafael J. Wysocki
  0 siblings, 1 reply; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-03  7:43 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On 2017-11-02 at 00:03:54 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The special value of 0 for device resume latency PM QoS means
> "no restriction", but there are two problems with that.
> 
> First, device resume latency PM QoS requests with 0 as the
> value are always put in front of requests with positive
> values in the priority lists used internally by the PM QoS
> framework, causing 0 to be chosen as an effective constraint
> value.  However, that 0 is then interpreted as "no restriction"
> effectively overriding the other requests with specific
> restrictions which is incorrect.
> 
> Second, the users of device resume latency PM QoS have no
> way to specify that *any* resume latency at all should be
> avoided, which is an artificial limitation in general.
> 
> To address these issues, modify device resume latency PM QoS to
> use S32_MAX as the "no constraint" value and 0 as the "no
> latency at all" one and rework its users (the cpuidle menu
> governor, the genpd QoS governor and the runtime PM framework)
> to follow these changes.
> 
> Also add a special "n/a" value to the corresponding user space I/F
> to allow user space to indicate that it cannot accept any resume
> latencies at all for the given device.
> 
> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-devices-power |    4 ++-
>  drivers/base/cpu.c                            |    3 +-
>  drivers/base/power/domain.c                   |    2 -
>  drivers/base/power/domain_governor.c          |   27 ++++++++++++--------------
>  drivers/base/power/qos.c                      |    5 +++-
>  drivers/base/power/runtime.c                  |    2 -
>  drivers/base/power/sysfs.c                    |   25 ++++++++++++++++++++----
>  drivers/cpuidle/governors/menu.c              |    4 +--
>  include/linux/pm_qos.h                        |   24 +++++++++++++++--------
>  9 files changed, 63 insertions(+), 33 deletions(-)
> 
> Index: linux-pm/drivers/base/power/sysfs.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/sysfs.c
> +++ linux-pm/drivers/base/power/sysfs.c
> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>  					  struct device_attribute *attr,
>  					  char *buf)
>  {
> -	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
> +	s32 value = dev_pm_qos_requested_resume_latency(dev);
> +
> +	if (value == 0)
> +		return sprintf(buf, "n/a\n");
> +	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +		value = 0;
> +
> +	return sprintf(buf, "%d\n", value);
>  }
>  
>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>  	s32 value;
>  	int ret;
>  
> -	if (kstrtos32(buf, 0, &value))
> -		return -EINVAL;
> +	if (!kstrtos32(buf, 0, &value)) {
> +		/*
> +		 * Prevent users from writing negative or "no constraint" values
> +		 * directly.
> +		 */
> +		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +			return -EINVAL;
>  
> -	if (value < 0)
> +		if (value == 0)
> +			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
> +		value = 0;
> +	} else {
>  		return -EINVAL;
> +	}
>  
>  	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>  					value);
> Index: linux-pm/include/linux/pm_qos.h
> ===================================================================
> --- linux-pm.orig/include/linux/pm_qos.h
> +++ linux-pm/include/linux/pm_qos.h
> @@ -27,16 +27,17 @@ enum pm_qos_flags_status {
>  	PM_QOS_FLAGS_ALL,
>  };
>  
> -#define PM_QOS_DEFAULT_VALUE -1
> +#define PM_QOS_DEFAULT_VALUE	(-1)
> +#define PM_QOS_LATENCY_ANY	S32_MAX
>  
>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
> -#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
>  
>  #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
>  
> @@ -173,7 +174,8 @@ static inline s32 dev_pm_qos_requested_f
>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>  {
>  	return IS_ERR_OR_NULL(dev->power.qos) ?
> -		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
> +		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
> +		pm_qos_read_value(&dev->power.qos->resume_latency);
>  }
>  #else
>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
> @@ -183,9 +185,9 @@ static inline enum pm_qos_flags_status d
>  							s32 mask)
>  			{ return PM_QOS_FLAGS_UNDEFINED; }
>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline s32 dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline int dev_pm_qos_add_request(struct device *dev,
>  					 struct dev_pm_qos_request *req,
>  					 enum dev_pm_qos_req_type type,
> @@ -231,9 +233,15 @@ static inline int dev_pm_qos_expose_late
>  			{ return 0; }
>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>  
> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  #endif
>  
>  #endif
> Index: linux-pm/drivers/cpuidle/governors/menu.c
> ===================================================================
> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
> +++ linux-pm/drivers/cpuidle/governors/menu.c
> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>  		data->needs_update = 0;
>  	}
>  
> -	/* resume_latency is 0 means no restriction */
> -	if (resume_latency && resume_latency < latency_req)
> +	if (resume_latency < latency_req &&
> +	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>  		latency_req = resume_latency;
>  
>  	/* Special case when user has set very strict latency requirement */
> Index: linux-pm/drivers/base/power/runtime.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/runtime.c
> +++ linux-pm/drivers/base/power/runtime.c
> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>  	    || (dev->power.request_pending
>  			&& dev->power.request == RPM_REQ_RESUME))
>  		retval = -EAGAIN;
> -	else if (__dev_pm_qos_read_value(dev) < 0)
> +	else if (__dev_pm_qos_read_value(dev) == 0)
>  		retval = -EPERM;
>  	else if (dev->power.runtime_status == RPM_SUSPENDED)
>  		retval = 1;
> Index: linux-pm/drivers/base/cpu.c
> ===================================================================
> --- linux-pm.orig/drivers/base/cpu.c
> +++ linux-pm/drivers/base/cpu.c
> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>  
>  	per_cpu(cpu_sys_devices, num) = &cpu->dev;
>  	register_cpu_under_node(num, cpu_to_node(num));
> -	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
> +	dev_pm_qos_expose_latency_limit(&cpu->dev,
> +					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>  
>  	return 0;
>  }
> Index: linux-pm/drivers/base/power/qos.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/qos.c
> +++ linux-pm/drivers/base/power/qos.c
> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>  
>  	switch(req->type) {
>  	case DEV_PM_QOS_RESUME_LATENCY:
> +		if (WARN_ON(value < 0))
> +			value = 0;
> +
>  		ret = pm_qos_update_target(&qos->resume_latency,
>  					   &req->data.pnode, action, value);
>  		break;
> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>  	plist_head_init(&c->list);
>  	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>  	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> -	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> +	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>  	c->type = PM_QOS_MIN;
>  	c->notifiers = n;
>  
> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
> ===================================================================
> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
> @@ -211,7 +211,9 @@ Description:
>  		device, after it has been suspended at run time, from a resume
>  		request to the moment the device will be ready to process I/O,
>  		in microseconds.  If it is equal to 0, however, this means that
> -		the PM QoS resume latency may be arbitrary.
> +		the PM QoS resume latency may be arbitrary and the special value
> +		"n/a" means that user space cannot accept any resume latency at
> +		all for the given device.
>  
>  		Not all drivers support this attribute.  If it isn't supported,
>  		it is not present.
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>  
>  	gpd_data->base.dev = dev;
>  	gpd_data->td.constraint_changed = true;
> -	gpd_data->td.effective_constraint_ns = 0;
> +	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>  	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>  
>  	spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -26,11 +26,11 @@ static int dev_update_qos_constraint(str
>  	 * to take effect, the device has to be resumed and suspended again.
>  	 */
>  	constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
> -	/* 0 means "no constraint" */
> -	if (constraint_ns == 0)
> +	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>  		return 0;
>  
> -	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
> +	if (constraint_ns < *constraint_ns_p ||
> +	    *constraint_ns_p == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)

Check for constraint_ns < *constraint_ns_p should be enough because
PM_QOS_RESUME_LATENCY_NO_CONSTRAINT = S32_MAX which is the largest possible
value, if that can be assumed here.

>  		*constraint_ns_p = constraint_ns;
>  
>  	return 0;
> @@ -58,12 +58,12 @@ static bool default_suspend_ok(struct de
>  	}
>  	td->constraint_changed = false;
>  	td->cached_suspend_ok = false;
> -	td->effective_constraint_ns = -1;
> +	td->effective_constraint_ns = 0;
>  	constraint_ns = __dev_pm_qos_read_value(dev);

Why not initialize td->effective_constraint_ns with what is read by
__dev_pm_qos_read_value()? Even though this value will stay only if false
is returned, in which case it does not matter anyway, it looks like more
meaningful value. Also PM_QOS_RESUME_LATENCY_NO_CONSTRAINT may be ok as it
is initialized with at creation.

>  
>  	spin_unlock_irqrestore(&dev->power.lock, flags);
>  
> -	if (constraint_ns < 0)
> +	if (constraint_ns == 0)
>  		return false;
>  
>  	constraint_ns *= NSEC_PER_USEC;

This will go wrong if PM_QOS_RESUME_LATENCY_NO_CONSTRAINT was the value
Code below and in dev_update_qos_constraint check for that special value.

May be those places can check PM_QOS_RESUME_LATENCY_NO_CONSTRAINT * NSEC_PER_USEC
There may be other places that this might be an issue

> @@ -76,14 +76,14 @@ static bool default_suspend_ok(struct de
>  		device_for_each_child(dev, &constraint_ns,
>  				      dev_update_qos_constraint);
>  
> -	if (constraint_ns == 0) {
> +	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) {
>  		/* "No restriction", so the device is allowed to suspend. */
> -		td->effective_constraint_ns = 0;
> +		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>  		td->cached_suspend_ok = true;
> -	} else if (WARN_ON(constraint_ns < 0)) {
> +	} else if (WARN_ON(constraint_ns == 0)) {

This can never happen as this device will not be suspending if the child had
failed to suspend (only case where this value is possible).

>  		/*
> -		 * effective_constraint_ns is negative already and
> -		 * cached_suspend_ok is false, so return right away.
> +		 * effective_constraint_ns is 0 already and cached_suspend_ok is
> +		 * false, so return right away.
>  		 */
>  		return false;
>  	} else {
> @@ -156,12 +156,11 @@ static bool __default_power_down_ok(stru
>  		 */
>  		td = &to_gpd_data(pdd)->td;
>  		constraint_ns = td->effective_constraint_ns;
> -		/* Negative values mean "no suspend at all" */
> -		if (WARN_ON(constraint_ns < 0))
> +		/* 0 mean "no suspend at all" */
> +		if (WARN_ON(constraint_ns == 0))
>  			return false;

If it did not suspend then it cannot powerdown. This check may not be
very useful here.

>  
> -		/* 0 means "no constraint" */
> -		if (constraint_ns == 0)
> +		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>  			continue;
>  
>  		if (constraint_ns <= off_on_time_ns)
> 

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

* Re: [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-03  7:05   ` Ramesh Thomas
@ 2017-11-03  7:51     ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-03  7:51 UTC (permalink / raw)
  To: ramesh.thomas
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

On Fri, Nov 3, 2017 at 8:05 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> On 2017-11-02 at 00:01:50 +0100, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> The genpd governor currently uses negative PM QoS values to indicate
>> the "no suspend" condition and 0 as "no restriction", but it doesn't
>> use them consistently.  Moreover, it tries to refresh QoS values for
>> already suspended devices in a quite questionable way.
>>
>> For the above reasons, rework it to be a bit more consistent.
>>
>> First off, note that dev_pm_qos_read_value() in
>> dev_update_qos_constraint() and __default_power_down_ok() is
>> evaluated for devices in suspend.  Moreover, that only happens if the
>> effective_constraint_ns value for them is negative (meaning "no
>> suspend").  It is not evaluated in any other cases, so effectively
>> the QoS values are only updated for devices in suspend that should
>> not have been suspended in the first place.  In all of the other
>> cases, the QoS values taken into account are the effective ones from
>> the time before the device has been suspended, so generally devices
>> need to be resumed and suspended again for new QoS values to take
>> effect anyway.  Thus evaluating dev_update_qos_constraint() in
>> those two places doesn't make sense at all, so drop it.
>>
>> Second, initialize effective_constraint_ns to 0 ("no constraint")
>> rather than to (-1) ("no suspend"), which makes more sense in
>> general and in case effective_constraint_ns is never updated
>> (the device is in suspend all the time or it is never suspended)
>> it doesn't affect the device's parent and so on.
>>
>> Finally, rework default_suspend_ok() to explicitly handle the
>> "no restriction" and "no suspend" special cases.
>>
>> Also add WARN_ON() around checks that should never trigger.

First, please note the above sentence.

>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> ---
>>  drivers/base/power/domain.c          |    2 -
>>  drivers/base/power/domain_governor.c |   56 ++++++++++++++++++++---------------
>>  2 files changed, 33 insertions(+), 25 deletions(-)
>>
>> Index: linux-pm/drivers/base/power/domain.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain.c
>> +++ linux-pm/drivers/base/power/domain.c
>> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>>
>>       gpd_data->base.dev = dev;
>>       gpd_data->td.constraint_changed = true;
>> -     gpd_data->td.effective_constraint_ns = -1;
>> +     gpd_data->td.effective_constraint_ns = 0;
>>       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>>
>>       spin_lock_irq(&dev->power.lock);
>> Index: linux-pm/drivers/base/power/domain_governor.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain_governor.c
>> +++ linux-pm/drivers/base/power/domain_governor.c
>> @@ -14,22 +14,22 @@
>>  static int dev_update_qos_constraint(struct device *dev, void *data)
>>  {
>>       s64 *constraint_ns_p = data;
>> -     s32 constraint_ns = -1;
>> -
>> -     if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
>> -             constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
>> +     s64 constraint_ns;
>>
>> -     if (constraint_ns < 0) {
>> -             constraint_ns = dev_pm_qos_read_value(dev);
>> -             constraint_ns *= NSEC_PER_USEC;
>> -     }
>> -     if (constraint_ns == 0)
>> +     if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
>>               return 0;
>>
>>       /*
>> -      * constraint_ns cannot be negative here, because the device has been
>> -      * suspended.
>> +      * Only take suspend-time QoS constraints of devices into account,
>> +      * because constraints updated after the device has been suspended are
>> +      * not guaranteed to be taken into account 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;
>> +     /* 0 means "no constraint" */
>> +     if (constraint_ns == 0)
>> +             return 0;
>> +
>>       if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>>               *constraint_ns_p = constraint_ns;
>>
>> @@ -76,14 +76,26 @@ static bool default_suspend_ok(struct de
>>               device_for_each_child(dev, &constraint_ns,
>>                                     dev_update_qos_constraint);
>>
>> -     if (constraint_ns > 0) {
>> +     if (constraint_ns == 0) {
>> +             /* "No restriction", so the device is allowed to suspend. */
>> +             td->effective_constraint_ns = 0;
>> +             td->cached_suspend_ok = true;
>> +     } else if (WARN_ON(constraint_ns < 0)) {
>
> Should never comer here. Child should not have suspended.
> Should be a fatal bug. This else block probably is not necessary.

Right.

>> +             /*
>> +              * effective_constraint_ns is negative already and
>> +              * cached_suspend_ok is false, so return right away.
>> +              */
>> +             return false;
>> +     } else {
>>               constraint_ns -= td->suspend_latency_ns +
>>                               td->resume_latency_ns;
>> -             if (constraint_ns == 0)
>> +             /* Again, if negative or zero, returning right away is fine. */
>> +             if (constraint_ns <= 0)
>>                       return false;
>> +
>> +             td->effective_constraint_ns = constraint_ns;
>> +             td->cached_suspend_ok = true;
>>       }
>> -     td->effective_constraint_ns = constraint_ns;
>> -     td->cached_suspend_ok = constraint_ns >= 0;
>>
>>       /*
>>        * The children have been suspended already, so we don't need to take
>> @@ -144,18 +156,14 @@ static bool __default_power_down_ok(stru
>>                */
>>               td = &to_gpd_data(pdd)->td;
>>               constraint_ns = td->effective_constraint_ns;
>> -             /* default_suspend_ok() need not be called before us. */
>> -             if (constraint_ns < 0) {
>> -                     constraint_ns = dev_pm_qos_read_value(pdd->dev);
>> -                     constraint_ns *= NSEC_PER_USEC;
>> -             }
>> +             /* Negative values mean "no suspend at all" */
>> +             if (WARN_ON(constraint_ns < 0))
>> +                     return false;
>
> Cannot come here if was not suspended. Looks like a redundant check.

Right, this and the above *are* probably redundant.  That's why
there's WARN_ON() here and in the other place.

Thanks,
Rafael

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

* Re: [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03  7:43   ` Ramesh Thomas
@ 2017-11-03  7:58     ` Rafael J. Wysocki
  2017-11-03 10:38       ` Rafael J. Wysocki
  0 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-03  7:58 UTC (permalink / raw)
  To: ramesh.thomas
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

 On Fri, Nov 3, 2017 at 8:43 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> On 2017-11-02 at 00:03:54 +0100, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> The special value of 0 for device resume latency PM QoS means
>> "no restriction", but there are two problems with that.
>>
>> First, device resume latency PM QoS requests with 0 as the
>> value are always put in front of requests with positive
>> values in the priority lists used internally by the PM QoS
>> framework, causing 0 to be chosen as an effective constraint
>> value.  However, that 0 is then interpreted as "no restriction"
>> effectively overriding the other requests with specific
>> restrictions which is incorrect.
>>
>> Second, the users of device resume latency PM QoS have no
>> way to specify that *any* resume latency at all should be
>> avoided, which is an artificial limitation in general.
>>
>> To address these issues, modify device resume latency PM QoS to
>> use S32_MAX as the "no constraint" value and 0 as the "no
>> latency at all" one and rework its users (the cpuidle menu
>> governor, the genpd QoS governor and the runtime PM framework)
>> to follow these changes.
>>
>> Also add a special "n/a" value to the corresponding user space I/F
>> to allow user space to indicate that it cannot accept any resume
>> latencies at all for the given device.
>>
>> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
>> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
>> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> ---
>>  Documentation/ABI/testing/sysfs-devices-power |    4 ++-
>>  drivers/base/cpu.c                            |    3 +-
>>  drivers/base/power/domain.c                   |    2 -
>>  drivers/base/power/domain_governor.c          |   27 ++++++++++++--------------
>>  drivers/base/power/qos.c                      |    5 +++-
>>  drivers/base/power/runtime.c                  |    2 -
>>  drivers/base/power/sysfs.c                    |   25 ++++++++++++++++++++----
>>  drivers/cpuidle/governors/menu.c              |    4 +--
>>  include/linux/pm_qos.h                        |   24 +++++++++++++++--------
>>  9 files changed, 63 insertions(+), 33 deletions(-)
>>
>> Index: linux-pm/drivers/base/power/sysfs.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/sysfs.c
>> +++ linux-pm/drivers/base/power/sysfs.c
>> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>>                                         struct device_attribute *attr,
>>                                         char *buf)
>>  {
>> -     return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
>> +     s32 value = dev_pm_qos_requested_resume_latency(dev);
>> +
>> +     if (value == 0)
>> +             return sprintf(buf, "n/a\n");
>> +     else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>> +             value = 0;
>> +
>> +     return sprintf(buf, "%d\n", value);
>>  }
>>
>>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
>> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>>       s32 value;
>>       int ret;
>>
>> -     if (kstrtos32(buf, 0, &value))
>> -             return -EINVAL;
>> +     if (!kstrtos32(buf, 0, &value)) {
>> +             /*
>> +              * Prevent users from writing negative or "no constraint" values
>> +              * directly.
>> +              */
>> +             if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>> +                     return -EINVAL;
>>
>> -     if (value < 0)
>> +             if (value == 0)
>> +                     value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>> +     } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
>> +             value = 0;
>> +     } else {
>>               return -EINVAL;
>> +     }
>>
>>       ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>>                                       value);
>> Index: linux-pm/include/linux/pm_qos.h
>> ===================================================================
>> --- linux-pm.orig/include/linux/pm_qos.h
>> +++ linux-pm/include/linux/pm_qos.h
>> @@ -27,16 +27,17 @@ enum pm_qos_flags_status {
>>       PM_QOS_FLAGS_ALL,
>>  };
>>
>> -#define PM_QOS_DEFAULT_VALUE -1
>> +#define PM_QOS_DEFAULT_VALUE (-1)
>> +#define PM_QOS_LATENCY_ANY   S32_MAX
>>
>>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE     (2000 * USEC_PER_SEC)
>>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE     (2000 * USEC_PER_SEC)
>>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE      0
>>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE        0
>> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE  0
>> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE  PM_QOS_LATENCY_ANY
>> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT  PM_QOS_LATENCY_ANY
>>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE       0
>>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT       (-1)
>> -#define PM_QOS_LATENCY_ANY                   ((s32)(~(__u32)0 >> 1))
>>
>>  #define PM_QOS_FLAG_NO_POWER_OFF     (1 << 0)
>>
>> @@ -173,7 +174,8 @@ static inline s32 dev_pm_qos_requested_f
>>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>>  {
>>       return IS_ERR_OR_NULL(dev->power.qos) ?
>> -             0 : pm_qos_read_value(&dev->power.qos->resume_latency);
>> +             PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
>> +             pm_qos_read_value(&dev->power.qos->resume_latency);
>>  }
>>  #else
>>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
>> @@ -183,9 +185,9 @@ static inline enum pm_qos_flags_status d
>>                                                       s32 mask)
>>                       { return PM_QOS_FLAGS_UNDEFINED; }
>>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
>> -                     { return 0; }
>> +                     { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>>  static inline s32 dev_pm_qos_read_value(struct device *dev)
>> -                     { return 0; }
>> +                     { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>>  static inline int dev_pm_qos_add_request(struct device *dev,
>>                                        struct dev_pm_qos_request *req,
>>                                        enum dev_pm_qos_req_type type,
>> @@ -231,9 +233,15 @@ static inline int dev_pm_qos_expose_late
>>                       { return 0; }
>>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>>
>> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
>> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
>> +{
>> +     return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>> +}
>>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
>> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
>> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>> +{
>> +     return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>> +}
>>  #endif
>>
>>  #endif
>> Index: linux-pm/drivers/cpuidle/governors/menu.c
>> ===================================================================
>> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
>> +++ linux-pm/drivers/cpuidle/governors/menu.c
>> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>>               data->needs_update = 0;
>>       }
>>
>> -     /* resume_latency is 0 means no restriction */
>> -     if (resume_latency && resume_latency < latency_req)
>> +     if (resume_latency < latency_req &&
>> +         resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>               latency_req = resume_latency;
>>
>>       /* Special case when user has set very strict latency requirement */
>> Index: linux-pm/drivers/base/power/runtime.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/runtime.c
>> +++ linux-pm/drivers/base/power/runtime.c
>> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>>           || (dev->power.request_pending
>>                       && dev->power.request == RPM_REQ_RESUME))
>>               retval = -EAGAIN;
>> -     else if (__dev_pm_qos_read_value(dev) < 0)
>> +     else if (__dev_pm_qos_read_value(dev) == 0)
>>               retval = -EPERM;
>>       else if (dev->power.runtime_status == RPM_SUSPENDED)
>>               retval = 1;
>> Index: linux-pm/drivers/base/cpu.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/cpu.c
>> +++ linux-pm/drivers/base/cpu.c
>> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>>
>>       per_cpu(cpu_sys_devices, num) = &cpu->dev;
>>       register_cpu_under_node(num, cpu_to_node(num));
>> -     dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
>> +     dev_pm_qos_expose_latency_limit(&cpu->dev,
>> +                                     PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>>
>>       return 0;
>>  }
>> Index: linux-pm/drivers/base/power/qos.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/qos.c
>> +++ linux-pm/drivers/base/power/qos.c
>> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>>
>>       switch(req->type) {
>>       case DEV_PM_QOS_RESUME_LATENCY:
>> +             if (WARN_ON(value < 0))
>> +                     value = 0;
>> +
>>               ret = pm_qos_update_target(&qos->resume_latency,
>>                                          &req->data.pnode, action, value);
>>               break;
>> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>>       plist_head_init(&c->list);
>>       c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>>       c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>> -     c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>> +     c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>       c->type = PM_QOS_MIN;
>>       c->notifiers = n;
>>
>> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
>> ===================================================================
>> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
>> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
>> @@ -211,7 +211,9 @@ Description:
>>               device, after it has been suspended at run time, from a resume
>>               request to the moment the device will be ready to process I/O,
>>               in microseconds.  If it is equal to 0, however, this means that
>> -             the PM QoS resume latency may be arbitrary.
>> +             the PM QoS resume latency may be arbitrary and the special value
>> +             "n/a" means that user space cannot accept any resume latency at
>> +             all for the given device.
>>
>>               Not all drivers support this attribute.  If it isn't supported,
>>               it is not present.
>> Index: linux-pm/drivers/base/power/domain.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain.c
>> +++ linux-pm/drivers/base/power/domain.c
>> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>>
>>       gpd_data->base.dev = dev;
>>       gpd_data->td.constraint_changed = true;
>> -     gpd_data->td.effective_constraint_ns = 0;
>> +     gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>>
>>       spin_lock_irq(&dev->power.lock);
>> Index: linux-pm/drivers/base/power/domain_governor.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain_governor.c
>> +++ linux-pm/drivers/base/power/domain_governor.c
>> @@ -26,11 +26,11 @@ static int dev_update_qos_constraint(str
>>        * to take effect, the device has to be resumed and suspended again.
>>        */
>>       constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
>> -     /* 0 means "no constraint" */
>> -     if (constraint_ns == 0)
>> +     if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>               return 0;
>>
>> -     if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>> +     if (constraint_ns < *constraint_ns_p ||
>> +         *constraint_ns_p == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>
> Check for constraint_ns < *constraint_ns_p should be enough because
> PM_QOS_RESUME_LATENCY_NO_CONSTRAINT = S32_MAX which is the largest possible
> value, if that can be assumed here.

Well, not quite.  effective_constraint_ns is s64 and it is the QoS
value multiplied by NSEC_PER_USEC.

Surely can be greater than PM_QOS_RESUME_LATENCY_NO_CONSTRAINT.

Which reminds me about the possible collision in default_suspend_ok()
which needs to be addressed. :-)

>>               *constraint_ns_p = constraint_ns;
>>
>>       return 0;
>> @@ -58,12 +58,12 @@ static bool default_suspend_ok(struct de
>>       }
>>       td->constraint_changed = false;
>>       td->cached_suspend_ok = false;
>> -     td->effective_constraint_ns = -1;
>> +     td->effective_constraint_ns = 0;
>>       constraint_ns = __dev_pm_qos_read_value(dev);
>
> Why not initialize td->effective_constraint_ns with what is read by
> __dev_pm_qos_read_value()? Even though this value will stay only if false
> is returned, in which case it does not matter anyway, it looks like more
> meaningful value. Also PM_QOS_RESUME_LATENCY_NO_CONSTRAINT may be ok as it
> is initialized with at creation.

This looks like a leftover or similar, thanks.

>>
>>       spin_unlock_irqrestore(&dev->power.lock, flags);
>>
>> -     if (constraint_ns < 0)
>> +     if (constraint_ns == 0)
>>               return false;
>>
>>       constraint_ns *= NSEC_PER_USEC;
>
> This will go wrong if PM_QOS_RESUME_LATENCY_NO_CONSTRAINT was the value
> Code below and in dev_update_qos_constraint check for that special value.
>
> May be those places can check PM_QOS_RESUME_LATENCY_NO_CONSTRAINT * NSEC_PER_USEC
> There may be other places that this might be an issue

Right, I forgot about this one.

>> @@ -76,14 +76,14 @@ static bool default_suspend_ok(struct de
>>               device_for_each_child(dev, &constraint_ns,
>>                                     dev_update_qos_constraint);
>>
>> -     if (constraint_ns == 0) {
>> +     if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) {
>>               /* "No restriction", so the device is allowed to suspend. */
>> -             td->effective_constraint_ns = 0;
>> +             td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>               td->cached_suspend_ok = true;
>> -     } else if (WARN_ON(constraint_ns < 0)) {
>> +     } else if (WARN_ON(constraint_ns == 0)) {
>
> This can never happen as this device will not be suspending if the child had
> failed to suspend (only case where this value is possible).
>
>>               /*
>> -              * effective_constraint_ns is negative already and
>> -              * cached_suspend_ok is false, so return right away.
>> +              * effective_constraint_ns is 0 already and cached_suspend_ok is
>> +              * false, so return right away.
>>                */
>>               return false;
>>       } else {
>> @@ -156,12 +156,11 @@ static bool __default_power_down_ok(stru
>>                */
>>               td = &to_gpd_data(pdd)->td;
>>               constraint_ns = td->effective_constraint_ns;
>> -             /* Negative values mean "no suspend at all" */
>> -             if (WARN_ON(constraint_ns < 0))
>> +             /* 0 mean "no suspend at all" */
>> +             if (WARN_ON(constraint_ns == 0))
>>                       return false;
>
> If it did not suspend then it cannot powerdown. This check may not be
> very useful here.

The checks with WARN_ON() are there to catch the unexpected.  They
aren't meant to trigger at all under normal conditions.

Thanks,
Rafael

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

* Re: [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03  7:58     ` Rafael J. Wysocki
@ 2017-11-03 10:38       ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-03 10:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ramesh.thomas, Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

On Fri, Nov 3, 2017 at 8:58 AM, Rafael J. Wysocki <rafael@kernel.org> wrote:
>  On Fri, Nov 3, 2017 at 8:43 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
>> On 2017-11-02 at 00:03:54 +0100, Rafael J. Wysocki wrote:
>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>
>>> The special value of 0 for device resume latency PM QoS means
>>> "no restriction", but there are two problems with that.
>>>
>>> First, device resume latency PM QoS requests with 0 as the
>>> value are always put in front of requests with positive
>>> values in the priority lists used internally by the PM QoS
>>> framework, causing 0 to be chosen as an effective constraint
>>> value.  However, that 0 is then interpreted as "no restriction"
>>> effectively overriding the other requests with specific
>>> restrictions which is incorrect.
>>>
>>> Second, the users of device resume latency PM QoS have no
>>> way to specify that *any* resume latency at all should be
>>> avoided, which is an artificial limitation in general.
>>>
>>> To address these issues, modify device resume latency PM QoS to
>>> use S32_MAX as the "no constraint" value and 0 as the "no
>>> latency at all" one and rework its users (the cpuidle menu
>>> governor, the genpd QoS governor and the runtime PM framework)
>>> to follow these changes.
>>>
>>> Also add a special "n/a" value to the corresponding user space I/F
>>> to allow user space to indicate that it cannot accept any resume
>>> latencies at all for the given device.
>>>
>>> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
>>> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
>>> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>> ---
>>>  Documentation/ABI/testing/sysfs-devices-power |    4 ++-
>>>  drivers/base/cpu.c                            |    3 +-
>>>  drivers/base/power/domain.c                   |    2 -
>>>  drivers/base/power/domain_governor.c          |   27 ++++++++++++--------------
>>>  drivers/base/power/qos.c                      |    5 +++-
>>>  drivers/base/power/runtime.c                  |    2 -
>>>  drivers/base/power/sysfs.c                    |   25 ++++++++++++++++++++----
>>>  drivers/cpuidle/governors/menu.c              |    4 +--
>>>  include/linux/pm_qos.h                        |   24 +++++++++++++++--------
>>>  9 files changed, 63 insertions(+), 33 deletions(-)
>>>
>>> Index: linux-pm/drivers/base/power/sysfs.c
>>> ===================================================================
>>> --- linux-pm.orig/drivers/base/power/sysfs.c
>>> +++ linux-pm/drivers/base/power/sysfs.c
>>> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>>>                                         struct device_attribute *attr,
>>>                                         char *buf)
>>>  {
>>> -     return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
>>> +     s32 value = dev_pm_qos_requested_resume_latency(dev);
>>> +
>>> +     if (value == 0)
>>> +             return sprintf(buf, "n/a\n");
>>> +     else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>> +             value = 0;
>>> +
>>> +     return sprintf(buf, "%d\n", value);
>>>  }
>>>
>>>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
>>> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>>>       s32 value;
>>>       int ret;
>>>
>>> -     if (kstrtos32(buf, 0, &value))
>>> -             return -EINVAL;
>>> +     if (!kstrtos32(buf, 0, &value)) {
>>> +             /*
>>> +              * Prevent users from writing negative or "no constraint" values
>>> +              * directly.
>>> +              */
>>> +             if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>> +                     return -EINVAL;
>>>
>>> -     if (value < 0)
>>> +             if (value == 0)
>>> +                     value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>> +     } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
>>> +             value = 0;
>>> +     } else {
>>>               return -EINVAL;
>>> +     }
>>>
>>>       ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>>>                                       value);
>>> Index: linux-pm/include/linux/pm_qos.h
>>> ===================================================================
>>> --- linux-pm.orig/include/linux/pm_qos.h
>>> +++ linux-pm/include/linux/pm_qos.h
>>> @@ -27,16 +27,17 @@ enum pm_qos_flags_status {
>>>       PM_QOS_FLAGS_ALL,
>>>  };
>>>
>>> -#define PM_QOS_DEFAULT_VALUE -1
>>> +#define PM_QOS_DEFAULT_VALUE (-1)
>>> +#define PM_QOS_LATENCY_ANY   S32_MAX
>>>
>>>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE     (2000 * USEC_PER_SEC)
>>>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE     (2000 * USEC_PER_SEC)
>>>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE      0
>>>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE        0
>>> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE  0
>>> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE  PM_QOS_LATENCY_ANY
>>> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT  PM_QOS_LATENCY_ANY
>>>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE       0
>>>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT       (-1)
>>> -#define PM_QOS_LATENCY_ANY                   ((s32)(~(__u32)0 >> 1))
>>>
>>>  #define PM_QOS_FLAG_NO_POWER_OFF     (1 << 0)
>>>
>>> @@ -173,7 +174,8 @@ static inline s32 dev_pm_qos_requested_f
>>>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>>>  {
>>>       return IS_ERR_OR_NULL(dev->power.qos) ?
>>> -             0 : pm_qos_read_value(&dev->power.qos->resume_latency);
>>> +             PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
>>> +             pm_qos_read_value(&dev->power.qos->resume_latency);
>>>  }
>>>  #else
>>>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
>>> @@ -183,9 +185,9 @@ static inline enum pm_qos_flags_status d
>>>                                                       s32 mask)
>>>                       { return PM_QOS_FLAGS_UNDEFINED; }
>>>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
>>> -                     { return 0; }
>>> +                     { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>>>  static inline s32 dev_pm_qos_read_value(struct device *dev)
>>> -                     { return 0; }
>>> +                     { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>>>  static inline int dev_pm_qos_add_request(struct device *dev,
>>>                                        struct dev_pm_qos_request *req,
>>>                                        enum dev_pm_qos_req_type type,
>>> @@ -231,9 +233,15 @@ static inline int dev_pm_qos_expose_late
>>>                       { return 0; }
>>>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>>>
>>> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
>>> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
>>> +{
>>> +     return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>> +}
>>>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
>>> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
>>> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>>> +{
>>> +     return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>> +}
>>>  #endif
>>>
>>>  #endif
>>> Index: linux-pm/drivers/cpuidle/governors/menu.c
>>> ===================================================================
>>> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
>>> +++ linux-pm/drivers/cpuidle/governors/menu.c
>>> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>>>               data->needs_update = 0;
>>>       }
>>>
>>> -     /* resume_latency is 0 means no restriction */
>>> -     if (resume_latency && resume_latency < latency_req)
>>> +     if (resume_latency < latency_req &&
>>> +         resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>>               latency_req = resume_latency;
>>>
>>>       /* Special case when user has set very strict latency requirement */
>>> Index: linux-pm/drivers/base/power/runtime.c
>>> ===================================================================
>>> --- linux-pm.orig/drivers/base/power/runtime.c
>>> +++ linux-pm/drivers/base/power/runtime.c
>>> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>>>           || (dev->power.request_pending
>>>                       && dev->power.request == RPM_REQ_RESUME))
>>>               retval = -EAGAIN;
>>> -     else if (__dev_pm_qos_read_value(dev) < 0)
>>> +     else if (__dev_pm_qos_read_value(dev) == 0)
>>>               retval = -EPERM;
>>>       else if (dev->power.runtime_status == RPM_SUSPENDED)
>>>               retval = 1;
>>> Index: linux-pm/drivers/base/cpu.c
>>> ===================================================================
>>> --- linux-pm.orig/drivers/base/cpu.c
>>> +++ linux-pm/drivers/base/cpu.c
>>> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>>>
>>>       per_cpu(cpu_sys_devices, num) = &cpu->dev;
>>>       register_cpu_under_node(num, cpu_to_node(num));
>>> -     dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
>>> +     dev_pm_qos_expose_latency_limit(&cpu->dev,
>>> +                                     PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>>>
>>>       return 0;
>>>  }
>>> Index: linux-pm/drivers/base/power/qos.c
>>> ===================================================================
>>> --- linux-pm.orig/drivers/base/power/qos.c
>>> +++ linux-pm/drivers/base/power/qos.c
>>> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>>>
>>>       switch(req->type) {
>>>       case DEV_PM_QOS_RESUME_LATENCY:
>>> +             if (WARN_ON(value < 0))
>>> +                     value = 0;
>>> +
>>>               ret = pm_qos_update_target(&qos->resume_latency,
>>>                                          &req->data.pnode, action, value);
>>>               break;
>>> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>>>       plist_head_init(&c->list);
>>>       c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>>>       c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>>> -     c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>>> +     c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>>       c->type = PM_QOS_MIN;
>>>       c->notifiers = n;
>>>
>>> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
>>> ===================================================================
>>> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
>>> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
>>> @@ -211,7 +211,9 @@ Description:
>>>               device, after it has been suspended at run time, from a resume
>>>               request to the moment the device will be ready to process I/O,
>>>               in microseconds.  If it is equal to 0, however, this means that
>>> -             the PM QoS resume latency may be arbitrary.
>>> +             the PM QoS resume latency may be arbitrary and the special value
>>> +             "n/a" means that user space cannot accept any resume latency at
>>> +             all for the given device.
>>>
>>>               Not all drivers support this attribute.  If it isn't supported,
>>>               it is not present.
>>> Index: linux-pm/drivers/base/power/domain.c
>>> ===================================================================
>>> --- linux-pm.orig/drivers/base/power/domain.c
>>> +++ linux-pm/drivers/base/power/domain.c
>>> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>>>
>>>       gpd_data->base.dev = dev;
>>>       gpd_data->td.constraint_changed = true;
>>> -     gpd_data->td.effective_constraint_ns = 0;
>>> +     gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>>       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>>>
>>>       spin_lock_irq(&dev->power.lock);
>>> Index: linux-pm/drivers/base/power/domain_governor.c
>>> ===================================================================
>>> --- linux-pm.orig/drivers/base/power/domain_governor.c
>>> +++ linux-pm/drivers/base/power/domain_governor.c
>>> @@ -26,11 +26,11 @@ static int dev_update_qos_constraint(str
>>>        * to take effect, the device has to be resumed and suspended again.
>>>        */
>>>       constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
>>> -     /* 0 means "no constraint" */
>>> -     if (constraint_ns == 0)
>>> +     if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>>               return 0;
>>>
>>> -     if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>>> +     if (constraint_ns < *constraint_ns_p ||
>>> +         *constraint_ns_p == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>
>> Check for constraint_ns < *constraint_ns_p should be enough because
>> PM_QOS_RESUME_LATENCY_NO_CONSTRAINT = S32_MAX which is the largest possible
>> value, if that can be assumed here.
>
> Well, not quite.  effective_constraint_ns is s64 and it is the QoS
> value multiplied by NSEC_PER_USEC.
>
> Surely can be greater than PM_QOS_RESUME_LATENCY_NO_CONSTRAINT.
>
> Which reminds me about the possible collision in default_suspend_ok()
> which needs to be addressed. :-)
>
>>>               *constraint_ns_p = constraint_ns;
>>>
>>>       return 0;
>>> @@ -58,12 +58,12 @@ static bool default_suspend_ok(struct de
>>>       }
>>>       td->constraint_changed = false;
>>>       td->cached_suspend_ok = false;
>>> -     td->effective_constraint_ns = -1;
>>> +     td->effective_constraint_ns = 0;
>>>       constraint_ns = __dev_pm_qos_read_value(dev);
>>
>> Why not initialize td->effective_constraint_ns with what is read by
>> __dev_pm_qos_read_value()?

Because if that is 0, we can return without scribbling on it again in
the following code and if it wasn't 0, it would need to be multiplied
by NSEC_PER_USEC.

Thanks,
Rafael

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

* [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix
  2017-11-01 23:00 [RFT][PATCH 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
  2017-11-01 23:01 ` [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
  2017-11-01 23:03 ` [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
@ 2017-11-03 11:42 ` Rafael J. Wysocki
  2017-11-03 11:47   ` [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
                     ` (3 more replies)
  2 siblings, 4 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-03 11:42 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

On Thursday, November 2, 2017 12:00:27 AM CET Rafael J. Wysocki wrote:
> Hi,
> 
> This series is a replacement for commit 0cc2b4e5a020 (PM / QoS: Fix device
> resume latency PM QoS) that had to be reverted due to problems introduced by it.
> 
> This time the genpd PM QoS governor is first updated to be more consistent
> and the PM QoS changes are made on top of that which simplifies the second
> patch quite a bit.
> 
> This is based on the linux-next branch from linux-pm.git as of now (should
> also apply to the current mainline just fine).
> 
> Please test if you can or let me know if you have any comments.

The v2 removes a couple of redundant checks from the first patch (and add
comments to explain why the checks are not needed) and fixes up the
"no constraint" value collision with a valid constraint multiplied by
NSEC_PER_USEC in the second patch.

Please test if possible and let me know about any issues.

Thanks,
Rafael

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

* [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-03 11:42 ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
@ 2017-11-03 11:47   ` Rafael J. Wysocki
  2017-11-04  2:34     ` Ramesh Thomas
  2017-11-06 12:10     ` Ulf Hansson
  2017-11-03 11:50   ` [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-03 11:47 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The genpd governor currently uses negative PM QoS values to indicate
the "no suspend" condition and 0 as "no restriction", but it doesn't
use them consistently.  Moreover, it tries to refresh QoS values for
already suspended devices in a quite questionable way.

For the above reasons, rework it to be a bit more consistent.

First off, note that dev_pm_qos_read_value() in
dev_update_qos_constraint() and __default_power_down_ok() is
evaluated for devices in suspend.  Moreover, that only happens if the
effective_constraint_ns value for them is negative (meaning "no
suspend").  It is not evaluated in any other cases, so effectively
the QoS values are only updated for devices in suspend that should
not have been suspended in the first place.  In all of the other
cases, the QoS values taken into account are the effective ones from
the time before the device has been suspended, so generally devices
need to be resumed and suspended again for new QoS values to take
effect anyway.  Thus evaluating dev_update_qos_constraint() in
those two places doesn't make sense at all, so drop it.

Second, initialize effective_constraint_ns to 0 ("no constraint")
rather than to (-1) ("no suspend"), which makes more sense in
general and in case effective_constraint_ns is never updated
(the device is in suspend all the time or it is never suspended)
it doesn't affect the device's parent and so on.

Finally, rework default_suspend_ok() to explicitly handle the
"no restriction" special case.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/base/power/domain.c          |    2 -
 drivers/base/power/domain_governor.c |   61 +++++++++++++++++++++--------------
 2 files changed, 38 insertions(+), 25 deletions(-)

Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = -1;
+	gpd_data->td.effective_constraint_ns = 0;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -14,22 +14,22 @@
 static int dev_update_qos_constraint(struct device *dev, void *data)
 {
 	s64 *constraint_ns_p = data;
-	s32 constraint_ns = -1;
-
-	if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
-		constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+	s64 constraint_ns;
 
-	if (constraint_ns < 0) {
-		constraint_ns = dev_pm_qos_read_value(dev);
-		constraint_ns *= NSEC_PER_USEC;
-	}
-	if (constraint_ns == 0)
+	if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
 		return 0;
 
 	/*
-	 * constraint_ns cannot be negative here, because the device has been
-	 * suspended.
+	 * Only take suspend-time QoS constraints of devices into account,
+	 * because constraints updated after the device has been suspended are
+	 * not guaranteed to be taken into account 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;
+	/* 0 means "no constraint" */
+	if (constraint_ns == 0)
+		return 0;
+
 	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
 		*constraint_ns_p = constraint_ns;
 
@@ -76,14 +76,29 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns > 0) {
+	if (constraint_ns == 0) {
+		/* "No restriction", so the device is allowed to suspend. */
+		td->effective_constraint_ns = 0;
+		td->cached_suspend_ok = true;
+	} else {
+		/*
+		 * constraint_ns must be positive here, because the children
+		 * walked above are all suspended, so effective_constraint_ns
+		 * cannot be negative for them.
+		 */
 		constraint_ns -= td->suspend_latency_ns +
 				td->resume_latency_ns;
-		if (constraint_ns == 0)
+		/*
+		 * effective_constraint_ns is negative already and
+		 * cached_suspend_ok is false, so if the computed value is not
+		 * positive, return right away.
+		 */
+		if (constraint_ns <= 0)
 			return false;
+
+		td->effective_constraint_ns = constraint_ns;
+		td->cached_suspend_ok = true;
 	}
-	td->effective_constraint_ns = constraint_ns;
-	td->cached_suspend_ok = constraint_ns >= 0;
 
 	/*
 	 * The children have been suspended already, so we don't need to take
@@ -144,18 +159,16 @@ static bool __default_power_down_ok(stru
 		 */
 		td = &to_gpd_data(pdd)->td;
 		constraint_ns = td->effective_constraint_ns;
-		/* default_suspend_ok() need not be called before us. */
-		if (constraint_ns < 0) {
-			constraint_ns = dev_pm_qos_read_value(pdd->dev);
-			constraint_ns *= NSEC_PER_USEC;
-		}
+		/*
+		 * Negative values mean "no suspend at all" and this runs only
+		 * when all devices in the domain are suspended, so it must be
+		 * 0 at least.
+		 *
+		 * 0 means "no constraint"
+		 */
 		if (constraint_ns == 0)
 			continue;
 
-		/*
-		 * constraint_ns cannot be negative here, because the device has
-		 * been suspended.
-		 */
 		if (constraint_ns <= off_on_time_ns)
 			return false;
 

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

* [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03 11:42 ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
  2017-11-03 11:47   ` [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
@ 2017-11-03 11:50   ` Rafael J. Wysocki
  2017-11-03 16:39     ` Reinette Chatre
                       ` (2 more replies)
  2017-11-06 13:46   ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Geert Uytterhoeven
  2017-11-07  1:17     ` Rafael J. Wysocki
  3 siblings, 3 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-03 11:50 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The special value of 0 for device resume latency PM QoS means
"no restriction", but there are two problems with that.

First, device resume latency PM QoS requests with 0 as the
value are always put in front of requests with positive
values in the priority lists used internally by the PM QoS
framework, causing 0 to be chosen as an effective constraint
value.  However, that 0 is then interpreted as "no restriction"
effectively overriding the other requests with specific
restrictions which is incorrect.

Second, the users of device resume latency PM QoS have no
way to specify that *any* resume latency at all should be
avoided, which is an artificial limitation in general.

To address these issues, modify device resume latency PM QoS to
use S32_MAX as the "no constraint" value and 0 as the "no
latency at all" one and rework its users (the cpuidle menu
governor, the genpd QoS governor and the runtime PM framework)
to follow these changes.

Also add a special "n/a" value to the corresponding user space I/F
to allow user space to indicate that it cannot accept any resume
latencies at all for the given device.

Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 Documentation/ABI/testing/sysfs-devices-power |    4 +++-
 drivers/base/cpu.c                            |    3 ++-
 drivers/base/power/domain.c                   |    2 +-
 drivers/base/power/domain_governor.c          |   26 ++++++++++----------------
 drivers/base/power/qos.c                      |    5 ++++-
 drivers/base/power/runtime.c                  |    2 +-
 drivers/base/power/sysfs.c                    |   25 +++++++++++++++++++++----
 drivers/cpuidle/governors/menu.c              |    4 ++--
 include/linux/pm_qos.h                        |   26 ++++++++++++++++++--------
 9 files changed, 62 insertions(+), 35 deletions(-)

Index: linux-pm/drivers/base/power/sysfs.c
===================================================================
--- linux-pm.orig/drivers/base/power/sysfs.c
+++ linux-pm/drivers/base/power/sysfs.c
@@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
 					  struct device_attribute *attr,
 					  char *buf)
 {
-	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
+	s32 value = dev_pm_qos_requested_resume_latency(dev);
+
+	if (value == 0)
+		return sprintf(buf, "n/a\n");
+	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+		value = 0;
+
+	return sprintf(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_resume_latency_store(struct device *dev,
@@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
 	s32 value;
 	int ret;
 
-	if (kstrtos32(buf, 0, &value))
-		return -EINVAL;
+	if (!kstrtos32(buf, 0, &value)) {
+		/*
+		 * Prevent users from writing negative or "no constraint" values
+		 * directly.
+		 */
+		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+			return -EINVAL;
 
-	if (value < 0)
+		if (value == 0)
+			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
+		value = 0;
+	} else {
 		return -EINVAL;
+	}
 
 	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
 					value);
Index: linux-pm/include/linux/pm_qos.h
===================================================================
--- linux-pm.orig/include/linux/pm_qos.h
+++ linux-pm/include/linux/pm_qos.h
@@ -28,16 +28,19 @@ enum pm_qos_flags_status {
 	PM_QOS_FLAGS_ALL,
 };
 
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_DEFAULT_VALUE	(-1)
+#define PM_QOS_LATENCY_ANY	S32_MAX
+#define PM_QOS_LATENCY_ANY_NS	((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
 
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
-#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS	PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
-#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
 
@@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
 static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
 {
 	return IS_ERR_OR_NULL(dev->power.qos) ?
-		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
+		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
+		pm_qos_read_value(&dev->power.qos->resume_latency);
 }
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
 							s32 mask)
 			{ return PM_QOS_FLAGS_UNDEFINED; }
 static inline s32 __dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline s32 dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline int dev_pm_qos_add_request(struct device *dev,
 					 struct dev_pm_qos_request *req,
 					 enum dev_pm_qos_req_type type,
@@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
 			{ return 0; }
 static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
 
-static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 #endif
 
 #endif
Index: linux-pm/drivers/cpuidle/governors/menu.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/menu.c
+++ linux-pm/drivers/cpuidle/governors/menu.c
@@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
 		data->needs_update = 0;
 	}
 
-	/* resume_latency is 0 means no restriction */
-	if (resume_latency && resume_latency < latency_req)
+	if (resume_latency < latency_req &&
+	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		latency_req = resume_latency;
 
 	/* Special case when user has set very strict latency requirement */
Index: linux-pm/drivers/base/power/runtime.c
===================================================================
--- linux-pm.orig/drivers/base/power/runtime.c
+++ linux-pm/drivers/base/power/runtime.c
@@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
-	else if (__dev_pm_qos_read_value(dev) < 0)
+	else if (__dev_pm_qos_read_value(dev) == 0)
 		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
Index: linux-pm/drivers/base/cpu.c
===================================================================
--- linux-pm.orig/drivers/base/cpu.c
+++ linux-pm/drivers/base/cpu.c
@@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
 
 	per_cpu(cpu_sys_devices, num) = &cpu->dev;
 	register_cpu_under_node(num, cpu_to_node(num));
-	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
+	dev_pm_qos_expose_latency_limit(&cpu->dev,
+					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
 
 	return 0;
 }
Index: linux-pm/drivers/base/power/qos.c
===================================================================
--- linux-pm.orig/drivers/base/power/qos.c
+++ linux-pm/drivers/base/power/qos.c
@@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
 
 	switch(req->type) {
 	case DEV_PM_QOS_RESUME_LATENCY:
+		if (WARN_ON(value < 0))
+			value = 0;
+
 		ret = pm_qos_update_target(&qos->resume_latency,
 					   &req->data.pnode, action, value);
 		break;
@@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
 	plist_head_init(&c->list);
 	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
 	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
-	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 	c->type = PM_QOS_MIN;
 	c->notifiers = n;
 
Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
===================================================================
--- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
+++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
@@ -211,7 +211,9 @@ Description:
 		device, after it has been suspended at run time, from a resume
 		request to the moment the device will be ready to process I/O,
 		in microseconds.  If it is equal to 0, however, this means that
-		the PM QoS resume latency may be arbitrary.
+		the PM QoS resume latency may be arbitrary and the special value
+		"n/a" means that user space cannot accept any resume latency at
+		all for the given device.
 
 		Not all drivers support this attribute.  If it isn't supported,
 		it is not present.
Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = 0;
+	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -26,11 +26,7 @@ static int dev_update_qos_constraint(str
 	 * to take effect, the device has to be resumed and suspended again.
 	 */
 	constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
-	/* 0 means "no constraint" */
-	if (constraint_ns == 0)
-		return 0;
-
-	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+	if (constraint_ns < *constraint_ns_p)
 		*constraint_ns_p = constraint_ns;
 
 	return 0;
@@ -58,12 +54,12 @@ static bool default_suspend_ok(struct de
 	}
 	td->constraint_changed = false;
 	td->cached_suspend_ok = false;
-	td->effective_constraint_ns = -1;
+	td->effective_constraint_ns = 0;
 	constraint_ns = __dev_pm_qos_read_value(dev);
 
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
-	if (constraint_ns < 0)
+	if (constraint_ns == 0)
 		return false;
 
 	constraint_ns *= NSEC_PER_USEC;
@@ -76,22 +72,22 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns == 0) {
+	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
 		/* "No restriction", so the device is allowed to suspend. */
-		td->effective_constraint_ns = 0;
+		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 		td->cached_suspend_ok = true;
 	} else {
 		/*
 		 * constraint_ns must be positive here, because the children
 		 * walked above are all suspended, so effective_constraint_ns
-		 * cannot be negative for them.
+		 * cannot be 0 for them.
 		 */
 		constraint_ns -= td->suspend_latency_ns +
 				td->resume_latency_ns;
 		/*
-		 * effective_constraint_ns is negative already and
-		 * cached_suspend_ok is false, so if the computed value is not
-		 * positive, return right away.
+		 * effective_constraint_ns is 0 already and cached_suspend_ok is
+		 * false, so if the computed value is not positive, return right
+		 * away.
 		 */
 		if (constraint_ns <= 0)
 			return false;
@@ -163,10 +159,8 @@ static bool __default_power_down_ok(stru
 		 * Negative values mean "no suspend at all" and this runs only
 		 * when all devices in the domain are suspended, so it must be
 		 * 0 at least.
-		 *
-		 * 0 means "no constraint"
 		 */
-		if (constraint_ns == 0)
+		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
 			continue;
 
 		if (constraint_ns <= off_on_time_ns)

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

* Re: [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03 11:50   ` [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
@ 2017-11-03 16:39     ` Reinette Chatre
  2017-11-04  2:28       ` Ramesh Thomas
  2017-11-04 11:28       ` Rafael J. Wysocki
  2017-11-04  2:38     ` Ramesh Thomas
  2017-11-04 12:34     ` [RFT][Update][PATCH " Rafael J. Wysocki
  2 siblings, 2 replies; 47+ messages in thread
From: Reinette Chatre @ 2017-11-03 16:39 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Ramesh Thomas, Alex Shi

Hi Rafael,

I started to test this but found myself triggering one of the warnings:

On 11/3/2017 4:50 AM, Rafael J. Wysocki wrote:
> --- linux-pm.orig/include/linux/pm_qos.h
> +++ linux-pm/include/linux/pm_qos.h
> @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>  	PM_QOS_FLAGS_ALL,
>  };
>  
> -#define PM_QOS_DEFAULT_VALUE -1
> +#define PM_QOS_DEFAULT_VALUE	(-1)

PM_QOS_DEFAULT_VALUE is -1 ...


> ===================================================================
> --- linux-pm.orig/drivers/base/power/qos.c
> +++ linux-pm/drivers/base/power/qos.c
> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>  
>  	switch(req->type) {
>  	case DEV_PM_QOS_RESUME_LATENCY:
> +		if (WARN_ON(value < 0))
> +			value = 0;
> +

... causing me to hit this WARN_ON because apply_constraint() is called by __dev_pm_qos_remove_request() with the value parameter set to PM_QOS_DEFAULT_VALUE.

Reinette

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

* Re: [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03 16:39     ` Reinette Chatre
@ 2017-11-04  2:28       ` Ramesh Thomas
  2017-11-04 11:30         ` Rafael J. Wysocki
  2017-11-04 11:28       ` Rafael J. Wysocki
  1 sibling, 1 reply; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-04  2:28 UTC (permalink / raw)
  To: Reinette Chatre
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Alex Shi

On 2017-11-03 at 09:39:08 -0700, Reinette Chatre wrote:
> Hi Rafael,
> 
> I started to test this but found myself triggering one of the warnings:
> 
> On 11/3/2017 4:50 AM, Rafael J. Wysocki wrote:
> > --- linux-pm.orig/include/linux/pm_qos.h
> > +++ linux-pm/include/linux/pm_qos.h
> > @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
> >  	PM_QOS_FLAGS_ALL,
> >  };
> >  
> > -#define PM_QOS_DEFAULT_VALUE -1
> > +#define PM_QOS_DEFAULT_VALUE	(-1)
> 
> PM_QOS_DEFAULT_VALUE is -1 ...
> 
> 
> > ===================================================================
> > --- linux-pm.orig/drivers/base/power/qos.c
> > +++ linux-pm/drivers/base/power/qos.c
> > @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
> >  
> >  	switch(req->type) {
> >  	case DEV_PM_QOS_RESUME_LATENCY:
> > +		if (WARN_ON(value < 0))
> > +			value = 0;
> > +
> 
> ... causing me to hit this WARN_ON because apply_constraint() is called by __dev_pm_qos_remove_request() with the value parameter set to PM_QOS_DEFAULT_VALUE.

That value does not get used if action is PM_QOS_REMOVE_REQ. May be just pass
0 or PM_QOS_RESUME_LATENCY_DEFAULT_VALUE everywhere apply_constraint is called
with PM_QOS_REMOVE_REQ action.

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-03 11:47   ` [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
@ 2017-11-04  2:34     ` Ramesh Thomas
  2017-11-04 11:24       ` Rafael J. Wysocki
  2017-11-06 12:10     ` Ulf Hansson
  1 sibling, 1 reply; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-04  2:34 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On 2017-11-03 at 12:47:20 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The genpd governor currently uses negative PM QoS values to indicate
> the "no suspend" condition and 0 as "no restriction", but it doesn't
> use them consistently.  Moreover, it tries to refresh QoS values for
> already suspended devices in a quite questionable way.
> 
> For the above reasons, rework it to be a bit more consistent.
> 
> First off, note that dev_pm_qos_read_value() in
> dev_update_qos_constraint() and __default_power_down_ok() is
> evaluated for devices in suspend.  Moreover, that only happens if the
> effective_constraint_ns value for them is negative (meaning "no
> suspend").  It is not evaluated in any other cases, so effectively
> the QoS values are only updated for devices in suspend that should
> not have been suspended in the first place.  In all of the other
> cases, the QoS values taken into account are the effective ones from
> the time before the device has been suspended, so generally devices
> need to be resumed and suspended again for new QoS values to take
> effect anyway.  Thus evaluating dev_update_qos_constraint() in
> those two places doesn't make sense at all, so drop it.
> 
> Second, initialize effective_constraint_ns to 0 ("no constraint")
> rather than to (-1) ("no suspend"), which makes more sense in
> general and in case effective_constraint_ns is never updated
> (the device is in suspend all the time or it is never suspended)
> it doesn't affect the device's parent and so on.
> 
> Finally, rework default_suspend_ok() to explicitly handle the
> "no restriction" special case.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/base/power/domain.c          |    2 -
>  drivers/base/power/domain_governor.c |   61 +++++++++++++++++++++--------------
>  2 files changed, 38 insertions(+), 25 deletions(-)
> 
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>  
>  	gpd_data->base.dev = dev;
>  	gpd_data->td.constraint_changed = true;
> -	gpd_data->td.effective_constraint_ns = -1;
> +	gpd_data->td.effective_constraint_ns = 0;
>  	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>  
>  	spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -14,22 +14,22 @@
>  static int dev_update_qos_constraint(struct device *dev, void *data)
>  {
>  	s64 *constraint_ns_p = data;
> -	s32 constraint_ns = -1;
> -
> -	if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
> -		constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
> +	s64 constraint_ns;
>  
> -	if (constraint_ns < 0) {
> -		constraint_ns = dev_pm_qos_read_value(dev);
> -		constraint_ns *= NSEC_PER_USEC;
> -	}
> -	if (constraint_ns == 0)
> +	if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
>  		return 0;
>  
>  	/*
> -	 * constraint_ns cannot be negative here, because the device has been
> -	 * suspended.
> +	 * Only take suspend-time QoS constraints of devices into account,
> +	 * because constraints updated after the device has been suspended are
> +	 * not guaranteed to be taken into account 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;
> +	/* 0 means "no constraint" */
> +	if (constraint_ns == 0)
> +		return 0;
> +
>  	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>  		*constraint_ns_p = constraint_ns;
>  
> @@ -76,14 +76,29 @@ static bool default_suspend_ok(struct de
>  		device_for_each_child(dev, &constraint_ns,
>  				      dev_update_qos_constraint);
>  
> -	if (constraint_ns > 0) {
> +	if (constraint_ns == 0) {
> +		/* "No restriction", so the device is allowed to suspend. */
> +		td->effective_constraint_ns = 0;
> +		td->cached_suspend_ok = true;
> +	} else {
> +		/*
> +		 * constraint_ns must be positive here, because the children
> +		 * walked above are all suspended, so effective_constraint_ns
> +		 * cannot be negative for them.
> +		 */
>  		constraint_ns -= td->suspend_latency_ns +
>  				td->resume_latency_ns;
> -		if (constraint_ns == 0)
> +		/*
> +		 * effective_constraint_ns is negative already and
> +		 * cached_suspend_ok is false, so if the computed value is not
> +		 * positive, return right away.
> +		 */
> +		if (constraint_ns <= 0)
>  			return false;
> +
> +		td->effective_constraint_ns = constraint_ns;
> +		td->cached_suspend_ok = true;
>  	}
> -	td->effective_constraint_ns = constraint_ns;
> -	td->cached_suspend_ok = constraint_ns >= 0;
>  
>  	/*
>  	 * The children have been suspended already, so we don't need to take
> @@ -144,18 +159,16 @@ static bool __default_power_down_ok(stru
>  		 */
>  		td = &to_gpd_data(pdd)->td;
>  		constraint_ns = td->effective_constraint_ns;
> -		/* default_suspend_ok() need not be called before us. */
> -		if (constraint_ns < 0) {
> -			constraint_ns = dev_pm_qos_read_value(pdd->dev);
> -			constraint_ns *= NSEC_PER_USEC;
> -		}
> +		/*
> +		 * Negative values mean "no suspend at all" and this runs only
> +		 * when all devices in the domain are suspended, so it must be
> +		 * 0 at least.
> +		 *
> +		 * 0 means "no constraint"
> +		 */
>  		if (constraint_ns == 0)
>  			continue;
>  
> -		/*
> -		 * constraint_ns cannot be negative here, because the device has
> -		 * been suspended.
> -		 */
>  		if (constraint_ns <= off_on_time_ns)
>  			return false;
>  
> 

Looks good to me.

Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>

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

* Re: [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03 11:50   ` [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
  2017-11-03 16:39     ` Reinette Chatre
@ 2017-11-04  2:38     ` Ramesh Thomas
  2017-11-04 12:34     ` [RFT][Update][PATCH " Rafael J. Wysocki
  2 siblings, 0 replies; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-04  2:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On 2017-11-03 at 12:50:15 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The special value of 0 for device resume latency PM QoS means
> "no restriction", but there are two problems with that.
> 
> First, device resume latency PM QoS requests with 0 as the
> value are always put in front of requests with positive
> values in the priority lists used internally by the PM QoS
> framework, causing 0 to be chosen as an effective constraint
> value.  However, that 0 is then interpreted as "no restriction"
> effectively overriding the other requests with specific
> restrictions which is incorrect.
> 
> Second, the users of device resume latency PM QoS have no
> way to specify that *any* resume latency at all should be
> avoided, which is an artificial limitation in general.
> 
> To address these issues, modify device resume latency PM QoS to
> use S32_MAX as the "no constraint" value and 0 as the "no
> latency at all" one and rework its users (the cpuidle menu
> governor, the genpd QoS governor and the runtime PM framework)
> to follow these changes.
> 
> Also add a special "n/a" value to the corresponding user space I/F
> to allow user space to indicate that it cannot accept any resume
> latencies at all for the given device.
> 
> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-devices-power |    4 +++-
>  drivers/base/cpu.c                            |    3 ++-
>  drivers/base/power/domain.c                   |    2 +-
>  drivers/base/power/domain_governor.c          |   26 ++++++++++----------------
>  drivers/base/power/qos.c                      |    5 ++++-
>  drivers/base/power/runtime.c                  |    2 +-
>  drivers/base/power/sysfs.c                    |   25 +++++++++++++++++++++----
>  drivers/cpuidle/governors/menu.c              |    4 ++--
>  include/linux/pm_qos.h                        |   26 ++++++++++++++++++--------
>  9 files changed, 62 insertions(+), 35 deletions(-)
> 
> Index: linux-pm/drivers/base/power/sysfs.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/sysfs.c
> +++ linux-pm/drivers/base/power/sysfs.c
> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>  					  struct device_attribute *attr,
>  					  char *buf)
>  {
> -	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
> +	s32 value = dev_pm_qos_requested_resume_latency(dev);
> +
> +	if (value == 0)
> +		return sprintf(buf, "n/a\n");
> +	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +		value = 0;
> +
> +	return sprintf(buf, "%d\n", value);
>  }
>  
>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>  	s32 value;
>  	int ret;
>  
> -	if (kstrtos32(buf, 0, &value))
> -		return -EINVAL;
> +	if (!kstrtos32(buf, 0, &value)) {
> +		/*
> +		 * Prevent users from writing negative or "no constraint" values
> +		 * directly.
> +		 */
> +		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +			return -EINVAL;
>  
> -	if (value < 0)
> +		if (value == 0)
> +			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
> +		value = 0;
> +	} else {
>  		return -EINVAL;
> +	}
>  
>  	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>  					value);
> Index: linux-pm/include/linux/pm_qos.h
> ===================================================================
> --- linux-pm.orig/include/linux/pm_qos.h
> +++ linux-pm/include/linux/pm_qos.h
> @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>  	PM_QOS_FLAGS_ALL,
>  };
>  
> -#define PM_QOS_DEFAULT_VALUE -1
> +#define PM_QOS_DEFAULT_VALUE	(-1)
> +#define PM_QOS_LATENCY_ANY	S32_MAX
> +#define PM_QOS_LATENCY_ANY_NS	((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
>  
>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS	PM_QOS_LATENCY_ANY_NS
>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
> -#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
>  
>  #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
>  
> @@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>  {
>  	return IS_ERR_OR_NULL(dev->power.qos) ?
> -		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
> +		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
> +		pm_qos_read_value(&dev->power.qos->resume_latency);
>  }
>  #else
>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
> @@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
>  							s32 mask)
>  			{ return PM_QOS_FLAGS_UNDEFINED; }
>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline s32 dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline int dev_pm_qos_add_request(struct device *dev,
>  					 struct dev_pm_qos_request *req,
>  					 enum dev_pm_qos_req_type type,
> @@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
>  			{ return 0; }
>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>  
> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  #endif
>  
>  #endif
> Index: linux-pm/drivers/cpuidle/governors/menu.c
> ===================================================================
> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
> +++ linux-pm/drivers/cpuidle/governors/menu.c
> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>  		data->needs_update = 0;
>  	}
>  
> -	/* resume_latency is 0 means no restriction */
> -	if (resume_latency && resume_latency < latency_req)
> +	if (resume_latency < latency_req &&
> +	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>  		latency_req = resume_latency;
>  
>  	/* Special case when user has set very strict latency requirement */
> Index: linux-pm/drivers/base/power/runtime.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/runtime.c
> +++ linux-pm/drivers/base/power/runtime.c
> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>  	    || (dev->power.request_pending
>  			&& dev->power.request == RPM_REQ_RESUME))
>  		retval = -EAGAIN;
> -	else if (__dev_pm_qos_read_value(dev) < 0)
> +	else if (__dev_pm_qos_read_value(dev) == 0)
>  		retval = -EPERM;
>  	else if (dev->power.runtime_status == RPM_SUSPENDED)
>  		retval = 1;
> Index: linux-pm/drivers/base/cpu.c
> ===================================================================
> --- linux-pm.orig/drivers/base/cpu.c
> +++ linux-pm/drivers/base/cpu.c
> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>  
>  	per_cpu(cpu_sys_devices, num) = &cpu->dev;
>  	register_cpu_under_node(num, cpu_to_node(num));
> -	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
> +	dev_pm_qos_expose_latency_limit(&cpu->dev,
> +					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>  
>  	return 0;
>  }
> Index: linux-pm/drivers/base/power/qos.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/qos.c
> +++ linux-pm/drivers/base/power/qos.c
> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>  
>  	switch(req->type) {
>  	case DEV_PM_QOS_RESUME_LATENCY:
> +		if (WARN_ON(value < 0))
> +			value = 0;
> +
>  		ret = pm_qos_update_target(&qos->resume_latency,
>  					   &req->data.pnode, action, value);
>  		break;
> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>  	plist_head_init(&c->list);
>  	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>  	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> -	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> +	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>  	c->type = PM_QOS_MIN;
>  	c->notifiers = n;
>  
> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
> ===================================================================
> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
> @@ -211,7 +211,9 @@ Description:
>  		device, after it has been suspended at run time, from a resume
>  		request to the moment the device will be ready to process I/O,
>  		in microseconds.  If it is equal to 0, however, this means that
> -		the PM QoS resume latency may be arbitrary.
> +		the PM QoS resume latency may be arbitrary and the special value
> +		"n/a" means that user space cannot accept any resume latency at
> +		all for the given device.
>  
>  		Not all drivers support this attribute.  If it isn't supported,
>  		it is not present.
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>  
>  	gpd_data->base.dev = dev;
>  	gpd_data->td.constraint_changed = true;
> -	gpd_data->td.effective_constraint_ns = 0;
> +	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>  	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>  
>  	spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -26,11 +26,7 @@ static int dev_update_qos_constraint(str
>  	 * to take effect, the device has to be resumed and suspended again.
>  	 */
>  	constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
> -	/* 0 means "no constraint" */
> -	if (constraint_ns == 0)
> -		return 0;
> -
> -	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
> +	if (constraint_ns < *constraint_ns_p)
>  		*constraint_ns_p = constraint_ns;
>  
>  	return 0;
> @@ -58,12 +54,12 @@ static bool default_suspend_ok(struct de
>  	}
>  	td->constraint_changed = false;
>  	td->cached_suspend_ok = false;
> -	td->effective_constraint_ns = -1;
> +	td->effective_constraint_ns = 0;
>  	constraint_ns = __dev_pm_qos_read_value(dev);
>  
>  	spin_unlock_irqrestore(&dev->power.lock, flags);
>  
> -	if (constraint_ns < 0)
> +	if (constraint_ns == 0)
>  		return false;
>  
>  	constraint_ns *= NSEC_PER_USEC;
> @@ -76,22 +72,22 @@ static bool default_suspend_ok(struct de
>  		device_for_each_child(dev, &constraint_ns,
>  				      dev_update_qos_constraint);
>  
> -	if (constraint_ns == 0) {
> +	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
>  		/* "No restriction", so the device is allowed to suspend. */
> -		td->effective_constraint_ns = 0;
> +		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>  		td->cached_suspend_ok = true;
>  	} else {
>  		/*
>  		 * constraint_ns must be positive here, because the children
>  		 * walked above are all suspended, so effective_constraint_ns
> -		 * cannot be negative for them.
> +		 * cannot be 0 for them.
>  		 */
>  		constraint_ns -= td->suspend_latency_ns +
>  				td->resume_latency_ns;
>  		/*
> -		 * effective_constraint_ns is negative already and
> -		 * cached_suspend_ok is false, so if the computed value is not
> -		 * positive, return right away.
> +		 * effective_constraint_ns is 0 already and cached_suspend_ok is
> +		 * false, so if the computed value is not positive, return right
> +		 * away.
>  		 */
>  		if (constraint_ns <= 0)
>  			return false;
> @@ -163,10 +159,8 @@ static bool __default_power_down_ok(stru
>  		 * Negative values mean "no suspend at all" and this runs only
>  		 * when all devices in the domain are suspended, so it must be
>  		 * 0 at least.
> -		 *
> -		 * 0 means "no constraint"
>  		 */
> -		if (constraint_ns == 0)
> +		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
>  			continue;
>  
>  		if (constraint_ns <= off_on_time_ns)
> 

Looks good to me except for the warning issue reported by Reinette, which
probably should be an easy fix.

Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-04  2:34     ` Ramesh Thomas
@ 2017-11-04 11:24       ` Rafael J. Wysocki
  2017-11-06  7:47         ` Ramesh Thomas
  0 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-04 11:24 UTC (permalink / raw)
  To: ramesh.thomas
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

On Sat, Nov 4, 2017 at 3:34 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> On 2017-11-03 at 12:47:20 +0100, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> The genpd governor currently uses negative PM QoS values to indicate
>> the "no suspend" condition and 0 as "no restriction", but it doesn't
>> use them consistently.  Moreover, it tries to refresh QoS values for
>> already suspended devices in a quite questionable way.
>>
>> For the above reasons, rework it to be a bit more consistent.
>>
>> First off, note that dev_pm_qos_read_value() in
>> dev_update_qos_constraint() and __default_power_down_ok() is
>> evaluated for devices in suspend.  Moreover, that only happens if the
>> effective_constraint_ns value for them is negative (meaning "no
>> suspend").  It is not evaluated in any other cases, so effectively
>> the QoS values are only updated for devices in suspend that should
>> not have been suspended in the first place.  In all of the other
>> cases, the QoS values taken into account are the effective ones from
>> the time before the device has been suspended, so generally devices
>> need to be resumed and suspended again for new QoS values to take
>> effect anyway.  Thus evaluating dev_update_qos_constraint() in
>> those two places doesn't make sense at all, so drop it.
>>
>> Second, initialize effective_constraint_ns to 0 ("no constraint")
>> rather than to (-1) ("no suspend"), which makes more sense in
>> general and in case effective_constraint_ns is never updated
>> (the device is in suspend all the time or it is never suspended)
>> it doesn't affect the device's parent and so on.
>>
>> Finally, rework default_suspend_ok() to explicitly handle the
>> "no restriction" special case.
>>
>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> ---

[cut]

> Looks good to me.
>
> Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>

Thanks!

Do you actually mean Reviewed-by?

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

* Re: [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03 16:39     ` Reinette Chatre
  2017-11-04  2:28       ` Ramesh Thomas
@ 2017-11-04 11:28       ` Rafael J. Wysocki
  1 sibling, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-04 11:28 UTC (permalink / raw)
  To: Reinette Chatre
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Ramesh Thomas, Alex Shi

On Fri, Nov 3, 2017 at 5:39 PM, Reinette Chatre
<reinette.chatre@intel.com> wrote:
> Hi Rafael,
>
> I started to test this but found myself triggering one of the warnings:
>
> On 11/3/2017 4:50 AM, Rafael J. Wysocki wrote:
>> --- linux-pm.orig/include/linux/pm_qos.h
>> +++ linux-pm/include/linux/pm_qos.h
>> @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>>       PM_QOS_FLAGS_ALL,
>>  };
>>
>> -#define PM_QOS_DEFAULT_VALUE -1
>> +#define PM_QOS_DEFAULT_VALUE (-1)
>
> PM_QOS_DEFAULT_VALUE is -1 ...
>
>
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/qos.c
>> +++ linux-pm/drivers/base/power/qos.c
>> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>>
>>       switch(req->type) {
>>       case DEV_PM_QOS_RESUME_LATENCY:
>> +             if (WARN_ON(value < 0))
>> +                     value = 0;
>> +
>
> ... causing me to hit this WARN_ON because apply_constraint() is called by __dev_pm_qos_remove_request() with the value parameter set to PM_QOS_DEFAULT_VALUE.

Thanks for the report!

I've added it to catch bugs in the future, but it has caught a bug
right away. :-)

That actually is a bug in the existing code that needs to be fixed.

Thanks,
Rafael

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

* Re: [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-04  2:28       ` Ramesh Thomas
@ 2017-11-04 11:30         ` Rafael J. Wysocki
  2017-11-04 11:58           ` Rafael J. Wysocki
  0 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-04 11:30 UTC (permalink / raw)
  To: Ramesh Thomas
  Cc: Reinette Chatre, Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Alex Shi

On Sat, Nov 4, 2017 at 3:28 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> On 2017-11-03 at 09:39:08 -0700, Reinette Chatre wrote:
>> Hi Rafael,
>>
>> I started to test this but found myself triggering one of the warnings:
>>
>> On 11/3/2017 4:50 AM, Rafael J. Wysocki wrote:
>> > --- linux-pm.orig/include/linux/pm_qos.h
>> > +++ linux-pm/include/linux/pm_qos.h
>> > @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>> >     PM_QOS_FLAGS_ALL,
>> >  };
>> >
>> > -#define PM_QOS_DEFAULT_VALUE -1
>> > +#define PM_QOS_DEFAULT_VALUE       (-1)
>>
>> PM_QOS_DEFAULT_VALUE is -1 ...
>>
>>
>> > ===================================================================
>> > --- linux-pm.orig/drivers/base/power/qos.c
>> > +++ linux-pm/drivers/base/power/qos.c
>> > @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>> >
>> >     switch(req->type) {
>> >     case DEV_PM_QOS_RESUME_LATENCY:
>> > +           if (WARN_ON(value < 0))
>> > +                   value = 0;
>> > +
>>
>> ... causing me to hit this WARN_ON because apply_constraint() is called by __dev_pm_qos_remove_request() with the value parameter set to PM_QOS_DEFAULT_VALUE.
>
> That value does not get used if action is PM_QOS_REMOVE_REQ. May be just pass
> 0 or PM_QOS_RESUME_LATENCY_DEFAULT_VALUE everywhere apply_constraint is called
> with PM_QOS_REMOVE_REQ action.

I think it's better to pass the "no constraint" value as that should
not reorder it to the top of the list.

Thanks,
Rafael

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

* Re: [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-04 11:30         ` Rafael J. Wysocki
@ 2017-11-04 11:58           ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-04 11:58 UTC (permalink / raw)
  To: Ramesh Thomas
  Cc: Reinette Chatre, Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Alex Shi

On Sat, Nov 4, 2017 at 12:30 PM, Rafael J. Wysocki <rafael@kernel.org> wrote:
> On Sat, Nov 4, 2017 at 3:28 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
>> On 2017-11-03 at 09:39:08 -0700, Reinette Chatre wrote:
>>> Hi Rafael,
>>>
>>> I started to test this but found myself triggering one of the warnings:
>>>
>>> On 11/3/2017 4:50 AM, Rafael J. Wysocki wrote:
>>> > --- linux-pm.orig/include/linux/pm_qos.h
>>> > +++ linux-pm/include/linux/pm_qos.h
>>> > @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>>> >     PM_QOS_FLAGS_ALL,
>>> >  };
>>> >
>>> > -#define PM_QOS_DEFAULT_VALUE -1
>>> > +#define PM_QOS_DEFAULT_VALUE       (-1)
>>>
>>> PM_QOS_DEFAULT_VALUE is -1 ...
>>>
>>>
>>> > ===================================================================
>>> > --- linux-pm.orig/drivers/base/power/qos.c
>>> > +++ linux-pm/drivers/base/power/qos.c
>>> > @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>>> >
>>> >     switch(req->type) {
>>> >     case DEV_PM_QOS_RESUME_LATENCY:
>>> > +           if (WARN_ON(value < 0))
>>> > +                   value = 0;
>>> > +
>>>
>>> ... causing me to hit this WARN_ON because apply_constraint() is called by __dev_pm_qos_remove_request() with the value parameter set to PM_QOS_DEFAULT_VALUE.
>>
>> That value does not get used if action is PM_QOS_REMOVE_REQ. May be just pass
>> 0 or PM_QOS_RESUME_LATENCY_DEFAULT_VALUE everywhere apply_constraint is called
>> with PM_QOS_REMOVE_REQ action.
>
> I think it's better to pass the "no constraint" value as that should
> not reorder it to the top of the list.

Actually, no.  The value is ignored if action is PM_QOS_REMOVE_REQ, so
it is better to simply check the action under the WARN_ON() too.

Thanks,
Rafael

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

* [RFT][Update][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-03 11:50   ` [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
  2017-11-03 16:39     ` Reinette Chatre
  2017-11-04  2:38     ` Ramesh Thomas
@ 2017-11-04 12:34     ` Rafael J. Wysocki
  2017-11-06 17:47       ` Reinette Chatre
  2 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-04 12:34 UTC (permalink / raw)
  To: Linux PM, Reinette Chatre
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The special value of 0 for device resume latency PM QoS means
"no restriction", but there are two problems with that.

First, device resume latency PM QoS requests with 0 as the
value are always put in front of requests with positive
values in the priority lists used internally by the PM QoS
framework, causing 0 to be chosen as an effective constraint
value.  However, that 0 is then interpreted as "no restriction"
effectively overriding the other requests with specific
restrictions which is incorrect.

Second, the users of device resume latency PM QoS have no
way to specify that *any* resume latency at all should be
avoided, which is an artificial limitation in general.

To address these issues, modify device resume latency PM QoS to
use S32_MAX as the "no constraint" value and 0 as the "no
latency at all" one and rework its users (the cpuidle menu
governor, the genpd QoS governor and the runtime PM framework)
to follow these changes.

Also add a special "n/a" value to the corresponding user space I/F
to allow user space to indicate that it cannot accept any resume
latencies at all for the given device.

Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>
---

Re-sending as an update rather than as v3, because the update is very minor
(an additional check under the WARN_ON() in apply_constraint()).

Reinette, please test this one instead of the last version.  The WARN_ON()
issue should be gone with this.

Thanks,
Rafael

---
 Documentation/ABI/testing/sysfs-devices-power |    4 +++-
 drivers/base/cpu.c                            |    3 ++-
 drivers/base/power/domain.c                   |    2 +-
 drivers/base/power/domain_governor.c          |   26 ++++++++++----------------
 drivers/base/power/qos.c                      |    5 ++++-
 drivers/base/power/runtime.c                  |    2 +-
 drivers/base/power/sysfs.c                    |   25 +++++++++++++++++++++----
 drivers/cpuidle/governors/menu.c              |    4 ++--
 include/linux/pm_qos.h                        |   26 ++++++++++++++++++--------
 9 files changed, 62 insertions(+), 35 deletions(-)

Index: linux-pm/drivers/base/power/sysfs.c
===================================================================
--- linux-pm.orig/drivers/base/power/sysfs.c
+++ linux-pm/drivers/base/power/sysfs.c
@@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
 					  struct device_attribute *attr,
 					  char *buf)
 {
-	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
+	s32 value = dev_pm_qos_requested_resume_latency(dev);
+
+	if (value == 0)
+		return sprintf(buf, "n/a\n");
+	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+		value = 0;
+
+	return sprintf(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_resume_latency_store(struct device *dev,
@@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
 	s32 value;
 	int ret;
 
-	if (kstrtos32(buf, 0, &value))
-		return -EINVAL;
+	if (!kstrtos32(buf, 0, &value)) {
+		/*
+		 * Prevent users from writing negative or "no constraint" values
+		 * directly.
+		 */
+		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+			return -EINVAL;
 
-	if (value < 0)
+		if (value == 0)
+			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
+		value = 0;
+	} else {
 		return -EINVAL;
+	}
 
 	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
 					value);
Index: linux-pm/include/linux/pm_qos.h
===================================================================
--- linux-pm.orig/include/linux/pm_qos.h
+++ linux-pm/include/linux/pm_qos.h
@@ -28,16 +28,19 @@ enum pm_qos_flags_status {
 	PM_QOS_FLAGS_ALL,
 };
 
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_DEFAULT_VALUE	(-1)
+#define PM_QOS_LATENCY_ANY	S32_MAX
+#define PM_QOS_LATENCY_ANY_NS	((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
 
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
-#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS	PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
-#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
 
@@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
 static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
 {
 	return IS_ERR_OR_NULL(dev->power.qos) ?
-		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
+		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
+		pm_qos_read_value(&dev->power.qos->resume_latency);
 }
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
 							s32 mask)
 			{ return PM_QOS_FLAGS_UNDEFINED; }
 static inline s32 __dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline s32 dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline int dev_pm_qos_add_request(struct device *dev,
 					 struct dev_pm_qos_request *req,
 					 enum dev_pm_qos_req_type type,
@@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
 			{ return 0; }
 static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
 
-static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 #endif
 
 #endif
Index: linux-pm/drivers/cpuidle/governors/menu.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/menu.c
+++ linux-pm/drivers/cpuidle/governors/menu.c
@@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
 		data->needs_update = 0;
 	}
 
-	/* resume_latency is 0 means no restriction */
-	if (resume_latency && resume_latency < latency_req)
+	if (resume_latency < latency_req &&
+	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		latency_req = resume_latency;
 
 	/* Special case when user has set very strict latency requirement */
Index: linux-pm/drivers/base/power/runtime.c
===================================================================
--- linux-pm.orig/drivers/base/power/runtime.c
+++ linux-pm/drivers/base/power/runtime.c
@@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
-	else if (__dev_pm_qos_read_value(dev) < 0)
+	else if (__dev_pm_qos_read_value(dev) == 0)
 		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
Index: linux-pm/drivers/base/cpu.c
===================================================================
--- linux-pm.orig/drivers/base/cpu.c
+++ linux-pm/drivers/base/cpu.c
@@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
 
 	per_cpu(cpu_sys_devices, num) = &cpu->dev;
 	register_cpu_under_node(num, cpu_to_node(num));
-	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
+	dev_pm_qos_expose_latency_limit(&cpu->dev,
+					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
 
 	return 0;
 }
Index: linux-pm/drivers/base/power/qos.c
===================================================================
--- linux-pm.orig/drivers/base/power/qos.c
+++ linux-pm/drivers/base/power/qos.c
@@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
 
 	switch(req->type) {
 	case DEV_PM_QOS_RESUME_LATENCY:
+		if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
+			value = 0;
+
 		ret = pm_qos_update_target(&qos->resume_latency,
 					   &req->data.pnode, action, value);
 		break;
@@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
 	plist_head_init(&c->list);
 	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
 	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
-	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 	c->type = PM_QOS_MIN;
 	c->notifiers = n;
 
Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
===================================================================
--- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
+++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
@@ -211,7 +211,9 @@ Description:
 		device, after it has been suspended at run time, from a resume
 		request to the moment the device will be ready to process I/O,
 		in microseconds.  If it is equal to 0, however, this means that
-		the PM QoS resume latency may be arbitrary.
+		the PM QoS resume latency may be arbitrary and the special value
+		"n/a" means that user space cannot accept any resume latency at
+		all for the given device.
 
 		Not all drivers support this attribute.  If it isn't supported,
 		it is not present.
Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = 0;
+	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -26,11 +26,7 @@ static int dev_update_qos_constraint(str
 	 * to take effect, the device has to be resumed and suspended again.
 	 */
 	constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
-	/* 0 means "no constraint" */
-	if (constraint_ns == 0)
-		return 0;
-
-	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+	if (constraint_ns < *constraint_ns_p)
 		*constraint_ns_p = constraint_ns;
 
 	return 0;
@@ -58,12 +54,12 @@ static bool default_suspend_ok(struct de
 	}
 	td->constraint_changed = false;
 	td->cached_suspend_ok = false;
-	td->effective_constraint_ns = -1;
+	td->effective_constraint_ns = 0;
 	constraint_ns = __dev_pm_qos_read_value(dev);
 
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
-	if (constraint_ns < 0)
+	if (constraint_ns == 0)
 		return false;
 
 	constraint_ns *= NSEC_PER_USEC;
@@ -76,22 +72,22 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns == 0) {
+	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
 		/* "No restriction", so the device is allowed to suspend. */
-		td->effective_constraint_ns = 0;
+		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 		td->cached_suspend_ok = true;
 	} else {
 		/*
 		 * constraint_ns must be positive here, because the children
 		 * walked above are all suspended, so effective_constraint_ns
-		 * cannot be negative for them.
+		 * cannot be 0 for them.
 		 */
 		constraint_ns -= td->suspend_latency_ns +
 				td->resume_latency_ns;
 		/*
-		 * effective_constraint_ns is negative already and
-		 * cached_suspend_ok is false, so if the computed value is not
-		 * positive, return right away.
+		 * effective_constraint_ns is 0 already and cached_suspend_ok is
+		 * false, so if the computed value is not positive, return right
+		 * away.
 		 */
 		if (constraint_ns <= 0)
 			return false;
@@ -163,10 +159,8 @@ static bool __default_power_down_ok(stru
 		 * Negative values mean "no suspend at all" and this runs only
 		 * when all devices in the domain are suspended, so it must be
 		 * 0 at least.
-		 *
-		 * 0 means "no constraint"
 		 */
-		if (constraint_ns == 0)
+		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
 			continue;
 
 		if (constraint_ns <= off_on_time_ns)

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-04 11:24       ` Rafael J. Wysocki
@ 2017-11-06  7:47         ` Ramesh Thomas
  0 siblings, 0 replies; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-06  7:47 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

On 2017-11-04 at 12:24:15 +0100, Rafael J. Wysocki wrote:
> On Sat, Nov 4, 2017 at 3:34 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> > On 2017-11-03 at 12:47:20 +0100, Rafael J. Wysocki wrote:
> >> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>
> >> The genpd governor currently uses negative PM QoS values to indicate
> >> the "no suspend" condition and 0 as "no restriction", but it doesn't
> >> use them consistently.  Moreover, it tries to refresh QoS values for
> >> already suspended devices in a quite questionable way.
> >>
> >> For the above reasons, rework it to be a bit more consistent.
> >>
> >> First off, note that dev_pm_qos_read_value() in
> >> dev_update_qos_constraint() and __default_power_down_ok() is
> >> evaluated for devices in suspend.  Moreover, that only happens if the
> >> effective_constraint_ns value for them is negative (meaning "no
> >> suspend").  It is not evaluated in any other cases, so effectively
> >> the QoS values are only updated for devices in suspend that should
> >> not have been suspended in the first place.  In all of the other
> >> cases, the QoS values taken into account are the effective ones from
> >> the time before the device has been suspended, so generally devices
> >> need to be resumed and suspended again for new QoS values to take
> >> effect anyway.  Thus evaluating dev_update_qos_constraint() in
> >> those two places doesn't make sense at all, so drop it.
> >>
> >> Second, initialize effective_constraint_ns to 0 ("no constraint")
> >> rather than to (-1) ("no suspend"), which makes more sense in
> >> general and in case effective_constraint_ns is never updated
> >> (the device is in suspend all the time or it is never suspended)
> >> it doesn't affect the device's parent and so on.
> >>
> >> Finally, rework default_suspend_ok() to explicitly handle the
> >> "no restriction" special case.
> >>
> >> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> ---
> 
> [cut]
> 
> > Looks good to me.
> >
> > Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>
> 
> Thanks!
> 
> Do you actually mean Reviewed-by?

Yes, it should be Reveiewed-by for both patches!

Thanks,
Ramesh

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-03 11:47   ` [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
  2017-11-04  2:34     ` Ramesh Thomas
@ 2017-11-06 12:10     ` Ulf Hansson
  2017-11-06 12:34       ` Rafael J. Wysocki
  1 sibling, 1 reply; 47+ messages in thread
From: Ulf Hansson @ 2017-11-06 12:10 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Geert Uytterhoeven, Tero Kristo, Reinette Chatre,
	Ramesh Thomas, Alex Shi

On 3 November 2017 at 12:47, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> The genpd governor currently uses negative PM QoS values to indicate
> the "no suspend" condition and 0 as "no restriction", but it doesn't
> use them consistently.  Moreover, it tries to refresh QoS values for
> already suspended devices in a quite questionable way.
>
> For the above reasons, rework it to be a bit more consistent.
>
> First off, note that dev_pm_qos_read_value() in
> dev_update_qos_constraint() and __default_power_down_ok() is
> evaluated for devices in suspend.  Moreover, that only happens if the
> effective_constraint_ns value for them is negative (meaning "no
> suspend").  It is not evaluated in any other cases, so effectively
> the QoS values are only updated for devices in suspend that should
> not have been suspended in the first place.  In all of the other
> cases, the QoS values taken into account are the effective ones from
> the time before the device has been suspended, so generally devices
> need to be resumed and suspended again for new QoS values to take
> effect anyway.  Thus evaluating dev_update_qos_constraint() in
> those two places doesn't make sense at all, so drop it.
>
> Second, initialize effective_constraint_ns to 0 ("no constraint")
> rather than to (-1) ("no suspend"), which makes more sense in
> general and in case effective_constraint_ns is never updated
> (the device is in suspend all the time or it is never suspended)
> it doesn't affect the device's parent and so on.
>
> Finally, rework default_suspend_ok() to explicitly handle the
> "no restriction" special case.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/base/power/domain.c          |    2 -
>  drivers/base/power/domain_governor.c |   61 +++++++++++++++++++++--------------
>  2 files changed, 38 insertions(+), 25 deletions(-)
>
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>
>         gpd_data->base.dev = dev;
>         gpd_data->td.constraint_changed = true;
> -       gpd_data->td.effective_constraint_ns = -1;
> +       gpd_data->td.effective_constraint_ns = 0;
>         gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>
>         spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -14,22 +14,22 @@
>  static int dev_update_qos_constraint(struct device *dev, void *data)
>  {
>         s64 *constraint_ns_p = data;
> -       s32 constraint_ns = -1;
> -
> -       if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
> -               constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
> +       s64 constraint_ns;
>
> -       if (constraint_ns < 0) {
> -               constraint_ns = dev_pm_qos_read_value(dev);
> -               constraint_ns *= NSEC_PER_USEC;
> -       }
> -       if (constraint_ns == 0)
> +       if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
>                 return 0;
>
>         /*
> -        * constraint_ns cannot be negative here, because the device has been
> -        * suspended.
> +        * Only take suspend-time QoS constraints of devices into account,
> +        * because constraints updated after the device has been suspended are
> +        * not guaranteed to be taken into account anyway.  In order for them
> +        * to take effect, the device has to be resumed and suspended again.
>          */

This means a change in behavior, because earlier we took into account
QoS values for child devices that were not attached to a genpd.

Is there any reason you think we should change this, or is it just
something you overlooked here?

I understand, that if the QoS constraint has been updated after such
child device has been suspended, it's tricky to take a correct
decision.

To really solve this, we would either have to register a QoS notifier
for all children devices that has its parent attached to a genpd, or
always runtime resume devices before updating QoS constraints.

Non of these options is perfect, so perhaps we should consider a "best
effort" approach instead? Whatever that may be.

> +       constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
> +       /* 0 means "no constraint" */
> +       if (constraint_ns == 0)
> +               return 0;
> +
>         if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>                 *constraint_ns_p = constraint_ns;
>
> @@ -76,14 +76,29 @@ static bool default_suspend_ok(struct de
>                 device_for_each_child(dev, &constraint_ns,
>                                       dev_update_qos_constraint);
>
> -       if (constraint_ns > 0) {
> +       if (constraint_ns == 0) {
> +               /* "No restriction", so the device is allowed to suspend. */
> +               td->effective_constraint_ns = 0;
> +               td->cached_suspend_ok = true;
> +       } else {
> +               /*
> +                * constraint_ns must be positive here, because the children
> +                * walked above are all suspended, so effective_constraint_ns
> +                * cannot be negative for them.
> +                */
>                 constraint_ns -= td->suspend_latency_ns +
>                                 td->resume_latency_ns;
> -               if (constraint_ns == 0)
> +               /*
> +                * effective_constraint_ns is negative already and
> +                * cached_suspend_ok is false, so if the computed value is not
> +                * positive, return right away.
> +                */
> +               if (constraint_ns <= 0)
>                         return false;
> +
> +               td->effective_constraint_ns = constraint_ns;
> +               td->cached_suspend_ok = true;
>         }
> -       td->effective_constraint_ns = constraint_ns;
> -       td->cached_suspend_ok = constraint_ns >= 0;
>
>         /*
>          * The children have been suspended already, so we don't need to take
> @@ -144,18 +159,16 @@ static bool __default_power_down_ok(stru
>                  */
>                 td = &to_gpd_data(pdd)->td;
>                 constraint_ns = td->effective_constraint_ns;
> -               /* default_suspend_ok() need not be called before us. */
> -               if (constraint_ns < 0) {
> -                       constraint_ns = dev_pm_qos_read_value(pdd->dev);
> -                       constraint_ns *= NSEC_PER_USEC;
> -               }
> +               /*
> +                * Negative values mean "no suspend at all" and this runs only
> +                * when all devices in the domain are suspended, so it must be
> +                * 0 at least.
> +                *
> +                * 0 means "no constraint"
> +                */
>                 if (constraint_ns == 0)
>                         continue;
>
> -               /*
> -                * constraint_ns cannot be negative here, because the device has
> -                * been suspended.
> -                */
>                 if (constraint_ns <= off_on_time_ns)
>                         return false;
>
>

Kind regards
Uffe

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-06 12:10     ` Ulf Hansson
@ 2017-11-06 12:34       ` Rafael J. Wysocki
  2017-11-06 12:44         ` Ulf Hansson
  0 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-06 12:34 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rafael J. Wysocki, Linux PM, LKML, Geert Uytterhoeven,
	Tero Kristo, Reinette Chatre, Ramesh Thomas, Alex Shi

On Mon, Nov 6, 2017 at 1:10 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 3 November 2017 at 12:47, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> The genpd governor currently uses negative PM QoS values to indicate
>> the "no suspend" condition and 0 as "no restriction", but it doesn't
>> use them consistently.  Moreover, it tries to refresh QoS values for
>> already suspended devices in a quite questionable way.
>>
>> For the above reasons, rework it to be a bit more consistent.
>>
>> First off, note that dev_pm_qos_read_value() in
>> dev_update_qos_constraint() and __default_power_down_ok() is
>> evaluated for devices in suspend.  Moreover, that only happens if the
>> effective_constraint_ns value for them is negative (meaning "no
>> suspend").  It is not evaluated in any other cases, so effectively
>> the QoS values are only updated for devices in suspend that should
>> not have been suspended in the first place.  In all of the other
>> cases, the QoS values taken into account are the effective ones from
>> the time before the device has been suspended, so generally devices
>> need to be resumed and suspended again for new QoS values to take
>> effect anyway.  Thus evaluating dev_update_qos_constraint() in
>> those two places doesn't make sense at all, so drop it.
>>
>> Second, initialize effective_constraint_ns to 0 ("no constraint")
>> rather than to (-1) ("no suspend"), which makes more sense in
>> general and in case effective_constraint_ns is never updated
>> (the device is in suspend all the time or it is never suspended)
>> it doesn't affect the device's parent and so on.
>>
>> Finally, rework default_suspend_ok() to explicitly handle the
>> "no restriction" special case.
>>
>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> ---
>>  drivers/base/power/domain.c          |    2 -
>>  drivers/base/power/domain_governor.c |   61 +++++++++++++++++++++--------------
>>  2 files changed, 38 insertions(+), 25 deletions(-)
>>
>> Index: linux-pm/drivers/base/power/domain.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain.c
>> +++ linux-pm/drivers/base/power/domain.c
>> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>>
>>         gpd_data->base.dev = dev;
>>         gpd_data->td.constraint_changed = true;
>> -       gpd_data->td.effective_constraint_ns = -1;
>> +       gpd_data->td.effective_constraint_ns = 0;
>>         gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>>
>>         spin_lock_irq(&dev->power.lock);
>> Index: linux-pm/drivers/base/power/domain_governor.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain_governor.c
>> +++ linux-pm/drivers/base/power/domain_governor.c
>> @@ -14,22 +14,22 @@
>>  static int dev_update_qos_constraint(struct device *dev, void *data)
>>  {
>>         s64 *constraint_ns_p = data;
>> -       s32 constraint_ns = -1;
>> -
>> -       if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
>> -               constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
>> +       s64 constraint_ns;
>>
>> -       if (constraint_ns < 0) {
>> -               constraint_ns = dev_pm_qos_read_value(dev);
>> -               constraint_ns *= NSEC_PER_USEC;
>> -       }
>> -       if (constraint_ns == 0)
>> +       if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
>>                 return 0;
>>
>>         /*
>> -        * constraint_ns cannot be negative here, because the device has been
>> -        * suspended.
>> +        * Only take suspend-time QoS constraints of devices into account,
>> +        * because constraints updated after the device has been suspended are
>> +        * not guaranteed to be taken into account anyway.  In order for them
>> +        * to take effect, the device has to be resumed and suspended again.
>>          */
>
> This means a change in behavior, because earlier we took into account
> QoS values for child devices that were not attached to a genpd.

OK

I have overlooked it or rather have forgotten about that.

> Is there any reason you think we should change this, or is it just
> something you overlooked here?
>
> I understand, that if the QoS constraint has been updated after such
> child device has been suspended, it's tricky to take a correct
> decision.

Right, but if they are not in a domain, the best we can do is to look
at the current value.

> To really solve this, we would either have to register a QoS notifier
> for all children devices that has its parent attached to a genpd, or
> always runtime resume devices before updating QoS constraints.
>
> Non of these options is perfect, so perhaps we should consider a "best
> effort" approach instead? Whatever that may be.

I think best effort makes most sense.

So I guess I'll simply evaluate dev_pm_qos_read_value(dev) if
subsys_data or subsys_data->domain_data is not there.

Of course, that doesn't apply to the code in __default_power_down_ok()
as that only takes device in the domain into account anyway.

Thanks,
Rafael

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-06 12:34       ` Rafael J. Wysocki
@ 2017-11-06 12:44         ` Ulf Hansson
  2017-11-06 12:49           ` Rafael J. Wysocki
  0 siblings, 1 reply; 47+ messages in thread
From: Ulf Hansson @ 2017-11-06 12:44 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Rafael J. Wysocki, Linux PM, LKML, Geert Uytterhoeven,
	Tero Kristo, Reinette Chatre, Ramesh Thomas, Alex Shi

[...]

>>>  static int dev_update_qos_constraint(struct device *dev, void *data)
>>>  {
>>>         s64 *constraint_ns_p = data;
>>> -       s32 constraint_ns = -1;
>>> -
>>> -       if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
>>> -               constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
>>> +       s64 constraint_ns;
>>>
>>> -       if (constraint_ns < 0) {
>>> -               constraint_ns = dev_pm_qos_read_value(dev);
>>> -               constraint_ns *= NSEC_PER_USEC;
>>> -       }
>>> -       if (constraint_ns == 0)
>>> +       if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
>>>                 return 0;
>>>
>>>         /*
>>> -        * constraint_ns cannot be negative here, because the device has been
>>> -        * suspended.
>>> +        * Only take suspend-time QoS constraints of devices into account,
>>> +        * because constraints updated after the device has been suspended are
>>> +        * not guaranteed to be taken into account anyway.  In order for them
>>> +        * to take effect, the device has to be resumed and suspended again.
>>>          */
>>
>> This means a change in behavior, because earlier we took into account
>> QoS values for child devices that were not attached to a genpd.
>
> OK
>
> I have overlooked it or rather have forgotten about that.
>
>> Is there any reason you think we should change this, or is it just
>> something you overlooked here?
>>
>> I understand, that if the QoS constraint has been updated after such
>> child device has been suspended, it's tricky to take a correct
>> decision.
>
> Right, but if they are not in a domain, the best we can do is to look
> at the current value.
>
>> To really solve this, we would either have to register a QoS notifier
>> for all children devices that has its parent attached to a genpd, or
>> always runtime resume devices before updating QoS constraints.
>>
>> Non of these options is perfect, so perhaps we should consider a "best
>> effort" approach instead? Whatever that may be.
>
> I think best effort makes most sense.

Okay!

>
> So I guess I'll simply evaluate dev_pm_qos_read_value(dev) if
> subsys_data or subsys_data->domain_data is not there.

Yes.

However, if it returns -1, what value should you pick? 0?

>
> Of course, that doesn't apply to the code in __default_power_down_ok()
> as that only takes device in the domain into account anyway.

Yep, agree!

Kind regards
Uffe

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-06 12:44         ` Ulf Hansson
@ 2017-11-06 12:49           ` Rafael J. Wysocki
  2017-11-06 14:38             ` Ulf Hansson
  0 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-06 12:49 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rafael J. Wysocki, Rafael J. Wysocki, Linux PM, LKML,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Ramesh Thomas,
	Alex Shi

On Mon, Nov 6, 2017 at 1:44 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> [...]
>
>>>>  static int dev_update_qos_constraint(struct device *dev, void *data)
>>>>  {
>>>>         s64 *constraint_ns_p = data;
>>>> -       s32 constraint_ns = -1;
>>>> -
>>>> -       if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
>>>> -               constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
>>>> +       s64 constraint_ns;
>>>>
>>>> -       if (constraint_ns < 0) {
>>>> -               constraint_ns = dev_pm_qos_read_value(dev);
>>>> -               constraint_ns *= NSEC_PER_USEC;
>>>> -       }
>>>> -       if (constraint_ns == 0)
>>>> +       if (!dev->power.subsys_data || !dev->power.subsys_data->domain_data)
>>>>                 return 0;
>>>>
>>>>         /*
>>>> -        * constraint_ns cannot be negative here, because the device has been
>>>> -        * suspended.
>>>> +        * Only take suspend-time QoS constraints of devices into account,
>>>> +        * because constraints updated after the device has been suspended are
>>>> +        * not guaranteed to be taken into account anyway.  In order for them
>>>> +        * to take effect, the device has to be resumed and suspended again.
>>>>          */
>>>
>>> This means a change in behavior, because earlier we took into account
>>> QoS values for child devices that were not attached to a genpd.
>>
>> OK
>>
>> I have overlooked it or rather have forgotten about that.
>>
>>> Is there any reason you think we should change this, or is it just
>>> something you overlooked here?
>>>
>>> I understand, that if the QoS constraint has been updated after such
>>> child device has been suspended, it's tricky to take a correct
>>> decision.
>>
>> Right, but if they are not in a domain, the best we can do is to look
>> at the current value.
>>
>>> To really solve this, we would either have to register a QoS notifier
>>> for all children devices that has its parent attached to a genpd, or
>>> always runtime resume devices before updating QoS constraints.
>>>
>>> Non of these options is perfect, so perhaps we should consider a "best
>>> effort" approach instead? Whatever that may be.
>>
>> I think best effort makes most sense.
>
> Okay!
>
>>
>> So I guess I'll simply evaluate dev_pm_qos_read_value(dev) if
>> subsys_data or subsys_data->domain_data is not there.
>
> Yes.
>
> However, if it returns -1, what value should you pick? 0?

Without the second patch, -1 will just mean "no suspend", so the
parent cannot be suspended too, but that should just work AFAICS
(effective_constraint_ns may be -1 too at that point, if present).

With the second patch it cannot be -1 any more. :-)

Thanks,
Rafael

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

* Re: [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix
  2017-11-03 11:42 ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
  2017-11-03 11:47   ` [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
  2017-11-03 11:50   ` [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
@ 2017-11-06 13:46   ` Geert Uytterhoeven
  2017-11-07  1:08     ` Rafael J. Wysocki
  2017-11-07  1:17     ` Rafael J. Wysocki
  3 siblings, 1 reply; 47+ messages in thread
From: Geert Uytterhoeven @ 2017-11-06 13:46 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Tero Kristo, Reinette Chatre,
	Ramesh Thomas, Alex Shi

Hi Rafael,

On Fri, Nov 3, 2017 at 12:42 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Thursday, November 2, 2017 12:00:27 AM CET Rafael J. Wysocki wrote:
>> This series is a replacement for commit 0cc2b4e5a020 (PM / QoS: Fix device
>> resume latency PM QoS) that had to be reverted due to problems introduced by it.
>>
>> This time the genpd PM QoS governor is first updated to be more consistent
>> and the PM QoS changes are made on top of that which simplifies the second
>> patch quite a bit.
>>
>> This is based on the linux-next branch from linux-pm.git as of now (should
>> also apply to the current mainline just fine).
>>
>> Please test if you can or let me know if you have any comments.
>
> The v2 removes a couple of redundant checks from the first patch (and add
> comments to explain why the checks are not needed) and fixes up the
> "no constraint" value collision with a valid constraint multiplied by
> NSEC_PER_USEC in the second patch.
>
> Please test if possible and let me know about any issues.

With this series, the 3 issues I reported before do not happen.

Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>

Thank you.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-06 12:49           ` Rafael J. Wysocki
@ 2017-11-06 14:38             ` Ulf Hansson
  2017-11-06 23:07               ` Rafael J. Wysocki
  0 siblings, 1 reply; 47+ messages in thread
From: Ulf Hansson @ 2017-11-06 14:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Rafael J. Wysocki, Linux PM, LKML, Geert Uytterhoeven,
	Tero Kristo, Reinette Chatre, Ramesh Thomas, Alex Shi

[...]

>>>
>>> So I guess I'll simply evaluate dev_pm_qos_read_value(dev) if
>>> subsys_data or subsys_data->domain_data is not there.
>>
>> Yes.
>>
>> However, if it returns -1, what value should you pick? 0?
>
> Without the second patch, -1 will just mean "no suspend", so the
> parent cannot be suspended too, but that should just work AFAICS
> (effective_constraint_ns may be -1 too at that point, if present).

I am fine with whatever policy you pick.

However, I suspect it may be more tricky respecting a -1 (no suspend),
because this means dev_update_qos_constraint() then may continue to
return a negative value, which you changed the caller,
default_suspend_ok(), to not cope with.

Anyway, let me look at the code one you posted a new version. :-)

[...]

Kind regards
Uffe

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

* Re: [RFT][Update][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-04 12:34     ` [RFT][Update][PATCH " Rafael J. Wysocki
@ 2017-11-06 17:47       ` Reinette Chatre
  2017-11-07  1:07         ` Rafael J. Wysocki
  0 siblings, 1 reply; 47+ messages in thread
From: Reinette Chatre @ 2017-11-06 17:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Ramesh Thomas, Alex Shi

Hi Rafael,

On 11/4/2017 5:34 AM, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The special value of 0 for device resume latency PM QoS means
> "no restriction", but there are two problems with that.
> 
> First, device resume latency PM QoS requests with 0 as the
> value are always put in front of requests with positive
> values in the priority lists used internally by the PM QoS
> framework, causing 0 to be chosen as an effective constraint
> value.  However, that 0 is then interpreted as "no restriction"
> effectively overriding the other requests with specific
> restrictions which is incorrect.
> 
> Second, the users of device resume latency PM QoS have no
> way to specify that *any* resume latency at all should be
> avoided, which is an artificial limitation in general.
> 
> To address these issues, modify device resume latency PM QoS to
> use S32_MAX as the "no constraint" value and 0 as the "no
> latency at all" one and rework its users (the cpuidle menu
> governor, the genpd QoS governor and the runtime PM framework)
> to follow these changes.
> 
> Also add a special "n/a" value to the corresponding user space I/F
> to allow user space to indicate that it cannot accept any resume
> latencies at all for the given device.
> 
> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>
> ---
> 
> Re-sending as an update rather than as v3, because the update is very minor
> (an additional check under the WARN_ON() in apply_constraint()).
> 
> Reinette, please test this one instead of the last version.  The WARN_ON()
> issue should be gone with this.
> 

I tested this update of the v2 2/2 patch with v2 of 1/2 but please note as captured below that I am testing with the menu governor, so not testing 1/2 if I understand correctly.

I just repeated the test I ran against the original patch that was merged, with some details added. I hope that it has some value to you considering that it did not catch all issues the first time :(

I tested on an Intel(R) NUC NUC6CAYS (Apollo Lake with a Goldmont cpu). As you maybe know it has some issues with monitor/mwait, so acpi_idle is used:
# grep . /sys/devices/system/cpu/cpuidle/current_*
/sys/devices/system/cpu/cpuidle/current_driver:acpi_idle
/sys/devices/system/cpu/cpuidle/current_governor_ro:menu

As with your original patch I still see the new behavior on boot:
       swapper/0-1     [000] ....     0.347284: dev_pm_qos_add_request: device=cpu0 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
       swapper/0-1     [000] ....     0.347300: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647
       swapper/0-1     [000] ....     0.347533: dev_pm_qos_add_request: device=cpu1 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
       swapper/0-1     [000] ....     0.347536: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647
       swapper/0-1     [000] ....     0.347741: dev_pm_qos_add_request: device=cpu2 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
       swapper/0-1     [000] ....     0.347743: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647
       swapper/0-1     [000] ....     0.347958: dev_pm_qos_add_request: device=cpu3 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
       swapper/0-1     [000] ....     0.347961: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647

Even though the default latency required values on boot are much higher, the user API still shows zero:
# grep . /sys/devices/system/cpu/cpu?/power/pm_qos_resume_latency_us
/sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu1/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu2/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu3/power/pm_qos_resume_latency_us:0

At this time when I run turbostat I observe that more than 99% of time is spent in C6 as reported by the actual hardware counters (the CPU%c6 value). I also see that the requested value is more than 99% for C3.

In my code the dev_pm_qos_add_request() API is used to request a new latency requirement of 30 usec (this previously failed) from core #2 and #3. I run my code with tracing enabled while also running turbostat. Tracing now shows me a successful request:

           runit-505   [003] ....   393.656679: dev_pm_qos_add_request: device=cpu2 type=DEV_PM_QOS_RESUME_LATENCY new_value=30
           runit-505   [003] ....   393.656700: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=30
           runit-505   [003] ....   393.656705: dev_pm_qos_add_request: device=cpu3 type=DEV_PM_QOS_RESUME_LATENCY new_value=30
           runit-505   [003] ....   393.656707: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=30

Turbostat also reflects this with cores 2 and 3 now reporting more than 99% in their CPU%c1 and C1% columns.

User API still shows:
# grep . /sys/devices/system/cpu/cpu?/power/pm_qos_resume_latency_us
/sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu1/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu2/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu3/power/pm_qos_resume_latency_us:0

Next I use dev_pm_qos_remove_request() to remove the previous latency requirement (again with tracing and turbostat running).

           rmdir-665   [002] ....   686.925230: dev_pm_qos_remove_request: device=cpu3 type=DEV_PM_QOS_RESUME_LATENCY new_value=-1
           rmdir-665   [002] ....   686.925250: pm_qos_update_target: action=REMOVE_REQ prev_value=30 curr_value=2147483647
           rmdir-665   [002] ....   686.925254: dev_pm_qos_remove_request: device=cpu2 type=DEV_PM_QOS_RESUME_LATENCY new_value=-1
           rmdir-665   [002] ....   686.925257: pm_qos_update_target: action=REMOVE_REQ prev_value=30 curr_value=2147483647

Turbostat also shows that cores 2 and 3 return to their high residency in C6.

As before, user API shows:
# grep . /sys/devices/system/cpu/cpu?/power/pm_qos_resume_latency_us
/sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu1/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu2/power/pm_qos_resume_latency_us:0
/sys/devices/system/cpu/cpu3/power/pm_qos_resume_latency_us:0


Thank you very much for making this work!

Tested-by: Reinette Chatre <reinette.chatre@intel.com>

Reinette

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

* Re: [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-06 14:38             ` Ulf Hansson
@ 2017-11-06 23:07               ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-06 23:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rafael J. Wysocki, Rafael J. Wysocki, Linux PM, LKML,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Ramesh Thomas,
	Alex Shi

On Mon, Nov 6, 2017 at 3:38 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> [...]
>
>>>>
>>>> So I guess I'll simply evaluate dev_pm_qos_read_value(dev) if
>>>> subsys_data or subsys_data->domain_data is not there.
>>>
>>> Yes.
>>>
>>> However, if it returns -1, what value should you pick? 0?
>>
>> Without the second patch, -1 will just mean "no suspend", so the
>> parent cannot be suspended too, but that should just work AFAICS
>> (effective_constraint_ns may be -1 too at that point, if present).
>
> I am fine with whatever policy you pick.
>
> However, I suspect it may be more tricky respecting a -1 (no suspend),
> because this means dev_update_qos_constraint() then may continue to
> return a negative value, which you changed the caller,
> default_suspend_ok(), to not cope with.

Oh, I just need to restore the constraint_ns < 0 check I dropped,
because it was never going to trigger.

Thanks,
Rafael

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

* Re: [RFT][Update][PATCH v2 2/2] PM / QoS: Fix device resume latency framework
  2017-11-06 17:47       ` Reinette Chatre
@ 2017-11-07  1:07         ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07  1:07 UTC (permalink / raw)
  To: Reinette Chatre
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Ramesh Thomas, Alex Shi

On Monday, November 6, 2017 6:47:35 PM CET Reinette Chatre wrote:
> Hi Rafael,
> 
> On 11/4/2017 5:34 AM, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > 
> > The special value of 0 for device resume latency PM QoS means
> > "no restriction", but there are two problems with that.
> > 
> > First, device resume latency PM QoS requests with 0 as the
> > value are always put in front of requests with positive
> > values in the priority lists used internally by the PM QoS
> > framework, causing 0 to be chosen as an effective constraint
> > value.  However, that 0 is then interpreted as "no restriction"
> > effectively overriding the other requests with specific
> > restrictions which is incorrect.
> > 
> > Second, the users of device resume latency PM QoS have no
> > way to specify that *any* resume latency at all should be
> > avoided, which is an artificial limitation in general.
> > 
> > To address these issues, modify device resume latency PM QoS to
> > use S32_MAX as the "no constraint" value and 0 as the "no
> > latency at all" one and rework its users (the cpuidle menu
> > governor, the genpd QoS governor and the runtime PM framework)
> > to follow these changes.
> > 
> > Also add a special "n/a" value to the corresponding user space I/F
> > to allow user space to indicate that it cannot accept any resume
> > latencies at all for the given device.
> > 
> > Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> > Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> > Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > Acked-by: Ramesh Thomas <ramesh.thomas@intel.com>
> > ---
> > 
> > Re-sending as an update rather than as v3, because the update is very minor
> > (an additional check under the WARN_ON() in apply_constraint()).
> > 
> > Reinette, please test this one instead of the last version.  The WARN_ON()
> > issue should be gone with this.
> > 
> 
> I tested this update of the v2 2/2 patch with v2 of 1/2 but please note as captured below that I am testing with the menu governor, so not testing 1/2 if I understand correctly.
> 
> I just repeated the test I ran against the original patch that was merged, with some details added. I hope that it has some value to you considering that it did not catch all issues the first time :(
> 
> I tested on an Intel(R) NUC NUC6CAYS (Apollo Lake with a Goldmont cpu). As you maybe know it has some issues with monitor/mwait, so acpi_idle is used:
> # grep . /sys/devices/system/cpu/cpuidle/current_*
> /sys/devices/system/cpu/cpuidle/current_driver:acpi_idle
> /sys/devices/system/cpu/cpuidle/current_governor_ro:menu
> 
> As with your original patch I still see the new behavior on boot:
>        swapper/0-1     [000] ....     0.347284: dev_pm_qos_add_request: device=cpu0 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
>        swapper/0-1     [000] ....     0.347300: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647
>        swapper/0-1     [000] ....     0.347533: dev_pm_qos_add_request: device=cpu1 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
>        swapper/0-1     [000] ....     0.347536: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647
>        swapper/0-1     [000] ....     0.347741: dev_pm_qos_add_request: device=cpu2 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
>        swapper/0-1     [000] ....     0.347743: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647
>        swapper/0-1     [000] ....     0.347958: dev_pm_qos_add_request: device=cpu3 type=DEV_PM_QOS_RESUME_LATENCY new_value=2147483647
>        swapper/0-1     [000] ....     0.347961: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=2147483647
> 
> Even though the default latency required values on boot are much higher, the user API still shows zero:
> # grep . /sys/devices/system/cpu/cpu?/power/pm_qos_resume_latency_us
> /sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu1/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu2/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu3/power/pm_qos_resume_latency_us:0
> 
> At this time when I run turbostat I observe that more than 99% of time is spent in C6 as reported by the actual hardware counters (the CPU%c6 value). I also see that the requested value is more than 99% for C3.
> 
> In my code the dev_pm_qos_add_request() API is used to request a new latency requirement of 30 usec (this previously failed) from core #2 and #3. I run my code with tracing enabled while also running turbostat. Tracing now shows me a successful request:
> 
>            runit-505   [003] ....   393.656679: dev_pm_qos_add_request: device=cpu2 type=DEV_PM_QOS_RESUME_LATENCY new_value=30
>            runit-505   [003] ....   393.656700: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=30
>            runit-505   [003] ....   393.656705: dev_pm_qos_add_request: device=cpu3 type=DEV_PM_QOS_RESUME_LATENCY new_value=30
>            runit-505   [003] ....   393.656707: pm_qos_update_target: action=ADD_REQ prev_value=2147483647 curr_value=30
> 
> Turbostat also reflects this with cores 2 and 3 now reporting more than 99% in their CPU%c1 and C1% columns.
> 
> User API still shows:
> # grep . /sys/devices/system/cpu/cpu?/power/pm_qos_resume_latency_us
> /sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu1/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu2/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu3/power/pm_qos_resume_latency_us:0
> 
> Next I use dev_pm_qos_remove_request() to remove the previous latency requirement (again with tracing and turbostat running).
> 
>            rmdir-665   [002] ....   686.925230: dev_pm_qos_remove_request: device=cpu3 type=DEV_PM_QOS_RESUME_LATENCY new_value=-1
>            rmdir-665   [002] ....   686.925250: pm_qos_update_target: action=REMOVE_REQ prev_value=30 curr_value=2147483647
>            rmdir-665   [002] ....   686.925254: dev_pm_qos_remove_request: device=cpu2 type=DEV_PM_QOS_RESUME_LATENCY new_value=-1
>            rmdir-665   [002] ....   686.925257: pm_qos_update_target: action=REMOVE_REQ prev_value=30 curr_value=2147483647
> 
> Turbostat also shows that cores 2 and 3 return to their high residency in C6.
> 
> As before, user API shows:
> # grep . /sys/devices/system/cpu/cpu?/power/pm_qos_resume_latency_us
> /sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu1/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu2/power/pm_qos_resume_latency_us:0
> /sys/devices/system/cpu/cpu3/power/pm_qos_resume_latency_us:0
> 
> 
> Thank you very much for making this work!
> 
> Tested-by: Reinette Chatre <reinette.chatre@intel.com>

Thanks!

Rafael

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

* Re: [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix
  2017-11-06 13:46   ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Geert Uytterhoeven
@ 2017-11-07  1:08     ` Rafael J. Wysocki
  2017-11-08  9:09       ` Tero Kristo
  0 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07  1:08 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Linux PM, LKML, Ulf Hansson, Tero Kristo, Reinette Chatre,
	Ramesh Thomas, Alex Shi

On Monday, November 6, 2017 2:46:48 PM CET Geert Uytterhoeven wrote:
> Hi Rafael,
> 
> On Fri, Nov 3, 2017 at 12:42 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> > On Thursday, November 2, 2017 12:00:27 AM CET Rafael J. Wysocki wrote:
> >> This series is a replacement for commit 0cc2b4e5a020 (PM / QoS: Fix device
> >> resume latency PM QoS) that had to be reverted due to problems introduced by it.
> >>
> >> This time the genpd PM QoS governor is first updated to be more consistent
> >> and the PM QoS changes are made on top of that which simplifies the second
> >> patch quite a bit.
> >>
> >> This is based on the linux-next branch from linux-pm.git as of now (should
> >> also apply to the current mainline just fine).
> >>
> >> Please test if you can or let me know if you have any comments.
> >
> > The v2 removes a couple of redundant checks from the first patch (and add
> > comments to explain why the checks are not needed) and fixes up the
> > "no constraint" value collision with a valid constraint multiplied by
> > NSEC_PER_USEC in the second patch.
> >
> > Please test if possible and let me know about any issues.
> 
> With this series, the 3 issues I reported before do not happen.
> 
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> 
> Thank you.

Thanks!

Rafael

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

* [PATCH v3 0/2] PM / QoS: Device resume latency framework fix
  2017-11-03 11:42 ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
@ 2017-11-07  1:17     ` Rafael J. Wysocki
  2017-11-03 11:50   ` [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07  1:17 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Ramesh Thomas,
	Alex Shi

On Friday, November 3, 2017 12:42:57 PM CET Rafael J. Wysocki wrote:
> On Thursday, November 2, 2017 12:00:27 AM CET Rafael J. Wysocki wrote:
> > Hi,
> > 
> > This series is a replacement for commit 0cc2b4e5a020 (PM / QoS: Fix device
> > resume latency PM QoS) that had to be reverted due to problems introduced by it.
> > 
> > This time the genpd PM QoS governor is first updated to be more consistent
> > and the PM QoS changes are made on top of that which simplifies the second
> > patch quite a bit.
> > 
> > This is based on the linux-next branch from linux-pm.git as of now (should
> > also apply to the current mainline just fine).
> > 
> > Please test if you can or let me know if you have any comments.
> 
> The v2 removes a couple of redundant checks from the first patch (and add
> comments to explain why the checks are not needed) and fixes up the
> "no constraint" value collision with a valid constraint multiplied by
> NSEC_PER_USEC in the second patch.
> 
> Please test if possible and let me know about any issues.

The v3 restores the handling of child devices that don't belong to any
domains handled by genpd as pointed out by Ulf, but it should not affect
test results reported so far, so the tags from Reinette and Geert are
there.

Thanks,
Rafael

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

* [PATCH v3 0/2] PM / QoS: Device resume latency framework fix
@ 2017-11-07  1:17     ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07  1:17 UTC (permalink / raw)
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Ramesh Thomas,
	Alex Shi

On Friday, November 3, 2017 12:42:57 PM CET Rafael J. Wysocki wrote:
> On Thursday, November 2, 2017 12:00:27 AM CET Rafael J. Wysocki wrote:
> > Hi,
> > 
> > This series is a replacement for commit 0cc2b4e5a020 (PM / QoS: Fix device
> > resume latency PM QoS) that had to be reverted due to problems introduced by it.
> > 
> > This time the genpd PM QoS governor is first updated to be more consistent
> > and the PM QoS changes are made on top of that which simplifies the second
> > patch quite a bit.
> > 
> > This is based on the linux-next branch from linux-pm.git as of now (should
> > also apply to the current mainline just fine).
> > 
> > Please test if you can or let me know if you have any comments.
> 
> The v2 removes a couple of redundant checks from the first patch (and add
> comments to explain why the checks are not needed) and fixes up the
> "no constraint" value collision with a valid constraint multiplied by
> NSEC_PER_USEC in the second patch.
> 
> Please test if possible and let me know about any issues.

The v3 restores the handling of child devices that don't belong to any
domains handled by genpd as pointed out by Ulf, but it should not affect
test results reported so far, so the tags from Reinette and Geert are
there.

Thanks,
Rafael

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

* [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-07  1:17     ` Rafael J. Wysocki
  (?)
@ 2017-11-07  1:23     ` Rafael J. Wysocki
  2017-11-07  5:05       ` Ramesh Thomas
  2017-11-10  7:49       ` Ulf Hansson
  -1 siblings, 2 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07  1:23 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The genpd governor currently uses negative PM QoS values to indicate
the "no suspend" condition and 0 as "no restriction", but it doesn't
use them consistently.  Moreover, it tries to refresh QoS values for
already suspended devices in a quite questionable way.

For the above reasons, rework it to be a bit more consistent.

First off, note that dev_pm_qos_read_value() in
dev_update_qos_constraint() and __default_power_down_ok() is
evaluated for devices in suspend.  Moreover, that only happens if the
effective_constraint_ns value for them is negative (meaning "no
suspend").  It is not evaluated in any other cases, so effectively
the QoS values are only updated for devices in suspend that should
not have been suspended in the first place.  In all of the other
cases, the QoS values taken into account are the effective ones from
the time before the device has been suspended, so generally devices
need to be resumed and suspended again for new QoS values to take
effect anyway.  Thus evaluating dev_update_qos_constraint() in
those two places doesn't make sense at all, so drop it.

Second, initialize effective_constraint_ns to 0 ("no constraint")
rather than to (-1) ("no suspend"), which makes more sense in
general and in case effective_constraint_ns is never updated
(the device is in suspend all the time or it is never suspended)
it doesn't affect the device's parent and so on.

Finally, rework default_suspend_ok() to explicitly handle the
"no restriction" and "no suspend" special cases.

Also add WARN_ON() around checks that should never trigger.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
---

v2 -> v3: Take children that don't belong to genpd power domains into
          account in dev_update_qos_constraint().

---
 drivers/base/power/domain.c          |    2 
 drivers/base/power/domain_governor.c |   71 ++++++++++++++++++++++++-----------
 2 files changed, 50 insertions(+), 23 deletions(-)

Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = -1;
+	gpd_data->td.effective_constraint_ns = 0;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -14,22 +14,33 @@
 static int dev_update_qos_constraint(struct device *dev, void *data)
 {
 	s64 *constraint_ns_p = data;
-	s32 constraint_ns = -1;
+	s64 constraint_ns;
 
-	if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
+	if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
+		/*
+		 * Only take suspend-time QoS constraints of devices into
+		 * account, because constraints updated after the device has
+		 * been suspended are not guaranteed to be taken into account
+		 * 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;
-
-	if (constraint_ns < 0) {
+	} else {
+		/*
+		 * The child is not in a domain and there's no info on its
+		 * suspend/resume latencies, so assume them to be negligible and
+		 * take its current PM QoS constraint (that's the only thing
+		 * known at this point anyway).
+		 */
 		constraint_ns = dev_pm_qos_read_value(dev);
-		constraint_ns *= NSEC_PER_USEC;
+		if (constraint_ns > 0)
+			constraint_ns *= NSEC_PER_USEC;
 	}
+
+	/* 0 means "no constraint" */
 	if (constraint_ns == 0)
 		return 0;
 
-	/*
-	 * constraint_ns cannot be negative here, because the device has been
-	 * suspended.
-	 */
 	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
 		*constraint_ns_p = constraint_ns;
 
@@ -76,14 +87,32 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns > 0) {
+	if (constraint_ns == 0) {
+		/* "No restriction", so the device is allowed to suspend. */
+		td->effective_constraint_ns = 0;
+		td->cached_suspend_ok = true;
+	} else if (constraint_ns < 0) {
+		/*
+		 * This triggers if one of the children that don't belong to a
+		 * domain has a negative PM QoS constraint and it's better not
+		 * to suspend then.  effective_constraint_ns is negative already
+		 * and cached_suspend_ok is false, so bail out.
+		 */
+		return false;
+	} else {
 		constraint_ns -= td->suspend_latency_ns +
 				td->resume_latency_ns;
-		if (constraint_ns == 0)
+		/*
+		 * effective_constraint_ns is negative already and
+		 * cached_suspend_ok is false, so if the computed value is not
+		 * positive, return right away.
+		 */
+		if (constraint_ns <= 0)
 			return false;
+
+		td->effective_constraint_ns = constraint_ns;
+		td->cached_suspend_ok = true;
 	}
-	td->effective_constraint_ns = constraint_ns;
-	td->cached_suspend_ok = constraint_ns >= 0;
 
 	/*
 	 * The children have been suspended already, so we don't need to take
@@ -144,18 +173,16 @@ static bool __default_power_down_ok(stru
 		 */
 		td = &to_gpd_data(pdd)->td;
 		constraint_ns = td->effective_constraint_ns;
-		/* default_suspend_ok() need not be called before us. */
-		if (constraint_ns < 0) {
-			constraint_ns = dev_pm_qos_read_value(pdd->dev);
-			constraint_ns *= NSEC_PER_USEC;
-		}
+		/*
+		 * Negative values mean "no suspend at all" and this runs only
+		 * when all devices in the domain are suspended, so it must be
+		 * 0 at least.
+		 *
+		 * 0 means "no constraint"
+		 */
 		if (constraint_ns == 0)
 			continue;
 
-		/*
-		 * constraint_ns cannot be negative here, because the device has
-		 * been suspended.
-		 */
 		if (constraint_ns <= off_on_time_ns)
 			return false;
 

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

* [PATCH v3 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07  1:17     ` Rafael J. Wysocki
  (?)
  (?)
@ 2017-11-07  1:27     ` Rafael J. Wysocki
  2017-11-07  4:33       ` Ramesh Thomas
  2017-11-07 10:33       ` [PATCH v4 " Rafael J. Wysocki
  -1 siblings, 2 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07  1:27 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The special value of 0 for device resume latency PM QoS means
"no restriction", but there are two problems with that.

First, device resume latency PM QoS requests with 0 as the
value are always put in front of requests with positive
values in the priority lists used internally by the PM QoS
framework, causing 0 to be chosen as an effective constraint
value.  However, that 0 is then interpreted as "no restriction"
effectively overriding the other requests with specific
restrictions which is incorrect.

Second, the users of device resume latency PM QoS have no
way to specify that *any* resume latency at all should be
avoided, which is an artificial limitation in general.

To address these issues, modify device resume latency PM QoS to
use S32_MAX as the "no constraint" value and 0 as the "no
latency at all" one and rework its users (the cpuidle menu
governor, the genpd QoS governor and the runtime PM framework)
to follow these changes.

Also add a special "n/a" value to the corresponding user space I/F
to allow user space to indicate that it cannot accept any resume
latencies at all for the given device.

Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Reinette Chatre <reinette.chatre@intel.com>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 Documentation/ABI/testing/sysfs-devices-power |    4 ++-
 drivers/base/cpu.c                            |    3 +-
 drivers/base/power/domain.c                   |    2 -
 drivers/base/power/domain_governor.c          |   33 ++++++++++----------------
 drivers/base/power/qos.c                      |    5 +++
 drivers/base/power/runtime.c                  |    2 -
 drivers/base/power/sysfs.c                    |   25 ++++++++++++++++---
 drivers/cpuidle/governors/menu.c              |    4 +--
 include/linux/pm_qos.h                        |   26 ++++++++++++++------
 9 files changed, 65 insertions(+), 39 deletions(-)

Index: linux-pm/drivers/base/power/sysfs.c
===================================================================
--- linux-pm.orig/drivers/base/power/sysfs.c
+++ linux-pm/drivers/base/power/sysfs.c
@@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
 					  struct device_attribute *attr,
 					  char *buf)
 {
-	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
+	s32 value = dev_pm_qos_requested_resume_latency(dev);
+
+	if (value == 0)
+		return sprintf(buf, "n/a\n");
+	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+		value = 0;
+
+	return sprintf(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_resume_latency_store(struct device *dev,
@@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
 	s32 value;
 	int ret;
 
-	if (kstrtos32(buf, 0, &value))
-		return -EINVAL;
+	if (!kstrtos32(buf, 0, &value)) {
+		/*
+		 * Prevent users from writing negative or "no constraint" values
+		 * directly.
+		 */
+		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+			return -EINVAL;
 
-	if (value < 0)
+		if (value == 0)
+			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
+		value = 0;
+	} else {
 		return -EINVAL;
+	}
 
 	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
 					value);
Index: linux-pm/include/linux/pm_qos.h
===================================================================
--- linux-pm.orig/include/linux/pm_qos.h
+++ linux-pm/include/linux/pm_qos.h
@@ -28,16 +28,19 @@ enum pm_qos_flags_status {
 	PM_QOS_FLAGS_ALL,
 };
 
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_DEFAULT_VALUE	(-1)
+#define PM_QOS_LATENCY_ANY	S32_MAX
+#define PM_QOS_LATENCY_ANY_NS	((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
 
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
-#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS	PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
-#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
 
@@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
 static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
 {
 	return IS_ERR_OR_NULL(dev->power.qos) ?
-		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
+		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
+		pm_qos_read_value(&dev->power.qos->resume_latency);
 }
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
 							s32 mask)
 			{ return PM_QOS_FLAGS_UNDEFINED; }
 static inline s32 __dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline s32 dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline int dev_pm_qos_add_request(struct device *dev,
 					 struct dev_pm_qos_request *req,
 					 enum dev_pm_qos_req_type type,
@@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
 			{ return 0; }
 static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
 
-static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 #endif
 
 #endif
Index: linux-pm/drivers/cpuidle/governors/menu.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/menu.c
+++ linux-pm/drivers/cpuidle/governors/menu.c
@@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
 		data->needs_update = 0;
 	}
 
-	/* resume_latency is 0 means no restriction */
-	if (resume_latency && resume_latency < latency_req)
+	if (resume_latency < latency_req &&
+	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		latency_req = resume_latency;
 
 	/* Special case when user has set very strict latency requirement */
Index: linux-pm/drivers/base/power/runtime.c
===================================================================
--- linux-pm.orig/drivers/base/power/runtime.c
+++ linux-pm/drivers/base/power/runtime.c
@@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
-	else if (__dev_pm_qos_read_value(dev) < 0)
+	else if (__dev_pm_qos_read_value(dev) == 0)
 		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
Index: linux-pm/drivers/base/cpu.c
===================================================================
--- linux-pm.orig/drivers/base/cpu.c
+++ linux-pm/drivers/base/cpu.c
@@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
 
 	per_cpu(cpu_sys_devices, num) = &cpu->dev;
 	register_cpu_under_node(num, cpu_to_node(num));
-	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
+	dev_pm_qos_expose_latency_limit(&cpu->dev,
+					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
 
 	return 0;
 }
Index: linux-pm/drivers/base/power/qos.c
===================================================================
--- linux-pm.orig/drivers/base/power/qos.c
+++ linux-pm/drivers/base/power/qos.c
@@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
 
 	switch(req->type) {
 	case DEV_PM_QOS_RESUME_LATENCY:
+		if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
+			value = 0;
+
 		ret = pm_qos_update_target(&qos->resume_latency,
 					   &req->data.pnode, action, value);
 		break;
@@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
 	plist_head_init(&c->list);
 	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
 	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
-	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 	c->type = PM_QOS_MIN;
 	c->notifiers = n;
 
Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
===================================================================
--- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
+++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
@@ -211,7 +211,9 @@ Description:
 		device, after it has been suspended at run time, from a resume
 		request to the moment the device will be ready to process I/O,
 		in microseconds.  If it is equal to 0, however, this means that
-		the PM QoS resume latency may be arbitrary.
+		the PM QoS resume latency may be arbitrary and the special value
+		"n/a" means that user space cannot accept any resume latency at
+		all for the given device.
 
 		Not all drivers support this attribute.  If it isn't supported,
 		it is not present.
Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = 0;
+	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -33,15 +33,10 @@ static int dev_update_qos_constraint(str
 		 * known at this point anyway).
 		 */
 		constraint_ns = dev_pm_qos_read_value(dev);
-		if (constraint_ns > 0)
-			constraint_ns *= NSEC_PER_USEC;
+		constraint_ns *= NSEC_PER_USEC;
 	}
 
-	/* 0 means "no constraint" */
-	if (constraint_ns == 0)
-		return 0;
-
-	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+	if (constraint_ns < *constraint_ns_p)
 		*constraint_ns_p = constraint_ns;
 
 	return 0;
@@ -69,12 +64,12 @@ static bool default_suspend_ok(struct de
 	}
 	td->constraint_changed = false;
 	td->cached_suspend_ok = false;
-	td->effective_constraint_ns = -1;
+	td->effective_constraint_ns = 0;
 	constraint_ns = __dev_pm_qos_read_value(dev);
 
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
-	if (constraint_ns < 0)
+	if (constraint_ns == 0)
 		return false;
 
 	constraint_ns *= NSEC_PER_USEC;
@@ -87,25 +82,25 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns == 0) {
+	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
 		/* "No restriction", so the device is allowed to suspend. */
 		td->effective_constraint_ns = 0;
 		td->cached_suspend_ok = true;
-	} else if (constraint_ns < 0) {
+	} else if (constraint_ns == 0) {
 		/*
 		 * This triggers if one of the children that don't belong to a
-		 * domain has a negative PM QoS constraint and it's better not
-		 * to suspend then.  effective_constraint_ns is negative already
-		 * and cached_suspend_ok is false, so bail out.
+		 * domain has a zero PM QoS constraint and it's better not to
+		 * suspend then.  effective_constraint_ns is zero already and
+		 * cached_suspend_ok is false, so bail out.
 		 */
 		return false;
 	} else {
 		constraint_ns -= td->suspend_latency_ns +
 				td->resume_latency_ns;
 		/*
-		 * effective_constraint_ns is negative already and
-		 * cached_suspend_ok is false, so if the computed value is not
-		 * positive, return right away.
+		 * effective_constraint_ns is zero already and cached_suspend_ok
+		 * is false, so if the computed value is not positive, return
+		 * right away.
 		 */
 		if (constraint_ns <= 0)
 			return false;
@@ -177,10 +172,8 @@ static bool __default_power_down_ok(stru
 		 * Negative values mean "no suspend at all" and this runs only
 		 * when all devices in the domain are suspended, so it must be
 		 * 0 at least.
-		 *
-		 * 0 means "no constraint"
 		 */
-		if (constraint_ns == 0)
+		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
 			continue;
 
 		if (constraint_ns <= off_on_time_ns)

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

* Re: [PATCH v3 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07  1:27     ` [PATCH v3 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
@ 2017-11-07  4:33       ` Ramesh Thomas
  2017-11-07 10:12         ` Rafael J. Wysocki
  2017-11-07 10:33       ` [PATCH v4 " Rafael J. Wysocki
  1 sibling, 1 reply; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-07  4:33 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On 2017-11-07 at 02:27:05 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The special value of 0 for device resume latency PM QoS means
> "no restriction", but there are two problems with that.
> 
> First, device resume latency PM QoS requests with 0 as the
> value are always put in front of requests with positive
> values in the priority lists used internally by the PM QoS
> framework, causing 0 to be chosen as an effective constraint
> value.  However, that 0 is then interpreted as "no restriction"
> effectively overriding the other requests with specific
> restrictions which is incorrect.
> 
> Second, the users of device resume latency PM QoS have no
> way to specify that *any* resume latency at all should be
> avoided, which is an artificial limitation in general.
> 
> To address these issues, modify device resume latency PM QoS to
> use S32_MAX as the "no constraint" value and 0 as the "no
> latency at all" one and rework its users (the cpuidle menu
> governor, the genpd QoS governor and the runtime PM framework)
> to follow these changes.
> 
> Also add a special "n/a" value to the corresponding user space I/F
> to allow user space to indicate that it cannot accept any resume
> latencies at all for the given device.
> 
> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Tested-by: Reinette Chatre <reinette.chatre@intel.com>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>  Documentation/ABI/testing/sysfs-devices-power |    4 ++-
>  drivers/base/cpu.c                            |    3 +-
>  drivers/base/power/domain.c                   |    2 -
>  drivers/base/power/domain_governor.c          |   33 ++++++++++----------------
>  drivers/base/power/qos.c                      |    5 +++
>  drivers/base/power/runtime.c                  |    2 -
>  drivers/base/power/sysfs.c                    |   25 ++++++++++++++++---
>  drivers/cpuidle/governors/menu.c              |    4 +--
>  include/linux/pm_qos.h                        |   26 ++++++++++++++------
>  9 files changed, 65 insertions(+), 39 deletions(-)
> 
> Index: linux-pm/drivers/base/power/sysfs.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/sysfs.c
> +++ linux-pm/drivers/base/power/sysfs.c
> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>  					  struct device_attribute *attr,
>  					  char *buf)
>  {
> -	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
> +	s32 value = dev_pm_qos_requested_resume_latency(dev);
> +
> +	if (value == 0)
> +		return sprintf(buf, "n/a\n");
> +	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +		value = 0;
> +
> +	return sprintf(buf, "%d\n", value);
>  }
>  
>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>  	s32 value;
>  	int ret;
>  
> -	if (kstrtos32(buf, 0, &value))
> -		return -EINVAL;
> +	if (!kstrtos32(buf, 0, &value)) {
> +		/*
> +		 * Prevent users from writing negative or "no constraint" values
> +		 * directly.
> +		 */
> +		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +			return -EINVAL;
>  
> -	if (value < 0)
> +		if (value == 0)
> +			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
> +		value = 0;
> +	} else {
>  		return -EINVAL;
> +	}
>  
>  	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>  					value);
> Index: linux-pm/include/linux/pm_qos.h
> ===================================================================
> --- linux-pm.orig/include/linux/pm_qos.h
> +++ linux-pm/include/linux/pm_qos.h
> @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>  	PM_QOS_FLAGS_ALL,
>  };
>  
> -#define PM_QOS_DEFAULT_VALUE -1
> +#define PM_QOS_DEFAULT_VALUE	(-1)
> +#define PM_QOS_LATENCY_ANY	S32_MAX
> +#define PM_QOS_LATENCY_ANY_NS	((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
>  
>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS	PM_QOS_LATENCY_ANY_NS
>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
> -#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
>  
>  #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
>  
> @@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>  {
>  	return IS_ERR_OR_NULL(dev->power.qos) ?
> -		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
> +		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
> +		pm_qos_read_value(&dev->power.qos->resume_latency);
>  }
>  #else
>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
> @@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
>  							s32 mask)
>  			{ return PM_QOS_FLAGS_UNDEFINED; }
>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline s32 dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline int dev_pm_qos_add_request(struct device *dev,
>  					 struct dev_pm_qos_request *req,
>  					 enum dev_pm_qos_req_type type,
> @@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
>  			{ return 0; }
>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>  
> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  #endif
>  
>  #endif
> Index: linux-pm/drivers/cpuidle/governors/menu.c
> ===================================================================
> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
> +++ linux-pm/drivers/cpuidle/governors/menu.c
> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>  		data->needs_update = 0;
>  	}
>  
> -	/* resume_latency is 0 means no restriction */
> -	if (resume_latency && resume_latency < latency_req)
> +	if (resume_latency < latency_req &&
> +	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>  		latency_req = resume_latency;
>  
>  	/* Special case when user has set very strict latency requirement */
> Index: linux-pm/drivers/base/power/runtime.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/runtime.c
> +++ linux-pm/drivers/base/power/runtime.c
> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>  	    || (dev->power.request_pending
>  			&& dev->power.request == RPM_REQ_RESUME))
>  		retval = -EAGAIN;
> -	else if (__dev_pm_qos_read_value(dev) < 0)
> +	else if (__dev_pm_qos_read_value(dev) == 0)
>  		retval = -EPERM;
>  	else if (dev->power.runtime_status == RPM_SUSPENDED)
>  		retval = 1;
> Index: linux-pm/drivers/base/cpu.c
> ===================================================================
> --- linux-pm.orig/drivers/base/cpu.c
> +++ linux-pm/drivers/base/cpu.c
> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>  
>  	per_cpu(cpu_sys_devices, num) = &cpu->dev;
>  	register_cpu_under_node(num, cpu_to_node(num));
> -	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
> +	dev_pm_qos_expose_latency_limit(&cpu->dev,
> +					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>  
>  	return 0;
>  }
> Index: linux-pm/drivers/base/power/qos.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/qos.c
> +++ linux-pm/drivers/base/power/qos.c
> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>  
>  	switch(req->type) {
>  	case DEV_PM_QOS_RESUME_LATENCY:
> +		if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
> +			value = 0;
> +
>  		ret = pm_qos_update_target(&qos->resume_latency,
>  					   &req->data.pnode, action, value);
>  		break;
> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>  	plist_head_init(&c->list);
>  	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>  	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> -	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> +	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>  	c->type = PM_QOS_MIN;
>  	c->notifiers = n;
>  
> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
> ===================================================================
> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
> @@ -211,7 +211,9 @@ Description:
>  		device, after it has been suspended at run time, from a resume
>  		request to the moment the device will be ready to process I/O,
>  		in microseconds.  If it is equal to 0, however, this means that
> -		the PM QoS resume latency may be arbitrary.
> +		the PM QoS resume latency may be arbitrary and the special value
> +		"n/a" means that user space cannot accept any resume latency at
> +		all for the given device.
>  
>  		Not all drivers support this attribute.  If it isn't supported,
>  		it is not present.
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>  
>  	gpd_data->base.dev = dev;
>  	gpd_data->td.constraint_changed = true;
> -	gpd_data->td.effective_constraint_ns = 0;
> +	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>  	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>  
>  	spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -33,15 +33,10 @@ static int dev_update_qos_constraint(str
>  		 * known at this point anyway).
>  		 */
>  		constraint_ns = dev_pm_qos_read_value(dev);
> -		if (constraint_ns > 0)
> -			constraint_ns *= NSEC_PER_USEC;
> +		constraint_ns *= NSEC_PER_USEC;
>  	}
>  
> -	/* 0 means "no constraint" */
> -	if (constraint_ns == 0)
> -		return 0;
> -
> -	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
> +	if (constraint_ns < *constraint_ns_p)
>  		*constraint_ns_p = constraint_ns;
>  
>  	return 0;
> @@ -69,12 +64,12 @@ static bool default_suspend_ok(struct de
>  	}
>  	td->constraint_changed = false;
>  	td->cached_suspend_ok = false;
> -	td->effective_constraint_ns = -1;
> +	td->effective_constraint_ns = 0;
>  	constraint_ns = __dev_pm_qos_read_value(dev);
>  
>  	spin_unlock_irqrestore(&dev->power.lock, flags);
>  
> -	if (constraint_ns < 0)
> +	if (constraint_ns == 0)
>  		return false;
>  
>  	constraint_ns *= NSEC_PER_USEC;
> @@ -87,25 +82,25 @@ static bool default_suspend_ok(struct de
>  		device_for_each_child(dev, &constraint_ns,
>  				      dev_update_qos_constraint);
>  
> -	if (constraint_ns == 0) {
> +	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
>  		/* "No restriction", so the device is allowed to suspend. */
>  		td->effective_constraint_ns = 0;

I think you forgot to change this. Assigning 0 would cause its parent to
fail suspend thinking this child has "no suspend at all" restriction. Should
assign PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS. 

Should a macro be created for "no suspend at all" so it will be more clear?

>  		td->cached_suspend_ok = true;
> -	} else if (constraint_ns < 0) {
> +	} else if (constraint_ns == 0) {
>  		/*
>  		 * This triggers if one of the children that don't belong to a
> -		 * domain has a negative PM QoS constraint and it's better not
> -		 * to suspend then.  effective_constraint_ns is negative already
> -		 * and cached_suspend_ok is false, so bail out.
> +		 * domain has a zero PM QoS constraint and it's better not to
> +		 * suspend then.  effective_constraint_ns is zero already and
> +		 * cached_suspend_ok is false, so bail out.
>  		 */
>  		return false;
>  	} else {
>  		constraint_ns -= td->suspend_latency_ns +
>  				td->resume_latency_ns;
>  		/*
> -		 * effective_constraint_ns is negative already and
> -		 * cached_suspend_ok is false, so if the computed value is not
> -		 * positive, return right away.
> +		 * effective_constraint_ns is zero already and cached_suspend_ok
> +		 * is false, so if the computed value is not positive, return
> +		 * right away.
>  		 */
>  		if (constraint_ns <= 0)
>  			return false;
> @@ -177,10 +172,8 @@ static bool __default_power_down_ok(stru
>  		 * Negative values mean "no suspend at all" and this runs only
>  		 * when all devices in the domain are suspended, so it must be
>  		 * 0 at least.

I think this message is carried from the previous patch and may need to be
revised.

In this change, negative value does not mean "no suspend at all". It also
cannot be 0 or else it would not have suspended. It will alway be > 0 if it
reaches here.

> -		 *
> -		 * 0 means "no constraint"
>  		 */
> -		if (constraint_ns == 0)
> +		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
>  			continue;
>  
>  		if (constraint_ns <= off_on_time_ns)
> 

Regards,
Ramesh

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

* Re: [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-07  1:23     ` [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
@ 2017-11-07  5:05       ` Ramesh Thomas
  2017-11-07 10:22         ` Rafael J. Wysocki
  2017-11-10  7:49       ` Ulf Hansson
  1 sibling, 1 reply; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-07  5:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On 2017-11-07 at 02:23:18 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The genpd governor currently uses negative PM QoS values to indicate
> the "no suspend" condition and 0 as "no restriction", but it doesn't
> use them consistently.  Moreover, it tries to refresh QoS values for
> already suspended devices in a quite questionable way.
> 
> For the above reasons, rework it to be a bit more consistent.
> 
> First off, note that dev_pm_qos_read_value() in
> dev_update_qos_constraint() and __default_power_down_ok() is
> evaluated for devices in suspend.  Moreover, that only happens if the
> effective_constraint_ns value for them is negative (meaning "no
> suspend").  It is not evaluated in any other cases, so effectively
> the QoS values are only updated for devices in suspend that should
> not have been suspended in the first place.  In all of the other
> cases, the QoS values taken into account are the effective ones from
> the time before the device has been suspended, so generally devices
> need to be resumed and suspended again for new QoS values to take
> effect anyway.  Thus evaluating dev_update_qos_constraint() in
> those two places doesn't make sense at all, so drop it.
> 
> Second, initialize effective_constraint_ns to 0 ("no constraint")
> rather than to (-1) ("no suspend"), which makes more sense in
> general and in case effective_constraint_ns is never updated
> (the device is in suspend all the time or it is never suspended)
> it doesn't affect the device's parent and so on.
> 
> Finally, rework default_suspend_ok() to explicitly handle the
> "no restriction" and "no suspend" special cases.
> 
> Also add WARN_ON() around checks that should never trigger.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> 
> v2 -> v3: Take children that don't belong to genpd power domains into
>           account in dev_update_qos_constraint().
> 
> ---
>  drivers/base/power/domain.c          |    2 
>  drivers/base/power/domain_governor.c |   71 ++++++++++++++++++++++++-----------
>  2 files changed, 50 insertions(+), 23 deletions(-)
> 
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>  
>  	gpd_data->base.dev = dev;
>  	gpd_data->td.constraint_changed = true;
> -	gpd_data->td.effective_constraint_ns = -1;
> +	gpd_data->td.effective_constraint_ns = 0;
>  	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>  
>  	spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -14,22 +14,33 @@
>  static int dev_update_qos_constraint(struct device *dev, void *data)
>  {
>  	s64 *constraint_ns_p = data;
> -	s32 constraint_ns = -1;
> +	s64 constraint_ns;
>  
> -	if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
> +	if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
> +		/*
> +		 * Only take suspend-time QoS constraints of devices into
> +		 * account, because constraints updated after the device has
> +		 * been suspended are not guaranteed to be taken into account
> +		 * 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;
> -
> -	if (constraint_ns < 0) {
> +	} else {
> +		/*
> +		 * The child is not in a domain and there's no info on its
> +		 * suspend/resume latencies, so assume them to be negligible and
> +		 * take its current PM QoS constraint (that's the only thing
> +		 * known at this point anyway).
> +		 */
>  		constraint_ns = dev_pm_qos_read_value(dev);
> -		constraint_ns *= NSEC_PER_USEC;
> +		if (constraint_ns > 0)
> +			constraint_ns *= NSEC_PER_USEC;
>  	}
> +
> +	/* 0 means "no constraint" */
>  	if (constraint_ns == 0)
>  		return 0;
>  
> -	/*
> -	 * constraint_ns cannot be negative here, because the device has been
> -	 * suspended.
> -	 */
>  	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>  		*constraint_ns_p = constraint_ns;
>  
> @@ -76,14 +87,32 @@ static bool default_suspend_ok(struct de
>  		device_for_each_child(dev, &constraint_ns,
>  				      dev_update_qos_constraint);
>  
> -	if (constraint_ns > 0) {
> +	if (constraint_ns == 0) {
> +		/* "No restriction", so the device is allowed to suspend. */
> +		td->effective_constraint_ns = 0;
> +		td->cached_suspend_ok = true;
> +	} else if (constraint_ns < 0) {
> +		/*
> +		 * This triggers if one of the children that don't belong to a
> +		 * domain has a negative PM QoS constraint and it's better not
> +		 * to suspend then.  effective_constraint_ns is negative already
> +		 * and cached_suspend_ok is false, so bail out.
> +		 */
> +		return false;

This change is ok. However, would like to bring to your attention a possible
inconsistency in the treatment of negative value as "no suspend at all" that
can affect this.

user level entry does not allow negative values. Only way to enter a negative
value is if the kernel API to add/update is used. In that interface, if -1
(PM_QOS_DEFAULT_VALUE) is passed, pm_qos_update_target will actually assign
the default value stored in the constraint. The default value is 
PM_QOS_RESUME_LATENCY_DEFAULT_VALUE which is 0. 0 means "no constraint".

All this gets fixed in the next patch though. 

> +	} else {
>  		constraint_ns -= td->suspend_latency_ns +
>  				td->resume_latency_ns;
> -		if (constraint_ns == 0)
> +		/*
> +		 * effective_constraint_ns is negative already and
> +		 * cached_suspend_ok is false, so if the computed value is not
> +		 * positive, return right away.
> +		 */
> +		if (constraint_ns <= 0)
>  			return false;
> +
> +		td->effective_constraint_ns = constraint_ns;
> +		td->cached_suspend_ok = true;
>  	}
> -	td->effective_constraint_ns = constraint_ns;
> -	td->cached_suspend_ok = constraint_ns >= 0;
>  
>  	/*
>  	 * The children have been suspended already, so we don't need to take
> @@ -144,18 +173,16 @@ static bool __default_power_down_ok(stru
>  		 */
>  		td = &to_gpd_data(pdd)->td;
>  		constraint_ns = td->effective_constraint_ns;
> -		/* default_suspend_ok() need not be called before us. */
> -		if (constraint_ns < 0) {
> -			constraint_ns = dev_pm_qos_read_value(pdd->dev);
> -			constraint_ns *= NSEC_PER_USEC;
> -		}
> +		/*
> +		 * Negative values mean "no suspend at all" and this runs only
> +		 * when all devices in the domain are suspended, so it must be
> +		 * 0 at least.
> +		 *
> +		 * 0 means "no constraint"
> +		 */
>  		if (constraint_ns == 0)
>  			continue;
>  
> -		/*
> -		 * constraint_ns cannot be negative here, because the device has
> -		 * been suspended.
> -		 */
>  		if (constraint_ns <= off_on_time_ns)
>  			return false;
>  
> 

Regards,
Ramesh

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

* Re: [PATCH v3 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07  4:33       ` Ramesh Thomas
@ 2017-11-07 10:12         ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07 10:12 UTC (permalink / raw)
  To: Ramesh Thomas
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

On Tue, Nov 7, 2017 at 5:33 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> On 2017-11-07 at 02:27:05 +0100, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> The special value of 0 for device resume latency PM QoS means
>> "no restriction", but there are two problems with that.
>>
>> First, device resume latency PM QoS requests with 0 as the
>> value are always put in front of requests with positive
>> values in the priority lists used internally by the PM QoS
>> framework, causing 0 to be chosen as an effective constraint
>> value.  However, that 0 is then interpreted as "no restriction"
>> effectively overriding the other requests with specific
>> restrictions which is incorrect.
>>
>> Second, the users of device resume latency PM QoS have no
>> way to specify that *any* resume latency at all should be
>> avoided, which is an artificial limitation in general.
>>
>> To address these issues, modify device resume latency PM QoS to
>> use S32_MAX as the "no constraint" value and 0 as the "no
>> latency at all" one and rework its users (the cpuidle menu
>> governor, the genpd QoS governor and the runtime PM framework)
>> to follow these changes.
>>
>> Also add a special "n/a" value to the corresponding user space I/F
>> to allow user space to indicate that it cannot accept any resume
>> latencies at all for the given device.
>>
>> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
>> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
>> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> Tested-by: Reinette Chatre <reinette.chatre@intel.com>
>> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
>> ---
>>  Documentation/ABI/testing/sysfs-devices-power |    4 ++-
>>  drivers/base/cpu.c                            |    3 +-
>>  drivers/base/power/domain.c                   |    2 -
>>  drivers/base/power/domain_governor.c          |   33 ++++++++++----------------
>>  drivers/base/power/qos.c                      |    5 +++
>>  drivers/base/power/runtime.c                  |    2 -
>>  drivers/base/power/sysfs.c                    |   25 ++++++++++++++++---
>>  drivers/cpuidle/governors/menu.c              |    4 +--
>>  include/linux/pm_qos.h                        |   26 ++++++++++++++------
>>  9 files changed, 65 insertions(+), 39 deletions(-)
>>
>> Index: linux-pm/drivers/base/power/sysfs.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/sysfs.c
>> +++ linux-pm/drivers/base/power/sysfs.c
>> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>>                                         struct device_attribute *attr,
>>                                         char *buf)
>>  {
>> -     return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
>> +     s32 value = dev_pm_qos_requested_resume_latency(dev);
>> +
>> +     if (value == 0)
>> +             return sprintf(buf, "n/a\n");
>> +     else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>> +             value = 0;
>> +
>> +     return sprintf(buf, "%d\n", value);
>>  }
>>
>>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
>> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>>       s32 value;
>>       int ret;
>>
>> -     if (kstrtos32(buf, 0, &value))
>> -             return -EINVAL;
>> +     if (!kstrtos32(buf, 0, &value)) {
>> +             /*
>> +              * Prevent users from writing negative or "no constraint" values
>> +              * directly.
>> +              */
>> +             if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>> +                     return -EINVAL;
>>
>> -     if (value < 0)
>> +             if (value == 0)
>> +                     value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>> +     } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
>> +             value = 0;
>> +     } else {
>>               return -EINVAL;
>> +     }
>>
>>       ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>>                                       value);
>> Index: linux-pm/include/linux/pm_qos.h
>> ===================================================================
>> --- linux-pm.orig/include/linux/pm_qos.h
>> +++ linux-pm/include/linux/pm_qos.h
>> @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>>       PM_QOS_FLAGS_ALL,
>>  };
>>
>> -#define PM_QOS_DEFAULT_VALUE -1
>> +#define PM_QOS_DEFAULT_VALUE (-1)
>> +#define PM_QOS_LATENCY_ANY   S32_MAX
>> +#define PM_QOS_LATENCY_ANY_NS        ((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
>>
>>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE     (2000 * USEC_PER_SEC)
>>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE     (2000 * USEC_PER_SEC)
>>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE      0
>>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE        0
>> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE  0
>> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE  PM_QOS_LATENCY_ANY
>> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT  PM_QOS_LATENCY_ANY
>> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS       PM_QOS_LATENCY_ANY_NS
>>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE       0
>>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT       (-1)
>> -#define PM_QOS_LATENCY_ANY                   ((s32)(~(__u32)0 >> 1))
>>
>>  #define PM_QOS_FLAG_NO_POWER_OFF     (1 << 0)
>>
>> @@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
>>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>>  {
>>       return IS_ERR_OR_NULL(dev->power.qos) ?
>> -             0 : pm_qos_read_value(&dev->power.qos->resume_latency);
>> +             PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
>> +             pm_qos_read_value(&dev->power.qos->resume_latency);
>>  }
>>  #else
>>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
>> @@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
>>                                                       s32 mask)
>>                       { return PM_QOS_FLAGS_UNDEFINED; }
>>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
>> -                     { return 0; }
>> +                     { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>>  static inline s32 dev_pm_qos_read_value(struct device *dev)
>> -                     { return 0; }
>> +                     { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>>  static inline int dev_pm_qos_add_request(struct device *dev,
>>                                        struct dev_pm_qos_request *req,
>>                                        enum dev_pm_qos_req_type type,
>> @@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
>>                       { return 0; }
>>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>>
>> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
>> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
>> +{
>> +     return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>> +}
>>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
>> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
>> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>> +{
>> +     return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>> +}
>>  #endif
>>
>>  #endif
>> Index: linux-pm/drivers/cpuidle/governors/menu.c
>> ===================================================================
>> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
>> +++ linux-pm/drivers/cpuidle/governors/menu.c
>> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>>               data->needs_update = 0;
>>       }
>>
>> -     /* resume_latency is 0 means no restriction */
>> -     if (resume_latency && resume_latency < latency_req)
>> +     if (resume_latency < latency_req &&
>> +         resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>>               latency_req = resume_latency;
>>
>>       /* Special case when user has set very strict latency requirement */
>> Index: linux-pm/drivers/base/power/runtime.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/runtime.c
>> +++ linux-pm/drivers/base/power/runtime.c
>> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>>           || (dev->power.request_pending
>>                       && dev->power.request == RPM_REQ_RESUME))
>>               retval = -EAGAIN;
>> -     else if (__dev_pm_qos_read_value(dev) < 0)
>> +     else if (__dev_pm_qos_read_value(dev) == 0)
>>               retval = -EPERM;
>>       else if (dev->power.runtime_status == RPM_SUSPENDED)
>>               retval = 1;
>> Index: linux-pm/drivers/base/cpu.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/cpu.c
>> +++ linux-pm/drivers/base/cpu.c
>> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>>
>>       per_cpu(cpu_sys_devices, num) = &cpu->dev;
>>       register_cpu_under_node(num, cpu_to_node(num));
>> -     dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
>> +     dev_pm_qos_expose_latency_limit(&cpu->dev,
>> +                                     PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>>
>>       return 0;
>>  }
>> Index: linux-pm/drivers/base/power/qos.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/qos.c
>> +++ linux-pm/drivers/base/power/qos.c
>> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>>
>>       switch(req->type) {
>>       case DEV_PM_QOS_RESUME_LATENCY:
>> +             if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
>> +                     value = 0;
>> +
>>               ret = pm_qos_update_target(&qos->resume_latency,
>>                                          &req->data.pnode, action, value);
>>               break;
>> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>>       plist_head_init(&c->list);
>>       c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>>       c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>> -     c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>> +     c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>>       c->type = PM_QOS_MIN;
>>       c->notifiers = n;
>>
>> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
>> ===================================================================
>> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
>> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
>> @@ -211,7 +211,9 @@ Description:
>>               device, after it has been suspended at run time, from a resume
>>               request to the moment the device will be ready to process I/O,
>>               in microseconds.  If it is equal to 0, however, this means that
>> -             the PM QoS resume latency may be arbitrary.
>> +             the PM QoS resume latency may be arbitrary and the special value
>> +             "n/a" means that user space cannot accept any resume latency at
>> +             all for the given device.
>>
>>               Not all drivers support this attribute.  If it isn't supported,
>>               it is not present.
>> Index: linux-pm/drivers/base/power/domain.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain.c
>> +++ linux-pm/drivers/base/power/domain.c
>> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>>
>>       gpd_data->base.dev = dev;
>>       gpd_data->td.constraint_changed = true;
>> -     gpd_data->td.effective_constraint_ns = 0;
>> +     gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>>       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>>
>>       spin_lock_irq(&dev->power.lock);
>> Index: linux-pm/drivers/base/power/domain_governor.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain_governor.c
>> +++ linux-pm/drivers/base/power/domain_governor.c
>> @@ -33,15 +33,10 @@ static int dev_update_qos_constraint(str
>>                * known at this point anyway).
>>                */
>>               constraint_ns = dev_pm_qos_read_value(dev);
>> -             if (constraint_ns > 0)
>> -                     constraint_ns *= NSEC_PER_USEC;
>> +             constraint_ns *= NSEC_PER_USEC;
>>       }
>>
>> -     /* 0 means "no constraint" */
>> -     if (constraint_ns == 0)
>> -             return 0;
>> -
>> -     if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>> +     if (constraint_ns < *constraint_ns_p)
>>               *constraint_ns_p = constraint_ns;
>>
>>       return 0;
>> @@ -69,12 +64,12 @@ static bool default_suspend_ok(struct de
>>       }
>>       td->constraint_changed = false;
>>       td->cached_suspend_ok = false;
>> -     td->effective_constraint_ns = -1;
>> +     td->effective_constraint_ns = 0;
>>       constraint_ns = __dev_pm_qos_read_value(dev);
>>
>>       spin_unlock_irqrestore(&dev->power.lock, flags);
>>
>> -     if (constraint_ns < 0)
>> +     if (constraint_ns == 0)
>>               return false;
>>
>>       constraint_ns *= NSEC_PER_USEC;
>> @@ -87,25 +82,25 @@ static bool default_suspend_ok(struct de
>>               device_for_each_child(dev, &constraint_ns,
>>                                     dev_update_qos_constraint);
>>
>> -     if (constraint_ns == 0) {
>> +     if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
>>               /* "No restriction", so the device is allowed to suspend. */
>>               td->effective_constraint_ns = 0;
>
> I think you forgot to change this. Assigning 0 would cause its parent to
> fail suspend thinking this child has "no suspend at all" restriction. Should
> assign PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS.

Yes, you are right, I'll send a v4 shortly.

> Should a macro be created for "no suspend at all" so it will be more clear?

Not really.  The 0 here could just be any other value and it still
would be incorrect. :-)



>>               td->cached_suspend_ok = true;
>> -     } else if (constraint_ns < 0) {
>> +     } else if (constraint_ns == 0) {
>>               /*
>>                * This triggers if one of the children that don't belong to a
>> -              * domain has a negative PM QoS constraint and it's better not
>> -              * to suspend then.  effective_constraint_ns is negative already
>> -              * and cached_suspend_ok is false, so bail out.
>> +              * domain has a zero PM QoS constraint and it's better not to
>> +              * suspend then.  effective_constraint_ns is zero already and
>> +              * cached_suspend_ok is false, so bail out.
>>                */
>>               return false;
>>       } else {
>>               constraint_ns -= td->suspend_latency_ns +
>>                               td->resume_latency_ns;
>>               /*
>> -              * effective_constraint_ns is negative already and
>> -              * cached_suspend_ok is false, so if the computed value is not
>> -              * positive, return right away.
>> +              * effective_constraint_ns is zero already and cached_suspend_ok
>> +              * is false, so if the computed value is not positive, return
>> +              * right away.
>>                */
>>               if (constraint_ns <= 0)
>>                       return false;
>> @@ -177,10 +172,8 @@ static bool __default_power_down_ok(stru
>>                * Negative values mean "no suspend at all" and this runs only
>>                * when all devices in the domain are suspended, so it must be
>>                * 0 at least.
>
> I think this message is carried from the previous patch and may need to be
> revised.
>
> In this change, negative value does not mean "no suspend at all". It also
> cannot be 0 or else it would not have suspended. It will alway be > 0 if it
> reaches here.

Right, I overlooked that too.

Thanks,
Rafael

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

* Re: [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-07  5:05       ` Ramesh Thomas
@ 2017-11-07 10:22         ` Rafael J. Wysocki
  2017-11-07 23:24           ` Ramesh Thomas
  0 siblings, 1 reply; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07 10:22 UTC (permalink / raw)
  To: Ramesh Thomas
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

On Tue, Nov 7, 2017 at 6:05 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> On 2017-11-07 at 02:23:18 +0100, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> The genpd governor currently uses negative PM QoS values to indicate
>> the "no suspend" condition and 0 as "no restriction", but it doesn't
>> use them consistently.  Moreover, it tries to refresh QoS values for
>> already suspended devices in a quite questionable way.
>>
>> For the above reasons, rework it to be a bit more consistent.
>>
>> First off, note that dev_pm_qos_read_value() in
>> dev_update_qos_constraint() and __default_power_down_ok() is
>> evaluated for devices in suspend.  Moreover, that only happens if the
>> effective_constraint_ns value for them is negative (meaning "no
>> suspend").  It is not evaluated in any other cases, so effectively
>> the QoS values are only updated for devices in suspend that should
>> not have been suspended in the first place.  In all of the other
>> cases, the QoS values taken into account are the effective ones from
>> the time before the device has been suspended, so generally devices
>> need to be resumed and suspended again for new QoS values to take
>> effect anyway.  Thus evaluating dev_update_qos_constraint() in
>> those two places doesn't make sense at all, so drop it.
>>
>> Second, initialize effective_constraint_ns to 0 ("no constraint")
>> rather than to (-1) ("no suspend"), which makes more sense in
>> general and in case effective_constraint_ns is never updated
>> (the device is in suspend all the time or it is never suspended)
>> it doesn't affect the device's parent and so on.
>>
>> Finally, rework default_suspend_ok() to explicitly handle the
>> "no restriction" and "no suspend" special cases.
>>
>> Also add WARN_ON() around checks that should never trigger.
>>
>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
>> ---
>>
>> v2 -> v3: Take children that don't belong to genpd power domains into
>>           account in dev_update_qos_constraint().
>>
>> ---
>>  drivers/base/power/domain.c          |    2
>>  drivers/base/power/domain_governor.c |   71 ++++++++++++++++++++++++-----------
>>  2 files changed, 50 insertions(+), 23 deletions(-)
>>
>> Index: linux-pm/drivers/base/power/domain.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain.c
>> +++ linux-pm/drivers/base/power/domain.c
>> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>>
>>       gpd_data->base.dev = dev;
>>       gpd_data->td.constraint_changed = true;
>> -     gpd_data->td.effective_constraint_ns = -1;
>> +     gpd_data->td.effective_constraint_ns = 0;
>>       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>>
>>       spin_lock_irq(&dev->power.lock);
>> Index: linux-pm/drivers/base/power/domain_governor.c
>> ===================================================================
>> --- linux-pm.orig/drivers/base/power/domain_governor.c
>> +++ linux-pm/drivers/base/power/domain_governor.c
>> @@ -14,22 +14,33 @@
>>  static int dev_update_qos_constraint(struct device *dev, void *data)
>>  {
>>       s64 *constraint_ns_p = data;
>> -     s32 constraint_ns = -1;
>> +     s64 constraint_ns;
>>
>> -     if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
>> +     if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
>> +             /*
>> +              * Only take suspend-time QoS constraints of devices into
>> +              * account, because constraints updated after the device has
>> +              * been suspended are not guaranteed to be taken into account
>> +              * 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;
>> -
>> -     if (constraint_ns < 0) {
>> +     } else {
>> +             /*
>> +              * The child is not in a domain and there's no info on its
>> +              * suspend/resume latencies, so assume them to be negligible and
>> +              * take its current PM QoS constraint (that's the only thing
>> +              * known at this point anyway).
>> +              */
>>               constraint_ns = dev_pm_qos_read_value(dev);
>> -             constraint_ns *= NSEC_PER_USEC;
>> +             if (constraint_ns > 0)
>> +                     constraint_ns *= NSEC_PER_USEC;
>>       }
>> +
>> +     /* 0 means "no constraint" */
>>       if (constraint_ns == 0)
>>               return 0;
>>
>> -     /*
>> -      * constraint_ns cannot be negative here, because the device has been
>> -      * suspended.
>> -      */
>>       if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>>               *constraint_ns_p = constraint_ns;
>>
>> @@ -76,14 +87,32 @@ static bool default_suspend_ok(struct de
>>               device_for_each_child(dev, &constraint_ns,
>>                                     dev_update_qos_constraint);
>>
>> -     if (constraint_ns > 0) {
>> +     if (constraint_ns == 0) {
>> +             /* "No restriction", so the device is allowed to suspend. */
>> +             td->effective_constraint_ns = 0;
>> +             td->cached_suspend_ok = true;
>> +     } else if (constraint_ns < 0) {
>> +             /*
>> +              * This triggers if one of the children that don't belong to a
>> +              * domain has a negative PM QoS constraint and it's better not
>> +              * to suspend then.  effective_constraint_ns is negative already
>> +              * and cached_suspend_ok is false, so bail out.
>> +              */
>> +             return false;
>
> This change is ok. However, would like to bring to your attention a possible
> inconsistency in the treatment of negative value as "no suspend at all" that
> can affect this.
>
> user level entry does not allow negative values. Only way to enter a negative
> value is if the kernel API to add/update is used. In that interface, if -1
> (PM_QOS_DEFAULT_VALUE) is passed, pm_qos_update_target will actually assign
> the default value stored in the constraint. The default value is
> PM_QOS_RESUME_LATENCY_DEFAULT_VALUE which is 0. 0 means "no constraint".

OK, but that only means that default_suspend_ok() will never see -1 as
a value.  It may see other negative values, though, and treating them
as "no suspend" is not incorrect.  So I don't think the patch needs to
be updated.

In any case, good catch!

Thanks,
Rafael

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

* [PATCH v4 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07  1:27     ` [PATCH v3 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
  2017-11-07  4:33       ` Ramesh Thomas
@ 2017-11-07 10:33       ` Rafael J. Wysocki
  2017-11-07 23:15         ` Ramesh Thomas
                           ` (2 more replies)
  1 sibling, 3 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-07 10:33 UTC (permalink / raw)
  To: Linux PM
  Cc: LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Ramesh Thomas, Alex Shi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The special value of 0 for device resume latency PM QoS means
"no restriction", but there are two problems with that.

First, device resume latency PM QoS requests with 0 as the
value are always put in front of requests with positive
values in the priority lists used internally by the PM QoS
framework, causing 0 to be chosen as an effective constraint
value.  However, that 0 is then interpreted as "no restriction"
effectively overriding the other requests with specific
restrictions which is incorrect.

Second, the users of device resume latency PM QoS have no
way to specify that *any* resume latency at all should be
avoided, which is an artificial limitation in general.

To address these issues, modify device resume latency PM QoS to
use S32_MAX as the "no constraint" value and 0 as the "no
latency at all" one and rework its users (the cpuidle menu
governor, the genpd QoS governor and the runtime PM framework)
to follow these changes.

Also add a special "n/a" value to the corresponding user space I/F
to allow user space to indicate that it cannot accept any resume
latencies at all for the given device.

Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Reinette Chatre <reinette.chatre@intel.com>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
---

As noticed by Ramesh, the v3 had issues with an overlooked value
conversion and a stale comment, so here goes a v4.

---
 Documentation/ABI/testing/sysfs-devices-power |    4 +-
 drivers/base/cpu.c                            |    3 +
 drivers/base/power/domain.c                   |    2 -
 drivers/base/power/domain_governor.c          |   40 ++++++++++----------------
 drivers/base/power/qos.c                      |    5 ++-
 drivers/base/power/runtime.c                  |    2 -
 drivers/base/power/sysfs.c                    |   25 +++++++++++++---
 drivers/cpuidle/governors/menu.c              |    4 +-
 include/linux/pm_qos.h                        |   26 +++++++++++-----
 9 files changed, 68 insertions(+), 43 deletions(-)

Index: linux-pm/drivers/base/power/sysfs.c
===================================================================
--- linux-pm.orig/drivers/base/power/sysfs.c
+++ linux-pm/drivers/base/power/sysfs.c
@@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
 					  struct device_attribute *attr,
 					  char *buf)
 {
-	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
+	s32 value = dev_pm_qos_requested_resume_latency(dev);
+
+	if (value == 0)
+		return sprintf(buf, "n/a\n");
+	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+		value = 0;
+
+	return sprintf(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_resume_latency_store(struct device *dev,
@@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
 	s32 value;
 	int ret;
 
-	if (kstrtos32(buf, 0, &value))
-		return -EINVAL;
+	if (!kstrtos32(buf, 0, &value)) {
+		/*
+		 * Prevent users from writing negative or "no constraint" values
+		 * directly.
+		 */
+		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+			return -EINVAL;
 
-	if (value < 0)
+		if (value == 0)
+			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
+		value = 0;
+	} else {
 		return -EINVAL;
+	}
 
 	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
 					value);
Index: linux-pm/include/linux/pm_qos.h
===================================================================
--- linux-pm.orig/include/linux/pm_qos.h
+++ linux-pm/include/linux/pm_qos.h
@@ -28,16 +28,19 @@ enum pm_qos_flags_status {
 	PM_QOS_FLAGS_ALL,
 };
 
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_DEFAULT_VALUE	(-1)
+#define PM_QOS_LATENCY_ANY	S32_MAX
+#define PM_QOS_LATENCY_ANY_NS	((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
 
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
 #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
-#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
+#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS	PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
-#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
 
@@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
 static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
 {
 	return IS_ERR_OR_NULL(dev->power.qos) ?
-		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
+		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
+		pm_qos_read_value(&dev->power.qos->resume_latency);
 }
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
 							s32 mask)
 			{ return PM_QOS_FLAGS_UNDEFINED; }
 static inline s32 __dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline s32 dev_pm_qos_read_value(struct device *dev)
-			{ return 0; }
+			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline int dev_pm_qos_add_request(struct device *dev,
 					 struct dev_pm_qos_request *req,
 					 enum dev_pm_qos_req_type type,
@@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
 			{ return 0; }
 static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
 
-static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+{
+	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 #endif
 
 #endif
Index: linux-pm/drivers/cpuidle/governors/menu.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/menu.c
+++ linux-pm/drivers/cpuidle/governors/menu.c
@@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
 		data->needs_update = 0;
 	}
 
-	/* resume_latency is 0 means no restriction */
-	if (resume_latency && resume_latency < latency_req)
+	if (resume_latency < latency_req &&
+	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		latency_req = resume_latency;
 
 	/* Special case when user has set very strict latency requirement */
Index: linux-pm/drivers/base/power/runtime.c
===================================================================
--- linux-pm.orig/drivers/base/power/runtime.c
+++ linux-pm/drivers/base/power/runtime.c
@@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
-	else if (__dev_pm_qos_read_value(dev) < 0)
+	else if (__dev_pm_qos_read_value(dev) == 0)
 		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
Index: linux-pm/drivers/base/cpu.c
===================================================================
--- linux-pm.orig/drivers/base/cpu.c
+++ linux-pm/drivers/base/cpu.c
@@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
 
 	per_cpu(cpu_sys_devices, num) = &cpu->dev;
 	register_cpu_under_node(num, cpu_to_node(num));
-	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
+	dev_pm_qos_expose_latency_limit(&cpu->dev,
+					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
 
 	return 0;
 }
Index: linux-pm/drivers/base/power/qos.c
===================================================================
--- linux-pm.orig/drivers/base/power/qos.c
+++ linux-pm/drivers/base/power/qos.c
@@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
 
 	switch(req->type) {
 	case DEV_PM_QOS_RESUME_LATENCY:
+		if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
+			value = 0;
+
 		ret = pm_qos_update_target(&qos->resume_latency,
 					   &req->data.pnode, action, value);
 		break;
@@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
 	plist_head_init(&c->list);
 	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
 	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
-	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 	c->type = PM_QOS_MIN;
 	c->notifiers = n;
 
Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
===================================================================
--- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
+++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
@@ -211,7 +211,9 @@ Description:
 		device, after it has been suspended at run time, from a resume
 		request to the moment the device will be ready to process I/O,
 		in microseconds.  If it is equal to 0, however, this means that
-		the PM QoS resume latency may be arbitrary.
+		the PM QoS resume latency may be arbitrary and the special value
+		"n/a" means that user space cannot accept any resume latency at
+		all for the given device.
 
 		Not all drivers support this attribute.  If it isn't supported,
 		it is not present.
Index: linux-pm/drivers/base/power/domain.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain.c
+++ linux-pm/drivers/base/power/domain.c
@@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
 
 	gpd_data->base.dev = dev;
 	gpd_data->td.constraint_changed = true;
-	gpd_data->td.effective_constraint_ns = 0;
+	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
 	spin_lock_irq(&dev->power.lock);
Index: linux-pm/drivers/base/power/domain_governor.c
===================================================================
--- linux-pm.orig/drivers/base/power/domain_governor.c
+++ linux-pm/drivers/base/power/domain_governor.c
@@ -33,15 +33,10 @@ static int dev_update_qos_constraint(str
 		 * known at this point anyway).
 		 */
 		constraint_ns = dev_pm_qos_read_value(dev);
-		if (constraint_ns > 0)
-			constraint_ns *= NSEC_PER_USEC;
+		constraint_ns *= NSEC_PER_USEC;
 	}
 
-	/* 0 means "no constraint" */
-	if (constraint_ns == 0)
-		return 0;
-
-	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+	if (constraint_ns < *constraint_ns_p)
 		*constraint_ns_p = constraint_ns;
 
 	return 0;
@@ -69,12 +64,12 @@ static bool default_suspend_ok(struct de
 	}
 	td->constraint_changed = false;
 	td->cached_suspend_ok = false;
-	td->effective_constraint_ns = -1;
+	td->effective_constraint_ns = 0;
 	constraint_ns = __dev_pm_qos_read_value(dev);
 
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
-	if (constraint_ns < 0)
+	if (constraint_ns == 0)
 		return false;
 
 	constraint_ns *= NSEC_PER_USEC;
@@ -87,25 +82,25 @@ static bool default_suspend_ok(struct de
 		device_for_each_child(dev, &constraint_ns,
 				      dev_update_qos_constraint);
 
-	if (constraint_ns == 0) {
+	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
 		/* "No restriction", so the device is allowed to suspend. */
-		td->effective_constraint_ns = 0;
+		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
 		td->cached_suspend_ok = true;
-	} else if (constraint_ns < 0) {
+	} else if (constraint_ns == 0) {
 		/*
 		 * This triggers if one of the children that don't belong to a
-		 * domain has a negative PM QoS constraint and it's better not
-		 * to suspend then.  effective_constraint_ns is negative already
-		 * and cached_suspend_ok is false, so bail out.
+		 * domain has a zero PM QoS constraint and it's better not to
+		 * suspend then.  effective_constraint_ns is zero already and
+		 * cached_suspend_ok is false, so bail out.
 		 */
 		return false;
 	} else {
 		constraint_ns -= td->suspend_latency_ns +
 				td->resume_latency_ns;
 		/*
-		 * effective_constraint_ns is negative already and
-		 * cached_suspend_ok is false, so if the computed value is not
-		 * positive, return right away.
+		 * effective_constraint_ns is zero already and cached_suspend_ok
+		 * is false, so if the computed value is not positive, return
+		 * right away.
 		 */
 		if (constraint_ns <= 0)
 			return false;
@@ -174,13 +169,10 @@ static bool __default_power_down_ok(stru
 		td = &to_gpd_data(pdd)->td;
 		constraint_ns = td->effective_constraint_ns;
 		/*
-		 * Negative values mean "no suspend at all" and this runs only
-		 * when all devices in the domain are suspended, so it must be
-		 * 0 at least.
-		 *
-		 * 0 means "no constraint"
+		 * Zero means "no suspend at all" and this runs only when all
+		 * devices in the domain are suspended, so it must be positive.
 		 */
-		if (constraint_ns == 0)
+		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
 			continue;
 
 		if (constraint_ns <= off_on_time_ns)

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

* Re: [PATCH v4 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07 10:33       ` [PATCH v4 " Rafael J. Wysocki
@ 2017-11-07 23:15         ` Ramesh Thomas
  2017-11-08  0:09           ` Rafael J. Wysocki
  2017-11-10  7:49         ` Ulf Hansson
  2017-11-10  8:03         ` Geert Uytterhoeven
  2 siblings, 1 reply; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-07 23:15 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On 2017-11-07 at 11:33:49 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The special value of 0 for device resume latency PM QoS means
> "no restriction", but there are two problems with that.
> 
> First, device resume latency PM QoS requests with 0 as the
> value are always put in front of requests with positive
> values in the priority lists used internally by the PM QoS
> framework, causing 0 to be chosen as an effective constraint
> value.  However, that 0 is then interpreted as "no restriction"
> effectively overriding the other requests with specific
> restrictions which is incorrect.
> 
> Second, the users of device resume latency PM QoS have no
> way to specify that *any* resume latency at all should be
> avoided, which is an artificial limitation in general.
> 
> To address these issues, modify device resume latency PM QoS to
> use S32_MAX as the "no constraint" value and 0 as the "no
> latency at all" one and rework its users (the cpuidle menu
> governor, the genpd QoS governor and the runtime PM framework)
> to follow these changes.
> 
> Also add a special "n/a" value to the corresponding user space I/F
> to allow user space to indicate that it cannot accept any resume
> latencies at all for the given device.
> 
> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Tested-by: Reinette Chatre <reinette.chatre@intel.com>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> 
> As noticed by Ramesh, the v3 had issues with an overlooked value
> conversion and a stale comment, so here goes a v4.
> 
> ---
>  Documentation/ABI/testing/sysfs-devices-power |    4 +-
>  drivers/base/cpu.c                            |    3 +
>  drivers/base/power/domain.c                   |    2 -
>  drivers/base/power/domain_governor.c          |   40 ++++++++++----------------
>  drivers/base/power/qos.c                      |    5 ++-
>  drivers/base/power/runtime.c                  |    2 -
>  drivers/base/power/sysfs.c                    |   25 +++++++++++++---
>  drivers/cpuidle/governors/menu.c              |    4 +-
>  include/linux/pm_qos.h                        |   26 +++++++++++-----
>  9 files changed, 68 insertions(+), 43 deletions(-)
> 
> Index: linux-pm/drivers/base/power/sysfs.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/sysfs.c
> +++ linux-pm/drivers/base/power/sysfs.c
> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>  					  struct device_attribute *attr,
>  					  char *buf)
>  {
> -	return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
> +	s32 value = dev_pm_qos_requested_resume_latency(dev);
> +
> +	if (value == 0)
> +		return sprintf(buf, "n/a\n");
> +	else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +		value = 0;
> +
> +	return sprintf(buf, "%d\n", value);
>  }
>  
>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>  	s32 value;
>  	int ret;
>  
> -	if (kstrtos32(buf, 0, &value))
> -		return -EINVAL;
> +	if (!kstrtos32(buf, 0, &value)) {
> +		/*
> +		 * Prevent users from writing negative or "no constraint" values
> +		 * directly.
> +		 */
> +		if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +			return -EINVAL;
>  
> -	if (value < 0)
> +		if (value == 0)
> +			value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +	} else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
> +		value = 0;
> +	} else {
>  		return -EINVAL;
> +	}
>  
>  	ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>  					value);
> Index: linux-pm/include/linux/pm_qos.h
> ===================================================================
> --- linux-pm.orig/include/linux/pm_qos.h
> +++ linux-pm/include/linux/pm_qos.h
> @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>  	PM_QOS_FLAGS_ALL,
>  };
>  
> -#define PM_QOS_DEFAULT_VALUE -1
> +#define PM_QOS_DEFAULT_VALUE	(-1)
> +#define PM_QOS_LATENCY_ANY	S32_MAX
> +#define PM_QOS_LATENCY_ANY_NS	((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
>  
>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE	0
> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT	PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS	PM_QOS_LATENCY_ANY_NS
>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
> -#define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
>  
>  #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
>  
> @@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>  {
>  	return IS_ERR_OR_NULL(dev->power.qos) ?
> -		0 : pm_qos_read_value(&dev->power.qos->resume_latency);
> +		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
> +		pm_qos_read_value(&dev->power.qos->resume_latency);
>  }
>  #else
>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
> @@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
>  							s32 mask)
>  			{ return PM_QOS_FLAGS_UNDEFINED; }
>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline s32 dev_pm_qos_read_value(struct device *dev)
> -			{ return 0; }
> +			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline int dev_pm_qos_add_request(struct device *dev,
>  					 struct dev_pm_qos_request *req,
>  					 enum dev_pm_qos_req_type type,
> @@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
>  			{ return 0; }
>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>  
> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
> +{
> +	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  #endif
>  
>  #endif
> Index: linux-pm/drivers/cpuidle/governors/menu.c
> ===================================================================
> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
> +++ linux-pm/drivers/cpuidle/governors/menu.c
> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>  		data->needs_update = 0;
>  	}
>  
> -	/* resume_latency is 0 means no restriction */
> -	if (resume_latency && resume_latency < latency_req)
> +	if (resume_latency < latency_req &&
> +	    resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>  		latency_req = resume_latency;
>  
>  	/* Special case when user has set very strict latency requirement */
> Index: linux-pm/drivers/base/power/runtime.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/runtime.c
> +++ linux-pm/drivers/base/power/runtime.c
> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>  	    || (dev->power.request_pending
>  			&& dev->power.request == RPM_REQ_RESUME))
>  		retval = -EAGAIN;
> -	else if (__dev_pm_qos_read_value(dev) < 0)
> +	else if (__dev_pm_qos_read_value(dev) == 0)
>  		retval = -EPERM;
>  	else if (dev->power.runtime_status == RPM_SUSPENDED)
>  		retval = 1;
> Index: linux-pm/drivers/base/cpu.c
> ===================================================================
> --- linux-pm.orig/drivers/base/cpu.c
> +++ linux-pm/drivers/base/cpu.c
> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>  
>  	per_cpu(cpu_sys_devices, num) = &cpu->dev;
>  	register_cpu_under_node(num, cpu_to_node(num));
> -	dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
> +	dev_pm_qos_expose_latency_limit(&cpu->dev,
> +					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>  
>  	return 0;
>  }
> Index: linux-pm/drivers/base/power/qos.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/qos.c
> +++ linux-pm/drivers/base/power/qos.c
> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>  
>  	switch(req->type) {
>  	case DEV_PM_QOS_RESUME_LATENCY:
> +		if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
> +			value = 0;
> +
>  		ret = pm_qos_update_target(&qos->resume_latency,
>  					   &req->data.pnode, action, value);
>  		break;
> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>  	plist_head_init(&c->list);
>  	c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>  	c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> -	c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> +	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>  	c->type = PM_QOS_MIN;
>  	c->notifiers = n;
>  
> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
> ===================================================================
> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
> @@ -211,7 +211,9 @@ Description:
>  		device, after it has been suspended at run time, from a resume
>  		request to the moment the device will be ready to process I/O,
>  		in microseconds.  If it is equal to 0, however, this means that
> -		the PM QoS resume latency may be arbitrary.
> +		the PM QoS resume latency may be arbitrary and the special value
> +		"n/a" means that user space cannot accept any resume latency at
> +		all for the given device.
>  
>  		Not all drivers support this attribute.  If it isn't supported,
>  		it is not present.
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>  
>  	gpd_data->base.dev = dev;
>  	gpd_data->td.constraint_changed = true;
> -	gpd_data->td.effective_constraint_ns = 0;
> +	gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>  	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>  
>  	spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -33,15 +33,10 @@ static int dev_update_qos_constraint(str
>  		 * known at this point anyway).
>  		 */
>  		constraint_ns = dev_pm_qos_read_value(dev);
> -		if (constraint_ns > 0)
> -			constraint_ns *= NSEC_PER_USEC;
> +		constraint_ns *= NSEC_PER_USEC;
>  	}
>  
> -	/* 0 means "no constraint" */
> -	if (constraint_ns == 0)
> -		return 0;
> -
> -	if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
> +	if (constraint_ns < *constraint_ns_p)
>  		*constraint_ns_p = constraint_ns;
>  
>  	return 0;
> @@ -69,12 +64,12 @@ static bool default_suspend_ok(struct de
>  	}
>  	td->constraint_changed = false;
>  	td->cached_suspend_ok = false;
> -	td->effective_constraint_ns = -1;
> +	td->effective_constraint_ns = 0;
>  	constraint_ns = __dev_pm_qos_read_value(dev);
>  
>  	spin_unlock_irqrestore(&dev->power.lock, flags);
>  
> -	if (constraint_ns < 0)
> +	if (constraint_ns == 0)
>  		return false;
>  
>  	constraint_ns *= NSEC_PER_USEC;
> @@ -87,25 +82,25 @@ static bool default_suspend_ok(struct de
>  		device_for_each_child(dev, &constraint_ns,
>  				      dev_update_qos_constraint);
>  
> -	if (constraint_ns == 0) {
> +	if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
>  		/* "No restriction", so the device is allowed to suspend. */
> -		td->effective_constraint_ns = 0;
> +		td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>  		td->cached_suspend_ok = true;
> -	} else if (constraint_ns < 0) {
> +	} else if (constraint_ns == 0) {
>  		/*
>  		 * This triggers if one of the children that don't belong to a
> -		 * domain has a negative PM QoS constraint and it's better not
> -		 * to suspend then.  effective_constraint_ns is negative already
> -		 * and cached_suspend_ok is false, so bail out.
> +		 * domain has a zero PM QoS constraint and it's better not to
> +		 * suspend then.  effective_constraint_ns is zero already and
> +		 * cached_suspend_ok is false, so bail out.
>  		 */
>  		return false;
>  	} else {
>  		constraint_ns -= td->suspend_latency_ns +
>  				td->resume_latency_ns;
>  		/*
> -		 * effective_constraint_ns is negative already and
> -		 * cached_suspend_ok is false, so if the computed value is not
> -		 * positive, return right away.
> +		 * effective_constraint_ns is zero already and cached_suspend_ok
> +		 * is false, so if the computed value is not positive, return
> +		 * right away.
>  		 */
>  		if (constraint_ns <= 0)
>  			return false;
> @@ -174,13 +169,10 @@ static bool __default_power_down_ok(stru
>  		td = &to_gpd_data(pdd)->td;
>  		constraint_ns = td->effective_constraint_ns;
>  		/*
> -		 * Negative values mean "no suspend at all" and this runs only
> -		 * when all devices in the domain are suspended, so it must be
> -		 * 0 at least.
> -		 *
> -		 * 0 means "no constraint"
> +		 * Zero means "no suspend at all" and this runs only when all
> +		 * devices in the domain are suspended, so it must be positive.
>  		 */
> -		if (constraint_ns == 0)
> +		if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
>  			continue;
>  
>  		if (constraint_ns <= off_on_time_ns)
> 

Looks good.

Reviewed-by: Ramesh Thomas <ramesh.thomas@intel.com>

Thanks,
Ramesh

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

* Re: [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-07 10:22         ` Rafael J. Wysocki
@ 2017-11-07 23:24           ` Ramesh Thomas
  0 siblings, 0 replies; 47+ messages in thread
From: Ramesh Thomas @ 2017-11-07 23:24 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Rafael J. Wysocki, Linux PM, LKML, Ulf Hansson,
	Geert Uytterhoeven, Tero Kristo, Reinette Chatre, Alex Shi

On 2017-11-07 at 11:22:48 +0100, Rafael J. Wysocki wrote:
> On Tue, Nov 7, 2017 at 6:05 AM, Ramesh Thomas <ramesh.thomas@intel.com> wrote:
> > On 2017-11-07 at 02:23:18 +0100, Rafael J. Wysocki wrote:
> >> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>
> >> The genpd governor currently uses negative PM QoS values to indicate
> >> the "no suspend" condition and 0 as "no restriction", but it doesn't
> >> use them consistently.  Moreover, it tries to refresh QoS values for
> >> already suspended devices in a quite questionable way.
> >>
> >> For the above reasons, rework it to be a bit more consistent.
> >>
> >> First off, note that dev_pm_qos_read_value() in
> >> dev_update_qos_constraint() and __default_power_down_ok() is
> >> evaluated for devices in suspend.  Moreover, that only happens if the
> >> effective_constraint_ns value for them is negative (meaning "no
> >> suspend").  It is not evaluated in any other cases, so effectively
> >> the QoS values are only updated for devices in suspend that should
> >> not have been suspended in the first place.  In all of the other
> >> cases, the QoS values taken into account are the effective ones from
> >> the time before the device has been suspended, so generally devices
> >> need to be resumed and suspended again for new QoS values to take
> >> effect anyway.  Thus evaluating dev_update_qos_constraint() in
> >> those two places doesn't make sense at all, so drop it.
> >>
> >> Second, initialize effective_constraint_ns to 0 ("no constraint")
> >> rather than to (-1) ("no suspend"), which makes more sense in
> >> general and in case effective_constraint_ns is never updated
> >> (the device is in suspend all the time or it is never suspended)
> >> it doesn't affect the device's parent and so on.
> >>
> >> Finally, rework default_suspend_ok() to explicitly handle the
> >> "no restriction" and "no suspend" special cases.
> >>
> >> Also add WARN_ON() around checks that should never trigger.
> >>
> >> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> >> ---
> >>
> >> v2 -> v3: Take children that don't belong to genpd power domains into
> >>           account in dev_update_qos_constraint().
> >>
> >> ---
> >>  drivers/base/power/domain.c          |    2
> >>  drivers/base/power/domain_governor.c |   71 ++++++++++++++++++++++++-----------
> >>  2 files changed, 50 insertions(+), 23 deletions(-)
> >>
> >> Index: linux-pm/drivers/base/power/domain.c
> >> ===================================================================
> >> --- linux-pm.orig/drivers/base/power/domain.c
> >> +++ linux-pm/drivers/base/power/domain.c
> >> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
> >>
> >>       gpd_data->base.dev = dev;
> >>       gpd_data->td.constraint_changed = true;
> >> -     gpd_data->td.effective_constraint_ns = -1;
> >> +     gpd_data->td.effective_constraint_ns = 0;
> >>       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
> >>
> >>       spin_lock_irq(&dev->power.lock);
> >> Index: linux-pm/drivers/base/power/domain_governor.c
> >> ===================================================================
> >> --- linux-pm.orig/drivers/base/power/domain_governor.c
> >> +++ linux-pm/drivers/base/power/domain_governor.c
> >> @@ -14,22 +14,33 @@
> >>  static int dev_update_qos_constraint(struct device *dev, void *data)
> >>  {
> >>       s64 *constraint_ns_p = data;
> >> -     s32 constraint_ns = -1;
> >> +     s64 constraint_ns;
> >>
> >> -     if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
> >> +     if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
> >> +             /*
> >> +              * Only take suspend-time QoS constraints of devices into
> >> +              * account, because constraints updated after the device has
> >> +              * been suspended are not guaranteed to be taken into account
> >> +              * 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;
> >> -
> >> -     if (constraint_ns < 0) {
> >> +     } else {
> >> +             /*
> >> +              * The child is not in a domain and there's no info on its
> >> +              * suspend/resume latencies, so assume them to be negligible and
> >> +              * take its current PM QoS constraint (that's the only thing
> >> +              * known at this point anyway).
> >> +              */
> >>               constraint_ns = dev_pm_qos_read_value(dev);
> >> -             constraint_ns *= NSEC_PER_USEC;
> >> +             if (constraint_ns > 0)
> >> +                     constraint_ns *= NSEC_PER_USEC;
> >>       }
> >> +
> >> +     /* 0 means "no constraint" */
> >>       if (constraint_ns == 0)
> >>               return 0;
> >>
> >> -     /*
> >> -      * constraint_ns cannot be negative here, because the device has been
> >> -      * suspended.
> >> -      */
> >>       if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
> >>               *constraint_ns_p = constraint_ns;
> >>
> >> @@ -76,14 +87,32 @@ static bool default_suspend_ok(struct de
> >>               device_for_each_child(dev, &constraint_ns,
> >>                                     dev_update_qos_constraint);
> >>
> >> -     if (constraint_ns > 0) {
> >> +     if (constraint_ns == 0) {
> >> +             /* "No restriction", so the device is allowed to suspend. */
> >> +             td->effective_constraint_ns = 0;
> >> +             td->cached_suspend_ok = true;
> >> +     } else if (constraint_ns < 0) {
> >> +             /*
> >> +              * This triggers if one of the children that don't belong to a
> >> +              * domain has a negative PM QoS constraint and it's better not
> >> +              * to suspend then.  effective_constraint_ns is negative already
> >> +              * and cached_suspend_ok is false, so bail out.
> >> +              */
> >> +             return false;
> >
> > This change is ok. However, would like to bring to your attention a possible
> > inconsistency in the treatment of negative value as "no suspend at all" that
> > can affect this.
> >
> > user level entry does not allow negative values. Only way to enter a negative
> > value is if the kernel API to add/update is used. In that interface, if -1
> > (PM_QOS_DEFAULT_VALUE) is passed, pm_qos_update_target will actually assign
> > the default value stored in the constraint. The default value is
> > PM_QOS_RESUME_LATENCY_DEFAULT_VALUE which is 0. 0 means "no constraint".
> 
> OK, but that only means that default_suspend_ok() will never see -1 as
> a value.  It may see other negative values, though, and treating them
> as "no suspend" is not incorrect.  So I don't think the patch needs to
> be updated.

Right. The issue with -1 is a bug at another place and the second patch fixes
that anyway. Looks good to me.

Reviewed-by: Ramesh Thomas <ramesh.thomas@intel.com>

Thanks,
Ramesh

> 
> In any case, good catch!
> 
> Thanks,
> Rafael

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

* Re: [PATCH v4 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07 23:15         ` Ramesh Thomas
@ 2017-11-08  0:09           ` Rafael J. Wysocki
  0 siblings, 0 replies; 47+ messages in thread
From: Rafael J. Wysocki @ 2017-11-08  0:09 UTC (permalink / raw)
  To: ramesh.thomas
  Cc: Linux PM, LKML, Ulf Hansson, Geert Uytterhoeven, Tero Kristo,
	Reinette Chatre, Alex Shi

On Wednesday, November 8, 2017 12:15:16 AM CET Ramesh Thomas wrote:
> On 2017-11-07 at 11:33:49 +0100, Rafael J. Wysocki wrote:

[cut]

> Looks good.
> 
> Reviewed-by: Ramesh Thomas <ramesh.thomas@intel.com>

Thanks a lot for the reviews, they help quite a bit.

Rafael

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

* Re: [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix
  2017-11-07  1:08     ` Rafael J. Wysocki
@ 2017-11-08  9:09       ` Tero Kristo
  0 siblings, 0 replies; 47+ messages in thread
From: Tero Kristo @ 2017-11-08  9:09 UTC (permalink / raw)
  To: Rafael J. Wysocki, Geert Uytterhoeven
  Cc: Linux PM, LKML, Ulf Hansson, Reinette Chatre, Ramesh Thomas, Alex Shi

On 07/11/17 03:08, Rafael J. Wysocki wrote:
> On Monday, November 6, 2017 2:46:48 PM CET Geert Uytterhoeven wrote:
>> Hi Rafael,
>>
>> On Fri, Nov 3, 2017 at 12:42 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>>> On Thursday, November 2, 2017 12:00:27 AM CET Rafael J. Wysocki wrote:
>>>> This series is a replacement for commit 0cc2b4e5a020 (PM / QoS: Fix device
>>>> resume latency PM QoS) that had to be reverted due to problems introduced by it.
>>>>
>>>> This time the genpd PM QoS governor is first updated to be more consistent
>>>> and the PM QoS changes are made on top of that which simplifies the second
>>>> patch quite a bit.
>>>>
>>>> This is based on the linux-next branch from linux-pm.git as of now (should
>>>> also apply to the current mainline just fine).
>>>>
>>>> Please test if you can or let me know if you have any comments.
>>>
>>> The v2 removes a couple of redundant checks from the first patch (and add
>>> comments to explain why the checks are not needed) and fixes up the
>>> "no constraint" value collision with a valid constraint multiplied by
>>> NSEC_PER_USEC in the second patch.
>>>
>>> Please test if possible and let me know about any issues.
>>
>> With this series, the 3 issues I reported before do not happen.
>>
>> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
>>
>> Thank you.
> 
> Thanks!
> 
> Rafael
> 

The latest patches (#1 v3 and #2 v4) seem to work fine in my sanity 
tests also.

Tested-by: Tero Kristo <t-kristo@ti.com>
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

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

* Re: [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent
  2017-11-07  1:23     ` [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
  2017-11-07  5:05       ` Ramesh Thomas
@ 2017-11-10  7:49       ` Ulf Hansson
  1 sibling, 0 replies; 47+ messages in thread
From: Ulf Hansson @ 2017-11-10  7:49 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Geert Uytterhoeven, Tero Kristo, Reinette Chatre,
	Ramesh Thomas, Alex Shi

On 7 November 2017 at 02:23, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> The genpd governor currently uses negative PM QoS values to indicate
> the "no suspend" condition and 0 as "no restriction", but it doesn't
> use them consistently.  Moreover, it tries to refresh QoS values for
> already suspended devices in a quite questionable way.
>
> For the above reasons, rework it to be a bit more consistent.
>
> First off, note that dev_pm_qos_read_value() in
> dev_update_qos_constraint() and __default_power_down_ok() is
> evaluated for devices in suspend.  Moreover, that only happens if the
> effective_constraint_ns value for them is negative (meaning "no
> suspend").  It is not evaluated in any other cases, so effectively
> the QoS values are only updated for devices in suspend that should
> not have been suspended in the first place.  In all of the other
> cases, the QoS values taken into account are the effective ones from
> the time before the device has been suspended, so generally devices
> need to be resumed and suspended again for new QoS values to take
> effect anyway.  Thus evaluating dev_update_qos_constraint() in
> those two places doesn't make sense at all, so drop it.
>
> Second, initialize effective_constraint_ns to 0 ("no constraint")
> rather than to (-1) ("no suspend"), which makes more sense in
> general and in case effective_constraint_ns is never updated
> (the device is in suspend all the time or it is never suspended)
> it doesn't affect the device's parent and so on.
>
> Finally, rework default_suspend_ok() to explicitly handle the
> "no restriction" and "no suspend" special cases.
>
> Also add WARN_ON() around checks that should never trigger.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>
> v2 -> v3: Take children that don't belong to genpd power domains into
>           account in dev_update_qos_constraint().
>
> ---
>  drivers/base/power/domain.c          |    2
>  drivers/base/power/domain_governor.c |   71 ++++++++++++++++++++++++-----------
>  2 files changed, 50 insertions(+), 23 deletions(-)
>
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>
>         gpd_data->base.dev = dev;
>         gpd_data->td.constraint_changed = true;
> -       gpd_data->td.effective_constraint_ns = -1;
> +       gpd_data->td.effective_constraint_ns = 0;
>         gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>
>         spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -14,22 +14,33 @@
>  static int dev_update_qos_constraint(struct device *dev, void *data)
>  {
>         s64 *constraint_ns_p = data;
> -       s32 constraint_ns = -1;
> +       s64 constraint_ns;
>
> -       if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
> +       if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
> +               /*
> +                * Only take suspend-time QoS constraints of devices into
> +                * account, because constraints updated after the device has
> +                * been suspended are not guaranteed to be taken into account
> +                * 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;
> -
> -       if (constraint_ns < 0) {
> +       } else {
> +               /*
> +                * The child is not in a domain and there's no info on its
> +                * suspend/resume latencies, so assume them to be negligible and
> +                * take its current PM QoS constraint (that's the only thing
> +                * known at this point anyway).
> +                */
>                 constraint_ns = dev_pm_qos_read_value(dev);
> -               constraint_ns *= NSEC_PER_USEC;
> +               if (constraint_ns > 0)
> +                       constraint_ns *= NSEC_PER_USEC;
>         }
> +
> +       /* 0 means "no constraint" */
>         if (constraint_ns == 0)
>                 return 0;
>
> -       /*
> -        * constraint_ns cannot be negative here, because the device has been
> -        * suspended.
> -        */
>         if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
>                 *constraint_ns_p = constraint_ns;
>
> @@ -76,14 +87,32 @@ static bool default_suspend_ok(struct de
>                 device_for_each_child(dev, &constraint_ns,
>                                       dev_update_qos_constraint);
>
> -       if (constraint_ns > 0) {
> +       if (constraint_ns == 0) {
> +               /* "No restriction", so the device is allowed to suspend. */
> +               td->effective_constraint_ns = 0;
> +               td->cached_suspend_ok = true;
> +       } else if (constraint_ns < 0) {
> +               /*
> +                * This triggers if one of the children that don't belong to a
> +                * domain has a negative PM QoS constraint and it's better not
> +                * to suspend then.  effective_constraint_ns is negative already
> +                * and cached_suspend_ok is false, so bail out.
> +                */
> +               return false;
> +       } else {
>                 constraint_ns -= td->suspend_latency_ns +
>                                 td->resume_latency_ns;
> -               if (constraint_ns == 0)
> +               /*
> +                * effective_constraint_ns is negative already and
> +                * cached_suspend_ok is false, so if the computed value is not
> +                * positive, return right away.
> +                */
> +               if (constraint_ns <= 0)
>                         return false;
> +
> +               td->effective_constraint_ns = constraint_ns;
> +               td->cached_suspend_ok = true;
>         }
> -       td->effective_constraint_ns = constraint_ns;
> -       td->cached_suspend_ok = constraint_ns >= 0;
>
>         /*
>          * The children have been suspended already, so we don't need to take
> @@ -144,18 +173,16 @@ static bool __default_power_down_ok(stru
>                  */
>                 td = &to_gpd_data(pdd)->td;
>                 constraint_ns = td->effective_constraint_ns;
> -               /* default_suspend_ok() need not be called before us. */
> -               if (constraint_ns < 0) {
> -                       constraint_ns = dev_pm_qos_read_value(pdd->dev);
> -                       constraint_ns *= NSEC_PER_USEC;
> -               }
> +               /*
> +                * Negative values mean "no suspend at all" and this runs only
> +                * when all devices in the domain are suspended, so it must be
> +                * 0 at least.
> +                *
> +                * 0 means "no constraint"
> +                */
>                 if (constraint_ns == 0)
>                         continue;
>
> -               /*
> -                * constraint_ns cannot be negative here, because the device has
> -                * been suspended.
> -                */
>                 if (constraint_ns <= off_on_time_ns)
>                         return false;
>
>

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

* Re: [PATCH v4 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07 10:33       ` [PATCH v4 " Rafael J. Wysocki
  2017-11-07 23:15         ` Ramesh Thomas
@ 2017-11-10  7:49         ` Ulf Hansson
  2017-11-10  8:03         ` Geert Uytterhoeven
  2 siblings, 0 replies; 47+ messages in thread
From: Ulf Hansson @ 2017-11-10  7:49 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Geert Uytterhoeven, Tero Kristo, Reinette Chatre,
	Ramesh Thomas, Alex Shi

On 7 November 2017 at 11:33, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> The special value of 0 for device resume latency PM QoS means
> "no restriction", but there are two problems with that.
>
> First, device resume latency PM QoS requests with 0 as the
> value are always put in front of requests with positive
> values in the priority lists used internally by the PM QoS
> framework, causing 0 to be chosen as an effective constraint
> value.  However, that 0 is then interpreted as "no restriction"
> effectively overriding the other requests with specific
> restrictions which is incorrect.
>
> Second, the users of device resume latency PM QoS have no
> way to specify that *any* resume latency at all should be
> avoided, which is an artificial limitation in general.
>
> To address these issues, modify device resume latency PM QoS to
> use S32_MAX as the "no constraint" value and 0 as the "no
> latency at all" one and rework its users (the cpuidle menu
> governor, the genpd QoS governor and the runtime PM framework)
> to follow these changes.
>
> Also add a special "n/a" value to the corresponding user space I/F
> to allow user space to indicate that it cannot accept any resume
> latencies at all for the given device.
>
> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Tested-by: Reinette Chatre <reinette.chatre@intel.com>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>
> As noticed by Ramesh, the v3 had issues with an overlooked value
> conversion and a stale comment, so here goes a v4.
>
> ---
>  Documentation/ABI/testing/sysfs-devices-power |    4 +-
>  drivers/base/cpu.c                            |    3 +
>  drivers/base/power/domain.c                   |    2 -
>  drivers/base/power/domain_governor.c          |   40 ++++++++++----------------
>  drivers/base/power/qos.c                      |    5 ++-
>  drivers/base/power/runtime.c                  |    2 -
>  drivers/base/power/sysfs.c                    |   25 +++++++++++++---
>  drivers/cpuidle/governors/menu.c              |    4 +-
>  include/linux/pm_qos.h                        |   26 +++++++++++-----
>  9 files changed, 68 insertions(+), 43 deletions(-)
>
> Index: linux-pm/drivers/base/power/sysfs.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/sysfs.c
> +++ linux-pm/drivers/base/power/sysfs.c
> @@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_sho
>                                           struct device_attribute *attr,
>                                           char *buf)
>  {
> -       return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
> +       s32 value = dev_pm_qos_requested_resume_latency(dev);
> +
> +       if (value == 0)
> +               return sprintf(buf, "n/a\n");
> +       else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +               value = 0;
> +
> +       return sprintf(buf, "%d\n", value);
>  }
>
>  static ssize_t pm_qos_resume_latency_store(struct device *dev,
> @@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_sto
>         s32 value;
>         int ret;
>
> -       if (kstrtos32(buf, 0, &value))
> -               return -EINVAL;
> +       if (!kstrtos32(buf, 0, &value)) {
> +               /*
> +                * Prevent users from writing negative or "no constraint" values
> +                * directly.
> +                */
> +               if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
> +                       return -EINVAL;
>
> -       if (value < 0)
> +               if (value == 0)
> +                       value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +       } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
> +               value = 0;
> +       } else {
>                 return -EINVAL;
> +       }
>
>         ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
>                                         value);
> Index: linux-pm/include/linux/pm_qos.h
> ===================================================================
> --- linux-pm.orig/include/linux/pm_qos.h
> +++ linux-pm/include/linux/pm_qos.h
> @@ -28,16 +28,19 @@ enum pm_qos_flags_status {
>         PM_QOS_FLAGS_ALL,
>  };
>
> -#define PM_QOS_DEFAULT_VALUE -1
> +#define PM_QOS_DEFAULT_VALUE   (-1)
> +#define PM_QOS_LATENCY_ANY     S32_MAX
> +#define PM_QOS_LATENCY_ANY_NS  ((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
>
>  #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
>  #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE        0
>  #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE  0
> -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE    0
> +#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE    PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT    PM_QOS_LATENCY_ANY
> +#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
>  #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
>  #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
> -#define PM_QOS_LATENCY_ANY                     ((s32)(~(__u32)0 >> 1))
>
>  #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
>
> @@ -174,7 +177,8 @@ static inline s32 dev_pm_qos_requested_f
>  static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
>  {
>         return IS_ERR_OR_NULL(dev->power.qos) ?
> -               0 : pm_qos_read_value(&dev->power.qos->resume_latency);
> +               PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
> +               pm_qos_read_value(&dev->power.qos->resume_latency);
>  }
>  #else
>  static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
> @@ -184,9 +188,9 @@ static inline enum pm_qos_flags_status d
>                                                         s32 mask)
>                         { return PM_QOS_FLAGS_UNDEFINED; }
>  static inline s32 __dev_pm_qos_read_value(struct device *dev)
> -                       { return 0; }
> +                       { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline s32 dev_pm_qos_read_value(struct device *dev)
> -                       { return 0; }
> +                       { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
>  static inline int dev_pm_qos_add_request(struct device *dev,
>                                          struct dev_pm_qos_request *req,
>                                          enum dev_pm_qos_req_type type,
> @@ -232,9 +236,15 @@ static inline int dev_pm_qos_expose_late
>                         { return 0; }
>  static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
>
> -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
> +{
> +       return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
> -static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; }
> +static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
> +{
> +       return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
> +}
>  #endif
>
>  #endif
> Index: linux-pm/drivers/cpuidle/governors/menu.c
> ===================================================================
> --- linux-pm.orig/drivers/cpuidle/governors/menu.c
> +++ linux-pm/drivers/cpuidle/governors/menu.c
> @@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_dr
>                 data->needs_update = 0;
>         }
>
> -       /* resume_latency is 0 means no restriction */
> -       if (resume_latency && resume_latency < latency_req)
> +       if (resume_latency < latency_req &&
> +           resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
>                 latency_req = resume_latency;
>
>         /* Special case when user has set very strict latency requirement */
> Index: linux-pm/drivers/base/power/runtime.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/runtime.c
> +++ linux-pm/drivers/base/power/runtime.c
> @@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(str
>             || (dev->power.request_pending
>                         && dev->power.request == RPM_REQ_RESUME))
>                 retval = -EAGAIN;
> -       else if (__dev_pm_qos_read_value(dev) < 0)
> +       else if (__dev_pm_qos_read_value(dev) == 0)
>                 retval = -EPERM;
>         else if (dev->power.runtime_status == RPM_SUSPENDED)
>                 retval = 1;
> Index: linux-pm/drivers/base/cpu.c
> ===================================================================
> --- linux-pm.orig/drivers/base/cpu.c
> +++ linux-pm/drivers/base/cpu.c
> @@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int nu
>
>         per_cpu(cpu_sys_devices, num) = &cpu->dev;
>         register_cpu_under_node(num, cpu_to_node(num));
> -       dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
> +       dev_pm_qos_expose_latency_limit(&cpu->dev,
> +                                       PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
>
>         return 0;
>  }
> Index: linux-pm/drivers/base/power/qos.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/qos.c
> +++ linux-pm/drivers/base/power/qos.c
> @@ -139,6 +139,9 @@ static int apply_constraint(struct dev_p
>
>         switch(req->type) {
>         case DEV_PM_QOS_RESUME_LATENCY:
> +               if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
> +                       value = 0;
> +
>                 ret = pm_qos_update_target(&qos->resume_latency,
>                                            &req->data.pnode, action, value);
>                 break;
> @@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_alloca
>         plist_head_init(&c->list);
>         c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
>         c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> -       c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
> +       c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
>         c->type = PM_QOS_MIN;
>         c->notifiers = n;
>
> Index: linux-pm/Documentation/ABI/testing/sysfs-devices-power
> ===================================================================
> --- linux-pm.orig/Documentation/ABI/testing/sysfs-devices-power
> +++ linux-pm/Documentation/ABI/testing/sysfs-devices-power
> @@ -211,7 +211,9 @@ Description:
>                 device, after it has been suspended at run time, from a resume
>                 request to the moment the device will be ready to process I/O,
>                 in microseconds.  If it is equal to 0, however, this means that
> -               the PM QoS resume latency may be arbitrary.
> +               the PM QoS resume latency may be arbitrary and the special value
> +               "n/a" means that user space cannot accept any resume latency at
> +               all for the given device.
>
>                 Not all drivers support this attribute.  If it isn't supported,
>                 it is not present.
> Index: linux-pm/drivers/base/power/domain.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain.c
> +++ linux-pm/drivers/base/power/domain.c
> @@ -1331,7 +1331,7 @@ static struct generic_pm_domain_data *ge
>
>         gpd_data->base.dev = dev;
>         gpd_data->td.constraint_changed = true;
> -       gpd_data->td.effective_constraint_ns = 0;
> +       gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>         gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
>
>         spin_lock_irq(&dev->power.lock);
> Index: linux-pm/drivers/base/power/domain_governor.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/domain_governor.c
> +++ linux-pm/drivers/base/power/domain_governor.c
> @@ -33,15 +33,10 @@ static int dev_update_qos_constraint(str
>                  * known at this point anyway).
>                  */
>                 constraint_ns = dev_pm_qos_read_value(dev);
> -               if (constraint_ns > 0)
> -                       constraint_ns *= NSEC_PER_USEC;
> +               constraint_ns *= NSEC_PER_USEC;
>         }
>
> -       /* 0 means "no constraint" */
> -       if (constraint_ns == 0)
> -               return 0;
> -
> -       if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
> +       if (constraint_ns < *constraint_ns_p)
>                 *constraint_ns_p = constraint_ns;
>
>         return 0;
> @@ -69,12 +64,12 @@ static bool default_suspend_ok(struct de
>         }
>         td->constraint_changed = false;
>         td->cached_suspend_ok = false;
> -       td->effective_constraint_ns = -1;
> +       td->effective_constraint_ns = 0;
>         constraint_ns = __dev_pm_qos_read_value(dev);
>
>         spin_unlock_irqrestore(&dev->power.lock, flags);
>
> -       if (constraint_ns < 0)
> +       if (constraint_ns == 0)
>                 return false;
>
>         constraint_ns *= NSEC_PER_USEC;
> @@ -87,25 +82,25 @@ static bool default_suspend_ok(struct de
>                 device_for_each_child(dev, &constraint_ns,
>                                       dev_update_qos_constraint);
>
> -       if (constraint_ns == 0) {
> +       if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
>                 /* "No restriction", so the device is allowed to suspend. */
> -               td->effective_constraint_ns = 0;
> +               td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
>                 td->cached_suspend_ok = true;
> -       } else if (constraint_ns < 0) {
> +       } else if (constraint_ns == 0) {
>                 /*
>                  * This triggers if one of the children that don't belong to a
> -                * domain has a negative PM QoS constraint and it's better not
> -                * to suspend then.  effective_constraint_ns is negative already
> -                * and cached_suspend_ok is false, so bail out.
> +                * domain has a zero PM QoS constraint and it's better not to
> +                * suspend then.  effective_constraint_ns is zero already and
> +                * cached_suspend_ok is false, so bail out.
>                  */
>                 return false;
>         } else {
>                 constraint_ns -= td->suspend_latency_ns +
>                                 td->resume_latency_ns;
>                 /*
> -                * effective_constraint_ns is negative already and
> -                * cached_suspend_ok is false, so if the computed value is not
> -                * positive, return right away.
> +                * effective_constraint_ns is zero already and cached_suspend_ok
> +                * is false, so if the computed value is not positive, return
> +                * right away.
>                  */
>                 if (constraint_ns <= 0)
>                         return false;
> @@ -174,13 +169,10 @@ static bool __default_power_down_ok(stru
>                 td = &to_gpd_data(pdd)->td;
>                 constraint_ns = td->effective_constraint_ns;
>                 /*
> -                * Negative values mean "no suspend at all" and this runs only
> -                * when all devices in the domain are suspended, so it must be
> -                * 0 at least.
> -                *
> -                * 0 means "no constraint"
> +                * Zero means "no suspend at all" and this runs only when all
> +                * devices in the domain are suspended, so it must be positive.
>                  */
> -               if (constraint_ns == 0)
> +               if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
>                         continue;
>
>                 if (constraint_ns <= off_on_time_ns)
>

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

* Re: [PATCH v4 2/2] PM / QoS: Fix device resume latency framework
  2017-11-07 10:33       ` [PATCH v4 " Rafael J. Wysocki
  2017-11-07 23:15         ` Ramesh Thomas
  2017-11-10  7:49         ` Ulf Hansson
@ 2017-11-10  8:03         ` Geert Uytterhoeven
  2 siblings, 0 replies; 47+ messages in thread
From: Geert Uytterhoeven @ 2017-11-10  8:03 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux PM, LKML, Ulf Hansson, Tero Kristo, Reinette Chatre,
	Ramesh Thomas, Alex Shi

Hi Rafael,

On Tue, Nov 7, 2017 at 11:33 AM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> The special value of 0 for device resume latency PM QoS means
> "no restriction", but there are two problems with that.
>
> First, device resume latency PM QoS requests with 0 as the
> value are always put in front of requests with positive
> values in the priority lists used internally by the PM QoS
> framework, causing 0 to be chosen as an effective constraint
> value.  However, that 0 is then interpreted as "no restriction"
> effectively overriding the other requests with specific
> restrictions which is incorrect.
>
> Second, the users of device resume latency PM QoS have no
> way to specify that *any* resume latency at all should be
> avoided, which is an artificial limitation in general.
>
> To address these issues, modify device resume latency PM QoS to
> use S32_MAX as the "no constraint" value and 0 as the "no
> latency at all" one and rework its users (the cpuidle menu
> governor, the genpd QoS governor and the runtime PM framework)
> to follow these changes.
>
> Also add a special "n/a" value to the corresponding user space I/F
> to allow user space to indicate that it cannot accept any resume
> latencies at all for the given device.
>
> Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints)
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323
> Reported-by: Reinette Chatre <reinette.chatre@intel.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Tested-by: Reinette Chatre <reinette.chatre@intel.com>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>
> As noticed by Ramesh, the v3 had issues with an overlooked value
> conversion and a stale comment, so here goes a v4.

JFTR, with v4, the WARN_ON() is no longer triggered when waking up
r8a7740/armadillo or sh73a0/kzm9g by tapping the touchscreen.

I hadn't reported that before, as I only noticed it with v2 after you had
already posted newer versions, so I wanted to try those first.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

end of thread, other threads:[~2017-11-10  8:03 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-01 23:00 [RFT][PATCH 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
2017-11-01 23:01 ` [RFT][PATCH 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
2017-11-03  7:05   ` Ramesh Thomas
2017-11-03  7:51     ` Rafael J. Wysocki
2017-11-01 23:03 ` [RFT][PATCH 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
2017-11-03  7:43   ` Ramesh Thomas
2017-11-03  7:58     ` Rafael J. Wysocki
2017-11-03 10:38       ` Rafael J. Wysocki
2017-11-03 11:42 ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Rafael J. Wysocki
2017-11-03 11:47   ` [RFT][PATCH v2 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
2017-11-04  2:34     ` Ramesh Thomas
2017-11-04 11:24       ` Rafael J. Wysocki
2017-11-06  7:47         ` Ramesh Thomas
2017-11-06 12:10     ` Ulf Hansson
2017-11-06 12:34       ` Rafael J. Wysocki
2017-11-06 12:44         ` Ulf Hansson
2017-11-06 12:49           ` Rafael J. Wysocki
2017-11-06 14:38             ` Ulf Hansson
2017-11-06 23:07               ` Rafael J. Wysocki
2017-11-03 11:50   ` [RFT][PATCH v2 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
2017-11-03 16:39     ` Reinette Chatre
2017-11-04  2:28       ` Ramesh Thomas
2017-11-04 11:30         ` Rafael J. Wysocki
2017-11-04 11:58           ` Rafael J. Wysocki
2017-11-04 11:28       ` Rafael J. Wysocki
2017-11-04  2:38     ` Ramesh Thomas
2017-11-04 12:34     ` [RFT][Update][PATCH " Rafael J. Wysocki
2017-11-06 17:47       ` Reinette Chatre
2017-11-07  1:07         ` Rafael J. Wysocki
2017-11-06 13:46   ` [RFT][PATCH v2 0/2] PM / QoS: Device resume latency framework fix Geert Uytterhoeven
2017-11-07  1:08     ` Rafael J. Wysocki
2017-11-08  9:09       ` Tero Kristo
2017-11-07  1:17   ` [PATCH v3 " Rafael J. Wysocki
2017-11-07  1:17     ` Rafael J. Wysocki
2017-11-07  1:23     ` [PATCH v3 1/2] PM / domains: Rework governor code to be more consistent Rafael J. Wysocki
2017-11-07  5:05       ` Ramesh Thomas
2017-11-07 10:22         ` Rafael J. Wysocki
2017-11-07 23:24           ` Ramesh Thomas
2017-11-10  7:49       ` Ulf Hansson
2017-11-07  1:27     ` [PATCH v3 2/2] PM / QoS: Fix device resume latency framework Rafael J. Wysocki
2017-11-07  4:33       ` Ramesh Thomas
2017-11-07 10:12         ` Rafael J. Wysocki
2017-11-07 10:33       ` [PATCH v4 " Rafael J. Wysocki
2017-11-07 23:15         ` Ramesh Thomas
2017-11-08  0:09           ` Rafael J. Wysocki
2017-11-10  7:49         ` Ulf Hansson
2017-11-10  8:03         ` Geert Uytterhoeven

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.