All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints
@ 2019-02-21 11:29 Viresh Kumar
  2019-02-21 11:29 ` [PATCH V2 1/5] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier() Viresh Kumar
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Viresh Kumar @ 2019-02-21 11:29 UTC (permalink / raw)
  To: Rafael Wysocki, Daniel Lezcano, Kevin Hilman, Len Brown,
	Pavel Machek, Ulf Hansson
  Cc: Viresh Kumar, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

Hello,

This patchset attempts to manage CPU frequency constraints using the PM
QoS framework. It only does the basic stuff right now and moves the
userspace constraints to use the QoS infrastructure.

Todo:
- Migrate all users to the QoS framework and get rid of cpufreq specific
  notifiers.
- Make PM QoS learn about the relation of CPUs in a policy, so a single
  list of constraints is managed for all of them instead of per-cpu
  constraints.

V1->V2:
- The previous version introduced a completely new framework, this one
  moves to PM QoS instead.
- Lots of changes because of this.

--
viresh

Viresh Kumar (5):
  PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier()
  PM / QOS: Pass request type to dev_pm_qos_read_value()
  PM / QoS: Add support for MIN/MAX frequency constraints
  cpufreq: Register notifiers with the PM QoS framework
  cpufreq: Add QoS requests for userspace constraints

 Documentation/power/pm_qos_interface.txt |  12 +-
 drivers/base/power/domain.c              |   8 +-
 drivers/base/power/domain_governor.c     |   4 +-
 drivers/base/power/qos.c                 | 115 +++++++++++--
 drivers/base/power/runtime.c             |   2 +-
 drivers/cpufreq/cpufreq.c                | 202 ++++++++++++++++-------
 drivers/cpuidle/governor.c               |   2 +-
 include/linux/cpufreq.h                  |  12 +-
 include/linux/pm_qos.h                   |  71 ++++++--
 9 files changed, 323 insertions(+), 105 deletions(-)

-- 
2.21.0.rc0.269.g1a574e7a288b


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

* [PATCH V2 1/5] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier()
  2019-02-21 11:29 [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Viresh Kumar
@ 2019-02-21 11:29 ` Viresh Kumar
  2019-02-21 11:29 ` [PATCH V2 2/5] PM / QOS: Pass request type to dev_pm_qos_read_value() Viresh Kumar
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Viresh Kumar @ 2019-02-21 11:29 UTC (permalink / raw)
  To: Rafael Wysocki, Len Brown, Pavel Machek, Kevin Hilman, Ulf Hansson
  Cc: Viresh Kumar, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

In order to use the same set of routines to register notifiers for
different request types, update the existing
dev_pm_qos_{add|remove}_notifier() routines with an additional
parameter: request-type.

For now, it only supports resume-latency request type.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 Documentation/power/pm_qos_interface.txt | 10 ++++++----
 drivers/base/power/domain.c              |  8 +++++---
 drivers/base/power/qos.c                 | 14 ++++++++++++--
 include/linux/pm_qos.h                   | 12 ++++++++----
 4 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index 19c5f7b1a7ba..ec7d662d1707 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -164,12 +164,14 @@ directory.
 Notification mechanisms:
 The per-device PM QoS framework has a per-device notification tree.
 
-int dev_pm_qos_add_notifier(device, notifier):
-Adds a notification callback function for the device.
+int dev_pm_qos_add_notifier(device, notifier, type):
+Adds a notification callback function for the device for a particular request
+type.
+
 The callback is called when the aggregated value of the device constraints list
-is changed (for resume latency device PM QoS only).
+is changed.
 
-int dev_pm_qos_remove_notifier(device, notifier):
+int dev_pm_qos_remove_notifier(device, notifier, type):
 Removes the notification callback function for the device.
 
 
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 2c334c01fc43..d8c37945a26d 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1486,7 +1486,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	if (ret)
 		genpd_free_dev_data(dev, gpd_data);
 	else
-		dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+		dev_pm_qos_add_notifier(dev, &gpd_data->nb,
+					DEV_PM_QOS_RESUME_LATENCY);
 
 	return ret;
 }
@@ -1519,7 +1520,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 
 	pdd = dev->power.subsys_data->domain_data;
 	gpd_data = to_gpd_data(pdd);
-	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+	dev_pm_qos_remove_notifier(dev, &gpd_data->nb,
+				   DEV_PM_QOS_RESUME_LATENCY);
 
 	genpd_lock(genpd);
 
@@ -1546,7 +1548,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 
  out:
 	genpd_unlock(genpd);
-	dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+	dev_pm_qos_add_notifier(dev, &gpd_data->nb, DEV_PM_QOS_RESUME_LATENCY);
 
 	return ret;
 }
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 3382542b39b7..49672f9dc8c4 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -471,6 +471,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
  *
  * @dev: target device for the constraint
  * @notifier: notifier block managed by caller.
+ * @type: request type.
  *
  * Will register the notifier into a notification chain that gets called
  * upon changes to the target value for the device.
@@ -478,10 +479,14 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
  * If the device's constraints object doesn't exist when this routine is called,
  * it will be created (or error code will be returned if that fails).
  */
-int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
+int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
+			    enum dev_pm_qos_req_type type)
 {
 	int ret = 0;
 
+	if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY))
+		return -EINVAL;
+
 	mutex_lock(&dev_pm_qos_mtx);
 
 	if (IS_ERR(dev->power.qos))
@@ -504,15 +509,20 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
  *
  * @dev: target device for the constraint
  * @notifier: notifier block to be removed.
+ * @type: request type.
  *
  * Will remove the notifier from the notification chain that gets called
  * upon changes to the target value.
  */
 int dev_pm_qos_remove_notifier(struct device *dev,
-			       struct notifier_block *notifier)
+			       struct notifier_block *notifier,
+			       enum dev_pm_qos_req_type type)
 {
 	int retval = 0;
 
+	if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY))
+		return -EINVAL;
+
 	mutex_lock(&dev_pm_qos_mtx);
 
 	/* Silently return if the constraints object is not present. */
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 6ea1ae373d77..1f4d456e8fff 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -146,9 +146,11 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
 int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
 int dev_pm_qos_remove_request(struct dev_pm_qos_request *req);
 int dev_pm_qos_add_notifier(struct device *dev,
-			    struct notifier_block *notifier);
+			    struct notifier_block *notifier,
+			    enum dev_pm_qos_req_type type);
 int dev_pm_qos_remove_notifier(struct device *dev,
-			       struct notifier_block *notifier);
+			       struct notifier_block *notifier,
+			       enum dev_pm_qos_req_type type);
 void dev_pm_qos_constraints_init(struct device *dev);
 void dev_pm_qos_constraints_destroy(struct device *dev);
 int dev_pm_qos_add_ancestor_request(struct device *dev,
@@ -202,10 +204,12 @@ static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
 static inline int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
 			{ return 0; }
 static inline int dev_pm_qos_add_notifier(struct device *dev,
-					  struct notifier_block *notifier)
+					  struct notifier_block *notifier,
+					  enum dev_pm_qos_req_type type);
 			{ return 0; }
 static inline int dev_pm_qos_remove_notifier(struct device *dev,
-					     struct notifier_block *notifier)
+					     struct notifier_block *notifier,
+					     enum dev_pm_qos_req_type type)
 			{ return 0; }
 static inline void dev_pm_qos_constraints_init(struct device *dev)
 {
-- 
2.21.0.rc0.269.g1a574e7a288b


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

* [PATCH V2 2/5] PM / QOS: Pass request type to dev_pm_qos_read_value()
  2019-02-21 11:29 [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Viresh Kumar
  2019-02-21 11:29 ` [PATCH V2 1/5] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier() Viresh Kumar
@ 2019-02-21 11:29 ` Viresh Kumar
  2019-02-21 11:29 ` [PATCH V2 3/5] PM / QoS: Add support for MIN/MAX frequency constraints Viresh Kumar
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Viresh Kumar @ 2019-02-21 11:29 UTC (permalink / raw)
  To: Rafael Wysocki, Len Brown, Pavel Machek, Kevin Hilman,
	Ulf Hansson, Daniel Lezcano
  Cc: Viresh Kumar, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

In order to use dev_pm_qos_read_value(), and other internal routines to
it, to read values for different QoS requests, pass request type as a
parameter to these routines.

For now, it only supports resume-latency request type.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 Documentation/power/pm_qos_interface.txt |  2 +-
 drivers/base/power/domain_governor.c     |  4 +--
 drivers/base/power/qos.c                 | 10 +++---
 drivers/base/power/runtime.c             |  2 +-
 drivers/cpuidle/governor.c               |  2 +-
 include/linux/pm_qos.h                   | 41 +++++++++++++++++-------
 6 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index ec7d662d1707..cfcb1df39799 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -123,7 +123,7 @@ Will remove the element.  After removal it will update the aggregate target and
 call the notification trees if the target was changed as a result of removing
 the request.
 
-s32 dev_pm_qos_read_value(device):
+s32 dev_pm_qos_read_value(device, type):
 Returns the aggregated value for a given device's constraints list.
 
 enum pm_qos_flags_status dev_pm_qos_flags(device, mask)
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 99896fbf18e4..c36925adba69 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -32,7 +32,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
 		 * 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 = dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY);
 		constraint_ns *= NSEC_PER_USEC;
 	}
 
@@ -65,7 +65,7 @@ static bool default_suspend_ok(struct device *dev)
 	td->constraint_changed = false;
 	td->cached_suspend_ok = false;
 	td->effective_constraint_ns = 0;
-	constraint_ns = __dev_pm_qos_read_value(dev);
+	constraint_ns = __dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY);
 
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 49672f9dc8c4..fda7266970e9 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -96,27 +96,29 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
 /**
  * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
  * @dev: Device to get the PM QoS constraint value for.
+ * @type: QoS request type.
  *
  * This routine must be called with dev->power.lock held.
  */
-s32 __dev_pm_qos_read_value(struct device *dev)
+s32 __dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
 {
 	lockdep_assert_held(&dev->power.lock);
 
-	return dev_pm_qos_raw_read_value(dev);
+	return dev_pm_qos_raw_read_value(dev, type);
 }
 
 /**
  * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
  * @dev: Device to get the PM QoS constraint value for.
+ * @type: QoS request type.
  */
-s32 dev_pm_qos_read_value(struct device *dev)
+s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
 {
 	unsigned long flags;
 	s32 ret;
 
 	spin_lock_irqsave(&dev->power.lock, flags);
-	ret = __dev_pm_qos_read_value(dev);
+	ret = __dev_pm_qos_read_value(dev, type);
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
 	return ret;
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 04407d9f76fd..997cd420accc 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -267,7 +267,7 @@ static int rpm_check_suspend_allowed(struct device *dev)
 	    || (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, DEV_PM_QOS_RESUME_LATENCY) == 0)
 		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c
index bb93e5cf6a4a..251d3ef4a1e5 100644
--- a/drivers/cpuidle/governor.c
+++ b/drivers/cpuidle/governor.c
@@ -109,7 +109,7 @@ int cpuidle_governor_latency_req(unsigned int cpu)
 {
 	int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 	struct device *device = get_cpu_device(cpu);
-	int device_req = dev_pm_qos_raw_read_value(device);
+	int device_req = dev_pm_qos_raw_read_value(device, DEV_PM_QOS_RESUME_LATENCY);
 
 	return device_req < global_req ? device_req : global_req;
 }
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 1f4d456e8fff..55814d48c39c 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -139,8 +139,8 @@ s32 pm_qos_read_value(struct pm_qos_constraints *c);
 #ifdef CONFIG_PM
 enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask);
 enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask);
-s32 __dev_pm_qos_read_value(struct device *dev);
-s32 dev_pm_qos_read_value(struct device *dev);
+s32 __dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type);
+s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type);
 int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
 			   enum dev_pm_qos_req_type type, s32 value);
 int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
@@ -176,11 +176,19 @@ static inline s32 dev_pm_qos_requested_flags(struct device *dev)
 	return dev->power.qos->flags_req->data.flr.flags;
 }
 
-static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev,
+					    enum dev_pm_qos_req_type type)
 {
-	return IS_ERR_OR_NULL(dev->power.qos) ?
-		PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
-		pm_qos_read_value(&dev->power.qos->resume_latency);
+	struct dev_pm_qos *qos = dev->power.qos;
+
+	switch (type) {
+	case DEV_PM_QOS_RESUME_LATENCY:
+		return IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
+			: pm_qos_read_value(&qos->resume_latency);
+	default:
+		WARN_ON(1);
+		return 0;
+	}
 }
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -189,10 +197,6 @@ static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
 static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev,
 							s32 mask)
 			{ return PM_QOS_FLAGS_UNDEFINED; }
-static inline s32 __dev_pm_qos_read_value(struct device *dev)
-			{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
-static inline s32 dev_pm_qos_read_value(struct device *dev)
-			{ 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,
@@ -245,10 +249,23 @@ 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)
+
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev,
+					    enum dev_pm_qos_req_type type)
 {
-	return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	switch type {
+	case DEV_PM_QOS_RESUME_LATENCY:
+		return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	default:
+		WARN_ON(1);
+		return 0;
+	}
 }
+
+static inline s32 __dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
+			{ return dev_pm_qos_raw_read_value(dev, type); }
+static inline s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
+			{ return dev_pm_qos_raw_read_value(dev, type); }
 #endif
 
 #endif
-- 
2.21.0.rc0.269.g1a574e7a288b


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

* [PATCH V2 3/5] PM / QoS: Add support for MIN/MAX frequency constraints
  2019-02-21 11:29 [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Viresh Kumar
  2019-02-21 11:29 ` [PATCH V2 1/5] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier() Viresh Kumar
  2019-02-21 11:29 ` [PATCH V2 2/5] PM / QOS: Pass request type to dev_pm_qos_read_value() Viresh Kumar
@ 2019-02-21 11:29 ` Viresh Kumar
  2019-02-21 11:29 ` [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework Viresh Kumar
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Viresh Kumar @ 2019-02-21 11:29 UTC (permalink / raw)
  To: Rafael Wysocki, Pavel Machek, Len Brown
  Cc: Viresh Kumar, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

This patch introduces the min-frequency and max-frequency device
constraints, which will be used by the cpufreq core to begin with.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/base/power/qos.c | 103 +++++++++++++++++++++++++++++++++------
 include/linux/pm_qos.h   |  18 +++++++
 2 files changed, 107 insertions(+), 14 deletions(-)

diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index fda7266970e9..30fe1e98b343 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -155,6 +155,14 @@ static int apply_constraint(struct dev_pm_qos_request *req,
 			req->dev->power.set_latency_tolerance(req->dev, value);
 		}
 		break;
+	case DEV_PM_QOS_MIN_FREQUENCY:
+		ret = pm_qos_update_target(&qos->min_frequency,
+					   &req->data.pnode, action, value);
+		break;
+	case DEV_PM_QOS_MAX_FREQUENCY:
+		ret = pm_qos_update_target(&qos->max_frequency,
+					   &req->data.pnode, action, value);
+		break;
 	case DEV_PM_QOS_FLAGS:
 		ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
 					  action, value);
@@ -183,12 +191,11 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
 	if (!qos)
 		return -ENOMEM;
 
-	n = kzalloc(sizeof(*n), GFP_KERNEL);
+	n = kzalloc(3 * sizeof(*n), GFP_KERNEL);
 	if (!n) {
 		kfree(qos);
 		return -ENOMEM;
 	}
-	BLOCKING_INIT_NOTIFIER_HEAD(n);
 
 	c = &qos->resume_latency;
 	plist_head_init(&c->list);
@@ -197,6 +204,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
 	c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
 	c->type = PM_QOS_MIN;
 	c->notifiers = n;
+	BLOCKING_INIT_NOTIFIER_HEAD(n);
 
 	c = &qos->latency_tolerance;
 	plist_head_init(&c->list);
@@ -205,6 +213,24 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
 	c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
 	c->type = PM_QOS_MIN;
 
+	c = &qos->min_frequency;
+	plist_head_init(&c->list);
+	c->target_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+	c->default_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+	c->type = PM_QOS_MAX;
+	c->notifiers = ++n;
+	BLOCKING_INIT_NOTIFIER_HEAD(n);
+
+	c = &qos->max_frequency;
+	plist_head_init(&c->list);
+	c->target_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+	c->default_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+	c->type = PM_QOS_MIN;
+	c->notifiers = ++n;
+	BLOCKING_INIT_NOTIFIER_HEAD(n);
+
 	INIT_LIST_HEAD(&qos->flags.list);
 
 	spin_lock_irq(&dev->power.lock);
@@ -258,11 +284,25 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
 		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
 		memset(req, 0, sizeof(*req));
 	}
+
 	c = &qos->latency_tolerance;
 	plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
 		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
 		memset(req, 0, sizeof(*req));
 	}
+
+	c = &qos->min_frequency;
+	plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
+		memset(req, 0, sizeof(*req));
+	}
+
+	c = &qos->max_frequency;
+	plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
+		memset(req, 0, sizeof(*req));
+	}
+
 	f = &qos->flags;
 	list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
 		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -374,6 +414,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
 	switch(req->type) {
 	case DEV_PM_QOS_RESUME_LATENCY:
 	case DEV_PM_QOS_LATENCY_TOLERANCE:
+	case DEV_PM_QOS_MIN_FREQUENCY:
+	case DEV_PM_QOS_MAX_FREQUENCY:
 		curr_value = req->data.pnode.prio;
 		break;
 	case DEV_PM_QOS_FLAGS:
@@ -486,9 +528,6 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
 {
 	int ret = 0;
 
-	if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY))
-		return -EINVAL;
-
 	mutex_lock(&dev_pm_qos_mtx);
 
 	if (IS_ERR(dev->power.qos))
@@ -496,10 +535,28 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
 	else if (!dev->power.qos)
 		ret = dev_pm_qos_constraints_allocate(dev);
 
-	if (!ret)
+	if (ret)
+		goto unlock;
+
+	switch (type) {
+	case DEV_PM_QOS_RESUME_LATENCY:
 		ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
 						       notifier);
+		break;
+	case DEV_PM_QOS_MIN_FREQUENCY:
+		ret = blocking_notifier_chain_register(dev->power.qos->min_frequency.notifiers,
+						       notifier);
+		break;
+	case DEV_PM_QOS_MAX_FREQUENCY:
+		ret = blocking_notifier_chain_register(dev->power.qos->max_frequency.notifiers,
+						       notifier);
+		break;
+	default:
+		WARN_ON(1);
+		ret = -EINVAL;
+	}
 
+unlock:
 	mutex_unlock(&dev_pm_qos_mtx);
 	return ret;
 }
@@ -520,20 +577,35 @@ int dev_pm_qos_remove_notifier(struct device *dev,
 			       struct notifier_block *notifier,
 			       enum dev_pm_qos_req_type type)
 {
-	int retval = 0;
-
-	if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY))
-		return -EINVAL;
+	int ret = 0;
 
 	mutex_lock(&dev_pm_qos_mtx);
 
 	/* Silently return if the constraints object is not present. */
-	if (!IS_ERR_OR_NULL(dev->power.qos))
-		retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
-							    notifier);
+	if (IS_ERR_OR_NULL(dev->power.qos))
+		goto unlock;
 
+	switch (type) {
+	case DEV_PM_QOS_RESUME_LATENCY:
+		ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
+							 notifier);
+		break;
+	case DEV_PM_QOS_MIN_FREQUENCY:
+		ret = blocking_notifier_chain_unregister(dev->power.qos->min_frequency.notifiers,
+							 notifier);
+		break;
+	case DEV_PM_QOS_MAX_FREQUENCY:
+		ret = blocking_notifier_chain_unregister(dev->power.qos->max_frequency.notifiers,
+							 notifier);
+		break;
+	default:
+		WARN_ON(1);
+		ret = -EINVAL;
+	}
+
+unlock:
 	mutex_unlock(&dev_pm_qos_mtx);
-	return retval;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
 
@@ -593,6 +665,9 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
 		req = dev->power.qos->flags_req;
 		dev->power.qos->flags_req = NULL;
 		break;
+	default:
+		WARN_ON(1);
+		return;
 	}
 	__dev_pm_qos_remove_request(req);
 	kfree(req);
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 55814d48c39c..3f994283a5ae 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -40,6 +40,8 @@ enum pm_qos_flags_status {
 #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_MIN_FREQUENCY_DEFAULT_VALUE	0
+#define PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE	(-1)
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
 
 #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
@@ -58,6 +60,8 @@ struct pm_qos_flags_request {
 enum dev_pm_qos_req_type {
 	DEV_PM_QOS_RESUME_LATENCY = 1,
 	DEV_PM_QOS_LATENCY_TOLERANCE,
+	DEV_PM_QOS_MIN_FREQUENCY,
+	DEV_PM_QOS_MAX_FREQUENCY,
 	DEV_PM_QOS_FLAGS,
 };
 
@@ -99,10 +103,14 @@ struct pm_qos_flags {
 struct dev_pm_qos {
 	struct pm_qos_constraints resume_latency;
 	struct pm_qos_constraints latency_tolerance;
+	struct pm_qos_constraints min_frequency;
+	struct pm_qos_constraints max_frequency;
 	struct pm_qos_flags flags;
 	struct dev_pm_qos_request *resume_latency_req;
 	struct dev_pm_qos_request *latency_tolerance_req;
 	struct dev_pm_qos_request *flags_req;
+	struct dev_pm_qos_request *min_frequency_req;
+	struct dev_pm_qos_request *max_frequency_req;
 };
 
 /* Action requested to pm_qos_update_target */
@@ -185,6 +193,12 @@ static inline s32 dev_pm_qos_raw_read_value(struct device *dev,
 	case DEV_PM_QOS_RESUME_LATENCY:
 		return IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
 			: pm_qos_read_value(&qos->resume_latency);
+	case DEV_PM_QOS_MIN_FREQUENCY:
+		return IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
+			: pm_qos_read_value(&qos->min_frequency);
+	case DEV_PM_QOS_MAX_FREQUENCY:
+		return IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
+			: pm_qos_read_value(&qos->max_frequency);
 	default:
 		WARN_ON(1);
 		return 0;
@@ -256,6 +270,10 @@ static inline s32 dev_pm_qos_raw_read_value(struct device *dev,
 	switch type {
 	case DEV_PM_QOS_RESUME_LATENCY:
 		return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+	case DEV_PM_QOS_MIN_FREQUENCY:
+		return PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+	case DEV_PM_QOS_MAX_FREQUENCY:
+		return PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
 	default:
 		WARN_ON(1);
 		return 0;
-- 
2.21.0.rc0.269.g1a574e7a288b


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

* [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-21 11:29 [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Viresh Kumar
                   ` (2 preceding siblings ...)
  2019-02-21 11:29 ` [PATCH V2 3/5] PM / QoS: Add support for MIN/MAX frequency constraints Viresh Kumar
@ 2019-02-21 11:29 ` Viresh Kumar
  2019-02-22 11:44   ` Qais Yousef
  2019-02-21 11:29 ` [PATCH V2 5/5] cpufreq: Add QoS requests for userspace constraints Viresh Kumar
  2019-02-21 11:30 ` [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Rafael J. Wysocki
  5 siblings, 1 reply; 16+ messages in thread
From: Viresh Kumar @ 2019-02-21 11:29 UTC (permalink / raw)
  To: Rafael Wysocki
  Cc: Viresh Kumar, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

This registers the notifiers for min/max frequency constraints with the
PM QoS framework. The constraints are also taken into consideration in
cpufreq_set_policy().

This also relocates cpufreq_policy_put_kobj() as it is required to be
called from cpufreq_policy_alloc() now.

No constraints are added until now though.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/cpufreq/cpufreq.c | 135 +++++++++++++++++++++++++++++++-------
 include/linux/cpufreq.h   |   4 ++
 2 files changed, 116 insertions(+), 23 deletions(-)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 0e626b00053b..d615bf35ac00 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -26,6 +26,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/pm_qos.h>
 #include <linux/slab.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
@@ -1082,11 +1083,77 @@ static void handle_update(struct work_struct *work)
 	cpufreq_update_policy(cpu);
 }
 
+static void cpufreq_update_freq_work(struct work_struct *work)
+{
+	struct cpufreq_policy *policy =
+		container_of(work, struct cpufreq_policy, req_work);
+	struct cpufreq_policy new_policy = *policy;
+
+	/* We should read constraint values from QoS layer */
+	new_policy.min = 0;
+	new_policy.max = UINT_MAX;
+
+	down_write(&policy->rwsem);
+
+	if (!policy_is_inactive(policy))
+		cpufreq_set_policy(policy, &new_policy);
+
+	up_write(&policy->rwsem);
+}
+
+static int cpufreq_update_freq(struct cpufreq_policy *policy)
+{
+	schedule_work(&policy->req_work);
+	return 0;
+}
+
+static int cpufreq_notifier_min(struct notifier_block *nb, unsigned long freq,
+				void *data)
+{
+	struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_min);
+
+	return cpufreq_update_freq(policy);
+}
+
+static int cpufreq_notifier_max(struct notifier_block *nb, unsigned long freq,
+				void *data)
+{
+	struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_max);
+
+	return cpufreq_update_freq(policy);
+}
+
+static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
+{
+	struct kobject *kobj;
+	struct completion *cmp;
+
+	down_write(&policy->rwsem);
+	cpufreq_stats_free_table(policy);
+	kobj = &policy->kobj;
+	cmp = &policy->kobj_unregister;
+	up_write(&policy->rwsem);
+	kobject_put(kobj);
+
+	/*
+	 * We need to make sure that the underlying kobj is
+	 * actually not referenced anymore by anybody before we
+	 * proceed with unloading.
+	 */
+	pr_debug("waiting for dropping of refcount\n");
+	wait_for_completion(cmp);
+	pr_debug("wait complete\n");
+}
+
 static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
 {
 	struct cpufreq_policy *policy;
+	struct device *dev = get_cpu_device(cpu);
 	int ret;
 
+	if (!dev)
+		return NULL;
+
 	policy = kzalloc(sizeof(*policy), GFP_KERNEL);
 	if (!policy)
 		return NULL;
@@ -1103,20 +1170,45 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
 	ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
 				   cpufreq_global_kobject, "policy%u", cpu);
 	if (ret) {
-		pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
+		dev_err(dev, "%s: failed to init policy->kobj: %d\n", __func__, ret);
 		goto err_free_real_cpus;
 	}
 
+	policy->nb_min.notifier_call = cpufreq_notifier_min;
+	policy->nb_max.notifier_call = cpufreq_notifier_max;
+
+	ret = dev_pm_qos_add_notifier(dev, &policy->nb_min,
+				      DEV_PM_QOS_MIN_FREQUENCY);
+	if (ret) {
+		dev_err(dev, "Failed to register MIN QoS notifier: %d (%*pbl)\n",
+			ret, cpumask_pr_args(policy->cpus));
+		goto err_kobj_remove;
+	}
+
+	ret = dev_pm_qos_add_notifier(dev, &policy->nb_max,
+				      DEV_PM_QOS_MAX_FREQUENCY);
+	if (ret) {
+		dev_err(dev, "Failed to register MAX QoS notifier: %d (%*pbl)\n",
+			ret, cpumask_pr_args(policy->cpus));
+		goto err_min_qos_notifier;
+	}
+
 	INIT_LIST_HEAD(&policy->policy_list);
 	init_rwsem(&policy->rwsem);
 	spin_lock_init(&policy->transition_lock);
 	init_waitqueue_head(&policy->transition_wait);
 	init_completion(&policy->kobj_unregister);
 	INIT_WORK(&policy->update, handle_update);
+	INIT_WORK(&policy->req_work, cpufreq_update_freq_work);
 
 	policy->cpu = cpu;
 	return policy;
 
+err_min_qos_notifier:
+	dev_pm_qos_remove_notifier(dev, &policy->nb_min,
+				   DEV_PM_QOS_MIN_FREQUENCY);
+err_kobj_remove:
+	cpufreq_policy_put_kobj(policy);
 err_free_real_cpus:
 	free_cpumask_var(policy->real_cpus);
 err_free_rcpumask:
@@ -1129,30 +1221,9 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
 	return NULL;
 }
 
-static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
-{
-	struct kobject *kobj;
-	struct completion *cmp;
-
-	down_write(&policy->rwsem);
-	cpufreq_stats_free_table(policy);
-	kobj = &policy->kobj;
-	cmp = &policy->kobj_unregister;
-	up_write(&policy->rwsem);
-	kobject_put(kobj);
-
-	/*
-	 * We need to make sure that the underlying kobj is
-	 * actually not referenced anymore by anybody before we
-	 * proceed with unloading.
-	 */
-	pr_debug("waiting for dropping of refcount\n");
-	wait_for_completion(cmp);
-	pr_debug("wait complete\n");
-}
-
 static void cpufreq_policy_free(struct cpufreq_policy *policy)
 {
+	struct device *dev = get_cpu_device(policy->cpu);
 	unsigned long flags;
 	int cpu;
 
@@ -1164,6 +1235,10 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
 		per_cpu(cpufreq_cpu_data, cpu) = NULL;
 	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
+	dev_pm_qos_remove_notifier(dev, &policy->nb_max,
+				   DEV_PM_QOS_MAX_FREQUENCY);
+	dev_pm_qos_remove_notifier(dev, &policy->nb_min,
+				   DEV_PM_QOS_MIN_FREQUENCY);
 	cpufreq_policy_put_kobj(policy);
 	free_cpumask_var(policy->real_cpus);
 	free_cpumask_var(policy->related_cpus);
@@ -2239,6 +2314,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 			      struct cpufreq_policy *new_policy)
 {
 	struct cpufreq_governor *old_gov;
+	struct device *cpu_dev = get_cpu_device(policy->cpu);
+	unsigned long min, max;
 	int ret;
 
 	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
@@ -2253,11 +2330,23 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 	if (new_policy->min > new_policy->max)
 		return -EINVAL;
 
+	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
+	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
+
+	if (min > new_policy->min)
+		new_policy->min = min;
+	if (max < new_policy->max)
+		new_policy->max = max;
+
 	/* verify the cpu speed can be set within this limit */
 	ret = cpufreq_driver->verify(new_policy);
 	if (ret)
 		return ret;
 
+	/*
+	 * The notifier-chain shall be removed once all the users of
+	 * CPUFREQ_ADJUST are moved to use the QoS framework.
+	 */
 	/* adjust if necessary - all reasons */
 	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
 			CPUFREQ_ADJUST, new_policy);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index b160e98076e3..f8f48d8a9b52 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -90,6 +90,7 @@ struct cpufreq_policy {
 
 	struct work_struct	update; /* if update_policy() needs to be
 					 * called, but you're in IRQ context */
+	struct work_struct	req_work;
 
 	struct cpufreq_user_policy user_policy;
 	struct cpufreq_frequency_table	*freq_table;
@@ -154,6 +155,9 @@ struct cpufreq_policy {
 
 	/* Pointer to the cooling device if used for thermal mitigation */
 	struct thermal_cooling_device *cdev;
+
+	struct notifier_block nb_min;
+	struct notifier_block nb_max;
 };
 
 /* Only for ACPI */
-- 
2.21.0.rc0.269.g1a574e7a288b


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

* [PATCH V2 5/5] cpufreq: Add QoS requests for userspace constraints
  2019-02-21 11:29 [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Viresh Kumar
                   ` (3 preceding siblings ...)
  2019-02-21 11:29 ` [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework Viresh Kumar
@ 2019-02-21 11:29 ` Viresh Kumar
  2019-02-21 11:30 ` [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Rafael J. Wysocki
  5 siblings, 0 replies; 16+ messages in thread
From: Viresh Kumar @ 2019-02-21 11:29 UTC (permalink / raw)
  To: Rafael Wysocki
  Cc: Viresh Kumar, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

This implements QoS requests to manage userspace configuration of min
and max frequency.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/cpufreq/cpufreq.c | 93 +++++++++++++++++++--------------------
 include/linux/cpufreq.h   |  8 +---
 2 files changed, 48 insertions(+), 53 deletions(-)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index d615bf35ac00..403e4540aea7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -686,23 +686,15 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 static ssize_t store_##file_name					\
 (struct cpufreq_policy *policy, const char *buf, size_t count)		\
 {									\
-	int ret, temp;							\
-	struct cpufreq_policy new_policy;				\
+	unsigned long val;						\
+	int ret;							\
 									\
-	memcpy(&new_policy, policy, sizeof(*policy));			\
-	new_policy.min = policy->user_policy.min;			\
-	new_policy.max = policy->user_policy.max;			\
-									\
-	ret = sscanf(buf, "%u", &new_policy.object);			\
+	ret = sscanf(buf, "%lu", &val);					\
 	if (ret != 1)							\
 		return -EINVAL;						\
 									\
-	temp = new_policy.object;					\
-	ret = cpufreq_set_policy(policy, &new_policy);		\
-	if (!ret)							\
-		policy->user_policy.object = temp;			\
-									\
-	return ret ? ret : count;					\
+	ret = dev_pm_qos_update_request(policy->object##_freq_req, val);\
+	return ret && ret != 1 ? ret : count;				\
 }
 
 store_one(scaling_min_freq, min);
@@ -1089,10 +1081,6 @@ static void cpufreq_update_freq_work(struct work_struct *work)
 		container_of(work, struct cpufreq_policy, req_work);
 	struct cpufreq_policy new_policy = *policy;
 
-	/* We should read constraint values from QoS layer */
-	new_policy.min = 0;
-	new_policy.max = UINT_MAX;
-
 	down_write(&policy->rwsem);
 
 	if (!policy_is_inactive(policy))
@@ -1193,6 +1181,12 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
 		goto err_min_qos_notifier;
 	}
 
+	policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req),
+				       GFP_KERNEL);
+	if (!policy->min_freq_req)
+		goto err_max_qos_notifier;
+
+	policy->max_freq_req = policy->min_freq_req + 1;
 	INIT_LIST_HEAD(&policy->policy_list);
 	init_rwsem(&policy->rwsem);
 	spin_lock_init(&policy->transition_lock);
@@ -1204,6 +1198,9 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
 	policy->cpu = cpu;
 	return policy;
 
+err_max_qos_notifier:
+	dev_pm_qos_remove_notifier(dev, &policy->nb_max,
+				   DEV_PM_QOS_MAX_FREQUENCY);
 err_min_qos_notifier:
 	dev_pm_qos_remove_notifier(dev, &policy->nb_min,
 				   DEV_PM_QOS_MIN_FREQUENCY);
@@ -1239,6 +1236,10 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
 				   DEV_PM_QOS_MAX_FREQUENCY);
 	dev_pm_qos_remove_notifier(dev, &policy->nb_min,
 				   DEV_PM_QOS_MIN_FREQUENCY);
+	dev_pm_qos_remove_request(policy->max_freq_req);
+	dev_pm_qos_remove_request(policy->min_freq_req);
+	kfree(policy->min_freq_req);
+
 	cpufreq_policy_put_kobj(policy);
 	free_cpumask_var(policy->real_cpus);
 	free_cpumask_var(policy->related_cpus);
@@ -1316,16 +1317,30 @@ static int cpufreq_online(unsigned int cpu)
 	cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
 
 	if (new_policy) {
-		policy->user_policy.min = policy->min;
-		policy->user_policy.max = policy->max;
+		struct device *dev = get_cpu_device(cpu);
 
 		for_each_cpu(j, policy->related_cpus) {
 			per_cpu(cpufreq_cpu_data, j) = policy;
 			add_cpu_dev_symlink(policy, j);
 		}
-	} else {
-		policy->min = policy->user_policy.min;
-		policy->max = policy->user_policy.max;
+
+		ret = dev_pm_qos_add_request(dev, policy->min_freq_req,
+					     DEV_PM_QOS_MIN_FREQUENCY,
+					     policy->min);
+		if (ret < 0) {
+			dev_err(dev, "Failed to add min-freq constraint (%d)\n",
+				ret);
+			goto out_destroy_policy;
+		}
+
+		ret = dev_pm_qos_add_request(dev, policy->max_freq_req,
+					     DEV_PM_QOS_MAX_FREQUENCY,
+					     policy->max);
+		if (ret < 0) {
+			dev_err(dev, "Failed to add max-freq constraint (%d)\n",
+				ret);
+			goto out_destroy_policy;
+		}
 	}
 
 	if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
@@ -2315,7 +2330,6 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 {
 	struct cpufreq_governor *old_gov;
 	struct device *cpu_dev = get_cpu_device(policy->cpu);
-	unsigned long min, max;
 	int ret;
 
 	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
@@ -2323,20 +2337,9 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 
 	memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
-	/*
-	* This check works well when we store new min/max freq attributes,
-	* because new_policy is a copy of policy with one field updated.
-	*/
-	if (new_policy->min > new_policy->max)
-		return -EINVAL;
-
-	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
-	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
-
-	if (min > new_policy->min)
-		new_policy->min = min;
-	if (max < new_policy->max)
-		new_policy->max = max;
+	/* Start with min/max as seen by QoS framework */
+	new_policy->min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
+	new_policy->max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
 
 	/* verify the cpu speed can be set within this limit */
 	ret = cpufreq_driver->verify(new_policy);
@@ -2425,10 +2428,9 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
  * @cpu: CPU to re-evaluate the policy for.
  *
  * Update the current frequency for the cpufreq policy of @cpu and use
- * cpufreq_set_policy() to re-apply the min and max limits saved in the
- * user_policy sub-structure of that policy, which triggers the evaluation
- * of policy notifiers and the cpufreq driver's ->verify() callback for the
- * policy in question, among other things.
+ * cpufreq_set_policy() to re-apply the min and max limits, which triggers the
+ * evaluation of policy notifiers and the cpufreq driver's ->verify() callback
+ * for the policy in question, among other things.
  */
 void cpufreq_update_policy(unsigned int cpu)
 {
@@ -2453,8 +2455,6 @@ void cpufreq_update_policy(unsigned int cpu)
 
 	pr_debug("updating policy for CPU %u\n", cpu);
 	memcpy(&new_policy, policy, sizeof(*policy));
-	new_policy.min = policy->user_policy.min;
-	new_policy.max = policy->user_policy.max;
 
 	cpufreq_set_policy(policy, &new_policy);
 
@@ -2485,10 +2485,9 @@ static int cpufreq_boost_set_sw(int state)
 			break;
 		}
 
-		down_write(&policy->rwsem);
-		policy->user_policy.max = policy->max;
-		cpufreq_governor_limits(policy);
-		up_write(&policy->rwsem);
+		ret = dev_pm_qos_update_request(policy->max_freq_req, policy->max);
+		if (ret)
+			break;
 	}
 
 	return ret;
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index f8f48d8a9b52..fc167a982c64 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -57,11 +57,6 @@ struct cpufreq_cpuinfo {
 	unsigned int		transition_latency;
 };
 
-struct cpufreq_user_policy {
-	unsigned int		min;    /* in kHz */
-	unsigned int		max;    /* in kHz */
-};
-
 struct cpufreq_policy {
 	/* CPUs sharing clock, require sw coordination */
 	cpumask_var_t		cpus;	/* Online CPUs only */
@@ -92,7 +87,8 @@ struct cpufreq_policy {
 					 * called, but you're in IRQ context */
 	struct work_struct	req_work;
 
-	struct cpufreq_user_policy user_policy;
+	struct dev_pm_qos_request *min_freq_req;
+	struct dev_pm_qos_request *max_freq_req;
 	struct cpufreq_frequency_table	*freq_table;
 	enum cpufreq_table_sorting freq_table_sorted;
 
-- 
2.21.0.rc0.269.g1a574e7a288b


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

* Re: [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints
  2019-02-21 11:29 [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Viresh Kumar
                   ` (4 preceding siblings ...)
  2019-02-21 11:29 ` [PATCH V2 5/5] cpufreq: Add QoS requests for userspace constraints Viresh Kumar
@ 2019-02-21 11:30 ` Rafael J. Wysocki
  2019-04-08 10:46   ` Viresh Kumar
  2019-05-20  6:16   ` Viresh Kumar
  5 siblings, 2 replies; 16+ messages in thread
From: Rafael J. Wysocki @ 2019-02-21 11:30 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Daniel Lezcano, Kevin Hilman, Len Brown, Pavel Machek,
	Ulf Hansson, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

On Thursday, February 21, 2019 12:29:26 PM CET Viresh Kumar wrote:
> Hello,
> 
> This patchset attempts to manage CPU frequency constraints using the PM
> QoS framework. It only does the basic stuff right now and moves the
> userspace constraints to use the QoS infrastructure.
> 
> Todo:
> - Migrate all users to the QoS framework and get rid of cpufreq specific
>   notifiers.
> - Make PM QoS learn about the relation of CPUs in a policy, so a single
>   list of constraints is managed for all of them instead of per-cpu
>   constraints.
> 
> V1->V2:
> - The previous version introduced a completely new framework, this one
>   moves to PM QoS instead.
> - Lots of changes because of this.

Well, thanks for working on this, but I'm rather unlikely to look at it in
detail before 5.1-rc1 is released.

Cheers,
Rafael


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

* Re: [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-21 11:29 ` [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework Viresh Kumar
@ 2019-02-22 11:44   ` Qais Yousef
  2019-02-25  4:31     ` Viresh Kumar
  0 siblings, 1 reply; 16+ messages in thread
From: Qais Yousef @ 2019-02-22 11:44 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Rafael Wysocki, linux-pm, Vincent Guittot, mka, juri.lelli, linux-kernel

Hi Verish

On 02/21/19 16:59, Viresh Kumar wrote:

[...]

> @@ -2239,6 +2314,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
>  			      struct cpufreq_policy *new_policy)
>  {
>  	struct cpufreq_governor *old_gov;
> +	struct device *cpu_dev = get_cpu_device(policy->cpu);
> +	unsigned long min, max;
>  	int ret;
>  
>  	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
> @@ -2253,11 +2330,23 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
>  	if (new_policy->min > new_policy->max)
>  		return -EINVAL;
>  
> +	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
> +	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
> +
> +	if (min > new_policy->min)
> +		new_policy->min = min;
> +	if (max < new_policy->max)
> +		new_policy->max = max;
> +

Assuming for example min and max range from 1-10, and thermal throttles max to
5 using pm_qos to deal with temporary thermal pressure. But shortly after
a driver thinks that max shouldn't be greater than 7 for one reason or another.

What will happen after thermal pressure removes its constraint? Will we still
remember the driver's request and apply it so max is set to 7 instead of 10?

Thanks

--
Qais Yousef

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

* Re: [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-22 11:44   ` Qais Yousef
@ 2019-02-25  4:31     ` Viresh Kumar
  2019-02-25  8:58       ` Qais Yousef
  0 siblings, 1 reply; 16+ messages in thread
From: Viresh Kumar @ 2019-02-25  4:31 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Rafael Wysocki, linux-pm, Vincent Guittot, mka, juri.lelli, linux-kernel

On 22-02-19, 11:44, Qais Yousef wrote:
> Hi Verish
> 
> On 02/21/19 16:59, Viresh Kumar wrote:
> 
> [...]
> 
> > @@ -2239,6 +2314,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
> >  			      struct cpufreq_policy *new_policy)
> >  {
> >  	struct cpufreq_governor *old_gov;
> > +	struct device *cpu_dev = get_cpu_device(policy->cpu);
> > +	unsigned long min, max;
> >  	int ret;
> >  
> >  	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
> > @@ -2253,11 +2330,23 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
> >  	if (new_policy->min > new_policy->max)
> >  		return -EINVAL;
> >  
> > +	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
> > +	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
> > +
> > +	if (min > new_policy->min)
> > +		new_policy->min = min;
> > +	if (max < new_policy->max)
> > +		new_policy->max = max;
> > +
> 
> Assuming for example min and max range from 1-10, and thermal throttles max to
> 5 using pm_qos to deal with temporary thermal pressure. But shortly after
> a driver thinks that max shouldn't be greater than 7 for one reason or another.
> 
> What will happen after thermal pressure removes its constraint? Will we still
> remember the driver's request and apply it so max is set to 7 instead of 10?

Once everything comes via PM QoS, it will remember all the presently available
requests and choose a target min/max frequency based on that.

But even with this patchset, with half stuff done with PM QoS and half done with
cpufreq notifiers, it should still work that way only.

-- 
viresh

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

* Re: [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-25  4:31     ` Viresh Kumar
@ 2019-02-25  8:58       ` Qais Yousef
  2019-02-25  9:09         ` Viresh Kumar
  0 siblings, 1 reply; 16+ messages in thread
From: Qais Yousef @ 2019-02-25  8:58 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Rafael Wysocki, linux-pm, Vincent Guittot, mka, juri.lelli, linux-kernel

On 02/25/19 10:01, Viresh Kumar wrote:
> On 22-02-19, 11:44, Qais Yousef wrote:
> > Hi Verish
> > 
> > On 02/21/19 16:59, Viresh Kumar wrote:
> > 
> > [...]
> > 
> > > @@ -2239,6 +2314,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
> > >  			      struct cpufreq_policy *new_policy)
> > >  {
> > >  	struct cpufreq_governor *old_gov;
> > > +	struct device *cpu_dev = get_cpu_device(policy->cpu);
> > > +	unsigned long min, max;
> > >  	int ret;
> > >  
> > >  	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
> > > @@ -2253,11 +2330,23 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
> > >  	if (new_policy->min > new_policy->max)
> > >  		return -EINVAL;
> > >  
> > > +	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
> > > +	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
> > > +
> > > +	if (min > new_policy->min)
> > > +		new_policy->min = min;
> > > +	if (max < new_policy->max)
> > > +		new_policy->max = max;
> > > +
> > 
> > Assuming for example min and max range from 1-10, and thermal throttles max to
> > 5 using pm_qos to deal with temporary thermal pressure. But shortly after
> > a driver thinks that max shouldn't be greater than 7 for one reason or another.
> > 
> > What will happen after thermal pressure removes its constraint? Will we still
> > remember the driver's request and apply it so max is set to 7 instead of 10?
> 
> Once everything comes via PM QoS, it will remember all the presently available
> requests and choose a target min/max frequency based on that.

OK I can see the logic now in kernel/power/qos.c now. Sorry I missed it and it
was easier to ask :-)

> 
> But even with this patchset, with half stuff done with PM QoS and half done with
> cpufreq notifiers, it should still work that way only.

And this is why we need to check here if the PM QoS value doesn't conflict with
the current min/max, right? Until the current notifier code is removed they
could trip over each others.

It would be nice to add a comment here about PM QoS managing and remembering
values and that we need to be careful that both mechanisms don't trip over
each others until this transient period is over.

I have a nit too. It would be nice to explicitly state this is
CPU_{MIN,MAX}_FREQUENCY. I can see someone else adding {MIN,MAX}_FREQUENCY for
something elsee (memory maybe?)

Although I looked at the previous series briefly, but this one looks more
compact and easier to follow, so +1 for that.

--
Qais Yousef

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

* Re: [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-25  8:58       ` Qais Yousef
@ 2019-02-25  9:09         ` Viresh Kumar
  2019-02-25 12:14           ` Qais Yousef
  0 siblings, 1 reply; 16+ messages in thread
From: Viresh Kumar @ 2019-02-25  9:09 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Rafael Wysocki, linux-pm, Vincent Guittot, mka, juri.lelli, linux-kernel

On 25-02-19, 08:58, Qais Yousef wrote:
> On 02/25/19 10:01, Viresh Kumar wrote:
> > > > +	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
> > > > +	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
> > > > +
> > > > +	if (min > new_policy->min)
> > > > +		new_policy->min = min;
> > > > +	if (max < new_policy->max)
> > > > +		new_policy->max = max;

> And this is why we need to check here if the PM QoS value doesn't conflict with
> the current min/max, right? Until the current notifier code is removed they
> could trip over each others.

No. The above if/else block is already removed as part of patch 5/5. It was
required because of conflict between userspace specific min/max and qos min/max,
which are migrated to use qos by patc 5/5.

The cpufreq notifier mechanism already lets users play with min/max and that is
already safe from conflicts.


> It would be nice to add a comment here about PM QoS managing and remembering
> values

I am not sure if that would add any value. Some documentation update may be
useful for people looking for details though, that I shall do after all the
changes get in and things become a bit stable.

> and that we need to be careful that both mechanisms don't trip over
> each others until this transient period is over.

The second mechanism will die very very soon once this is merged, migrating them
shouldn't be a big challenge AFAICT. I didn't attempt that because I didn't
wanted to waste time updating things in case this version also doesn't make
sense to others.

> I have a nit too. It would be nice to explicitly state this is
> CPU_{MIN,MAX}_FREQUENCY. I can see someone else adding {MIN,MAX}_FREQUENCY for
> something elsee (memory maybe?)

This is not CPU specific, but any device. The same interface shall be used by
devfreq as well, who wanted to use freq-constraints initially.

> Although I looked at the previous series briefly, but this one looks more
> compact and easier to follow, so +1 for that.

Thanks for looking into this Qais.

-- 
viresh

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

* Re: [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-25  9:09         ` Viresh Kumar
@ 2019-02-25 12:14           ` Qais Yousef
  2019-02-26  2:30             ` Viresh Kumar
  0 siblings, 1 reply; 16+ messages in thread
From: Qais Yousef @ 2019-02-25 12:14 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Rafael Wysocki, linux-pm, Vincent Guittot, mka, juri.lelli, linux-kernel

On 02/25/19 14:39, Viresh Kumar wrote:
> On 25-02-19, 08:58, Qais Yousef wrote:
> > On 02/25/19 10:01, Viresh Kumar wrote:
> > > > > +	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
> > > > > +	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
> > > > > +
> > > > > +	if (min > new_policy->min)
> > > > > +		new_policy->min = min;
> > > > > +	if (max < new_policy->max)
> > > > > +		new_policy->max = max;
> 
> > And this is why we need to check here if the PM QoS value doesn't conflict with
> > the current min/max, right? Until the current notifier code is removed they
> > could trip over each others.
> 
> No. The above if/else block is already removed as part of patch 5/5. It was
> required because of conflict between userspace specific min/max and qos min/max,
> which are migrated to use qos by patc 5/5.
> 
> The cpufreq notifier mechanism already lets users play with min/max and that is
> already safe from conflicts.
> 
> 
> > It would be nice to add a comment here about PM QoS managing and remembering
> > values
> 
> I am not sure if that would add any value. Some documentation update may be
> useful for people looking for details though, that I shall do after all the
> changes get in and things become a bit stable.
> 

Up to you. But not everyone is familiar with the code and a one line comment
that points to where aggregation is happening would be helpful for someone
scanning this code IMHO.

> > and that we need to be careful that both mechanisms don't trip over
> > each others until this transient period is over.
> 
> The second mechanism will die very very soon once this is merged, migrating them
> shouldn't be a big challenge AFAICT. I didn't attempt that because I didn't
> wanted to waste time updating things in case this version also doesn't make
> sense to others.
> 
> > I have a nit too. It would be nice to explicitly state this is
> > CPU_{MIN,MAX}_FREQUENCY. I can see someone else adding {MIN,MAX}_FREQUENCY for
> > something elsee (memory maybe?)
> 
> This is not CPU specific, but any device. The same interface shall be used by
> devfreq as well, who wanted to use freq-constraints initially.
> 

I don't get that to be honest. I probably have to read more.

Is what you're saying that when applying a MIN_FREQUENCY constraint the same
value will be applied to both cpufreq and devfreq? Isn't this too coarse?

> > Although I looked at the previous series briefly, but this one looks more
> > compact and easier to follow, so +1 for that.
> 
> Thanks for looking into this Qais.
> 
> -- 
> viresh

Thanks

--
Qais Yousef

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

* Re: [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-25 12:14           ` Qais Yousef
@ 2019-02-26  2:30             ` Viresh Kumar
  2019-02-26 10:00               ` Qais Yousef
  0 siblings, 1 reply; 16+ messages in thread
From: Viresh Kumar @ 2019-02-26  2:30 UTC (permalink / raw)
  To: Qais Yousef
  Cc: Rafael Wysocki, linux-pm, Vincent Guittot, mka, juri.lelli, linux-kernel

On 25-02-19, 12:14, Qais Yousef wrote:
> On 02/25/19 14:39, Viresh Kumar wrote:
> > On 25-02-19, 08:58, Qais Yousef wrote:
> > > On 02/25/19 10:01, Viresh Kumar wrote:
> > > > > > +	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
> > > > > > +	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
> > > > > > +
> > > > > > +	if (min > new_policy->min)
> > > > > > +		new_policy->min = min;
> > > > > > +	if (max < new_policy->max)
> > > > > > +		new_policy->max = max;
> > 
> > > And this is why we need to check here if the PM QoS value doesn't conflict with
> > > the current min/max, right? Until the current notifier code is removed they
> > > could trip over each others.
> > 
> > No. The above if/else block is already removed as part of patch 5/5. It was
> > required because of conflict between userspace specific min/max and qos min/max,
> > which are migrated to use qos by patc 5/5.
> > 
> > The cpufreq notifier mechanism already lets users play with min/max and that is
> > already safe from conflicts.
> > 
> > 
> > > It would be nice to add a comment here about PM QoS managing and remembering
> > > values
> > 
> > I am not sure if that would add any value. Some documentation update may be
> > useful for people looking for details though, that I shall do after all the
> > changes get in and things become a bit stable.
> > 
> 
> Up to you. But not everyone is familiar with the code and a one line comment
> that points to where aggregation is happening would be helpful for someone
> scanning this code IMHO.

Okay, will add something then.

> > > and that we need to be careful that both mechanisms don't trip over
> > > each others until this transient period is over.
> > 
> > The second mechanism will die very very soon once this is merged, migrating them
> > shouldn't be a big challenge AFAICT. I didn't attempt that because I didn't
> > wanted to waste time updating things in case this version also doesn't make
> > sense to others.
> > 
> > > I have a nit too. It would be nice to explicitly state this is
> > > CPU_{MIN,MAX}_FREQUENCY. I can see someone else adding {MIN,MAX}_FREQUENCY for
> > > something elsee (memory maybe?)
> > 
> > This is not CPU specific, but any device. The same interface shall be used by
> > devfreq as well, who wanted to use freq-constraints initially.
> > 
> 
> I don't get that to be honest. I probably have to read more.
> 
> Is what you're saying that when applying a MIN_FREQUENCY constraint the same
> value will be applied to both cpufreq and devfreq? Isn't this too coarse?

Oh no. A constraint with QoS is added like this:

        dev_pm_qos_add_request(dev, req, DEV_PM_QOS_MIN_FREQUENCY, min);

Now dev here can be any device struct, CPU's or GPU's or anything else. All the
MIN freq requests are stored/processed per device and for a CPU in cpufreq all
we will see is MIN requests for the CPUs. And so the macro is required to be a
bit generic and shouldn't have CPU word within it.

Hope I was able to clarify your doubt a bit. Thanks.

-- 
viresh

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

* Re: [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework
  2019-02-26  2:30             ` Viresh Kumar
@ 2019-02-26 10:00               ` Qais Yousef
  0 siblings, 0 replies; 16+ messages in thread
From: Qais Yousef @ 2019-02-26 10:00 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Rafael Wysocki, linux-pm, Vincent Guittot, mka, juri.lelli, linux-kernel

On 02/26/19 08:00, Viresh Kumar wrote:
> On 25-02-19, 12:14, Qais Yousef wrote:
> > On 02/25/19 14:39, Viresh Kumar wrote:
> > > On 25-02-19, 08:58, Qais Yousef wrote:
> > > > On 02/25/19 10:01, Viresh Kumar wrote:
> > > > > > > +	min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
> > > > > > > +	max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
> > > > > > > +
> > > > > > > +	if (min > new_policy->min)
> > > > > > > +		new_policy->min = min;
> > > > > > > +	if (max < new_policy->max)
> > > > > > > +		new_policy->max = max;
> > > 
> > > > And this is why we need to check here if the PM QoS value doesn't conflict with
> > > > the current min/max, right? Until the current notifier code is removed they
> > > > could trip over each others.
> > > 
> > > No. The above if/else block is already removed as part of patch 5/5. It was
> > > required because of conflict between userspace specific min/max and qos min/max,
> > > which are migrated to use qos by patc 5/5.
> > > 
> > > The cpufreq notifier mechanism already lets users play with min/max and that is
> > > already safe from conflicts.
> > > 
> > > 
> > > > It would be nice to add a comment here about PM QoS managing and remembering
> > > > values
> > > 
> > > I am not sure if that would add any value. Some documentation update may be
> > > useful for people looking for details though, that I shall do after all the
> > > changes get in and things become a bit stable.
> > > 
> > 
> > Up to you. But not everyone is familiar with the code and a one line comment
> > that points to where aggregation is happening would be helpful for someone
> > scanning this code IMHO.
> 
> Okay, will add something then.
> 
> > > > and that we need to be careful that both mechanisms don't trip over
> > > > each others until this transient period is over.
> > > 
> > > The second mechanism will die very very soon once this is merged, migrating them
> > > shouldn't be a big challenge AFAICT. I didn't attempt that because I didn't
> > > wanted to waste time updating things in case this version also doesn't make
> > > sense to others.
> > > 
> > > > I have a nit too. It would be nice to explicitly state this is
> > > > CPU_{MIN,MAX}_FREQUENCY. I can see someone else adding {MIN,MAX}_FREQUENCY for
> > > > something elsee (memory maybe?)
> > > 
> > > This is not CPU specific, but any device. The same interface shall be used by
> > > devfreq as well, who wanted to use freq-constraints initially.
> > > 
> > 
> > I don't get that to be honest. I probably have to read more.
> > 
> > Is what you're saying that when applying a MIN_FREQUENCY constraint the same
> > value will be applied to both cpufreq and devfreq? Isn't this too coarse?
> 
> Oh no. A constraint with QoS is added like this:
> 
>         dev_pm_qos_add_request(dev, req, DEV_PM_QOS_MIN_FREQUENCY, min);
> 
> Now dev here can be any device struct, CPU's or GPU's or anything else. All the
> MIN freq requests are stored/processed per device and for a CPU in cpufreq all
> we will see is MIN requests for the CPUs. And so the macro is required to be a
> bit generic and shouldn't have CPU word within it.
> 
> Hope I was able to clarify your doubt a bit. Thanks.

Ah I see yes it all makes sense now.

Thanks!

--
Qais Yousef

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

* Re: [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints
  2019-02-21 11:30 ` [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Rafael J. Wysocki
@ 2019-04-08 10:46   ` Viresh Kumar
  2019-05-20  6:16   ` Viresh Kumar
  1 sibling, 0 replies; 16+ messages in thread
From: Viresh Kumar @ 2019-04-08 10:46 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Daniel Lezcano, Kevin Hilman, Len Brown, Pavel Machek,
	Ulf Hansson, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

On 21-02-19, 12:30, Rafael J. Wysocki wrote:
> On Thursday, February 21, 2019 12:29:26 PM CET Viresh Kumar wrote:
> > Hello,
> > 
> > This patchset attempts to manage CPU frequency constraints using the PM
> > QoS framework. It only does the basic stuff right now and moves the
> > userspace constraints to use the QoS infrastructure.
> > 
> > Todo:
> > - Migrate all users to the QoS framework and get rid of cpufreq specific
> >   notifiers.
> > - Make PM QoS learn about the relation of CPUs in a policy, so a single
> >   list of constraints is managed for all of them instead of per-cpu
> >   constraints.
> > 
> > V1->V2:
> > - The previous version introduced a completely new framework, this one
> >   moves to PM QoS instead.
> > - Lots of changes because of this.
> 
> Well, thanks for working on this, but I'm rather unlikely to look at it in
> detail before 5.1-rc1 is released.

Ping!

-- 
viresh

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

* Re: [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints
  2019-02-21 11:30 ` [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Rafael J. Wysocki
  2019-04-08 10:46   ` Viresh Kumar
@ 2019-05-20  6:16   ` Viresh Kumar
  1 sibling, 0 replies; 16+ messages in thread
From: Viresh Kumar @ 2019-05-20  6:16 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Daniel Lezcano, Kevin Hilman, Len Brown, Pavel Machek,
	Ulf Hansson, linux-pm, Vincent Guittot, mka, juri.lelli,
	Qais.Yousef, linux-kernel

On 21-02-19, 12:30, Rafael J. Wysocki wrote:
> On Thursday, February 21, 2019 12:29:26 PM CET Viresh Kumar wrote:
> > Hello,
> > 
> > This patchset attempts to manage CPU frequency constraints using the PM
> > QoS framework. It only does the basic stuff right now and moves the
> > userspace constraints to use the QoS infrastructure.
> > 
> > Todo:
> > - Migrate all users to the QoS framework and get rid of cpufreq specific
> >   notifiers.
> > - Make PM QoS learn about the relation of CPUs in a policy, so a single
> >   list of constraints is managed for all of them instead of per-cpu
> >   constraints.
> > 
> > V1->V2:
> > - The previous version introduced a completely new framework, this one
> >   moves to PM QoS instead.
> > - Lots of changes because of this.
> 
> Well, thanks for working on this, but I'm rather unlikely to look at it in
> detail before 5.1-rc1 is released.

Hi Rafael,

This series was posted almost 3 months back. Any comments on this would be very
helpful.

-- 
viresh

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

end of thread, other threads:[~2019-05-20  6:16 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-21 11:29 [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Viresh Kumar
2019-02-21 11:29 ` [PATCH V2 1/5] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier() Viresh Kumar
2019-02-21 11:29 ` [PATCH V2 2/5] PM / QOS: Pass request type to dev_pm_qos_read_value() Viresh Kumar
2019-02-21 11:29 ` [PATCH V2 3/5] PM / QoS: Add support for MIN/MAX frequency constraints Viresh Kumar
2019-02-21 11:29 ` [PATCH V2 4/5] cpufreq: Register notifiers with the PM QoS framework Viresh Kumar
2019-02-22 11:44   ` Qais Yousef
2019-02-25  4:31     ` Viresh Kumar
2019-02-25  8:58       ` Qais Yousef
2019-02-25  9:09         ` Viresh Kumar
2019-02-25 12:14           ` Qais Yousef
2019-02-26  2:30             ` Viresh Kumar
2019-02-26 10:00               ` Qais Yousef
2019-02-21 11:29 ` [PATCH V2 5/5] cpufreq: Add QoS requests for userspace constraints Viresh Kumar
2019-02-21 11:30 ` [PATCH V2 0/5] cpufreq: Use QoS layer to manage freq-constraints Rafael J. Wysocki
2019-04-08 10:46   ` Viresh Kumar
2019-05-20  6:16   ` Viresh Kumar

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.