linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support
@ 2023-05-31 15:20 Cristian Marussi
  2023-05-31 15:20 ` [PATCH v3 1/3] firmware: arm_scmi: Refactor powercap get/set helpers Cristian Marussi
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Cristian Marussi @ 2023-05-31 15:20 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-pm
  Cc: sudeep.holla, james.quinlan, Jonathan.Cameron, f.fainelli,
	vincent.guittot, tarek.el-sherbiny, nicola.mazzucato,
	souvik.chakravarty, wleavitt, wbartczak, Cristian Marussi

Hi,

Upcoming SCMI v3.2 specification (publicly available as BETA at [1])
introduces support to disable powercapping as a whole on the desired
zones.

This small series at first add the needed support to the core SCMI Powercap
protocol, exposing a couple more enable/disable protocol operations, and
then wires such new ops in the related Powercap framework helpers.

Based on v6.4-rc4.

Thanks,
Cristian

[1]: https://developer.arm.com/documentation/den0056/e 

---

v2 --> v3
- rebased on v6.4-rc4
- added tags

v1 -> v2
- rebased on v6.3-rc1
- simplified enable status check logic

Cristian Marussi (3):
  firmware: arm_scmi: Refactor powercap get/set helpers
  firmware: arm_scmi: Add Powercap protocol enable support
  powercap: arm_scmi: Add support for disabling powercaps on a zone

 drivers/firmware/arm_scmi/powercap.c | 173 +++++++++++++++++++++++----
 drivers/powercap/arm_scmi_powercap.c |  16 +++
 include/linux/scmi_protocol.h        |  18 +++
 3 files changed, 182 insertions(+), 25 deletions(-)

-- 
2.34.1


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

* [PATCH v3 1/3] firmware: arm_scmi: Refactor powercap get/set helpers
  2023-05-31 15:20 [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Cristian Marussi
@ 2023-05-31 15:20 ` Cristian Marussi
  2023-05-31 15:20 ` [PATCH v3 2/3] firmware: arm_scmi: Add Powercap protocol enable support Cristian Marussi
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Cristian Marussi @ 2023-05-31 15:20 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-pm
  Cc: sudeep.holla, james.quinlan, Jonathan.Cameron, f.fainelli,
	vincent.guittot, tarek.el-sherbiny, nicola.mazzucato,
	souvik.chakravarty, wleavitt, wbartczak, Cristian Marussi

Refactor SCMI powercap internal get/set helpers.

Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> v3
- rebased on v6.4-rc4
- added tags
---
 drivers/firmware/arm_scmi/powercap.c | 65 +++++++++++++++++++---------
 1 file changed, 45 insertions(+), 20 deletions(-)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 83b90bde755c..2e490492f187 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -313,24 +313,33 @@ static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
 	return ret;
 }
 
-static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 *power_cap)
+static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
+				   const struct scmi_powercap_info *dom,
+				   u32 *power_cap)
 {
-	struct scmi_powercap_info *dom;
-	struct powercap_info *pi = ph->get_priv(ph);
-
-	if (!power_cap || domain_id >= pi->num_domains)
-		return -EINVAL;
-
-	dom = pi->powercaps + domain_id;
 	if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
 		*power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
-				   domain_id, *power_cap, 0);
+				   dom->id, *power_cap, 0);
 		return 0;
 	}
 
-	return scmi_powercap_xfer_cap_get(ph, domain_id, power_cap);
+	return scmi_powercap_xfer_cap_get(ph, dom->id, power_cap);
+}
+
+static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
+				 u32 domain_id, u32 *power_cap)
+{
+	const struct scmi_powercap_info *dom;
+
+	if (!power_cap)
+		return -EINVAL;
+
+	dom = scmi_powercap_dom_info_get(ph, domain_id);
+	if (!dom)
+		return -EINVAL;
+
+	return __scmi_powercap_cap_get(ph, dom, power_cap);
 }
 
 static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
@@ -375,17 +384,20 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 	return ret;
 }
 
-static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 power_cap,
-				 bool ignore_dresp)
+static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
+				   struct powercap_info *pi, u32 domain_id,
+				   u32 power_cap, bool ignore_dresp)
 {
+	int ret = -EINVAL;
 	const struct scmi_powercap_info *pc;
 
 	pc = scmi_powercap_dom_info_get(ph, domain_id);
-	if (!pc || !pc->powercap_cap_config || !power_cap ||
-	    power_cap < pc->min_power_cap ||
-	    power_cap > pc->max_power_cap)
-		return -EINVAL;
+	if (!pc || !pc->powercap_cap_config)
+		return ret;
+
+	if (power_cap &&
+	    (power_cap < pc->min_power_cap || power_cap > pc->max_power_cap))
+		return ret;
 
 	if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
 		struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
@@ -394,10 +406,23 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 		ph->hops->fastchannel_db_ring(fci->set_db);
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
 				   domain_id, power_cap, 0);
-		return 0;
+		ret = 0;
+	} else {
+		ret = scmi_powercap_xfer_cap_set(ph, pc, power_cap,
+						 ignore_dresp);
 	}
 
-	return scmi_powercap_xfer_cap_set(ph, pc, power_cap, ignore_dresp);
+	return ret;
+}
+
+static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
+				 u32 domain_id, u32 power_cap,
+				 bool ignore_dresp)
+{
+	struct powercap_info *pi = ph->get_priv(ph);
+
+	return __scmi_powercap_cap_set(ph, pi, domain_id,
+				       power_cap, ignore_dresp);
 }
 
 static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
-- 
2.34.1


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

* [PATCH v3 2/3] firmware: arm_scmi: Add Powercap protocol enable support
  2023-05-31 15:20 [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Cristian Marussi
  2023-05-31 15:20 ` [PATCH v3 1/3] firmware: arm_scmi: Refactor powercap get/set helpers Cristian Marussi
@ 2023-05-31 15:20 ` Cristian Marussi
  2023-05-31 15:20 ` [PATCH v3 3/3] powercap: arm_scmi: Add support for disabling powercaps on a zone Cristian Marussi
  2023-06-06 13:07 ` [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Sudeep Holla
  3 siblings, 0 replies; 5+ messages in thread
From: Cristian Marussi @ 2023-05-31 15:20 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-pm
  Cc: sudeep.holla, james.quinlan, Jonathan.Cameron, f.fainelli,
	vincent.guittot, tarek.el-sherbiny, nicola.mazzucato,
	souvik.chakravarty, wleavitt, wbartczak, Cristian Marussi

SCMI Powercap protocol v3.2 supports disabling the powercap on a zone
by zone basis by providing a zero valued powercap.

Expose new operations to enable/disable powercapping on a per-zone base.

Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> V3
- rebased v6.4-rc4
- added tags
v1 --> v2
- simplified enable requested checks
---
 drivers/firmware/arm_scmi/powercap.c | 110 +++++++++++++++++++++++++--
 include/linux/scmi_protocol.h        |  18 +++++
 2 files changed, 122 insertions(+), 6 deletions(-)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 2e490492f187..244929cb4f3e 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -108,6 +108,8 @@ struct scmi_powercap_meas_changed_notify_payld {
 };
 
 struct scmi_powercap_state {
+	bool enabled;
+	u32 last_pcap;
 	bool meas_notif_enabled;
 	u64 thresholds;
 #define THRESH_LOW(p, id)				\
@@ -412,6 +414,10 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 						 ignore_dresp);
 	}
 
+	/* Save the last explicitly set non-zero powercap value */
+	if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 && !ret && power_cap)
+		pi->states[domain_id].last_pcap = power_cap;
+
 	return ret;
 }
 
@@ -421,6 +427,20 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 {
 	struct powercap_info *pi = ph->get_priv(ph);
 
+	/*
+	 * Disallow zero as a possible explicitly requested powercap:
+	 * there are enable/disable operations for this.
+	 */
+	if (!power_cap)
+		return -EINVAL;
+
+	/* Just log the last set request if acting on a disabled domain */
+	if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 &&
+	    !pi->states[domain_id].enabled) {
+		pi->states[domain_id].last_pcap = power_cap;
+		return 0;
+	}
+
 	return __scmi_powercap_cap_set(ph, pi, domain_id,
 				       power_cap, ignore_dresp);
 }
@@ -589,11 +609,78 @@ scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
 	return ret;
 }
 
+static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
+					u32 domain_id, bool enable)
+{
+	int ret;
+	u32 power_cap;
+	struct powercap_info *pi = ph->get_priv(ph);
+
+	if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
+		return -EINVAL;
+
+	if (enable == pi->states[domain_id].enabled)
+		return 0;
+
+	if (enable) {
+		/* Cannot enable with a zero powercap. */
+		if (!pi->states[domain_id].last_pcap)
+			return -EINVAL;
+
+		ret = __scmi_powercap_cap_set(ph, pi, domain_id,
+					      pi->states[domain_id].last_pcap,
+					      true);
+	} else {
+		ret = __scmi_powercap_cap_set(ph, pi, domain_id, 0, true);
+	}
+
+	if (ret)
+		return ret;
+
+	/*
+	 * Update our internal state to reflect final platform state: the SCMI
+	 * server could have ignored a disable request and kept enforcing some
+	 * powercap limit requested by other agents.
+	 */
+	ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
+	if (!ret)
+		pi->states[domain_id].enabled = !!power_cap;
+
+	return ret;
+}
+
+static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
+					u32 domain_id, bool *enable)
+{
+	int ret;
+	u32 power_cap;
+	struct powercap_info *pi = ph->get_priv(ph);
+
+	*enable = true;
+	if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
+		return 0;
+
+	/*
+	 * Report always real platform state; platform could have ignored
+	 * a previous disable request. Default true on any error.
+	 */
+	ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
+	if (!ret)
+		*enable = !!power_cap;
+
+	/* Update internal state with current real platform state */
+	pi->states[domain_id].enabled = *enable;
+
+	return 0;
+}
+
 static const struct scmi_powercap_proto_ops powercap_proto_ops = {
 	.num_domains_get = scmi_powercap_num_domains_get,
 	.info_get = scmi_powercap_dom_info_get,
 	.cap_get = scmi_powercap_cap_get,
 	.cap_set = scmi_powercap_cap_set,
+	.cap_enable_set = scmi_powercap_cap_enable_set,
+	.cap_enable_get = scmi_powercap_cap_enable_get,
 	.pai_get = scmi_powercap_pai_get,
 	.pai_set = scmi_powercap_pai_set,
 	.measurements_get = scmi_powercap_measurements_get,
@@ -854,6 +941,11 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 	if (!pinfo->powercaps)
 		return -ENOMEM;
 
+	pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
+				     sizeof(*pinfo->states), GFP_KERNEL);
+	if (!pinfo->states)
+		return -ENOMEM;
+
 	/*
 	 * Note that any failure in retrieving any domain attribute leads to
 	 * the whole Powercap protocol initialization failure: this way the
@@ -868,15 +960,21 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 		if (pinfo->powercaps[domain].fastchannels)
 			scmi_powercap_domain_init_fc(ph, domain,
 						     &pinfo->powercaps[domain].fc_info);
-	}
 
-	pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
-				     sizeof(*pinfo->states), GFP_KERNEL);
-	if (!pinfo->states)
-		return -ENOMEM;
+		/* Grab initial state when disable is supported. */
+		if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
+			ret = __scmi_powercap_cap_get(ph,
+						      &pinfo->powercaps[domain],
+						      &pinfo->states[domain].last_pcap);
+			if (ret)
+				return ret;
 
-	pinfo->version = version;
+			pinfo->states[domain].enabled =
+				!!pinfo->states[domain].last_pcap;
+		}
+	}
 
+	pinfo->version = version;
 	return ph->set_priv(ph, pinfo);
 }
 
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 0ce5746a4470..e6fe4f73ffe6 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -629,11 +629,25 @@ struct scmi_powercap_info {
  * @num_domains_get: get the count of powercap domains provided by SCMI.
  * @info_get: get the information for the specified domain.
  * @cap_get: get the current CAP value for the specified domain.
+ *	     On SCMI platforms supporting powercap zone disabling, this could
+ *	     report a zero value for a zone where powercapping is disabled.
  * @cap_set: set the CAP value for the specified domain to the provided value;
  *	     if the domain supports setting the CAP with an asynchronous command
  *	     this request will finally trigger an asynchronous transfer, but, if
  *	     @ignore_dresp here is set to true, this call will anyway return
  *	     immediately without waiting for the related delayed response.
+ *	     Note that the powercap requested value must NOT be zero, even if
+ *	     the platform supports disabling a powercap by setting its cap to
+ *	     zero (since SCMI v3.2): there are dedicated operations that should
+ *	     be used for that. (@cap_enable_set/get)
+ * @cap_enable_set: enable or disable the powercapping on the specified domain,
+ *		    if supported by the SCMI platform implementation.
+ *		    Note that, by the SCMI specification, the platform can
+ *		    silently ignore our disable request and decide to enforce
+ *		    anyway some other powercap value requested by another agent
+ *		    on the system: for this reason @cap_get and @cap_enable_get
+ *		    will always report the final platform view of the powercaps.
+ * @cap_enable_get: get the current CAP enable status for the specified domain.
  * @pai_get: get the current PAI value for the specified domain.
  * @pai_set: set the PAI value for the specified domain to the provided value.
  * @measurements_get: retrieve the current average power measurements for the
@@ -662,6 +676,10 @@ struct scmi_powercap_proto_ops {
 		       u32 *power_cap);
 	int (*cap_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
 		       u32 power_cap, bool ignore_dresp);
+	int (*cap_enable_set)(const struct scmi_protocol_handle *ph,
+			      u32 domain_id, bool enable);
+	int (*cap_enable_get)(const struct scmi_protocol_handle *ph,
+			      u32 domain_id, bool *enable);
 	int (*pai_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
 		       u32 *pai);
 	int (*pai_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
-- 
2.34.1


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

* [PATCH v3 3/3] powercap: arm_scmi: Add support for disabling powercaps on a zone
  2023-05-31 15:20 [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Cristian Marussi
  2023-05-31 15:20 ` [PATCH v3 1/3] firmware: arm_scmi: Refactor powercap get/set helpers Cristian Marussi
  2023-05-31 15:20 ` [PATCH v3 2/3] firmware: arm_scmi: Add Powercap protocol enable support Cristian Marussi
@ 2023-05-31 15:20 ` Cristian Marussi
  2023-06-06 13:07 ` [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Sudeep Holla
  3 siblings, 0 replies; 5+ messages in thread
From: Cristian Marussi @ 2023-05-31 15:20 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-pm
  Cc: sudeep.holla, james.quinlan, Jonathan.Cameron, f.fainelli,
	vincent.guittot, tarek.el-sherbiny, nicola.mazzucato,
	souvik.chakravarty, wleavitt, wbartczak, Cristian Marussi,
	Rafael J . Wysocki

Add support to disable/enable powercapping on a zone.

Acked-by: Rafael J. Wysocki <rafael@kernel.org>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> v3
- rebased on v6.4-rc4
- added Acked-by
---
 drivers/powercap/arm_scmi_powercap.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index 05d0e516176a..5231f6d52ae3 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -70,10 +70,26 @@ static int scmi_powercap_get_power_uw(struct powercap_zone *pz,
 	return 0;
 }
 
+static int scmi_powercap_zone_enable_set(struct powercap_zone *pz, bool mode)
+{
+	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+
+	return powercap_ops->cap_enable_set(spz->ph, spz->info->id, mode);
+}
+
+static int scmi_powercap_zone_enable_get(struct powercap_zone *pz, bool *mode)
+{
+	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+
+	return powercap_ops->cap_enable_get(spz->ph, spz->info->id, mode);
+}
+
 static const struct powercap_zone_ops zone_ops = {
 	.get_max_power_range_uw = scmi_powercap_get_max_power_range_uw,
 	.get_power_uw = scmi_powercap_get_power_uw,
 	.release = scmi_powercap_zone_release,
+	.set_enable = scmi_powercap_zone_enable_set,
+	.get_enable = scmi_powercap_zone_enable_get,
 };
 
 static void scmi_powercap_normalize_cap(const struct scmi_powercap_zone *spz,
-- 
2.34.1


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

* Re: [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support
  2023-05-31 15:20 [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Cristian Marussi
                   ` (2 preceding siblings ...)
  2023-05-31 15:20 ` [PATCH v3 3/3] powercap: arm_scmi: Add support for disabling powercaps on a zone Cristian Marussi
@ 2023-06-06 13:07 ` Sudeep Holla
  3 siblings, 0 replies; 5+ messages in thread
From: Sudeep Holla @ 2023-06-06 13:07 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux-pm, Cristian Marussi
  Cc: Sudeep Holla, james.quinlan, Jonathan.Cameron, f.fainelli,
	vincent.guittot, tarek.el-sherbiny, nicola.mazzucato,
	souvik.chakravarty, wleavitt, wbartczak

On Wed, 31 May 2023 16:20:36 +0100, Cristian Marussi wrote:
> Upcoming SCMI v3.2 specification (publicly available as BETA at [1])
> introduces support to disable powercapping as a whole on the desired
> zones.
> 
> This small series at first add the needed support to the core SCMI Powercap
> protocol, exposing a couple more enable/disable protocol operations, and
> then wires such new ops in the related Powercap framework helpers.
> 
> [...]

Applied to sudeep.holla/linux (for-next/scmi/updates), thanks!

[1/3] firmware: arm_scmi: Refactor powercap get/set helpers
      https://git.kernel.org/sudeep.holla/c/4e1a53b4030e
[2/3] firmware: arm_scmi: Add Powercap protocol enable support
      https://git.kernel.org/sudeep.holla/c/758cd5fc13b2
[3/3] powercap: arm_scmi: Add support for disabling powercaps on a zone
      https://git.kernel.org/sudeep.holla/c/aaffb4cacd4c
--
Regards,
Sudeep


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

end of thread, other threads:[~2023-06-06 13:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-31 15:20 [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Cristian Marussi
2023-05-31 15:20 ` [PATCH v3 1/3] firmware: arm_scmi: Refactor powercap get/set helpers Cristian Marussi
2023-05-31 15:20 ` [PATCH v3 2/3] firmware: arm_scmi: Add Powercap protocol enable support Cristian Marussi
2023-05-31 15:20 ` [PATCH v3 3/3] powercap: arm_scmi: Add support for disabling powercaps on a zone Cristian Marussi
2023-06-06 13:07 ` [PATCH v3 0/3] Add SCMI v3.2 Powercap disable support Sudeep Holla

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).