linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] PM / Domains: Implement domain performance states
@ 2017-01-03 11:06 Viresh Kumar
  2017-01-03 11:06 ` [PATCH 1/6] PM / QOS: Add default case to the switch Viresh Kumar
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-03 11:06 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak, Viresh Kumar

Hi,

An earlier series[1] tried to implement bindings for PM domain
performance states. Rob Herring suggested that we can actually write the
supporting code first instead of bindings, as that will make things
easier to understand for all.

The bindings [1] aren't discarded yet and this series is based on a
version of those only. The bindings are only used by the last patch,
which should not be applied and is only sent for completeness.

All other patches can be reviewed/applied whenever the maintainers feel
they look good.


A brief summary of the problem this series is trying to solve:

Some platforms have the capability to configure the performance state of
their Power Domains. The performance levels are represented by positive
integer values, a lower value represents lower performance state.

We decided earlier that we should extend Power Domain framework to
support active state power management as well.  The power-domains until
now were only concentrating on the idle state management of the device
and this needs to change in order to reuse the infrastructure of power
domains for active state management.

The first 5 patches update the PM domain and QoS frameworks to support
that and the last one presents the front end interface to it.

All the patches are tested by hacking the OPP core a bit for now.

--
viresh

[1] https://marc.info/?l=linux-kernel&m=148154020127722&w=2

Viresh Kumar (6):
  PM / QOS: Add default case to the switch
  PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier()
  PM / QOS: Add 'performance' request
  PM / domain: Register for PM QOS performance notifier
  PM / domain: Save/restore performance state at runtime suspend/resume
  PM / OPP: Add support to parse domain-performance-state

 Documentation/power/pm_qos_interface.txt |  11 ++--
 drivers/base/power/domain.c              | 102 ++++++++++++++++++++++++++++---
 drivers/base/power/opp/core.c            |  75 +++++++++++++++++++++++
 drivers/base/power/opp/debugfs.c         |   4 ++
 drivers/base/power/opp/of.c              |  44 +++++++++++++
 drivers/base/power/opp/opp.h             |  12 ++++
 drivers/base/power/qos.c                 |  74 +++++++++++++++++++---
 include/linux/pm_domain.h                |   6 ++
 include/linux/pm_qos.h                   |  16 +++--
 9 files changed, 322 insertions(+), 22 deletions(-)

-- 
2.7.1.410.g6faf27b

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

* [PATCH 1/6] PM / QOS: Add default case to the switch
  2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
@ 2017-01-03 11:06 ` Viresh Kumar
  2017-01-03 11:06 ` [PATCH 2/6] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier() Viresh Kumar
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-03 11:06 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson, Pavel Machek, Len Brown
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak, Viresh Kumar

The switch block handles all the QOS request types present today, but
starts giving compilation warnings as soon as a new type is added and
not handled in this.

To prevent against that, add the default case as well and do a WARN from
it.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/base/power/qos.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 58fcc758334e..01f615b18055 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -621,6 +621,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);
-- 
2.7.1.410.g6faf27b

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

* [PATCH 2/6] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier()
  2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
  2017-01-03 11:06 ` [PATCH 1/6] PM / QOS: Add default case to the switch Viresh Kumar
@ 2017-01-03 11:06 ` Viresh Kumar
  2017-01-03 11:06 ` [PATCH 3/6] PM / QOS: Add 'performance' request Viresh Kumar
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-03 11:06 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson, Len Brown, Pavel Machek,
	Kevin Hilman
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak, Viresh Kumar

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 | 11 +++++++----
 drivers/base/power/domain.c              |  8 +++++---
 drivers/base/power/qos.c                 | 14 ++++++++++++--
 include/linux/pm_qos.h                   | 12 ++++++++----
 4 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index 129f7c0e1483..c7989d140428 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -166,12 +166,15 @@ under the device's power directory.
 The per-device PM QoS framework has 2 different and distinct notification trees:
 a per-device notification tree and a global 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. Currently it only supports the notifier to be registered for resume
+latency device PM QoS.
 
-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.
 
 int dev_pm_qos_add_global_notifier(notifier):
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 2997026b4dfb..12f16d9b6b55 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1203,7 +1203,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;
 }
@@ -1238,7 +1239,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);
 
@@ -1263,7 +1265,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 01f615b18055..9adc208cf1fc 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -481,6 +481,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.
@@ -488,10 +489,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))
@@ -514,15 +519,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 0f65d36c2a75..3b24f7d20299 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -144,9 +144,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);
 int dev_pm_qos_add_global_notifier(struct notifier_block *notifier);
 int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier);
 void dev_pm_qos_constraints_init(struct device *dev);
@@ -195,10 +197,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 int dev_pm_qos_add_global_notifier(
 					struct notifier_block *notifier)
-- 
2.7.1.410.g6faf27b

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

* [PATCH 3/6] PM / QOS: Add 'performance' request
  2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
  2017-01-03 11:06 ` [PATCH 1/6] PM / QOS: Add default case to the switch Viresh Kumar
  2017-01-03 11:06 ` [PATCH 2/6] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier() Viresh Kumar
@ 2017-01-03 11:06 ` Viresh Kumar
  2017-01-03 11:06 ` [PATCH 4/6] PM / domain: Register for PM QOS performance notifier Viresh Kumar
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-03 11:06 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson, Len Brown, Pavel Machek
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak, Viresh Kumar

Add a new QOS request type: DEV_PM_QOS_PERFORMANCE.

This is required to support runtime performance constraints for the
devices. Also allow notifiers to be registered against it, which can be
used by frameworks like genpd.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 Documentation/power/pm_qos_interface.txt |  2 +-
 drivers/base/power/qos.c                 | 69 +++++++++++++++++++++++++++-----
 include/linux/pm_qos.h                   |  4 ++
 3 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index c7989d140428..a0a45ecbc1a8 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -172,7 +172,7 @@ type.
 
 The callback is called when the aggregated value of the device constraints list
 is changed. Currently it only supports the notifier to be registered for resume
-latency device PM QoS.
+latency and performance device PM QoS.
 
 int dev_pm_qos_remove_notifier(device, notifier, type):
 Removes the notification callback function for the device.
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 9adc208cf1fc..cf070468a7ca 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -163,6 +163,10 @@ static int apply_constraint(struct dev_pm_qos_request *req,
 			req->dev->power.set_latency_tolerance(req->dev, value);
 		}
 		break;
+	case DEV_PM_QOS_PERFORMANCE:
+		ret = pm_qos_update_target(&qos->performance, &req->data.pnode,
+					   action, value);
+		break;
 	case DEV_PM_QOS_FLAGS:
 		ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
 					  action, value);
@@ -191,12 +195,13 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
 	if (!qos)
 		return -ENOMEM;
 
-	n = kzalloc(sizeof(*n), GFP_KERNEL);
+	n = kzalloc(2 * sizeof(*n), GFP_KERNEL);
 	if (!n) {
 		kfree(qos);
 		return -ENOMEM;
 	}
 	BLOCKING_INIT_NOTIFIER_HEAD(n);
+	BLOCKING_INIT_NOTIFIER_HEAD(n + 1);
 
 	c = &qos->resume_latency;
 	plist_head_init(&c->list);
@@ -213,6 +218,14 @@ 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->performance;
+	plist_head_init(&c->list);
+	c->target_value = PM_QOS_PERFORMANCE_DEFAULT_VALUE;
+	c->default_value = PM_QOS_PERFORMANCE_DEFAULT_VALUE;
+	c->no_constraint_value = PM_QOS_PERFORMANCE_DEFAULT_VALUE;
+	c->type = PM_QOS_MAX;
+	c->notifiers = n + 1;
+
 	INIT_LIST_HEAD(&qos->flags.list);
 
 	spin_lock_irq(&dev->power.lock);
@@ -271,6 +284,11 @@ 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->performance;
+	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));
+	}
 	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);
@@ -382,6 +400,7 @@ 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_PERFORMANCE:
 		curr_value = req->data.pnode.prio;
 		break;
 	case DEV_PM_QOS_FLAGS:
@@ -492,11 +511,9 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
 int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
 			    enum dev_pm_qos_req_type type)
 {
+	struct dev_pm_qos *qos;
 	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,10 +521,26 @@ 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)
-		ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
+	if (ret)
+		goto unlock;
+
+	qos = dev->power.qos;
+
+	switch (type) {
+	case DEV_PM_QOS_RESUME_LATENCY:
+		ret = blocking_notifier_chain_register(qos->resume_latency.notifiers,
+						       notifier);
+		break;
+	case DEV_PM_QOS_PERFORMANCE:
+		ret = blocking_notifier_chain_register(qos->performance.notifiers,
 						       notifier);
+		break;
+	default:
+		WARN_ON(1);
+		ret = -EINVAL;
+	}
 
+unlock:
 	mutex_unlock(&dev_pm_qos_mtx);
 	return ret;
 }
@@ -528,18 +561,32 @@ int dev_pm_qos_remove_notifier(struct device *dev,
 			       struct notifier_block *notifier,
 			       enum dev_pm_qos_req_type type)
 {
+	struct dev_pm_qos *qos;
 	int retval = 0;
 
-	if (WARN_ON(type != DEV_PM_QOS_RESUME_LATENCY))
-		return -EINVAL;
-
 	mutex_lock(&dev_pm_qos_mtx);
 
+	qos = dev->power.qos;
+
 	/* 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,
+	if (IS_ERR_OR_NULL(qos))
+		goto unlock;
+
+	switch (type) {
+	case DEV_PM_QOS_RESUME_LATENCY:
+		retval = blocking_notifier_chain_unregister(qos->resume_latency.notifiers,
+							    notifier);
+		break;
+	case DEV_PM_QOS_PERFORMANCE:
+		retval = blocking_notifier_chain_unregister(qos->performance.notifiers,
 							    notifier);
+		break;
+	default:
+		WARN_ON(1);
+		retval = -EINVAL;
+	}
 
+unlock:
 	mutex_unlock(&dev_pm_qos_mtx);
 	return retval;
 }
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 3b24f7d20299..42733f572d86 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -37,6 +37,7 @@ enum pm_qos_flags_status {
 #define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT	(-1)
+#define PM_QOS_PERFORMANCE_DEFAULT_VALUE	0
 #define PM_QOS_LATENCY_ANY			((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF	(1 << 0)
@@ -56,6 +57,7 @@ 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_PERFORMANCE,
 	DEV_PM_QOS_FLAGS,
 };
 
@@ -97,9 +99,11 @@ struct pm_qos_flags {
 struct dev_pm_qos {
 	struct pm_qos_constraints resume_latency;
 	struct pm_qos_constraints latency_tolerance;
+	struct pm_qos_constraints performance;
 	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 *performance_req;
 	struct dev_pm_qos_request *flags_req;
 };
 
-- 
2.7.1.410.g6faf27b

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

* [PATCH 4/6] PM / domain: Register for PM QOS performance notifier
  2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
                   ` (2 preceding siblings ...)
  2017-01-03 11:06 ` [PATCH 3/6] PM / QOS: Add 'performance' request Viresh Kumar
@ 2017-01-03 11:06 ` Viresh Kumar
  2017-01-19  4:36   ` Viresh Kumar
  2017-01-03 11:06 ` [PATCH 5/6] PM / domain: Save/restore performance state at runtime suspend/resume Viresh Kumar
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Viresh Kumar @ 2017-01-03 11:06 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson, Kevin Hilman, Len Brown,
	Pavel Machek
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak, Viresh Kumar

Some platforms have the capability to configure the performance state of
their Power Domains. The performance levels are represented by positive
integer values, a lower value represents lower performance state.

This patch registers the power domain framework for PM QOS performance
notifier in order to manage performance state of power domains.

This also allows the power domain drivers to implement a
->set_performance_state() callback, which will be called by the power
domain core from the notifier routine.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/base/power/domain.c | 75 +++++++++++++++++++++++++++++++++++++++++++--
 include/linux/pm_domain.h   |  5 +++
 2 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 12f16d9b6b55..f460be4ca5f7 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -367,6 +367,61 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 	return NOTIFY_DONE;
 }
 
+static void update_domain_performance_state(struct generic_pm_domain *genpd)
+{
+	struct generic_pm_domain_data *pd_data;
+	struct pm_domain_data *pdd;
+	unsigned int state = 0;
+
+	if (!genpd->set_performance_state)
+		return;
+
+	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+		pd_data = to_gpd_data(pdd);
+
+		if (pd_data->performance_state > state)
+			state = pd_data->performance_state;
+	}
+
+	if (genpd->performance_state == state)
+		return;
+
+	genpd->performance_state = state;
+	genpd->set_performance_state(genpd, state);
+}
+
+static int genpd_dev_pm_qos_perf_notifier(struct notifier_block *nb,
+					  unsigned long val, void *ptr)
+{
+	struct generic_pm_domain_data *gpd_data;
+	struct generic_pm_domain *genpd = ERR_PTR(-ENODATA);
+	struct pm_domain_data *pdd;
+	struct device *dev;
+
+	gpd_data = container_of(nb, struct generic_pm_domain_data, perf_nb);
+	dev = gpd_data->base.dev;
+
+	spin_lock_irq(&dev->power.lock);
+
+	pdd = dev->power.subsys_data ?
+		dev->power.subsys_data->domain_data : NULL;
+
+	if (pdd && pdd->dev)
+		genpd = dev_to_genpd(dev);
+
+	spin_unlock_irq(&dev->power.lock);
+
+	if (IS_ERR(genpd))
+		return NOTIFY_DONE;
+
+	genpd_lock(genpd);
+	gpd_data->performance_state = val;
+	update_domain_performance_state(genpd);
+	genpd_unlock(genpd);
+
+	return NOTIFY_DONE;
+}
+
 /**
  * genpd_poweroff - Remove power from a given PM domain.
  * @genpd: PM domain to power down.
@@ -1127,6 +1182,10 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
 	gpd_data->td.constraint_changed = true;
 	gpd_data->td.effective_constraint_ns = -1;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+	gpd_data->performance_state = 0;
+
+	if (genpd->set_performance_state)
+		gpd_data->perf_nb.notifier_call = genpd_dev_pm_qos_perf_notifier;
 
 	spin_lock_irq(&dev->power.lock);
 
@@ -1200,12 +1259,17 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
  out:
 	genpd_unlock(genpd);
 
-	if (ret)
+	if (ret) {
 		genpd_free_dev_data(dev, gpd_data);
-	else
+	} else {
 		dev_pm_qos_add_notifier(dev, &gpd_data->nb,
 					DEV_PM_QOS_RESUME_LATENCY);
 
+		if (genpd->set_performance_state)
+			dev_pm_qos_add_notifier(dev, &gpd_data->perf_nb,
+						DEV_PM_QOS_PERFORMANCE);
+	}
+
 	return ret;
 }
 
@@ -1239,6 +1303,9 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 
 	pdd = dev->power.subsys_data->domain_data;
 	gpd_data = to_gpd_data(pdd);
+	if (genpd->set_performance_state)
+		dev_pm_qos_remove_notifier(dev, &gpd_data->perf_nb,
+					   DEV_PM_QOS_PERFORMANCE);
 	dev_pm_qos_remove_notifier(dev, &gpd_data->nb,
 				   DEV_PM_QOS_RESUME_LATENCY);
 
@@ -1267,6 +1334,10 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 	genpd_unlock(genpd);
 	dev_pm_qos_add_notifier(dev, &gpd_data->nb, DEV_PM_QOS_RESUME_LATENCY);
 
+	if (genpd->set_performance_state)
+		dev_pm_qos_add_notifier(dev, &gpd_data->perf_nb,
+					DEV_PM_QOS_PERFORMANCE);
+
 	return ret;
 }
 
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 81ece61075df..d994ad5ba1c0 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -62,8 +62,11 @@ struct generic_pm_domain {
 	unsigned int device_count;	/* Number of devices */
 	unsigned int suspended_count;	/* System suspend device counter */
 	unsigned int prepared_count;	/* Suspend counter of prepared devices */
+	unsigned int performance_state;	/* Max requested performance state */
 	int (*power_off)(struct generic_pm_domain *domain);
 	int (*power_on)(struct generic_pm_domain *domain);
+	int (*set_performance_state)(struct generic_pm_domain *domain,
+				     unsigned int state);
 	struct gpd_dev_ops dev_ops;
 	s64 max_off_time_ns;	/* Maximum allowed "suspended" time. */
 	bool max_off_time_changed;
@@ -117,6 +120,8 @@ struct generic_pm_domain_data {
 	struct pm_domain_data base;
 	struct gpd_timing_data td;
 	struct notifier_block nb;
+	struct notifier_block perf_nb;
+	unsigned int performance_state;
 };
 
 #ifdef CONFIG_PM_GENERIC_DOMAINS
-- 
2.7.1.410.g6faf27b

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

* [PATCH 5/6] PM / domain: Save/restore performance state at runtime suspend/resume
  2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
                   ` (3 preceding siblings ...)
  2017-01-03 11:06 ` [PATCH 4/6] PM / domain: Register for PM QOS performance notifier Viresh Kumar
@ 2017-01-03 11:06 ` Viresh Kumar
  2017-01-03 11:06 ` [PATCH 6/6] PM / OPP: Add support to parse domain-performance-state Viresh Kumar
  2017-01-16  5:30 ` [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
  6 siblings, 0 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-03 11:06 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson, Kevin Hilman, Len Brown,
	Pavel Machek
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak, Viresh Kumar

With runtime PM, the devices get suspended while the system is up and
running in order to save power. At such times, it is important to
re-evaluate the required performance state of the domain, in order to
choose a lower state if possible.

This patch updates the genpd suspend/resume callbacks to do that.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/base/power/domain.c | 19 +++++++++++++++++--
 include/linux/pm_domain.h   |  1 +
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index f460be4ca5f7..ef4062927713 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -576,7 +576,8 @@ static int genpd_runtime_suspend(struct device *dev)
 {
 	struct generic_pm_domain *genpd;
 	bool (*suspend_ok)(struct device *__dev);
-	struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+	struct generic_pm_domain_data *pd_data = dev_gpd_data(dev);
+	struct gpd_timing_data *td = &pd_data->td;
 	bool runtime_pm = pm_runtime_enabled(dev);
 	ktime_t time_start;
 	s64 elapsed_ns;
@@ -633,7 +634,14 @@ static int genpd_runtime_suspend(struct device *dev)
 		return 0;
 
 	genpd_lock(genpd);
+
+	/* Re-evaluate performance state of the domain */
+	pd_data->cached_performance_state = pd_data->performance_state;
+	pd_data->performance_state = 0;
+	update_domain_performance_state(genpd);
+
 	genpd_poweroff(genpd, false);
+
 	genpd_unlock(genpd);
 
 	return 0;
@@ -650,7 +658,8 @@ static int genpd_runtime_suspend(struct device *dev)
 static int genpd_runtime_resume(struct device *dev)
 {
 	struct generic_pm_domain *genpd;
-	struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+	struct generic_pm_domain_data *pd_data = dev_gpd_data(dev);
+	struct gpd_timing_data *td = &pd_data->td;
 	bool runtime_pm = pm_runtime_enabled(dev);
 	ktime_t time_start;
 	s64 elapsed_ns;
@@ -673,7 +682,13 @@ static int genpd_runtime_resume(struct device *dev)
 	}
 
 	genpd_lock(genpd);
+
 	ret = genpd_poweron(genpd, 0);
+
+	/* Re-evaluate performance state of the domain */
+	pd_data->performance_state = pd_data->cached_performance_state;
+	update_domain_performance_state(genpd);
+
 	genpd_unlock(genpd);
 
 	if (ret)
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index d994ad5ba1c0..69b453d44adb 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -122,6 +122,7 @@ struct generic_pm_domain_data {
 	struct notifier_block nb;
 	struct notifier_block perf_nb;
 	unsigned int performance_state;
+	unsigned int cached_performance_state;
 };
 
 #ifdef CONFIG_PM_GENERIC_DOMAINS
-- 
2.7.1.410.g6faf27b

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

* [PATCH 6/6] PM / OPP: Add support to parse domain-performance-state
  2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
                   ` (4 preceding siblings ...)
  2017-01-03 11:06 ` [PATCH 5/6] PM / domain: Save/restore performance state at runtime suspend/resume Viresh Kumar
@ 2017-01-03 11:06 ` Viresh Kumar
  2017-01-16  5:30 ` [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
  6 siblings, 0 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-03 11:06 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson, Viresh Kumar,
	Nishanth Menon, Stephen Boyd
  Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh+dt,
	mark.rutland, lina.iyer, rnayak, Viresh Kumar

PLEASE DO NOT APPLY THIS

This patch is added to this series to show how kernel will get inputs
using the OPP framework. This patch is still based of the V1 bindings I
sent earlier. This also is based on some OPP core fixes which are
already reviewed on the lists, but that doesn't really much in this
patch.

Some platforms have the capability to configure the performance state of
their Power Domains. The performance levels are represented by positive
integer values, a lower value represents lower performance state.

This patch introduces code in the OPP core to parse
"domain-performance-state" property from the OPP nodes.

Either none or all OPP nodes in an OPP table shall have the property
set.

NOT-Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/base/power/opp/core.c    | 75 ++++++++++++++++++++++++++++++++++++++++
 drivers/base/power/opp/debugfs.c |  4 +++
 drivers/base/power/opp/of.c      | 44 +++++++++++++++++++++++
 drivers/base/power/opp/opp.h     | 12 +++++++
 4 files changed, 135 insertions(+)

diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 622dd32f8dda..dde01274db79 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -624,6 +624,63 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
 	return ret;
 }
 
+static int _update_pm_qos_request(struct device *dev,
+				  struct dev_pm_qos_request *req,
+				  unsigned int perf)
+{
+	int ret;
+
+	if (likely(dev_pm_qos_request_active(req)))
+		ret = dev_pm_qos_update_request(req, perf);
+	else
+		ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_PERFORMANCE,
+					     perf);
+
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int _generic_set_opp_pd(struct device *dev, struct clk *clk,
+			       struct dev_pm_qos_request *req,
+			       unsigned long old_freq, unsigned long freq,
+			       unsigned int old_perf, unsigned int new_perf)
+{
+	int ret;
+
+	/* Scaling up? Scale voltage before frequency */
+	if (freq > old_freq) {
+		ret = _update_pm_qos_request(dev, req, new_perf);
+		if (ret)
+			return ret;
+	}
+
+	/* Change frequency */
+	ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+	if (ret)
+		goto restore_perf;
+
+	/* Scaling down? Scale voltage after frequency */
+	if (freq < old_freq) {
+		ret = _update_pm_qos_request(dev, req, new_perf);
+		if (ret)
+			goto restore_freq;
+	}
+
+	return 0;
+
+restore_freq:
+	if (_generic_set_opp_clk_only(dev, clk, freq, old_freq))
+		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
+			__func__, old_freq);
+restore_perf:
+	if (old_perf)
+		_update_pm_qos_request(dev, req, old_perf);
+
+	return ret;
+}
+
 static int _generic_set_opp(struct dev_pm_set_opp_data *data)
 {
 	struct dev_pm_opp_supply *old_supply = data->old_opp.supplies;
@@ -745,6 +802,21 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 
 	regulators = opp_table->regulators;
 
+	/* Has power domains performance states */
+	if (opp_table->has_pd_perf_states) {
+		unsigned int old_perf = 0, new_perf;
+		struct dev_pm_qos_request *req = &opp_table->qos_request;
+
+		new_perf = opp->pd_perf_state;
+		if (!IS_ERR(old_opp))
+			old_perf = old_opp->pd_perf_state;
+
+		rcu_read_unlock();
+
+		return _generic_set_opp_pd(dev, clk, req, old_freq, freq,
+					   old_perf, new_perf);
+	}
+
 	/* Only frequency scaling */
 	if (!regulators) {
 		rcu_read_unlock();
@@ -897,6 +969,9 @@ static void _free_opp_table(struct opp_table *opp_table)
 {
 	struct opp_device *opp_dev;
 
+	if (dev_pm_qos_request_active(&opp_table->qos_request))
+		dev_pm_qos_remove_request(&opp_table->qos_request);
+
 	/* Release clk */
 	if (!IS_ERR(opp_table->clk))
 		clk_put(opp_table->clk);
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
index 95f433db4ac7..264958ab3de9 100644
--- a/drivers/base/power/opp/debugfs.c
+++ b/drivers/base/power/opp/debugfs.c
@@ -104,6 +104,10 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
 	if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
 		return -ENOMEM;
 
+	if (!debugfs_create_u32("power_domain_perf_state", S_IRUGO, d,
+				&opp->pd_perf_state))
+		return -ENOMEM;
+
 	if (!opp_debug_create_supplies(opp, opp_table, d))
 		return -ENOMEM;
 
diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c
index cdbf733ac9b1..dfe2d71d2606 100644
--- a/drivers/base/power/opp/of.c
+++ b/drivers/base/power/opp/of.c
@@ -316,6 +316,45 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
 	if (!of_property_read_u32(np, "clock-latency-ns", &val))
 		new_opp->clock_latency_ns = val;
 
+	/*
+	 * Make sure that all information is present around domain power states
+	 * and nothing is left out.
+	 */
+	if (!of_property_read_u32(np, "domain-performance-state",
+				  &new_opp->pd_perf_state)) {
+		if (!opp_table->has_pd) {
+			ret = -EINVAL;
+			dev_err(dev, "%s: OPP node can't have performance state as device doesn't have power-domain\n",
+				__func__);
+			goto free_opp;
+		}
+
+		if (!new_opp->pd_perf_state) {
+			ret = -EINVAL;
+			dev_err(dev, "%s: OPP node can't have performance state as 0\n",
+				__func__);
+			goto free_opp;
+		}
+
+		if (opp_table->has_pd_perf_states == -1) {
+			opp_table->has_pd_perf_states = 1;
+		} else if (!opp_table->has_pd_perf_states) {
+			ret = -EINVAL;
+			dev_err(dev, "%s: Not all OPP nodes have performance state\n",
+				__func__);
+			goto free_opp;
+		}
+	} else {
+		if (opp_table->has_pd_perf_states == -1) {
+			opp_table->has_pd_perf_states = 0;
+		} else if (opp_table->has_pd_perf_states) {
+			ret = -EINVAL;
+			dev_err(dev, "%s: Not all OPP nodes have performance state\n",
+				__func__);
+			goto free_opp;
+		}
+	}
+
 	ret = opp_parse_supplies(new_opp, dev, opp_table);
 	if (ret)
 		goto free_opp;
@@ -384,6 +423,11 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
 		goto unlock;
 	}
 
+	if (of_find_property(dev->of_node, "power-domains", NULL)) {
+		opp_table->has_pd = true;
+		opp_table->has_pd_perf_states = -1;
+	}
+
 	/* We have opp-table node now, iterate over it and add OPPs */
 	for_each_available_child_of_node(opp_np, np) {
 		count++;
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 0a5eb4d1e8f7..6818edafda16 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -19,6 +19,7 @@
 #include <linux/list.h>
 #include <linux/limits.h>
 #include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 
@@ -60,6 +61,7 @@ extern struct list_head opp_tables;
  * @dynamic:	not-created from static DT entries.
  * @turbo:	true if turbo (boost) OPP
  * @suspend:	true if suspend OPP
+ * @pd_perf_state: Performance state of power domain
  * @rate:	Frequency in hertz
  * @supplies:	Power supplies voltage/current values
  * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
@@ -78,6 +80,7 @@ struct dev_pm_opp {
 	bool dynamic;
 	bool turbo;
 	bool suspend;
+	unsigned int pd_perf_state;
 	unsigned long rate;
 
 	struct dev_pm_opp_supply *supplies;
@@ -143,6 +146,11 @@ enum opp_table_access {
  * @regulator_count: Number of power supply regulators
  * @set_opp: Platform specific set_opp callback
  * @set_opp_data: Data to be passed to set_opp callback
+ * @has_pd: True if the device node contains power-domain property
+ * @has_pd_perf_states: Can have value of 0, 1 or -1. -1 means uninitialized
+ * state, 0 means that OPP nodes don't have perf states and 1 means that OPP
+ * nodes have perf states.
+ * @qos_request: Qos request.
  * @dentry:	debugfs dentry pointer of the real device directory (not links).
  * @dentry_name: Name of the real dentry.
  *
@@ -183,6 +191,10 @@ struct opp_table {
 	int (*set_opp)(struct dev_pm_set_opp_data *data);
 	struct dev_pm_set_opp_data *set_opp_data;
 
+	bool has_pd;
+	int has_pd_perf_states;
+	struct dev_pm_qos_request qos_request;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *dentry;
 	char dentry_name[NAME_MAX];
-- 
2.7.1.410.g6faf27b

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

* Re: [PATCH 0/6] PM / Domains: Implement domain performance states
  2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
                   ` (5 preceding siblings ...)
  2017-01-03 11:06 ` [PATCH 6/6] PM / OPP: Add support to parse domain-performance-state Viresh Kumar
@ 2017-01-16  5:30 ` Viresh Kumar
  2017-01-16 21:47   ` Rafael J. Wysocki
  2017-02-06  5:35   ` Viresh Kumar
  6 siblings, 2 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-16  5:30 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak

On 03-01-17, 16:36, Viresh Kumar wrote:
> Hi,
> 
> An earlier series[1] tried to implement bindings for PM domain
> performance states. Rob Herring suggested that we can actually write the
> supporting code first instead of bindings, as that will make things
> easier to understand for all.
> 
> The bindings [1] aren't discarded yet and this series is based on a
> version of those only. The bindings are only used by the last patch,
> which should not be applied and is only sent for completeness.
> 
> All other patches can be reviewed/applied whenever the maintainers feel
> they look good.
> 
> 
> A brief summary of the problem this series is trying to solve:
> 
> Some platforms have the capability to configure the performance state of
> their Power Domains. The performance levels are represented by positive
> integer values, a lower value represents lower performance state.
> 
> We decided earlier that we should extend Power Domain framework to
> support active state power management as well.  The power-domains until
> now were only concentrating on the idle state management of the device
> and this needs to change in order to reuse the infrastructure of power
> domains for active state management.
> 
> The first 5 patches update the PM domain and QoS frameworks to support
> that and the last one presents the front end interface to it.
> 
> All the patches are tested by hacking the OPP core a bit for now.

Ping !

-- 
viresh

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

* Re: [PATCH 0/6] PM / Domains: Implement domain performance states
  2017-01-16  5:30 ` [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
@ 2017-01-16 21:47   ` Rafael J. Wysocki
  2017-01-17  3:21     ` Viresh Kumar
  2017-02-06  5:35   ` Viresh Kumar
  1 sibling, 1 reply; 13+ messages in thread
From: Rafael J. Wysocki @ 2017-01-16 21:47 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Rafael Wysocki, Kevin Hilman, Ulf Hansson, Lists linaro-kernel,
	Linux PM, Linux Kernel Mailing List, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, Rob Herring, Mark Rutland,
	Lina Iyer, Nayak, Rajendra

On Mon, Jan 16, 2017 at 6:30 AM, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> On 03-01-17, 16:36, Viresh Kumar wrote:
>> Hi,
>>
>> An earlier series[1] tried to implement bindings for PM domain
>> performance states. Rob Herring suggested that we can actually write the
>> supporting code first instead of bindings, as that will make things
>> easier to understand for all.
>>
>> The bindings [1] aren't discarded yet and this series is based on a
>> version of those only. The bindings are only used by the last patch,
>> which should not be applied and is only sent for completeness.
>>
>> All other patches can be reviewed/applied whenever the maintainers feel
>> they look good.
>>
>>
>> A brief summary of the problem this series is trying to solve:
>>
>> Some platforms have the capability to configure the performance state of
>> their Power Domains. The performance levels are represented by positive
>> integer values, a lower value represents lower performance state.
>>
>> We decided earlier that we should extend Power Domain framework to
>> support active state power management as well.  The power-domains until
>> now were only concentrating on the idle state management of the device
>> and this needs to change in order to reuse the infrastructure of power
>> domains for active state management.
>>
>> The first 5 patches update the PM domain and QoS frameworks to support
>> that and the last one presents the front end interface to it.
>>
>> All the patches are tested by hacking the OPP core a bit for now.
>
> Ping !

http://marc.info/?l=linux-pm&m=148410629024194&w=2

Pretty please!

I will start processing things when I'm back (which probably means the
end of the next week realistically).

Thanks,
Rafael

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

* Re: [PATCH 0/6] PM / Domains: Implement domain performance states
  2017-01-16 21:47   ` Rafael J. Wysocki
@ 2017-01-17  3:21     ` Viresh Kumar
  0 siblings, 0 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-17  3:21 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Rafael Wysocki, Kevin Hilman, Ulf Hansson, Lists linaro-kernel,
	Linux PM, Linux Kernel Mailing List, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, Rob Herring, Mark Rutland,
	Lina Iyer, Nayak, Rajendra

On 16-01-17, 22:47, Rafael J. Wysocki wrote:
> http://marc.info/?l=linux-pm&m=148410629024194&w=2
> 
> Pretty please!
> 
> I will start processing things when I'm back (which probably means the
> end of the next week realistically).

And I was wondering why aren't you applying any of my cpufreq patches now a days
:)

The ping was more for other stakeholders: Ulf, Kevin, Stephen and Rob though.

-- 
viresh

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

* Re: [PATCH 4/6] PM / domain: Register for PM QOS performance notifier
  2017-01-03 11:06 ` [PATCH 4/6] PM / domain: Register for PM QOS performance notifier Viresh Kumar
@ 2017-01-19  4:36   ` Viresh Kumar
  0 siblings, 0 replies; 13+ messages in thread
From: Viresh Kumar @ 2017-01-19  4:36 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson, Kevin Hilman, Len Brown,
	Pavel Machek
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak

On 03-01-17, 16:36, Viresh Kumar wrote:
> Some platforms have the capability to configure the performance state of
> their Power Domains. The performance levels are represented by positive
> integer values, a lower value represents lower performance state.
> 
> This patch registers the power domain framework for PM QOS performance
> notifier in order to manage performance state of power domains.
> 
> This also allows the power domain drivers to implement a
> ->set_performance_state() callback, which will be called by the power
> domain core from the notifier routine.

Rajendra helped me testing this stuff on his Qualcomm board and this patch has
received some updates to support the hierarchy of power domains, i.e. subdomains
withing power domains. Below is the new patch which worked for him.

-- 
viresh

-------------------------8<-------------------------

From: Viresh Kumar <viresh.kumar@linaro.org>
Date: Wed, 23 Nov 2016 11:00:41 +0530
Subject: [PATCH] PM / domain: Register for PM QOS performance notifier

Some platforms have the capability to configure the performance state of
their Power Domains. The performance levels are represented by positive
integer values, a lower value represents lower performance state.

This patch registers the power domain framework for PM QOS performance
notifier in order to manage performance state of power domains.

This also allows the power domain drivers to implement a
->set_performance_state() callback, which will be called by the power
domain core from the notifier routine.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/base/power/domain.c | 99 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pm_domain.h   |  5 +++
 2 files changed, 102 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 12f16d9b6b55..12ec1f8c42ed 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -367,6 +367,88 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 	return NOTIFY_DONE;
 }
 
+static void update_domain_performance_state(struct generic_pm_domain *genpd,
+					    int depth)
+{
+	struct generic_pm_domain_data *pd_data;
+	struct generic_pm_domain *subdomain;
+	struct pm_domain_data *pdd;
+	unsigned int state = 0;
+	struct gpd_link *link;
+
+	/* Traverse all devices within the domain */
+	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+		pd_data = to_gpd_data(pdd);
+
+		if (pd_data->performance_state > state)
+			state = pd_data->performance_state;
+	}
+
+	/* Traverse all subdomains within the domain */
+	list_for_each_entry(link, &genpd->master_links, master_node) {
+		subdomain = link->slave;
+
+		if (subdomain->performance_state > state)
+			state = subdomain->performance_state;
+	}
+
+	if (genpd->performance_state == state)
+		return;
+
+	genpd->performance_state = state;
+
+	if (genpd->set_performance_state) {
+		genpd->set_performance_state(genpd, state);
+		return;
+	}
+
+	/* Propagate only if this domain has a single parent */
+	if (list_is_singular(&genpd->slave_links)) {
+		/* Performance levels are managed by parent power domain */
+
+		struct generic_pm_domain *master;
+
+		link = list_first_entry(&genpd->slave_links, struct gpd_link, slave_node);
+		master = link->master;
+
+		genpd_lock_nested(master, depth + 1);
+		update_domain_performance_state(master, depth + 1);
+		genpd_unlock(master);
+	}
+}
+
+static int genpd_dev_pm_qos_perf_notifier(struct notifier_block *nb,
+					  unsigned long val, void *ptr)
+{
+	struct generic_pm_domain_data *gpd_data;
+	struct generic_pm_domain *genpd = ERR_PTR(-ENODATA);
+	struct pm_domain_data *pdd;
+	struct device *dev;
+
+	gpd_data = container_of(nb, struct generic_pm_domain_data, perf_nb);
+	dev = gpd_data->base.dev;
+
+	spin_lock_irq(&dev->power.lock);
+
+	pdd = dev->power.subsys_data ?
+		dev->power.subsys_data->domain_data : NULL;
+
+	if (pdd && pdd->dev)
+		genpd = dev_to_genpd(dev);
+
+	spin_unlock_irq(&dev->power.lock);
+
+	if (IS_ERR(genpd))
+		return NOTIFY_DONE;
+
+	genpd_lock(genpd);
+	gpd_data->performance_state = val;
+	update_domain_performance_state(genpd, 0);
+	genpd_unlock(genpd);
+
+	return NOTIFY_DONE;
+}
+
 /**
  * genpd_poweroff - Remove power from a given PM domain.
  * @genpd: PM domain to power down.
@@ -578,6 +660,7 @@ static int genpd_runtime_suspend(struct device *dev)
 		return 0;
 
 	genpd_lock(genpd);
+
 	genpd_poweroff(genpd, false);
 	genpd_unlock(genpd);
 
@@ -1127,6 +1210,9 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
 	gpd_data->td.constraint_changed = true;
 	gpd_data->td.effective_constraint_ns = -1;
 	gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+	gpd_data->performance_state = 0;
+
+	gpd_data->perf_nb.notifier_call = genpd_dev_pm_qos_perf_notifier;
 
 	spin_lock_irq(&dev->power.lock);
 
@@ -1200,12 +1286,16 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
  out:
 	genpd_unlock(genpd);
 
-	if (ret)
+	if (ret) {
 		genpd_free_dev_data(dev, gpd_data);
-	else
+	} else {
 		dev_pm_qos_add_notifier(dev, &gpd_data->nb,
 					DEV_PM_QOS_RESUME_LATENCY);
 
+		dev_pm_qos_add_notifier(dev, &gpd_data->perf_nb,
+					DEV_PM_QOS_PERFORMANCE);
+	}
+
 	return ret;
 }
 
@@ -1239,6 +1329,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->perf_nb,
+				   DEV_PM_QOS_PERFORMANCE);
 	dev_pm_qos_remove_notifier(dev, &gpd_data->nb,
 				   DEV_PM_QOS_RESUME_LATENCY);
 
@@ -1267,6 +1359,9 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
 	genpd_unlock(genpd);
 	dev_pm_qos_add_notifier(dev, &gpd_data->nb, DEV_PM_QOS_RESUME_LATENCY);
 
+	dev_pm_qos_add_notifier(dev, &gpd_data->perf_nb,
+				DEV_PM_QOS_PERFORMANCE);
+
 	return ret;
 }
 
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 81ece61075df..d994ad5ba1c0 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -62,8 +62,11 @@ struct generic_pm_domain {
 	unsigned int device_count;	/* Number of devices */
 	unsigned int suspended_count;	/* System suspend device counter */
 	unsigned int prepared_count;	/* Suspend counter of prepared devices */
+	unsigned int performance_state;	/* Max requested performance state */
 	int (*power_off)(struct generic_pm_domain *domain);
 	int (*power_on)(struct generic_pm_domain *domain);
+	int (*set_performance_state)(struct generic_pm_domain *domain,
+				     unsigned int state);
 	struct gpd_dev_ops dev_ops;
 	s64 max_off_time_ns;	/* Maximum allowed "suspended" time. */
 	bool max_off_time_changed;
@@ -117,6 +120,8 @@ struct generic_pm_domain_data {
 	struct pm_domain_data base;
 	struct gpd_timing_data td;
 	struct notifier_block nb;
+	struct notifier_block perf_nb;
+	unsigned int performance_state;
 };
 
 #ifdef CONFIG_PM_GENERIC_DOMAINS

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

* Re: [PATCH 0/6] PM / Domains: Implement domain performance states
  2017-01-16  5:30 ` [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
  2017-01-16 21:47   ` Rafael J. Wysocki
@ 2017-02-06  5:35   ` Viresh Kumar
  2017-02-06 11:39     ` Rafael J. Wysocki
  1 sibling, 1 reply; 13+ messages in thread
From: Viresh Kumar @ 2017-02-06  5:35 UTC (permalink / raw)
  To: Rafael Wysocki, khilman, ulf.hansson
  Cc: linaro-kernel, linux-pm, linux-kernel, Stephen Boyd,
	Nishanth Menon, Vincent Guittot, robh+dt, mark.rutland,
	lina.iyer, rnayak

On 16-01-17, 11:00, Viresh Kumar wrote:
> On 03-01-17, 16:36, Viresh Kumar wrote:
> > Hi,
> > 
> > An earlier series[1] tried to implement bindings for PM domain
> > performance states. Rob Herring suggested that we can actually write the
> > supporting code first instead of bindings, as that will make things
> > easier to understand for all.
> > 
> > The bindings [1] aren't discarded yet and this series is based on a
> > version of those only. The bindings are only used by the last patch,
> > which should not be applied and is only sent for completeness.
> > 
> > All other patches can be reviewed/applied whenever the maintainers feel
> > they look good.
> > 
> > 
> > A brief summary of the problem this series is trying to solve:
> > 
> > Some platforms have the capability to configure the performance state of
> > their Power Domains. The performance levels are represented by positive
> > integer values, a lower value represents lower performance state.
> > 
> > We decided earlier that we should extend Power Domain framework to
> > support active state power management as well.  The power-domains until
> > now were only concentrating on the idle state management of the device
> > and this needs to change in order to reuse the infrastructure of power
> > domains for active state management.
> > 
> > The first 5 patches update the PM domain and QoS frameworks to support
> > that and the last one presents the front end interface to it.
> > 
> > All the patches are tested by hacking the OPP core a bit for now.
> 
> Ping !

Ping !!

-- 
viresh

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

* Re: [PATCH 0/6] PM / Domains: Implement domain performance states
  2017-02-06  5:35   ` Viresh Kumar
@ 2017-02-06 11:39     ` Rafael J. Wysocki
  0 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2017-02-06 11:39 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: khilman, ulf.hansson, linaro-kernel, linux-pm, linux-kernel,
	Stephen Boyd, Nishanth Menon, Vincent Guittot, robh+dt,
	mark.rutland, lina.iyer, rnayak

On Monday, February 06, 2017 11:05:05 AM Viresh Kumar wrote:
> On 16-01-17, 11:00, Viresh Kumar wrote:
> > On 03-01-17, 16:36, Viresh Kumar wrote:
> > > Hi,
> > > 
> > > An earlier series[1] tried to implement bindings for PM domain
> > > performance states. Rob Herring suggested that we can actually write the
> > > supporting code first instead of bindings, as that will make things
> > > easier to understand for all.
> > > 
> > > The bindings [1] aren't discarded yet and this series is based on a
> > > version of those only. The bindings are only used by the last patch,
> > > which should not be applied and is only sent for completeness.
> > > 
> > > All other patches can be reviewed/applied whenever the maintainers feel
> > > they look good.
> > > 
> > > 
> > > A brief summary of the problem this series is trying to solve:
> > > 
> > > Some platforms have the capability to configure the performance state of
> > > their Power Domains. The performance levels are represented by positive
> > > integer values, a lower value represents lower performance state.
> > > 
> > > We decided earlier that we should extend Power Domain framework to
> > > support active state power management as well.  The power-domains until
> > > now were only concentrating on the idle state management of the device
> > > and this needs to change in order to reuse the infrastructure of power
> > > domains for active state management.
> > > 
> > > The first 5 patches update the PM domain and QoS frameworks to support
> > > that and the last one presents the front end interface to it.
> > > 
> > > All the patches are tested by hacking the OPP core a bit for now.
> > 
> > Ping !
> 
> Ping !!

I've been waiting for comments from Kevin and Ulf.

I guess it's better to resend at this point.

Thanks,
Rafael

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

end of thread, other threads:[~2017-02-06 11:44 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-03 11:06 [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
2017-01-03 11:06 ` [PATCH 1/6] PM / QOS: Add default case to the switch Viresh Kumar
2017-01-03 11:06 ` [PATCH 2/6] PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier() Viresh Kumar
2017-01-03 11:06 ` [PATCH 3/6] PM / QOS: Add 'performance' request Viresh Kumar
2017-01-03 11:06 ` [PATCH 4/6] PM / domain: Register for PM QOS performance notifier Viresh Kumar
2017-01-19  4:36   ` Viresh Kumar
2017-01-03 11:06 ` [PATCH 5/6] PM / domain: Save/restore performance state at runtime suspend/resume Viresh Kumar
2017-01-03 11:06 ` [PATCH 6/6] PM / OPP: Add support to parse domain-performance-state Viresh Kumar
2017-01-16  5:30 ` [PATCH 0/6] PM / Domains: Implement domain performance states Viresh Kumar
2017-01-16 21:47   ` Rafael J. Wysocki
2017-01-17  3:21     ` Viresh Kumar
2017-02-06  5:35   ` Viresh Kumar
2017-02-06 11:39     ` Rafael J. Wysocki

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