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.3-rc1.
Thanks,
Cristian
[1]: https://developer.arm.com/documentation/den0056/e
---
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
Refactor SCMI powercap internal get/set helpers.
Signed-off-by: Cristian Marussi <[email protected]>
---
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
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.
Signed-off-by: Cristian Marussi <[email protected]>
---
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
Add support to disable/enable powercapping on a zone.
Cc: "Rafael J. Wysocki" <[email protected]>
Signed-off-by: Cristian Marussi <[email protected]>
---
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
On Thu, Mar 9, 2023 at 3:09 PM Cristian Marussi
<[email protected]> wrote:
>
> Refactor SCMI powercap internal get/set helpers.
>
> Signed-off-by: Cristian Marussi <[email protected]>
I can apply this series if I get an ACK or preferably Reviewed-by:
from an SCMI person.
However, I think that it would be more appropriate to route it through
ARM/ARM64 anyway.
> ---
> 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
>
On Mon, Mar 27, 2023 at 07:06:36PM +0200, Rafael J. Wysocki wrote:
> On Thu, Mar 9, 2023 at 3:09 PM Cristian Marussi
> <[email protected]> wrote:
> >
> > Refactor SCMI powercap internal get/set helpers.
> >
> > Signed-off-by: Cristian Marussi <[email protected]>
>
Hi Rafael,
Thanks for having a look.
> I can apply this series if I get an ACK or preferably Reviewed-by:
> from an SCMI person.
>
I'll see if I can chase someone for this cycle :D
> However, I think that it would be more appropriate to route it through
> ARM/ARM64 anyway.
>
Yes, indeed it is what usually happens I think, but I thought
appropriate to Cc you being power related.
Thanks,
Cristian
On Mon, Mar 27, 2023 at 07:06:36PM +0200, Rafael J. Wysocki wrote:
> On Thu, Mar 9, 2023 at 3:09 PM Cristian Marussi
> <[email protected]> wrote:
> >
> > Refactor SCMI powercap internal get/set helpers.
> >
> > Signed-off-by: Cristian Marussi <[email protected]>
>
> I can apply this series if I get an ACK or preferably Reviewed-by:
> from an SCMI person.
>
Sorry, I had looked at this and just delayed asking you about your preference.
I am fine to take it or else
Reviewed-by: Sudeep Holla <[email protected]> (for SCMI parts)
Please ack 3/3 if you prefer me to take it once you are happy with it.
--
Regards,
Sudeep
On Wed, Mar 29, 2023 at 2:05 PM Sudeep Holla <[email protected]> wrote:
>
> On Mon, Mar 27, 2023 at 07:06:36PM +0200, Rafael J. Wysocki wrote:
> > On Thu, Mar 9, 2023 at 3:09 PM Cristian Marussi
> > <[email protected]> wrote:
> > >
> > > Refactor SCMI powercap internal get/set helpers.
> > >
> > > Signed-off-by: Cristian Marussi <[email protected]>
> >
> > I can apply this series if I get an ACK or preferably Reviewed-by:
> > from an SCMI person.
> >
>
> Sorry, I had looked at this and just delayed asking you about your preference.
> I am fine to take it
Yes, please!
> or else
>
> Reviewed-by: Sudeep Holla <[email protected]> (for SCMI parts)
>
> Please ack 3/3 if you prefer me to take it once you are happy with it.
Done, thanks!
On Thu, Mar 9, 2023 at 3:07 PM Cristian Marussi
<[email protected]> wrote:
>
> Add support to disable/enable powercapping on a zone.
>
> Cc: "Rafael J. Wysocki" <[email protected]>
> Signed-off-by: Cristian Marussi <[email protected]>
Acked-by: Rafael J. Wysocki <[email protected]>
> ---
> 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
>