1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface (SCMI) Powercap Protocol
5 * Copyright (C) 2022 ARM Ltd.
8 #define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
10 #include <linux/bitfield.h>
12 #include <linux/module.h>
13 #include <linux/scmi_protocol.h>
15 #include <trace/events/scmi.h>
17 #include "protocols.h"
20 /* Updated only after ALL the mandatory features for that version are merged */
21 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
23 enum scmi_powercap_protocol_cmd
{
24 POWERCAP_DOMAIN_ATTRIBUTES
= 0x3,
25 POWERCAP_CAP_GET
= 0x4,
26 POWERCAP_CAP_SET
= 0x5,
27 POWERCAP_PAI_GET
= 0x6,
28 POWERCAP_PAI_SET
= 0x7,
29 POWERCAP_DOMAIN_NAME_GET
= 0x8,
30 POWERCAP_MEASUREMENTS_GET
= 0x9,
31 POWERCAP_CAP_NOTIFY
= 0xa,
32 POWERCAP_MEASUREMENTS_NOTIFY
= 0xb,
33 POWERCAP_DESCRIBE_FASTCHANNEL
= 0xc,
42 struct scmi_msg_resp_powercap_domain_attributes
{
44 #define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(x) ((x) & BIT(31))
45 #define SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(x) ((x) & BIT(30))
46 #define SUPPORTS_ASYNC_POWERCAP_CAP_SET(x) ((x) & BIT(29))
47 #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(28))
48 #define SUPPORTS_POWERCAP_CAP_CONFIGURATION(x) ((x) & BIT(27))
49 #define SUPPORTS_POWERCAP_MONITORING(x) ((x) & BIT(26))
50 #define SUPPORTS_POWERCAP_PAI_CONFIGURATION(x) ((x) & BIT(25))
51 #define SUPPORTS_POWERCAP_FASTCHANNELS(x) ((x) & BIT(22))
52 #define POWERCAP_POWER_UNIT(x) \
53 (FIELD_GET(GENMASK(24, 23), (x)))
54 #define SUPPORTS_POWER_UNITS_MW(x) \
55 (POWERCAP_POWER_UNIT(x) == 0x2)
56 #define SUPPORTS_POWER_UNITS_UW(x) \
57 (POWERCAP_POWER_UNIT(x) == 0x1)
58 u8 name
[SCMI_SHORT_NAME_MAX_SIZE
];
64 __le32 power_cap_step
;
65 __le32 sustainable_power
;
70 struct scmi_msg_powercap_set_cap_or_pai
{
73 #define CAP_SET_ASYNC BIT(1)
74 #define CAP_SET_IGNORE_DRESP BIT(0)
78 struct scmi_msg_resp_powercap_cap_set_complete
{
83 struct scmi_msg_resp_powercap_meas_get
{
88 struct scmi_msg_powercap_notify_cap
{
93 struct scmi_msg_powercap_notify_thresh
{
96 __le32 power_thresh_low
;
97 __le32 power_thresh_high
;
100 struct scmi_powercap_cap_changed_notify_payld
{
107 struct scmi_powercap_meas_changed_notify_payld
{
113 struct scmi_powercap_state
{
116 bool meas_notif_enabled
;
118 #define THRESH_LOW(p, id) \
119 (lower_32_bits((p)->states[(id)].thresholds))
120 #define THRESH_HIGH(p, id) \
121 (upper_32_bits((p)->states[(id)].thresholds))
124 struct powercap_info
{
128 bool notify_measurements_cmd
;
129 struct scmi_powercap_state
*states
;
130 struct scmi_powercap_info
*powercaps
;
133 static enum scmi_powercap_protocol_cmd evt_2_cmd
[] = {
135 POWERCAP_MEASUREMENTS_NOTIFY
,
138 static int scmi_powercap_notify(const struct scmi_protocol_handle
*ph
,
139 u32 domain
, int message_id
, bool enable
);
142 scmi_powercap_attributes_get(const struct scmi_protocol_handle
*ph
,
143 struct powercap_info
*pi
)
148 ret
= ph
->xops
->xfer_get_init(ph
, PROTOCOL_ATTRIBUTES
, 0,
153 ret
= ph
->xops
->do_xfer(ph
, t
);
157 attributes
= get_unaligned_le32(t
->rx
.buf
);
158 pi
->num_domains
= FIELD_GET(GENMASK(15, 0), attributes
);
161 ph
->xops
->xfer_put(ph
, t
);
164 if (!ph
->hops
->protocol_msg_check(ph
,
165 POWERCAP_CAP_NOTIFY
, NULL
))
166 pi
->notify_cap_cmd
= true;
168 if (!ph
->hops
->protocol_msg_check(ph
,
169 POWERCAP_MEASUREMENTS_NOTIFY
,
171 pi
->notify_measurements_cmd
= true;
178 scmi_powercap_validate(unsigned int min_val
, unsigned int max_val
,
179 unsigned int step_val
, bool configurable
)
181 if (!min_val
|| !max_val
)
184 if ((configurable
&& min_val
== max_val
) ||
185 (!configurable
&& min_val
!= max_val
))
188 if (min_val
!= max_val
&& !step_val
)
195 scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle
*ph
,
196 struct powercap_info
*pinfo
, u32 domain
)
201 struct scmi_powercap_info
*dom_info
= pinfo
->powercaps
+ domain
;
202 struct scmi_msg_resp_powercap_domain_attributes
*resp
;
204 ret
= ph
->xops
->xfer_get_init(ph
, POWERCAP_DOMAIN_ATTRIBUTES
,
205 sizeof(domain
), sizeof(*resp
), &t
);
209 put_unaligned_le32(domain
, t
->tx
.buf
);
212 ret
= ph
->xops
->do_xfer(ph
, t
);
214 flags
= le32_to_cpu(resp
->attributes
);
216 dom_info
->id
= domain
;
217 if (pinfo
->notify_cap_cmd
)
218 dom_info
->notify_powercap_cap_change
=
219 SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags
);
220 if (pinfo
->notify_measurements_cmd
)
221 dom_info
->notify_powercap_measurement_change
=
222 SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags
);
223 dom_info
->async_powercap_cap_set
=
224 SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags
);
225 dom_info
->powercap_cap_config
=
226 SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags
);
227 dom_info
->powercap_monitoring
=
228 SUPPORTS_POWERCAP_MONITORING(flags
);
229 dom_info
->powercap_pai_config
=
230 SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags
);
231 dom_info
->powercap_scale_mw
=
232 SUPPORTS_POWER_UNITS_MW(flags
);
233 dom_info
->powercap_scale_uw
=
234 SUPPORTS_POWER_UNITS_UW(flags
);
235 dom_info
->fastchannels
=
236 SUPPORTS_POWERCAP_FASTCHANNELS(flags
);
238 strscpy(dom_info
->name
, resp
->name
, SCMI_SHORT_NAME_MAX_SIZE
);
240 dom_info
->min_pai
= le32_to_cpu(resp
->min_pai
);
241 dom_info
->max_pai
= le32_to_cpu(resp
->max_pai
);
242 dom_info
->pai_step
= le32_to_cpu(resp
->pai_step
);
243 ret
= scmi_powercap_validate(dom_info
->min_pai
,
246 dom_info
->powercap_pai_config
);
249 "Platform reported inconsistent PAI config for domain %d - %s\n",
250 dom_info
->id
, dom_info
->name
);
254 dom_info
->min_power_cap
= le32_to_cpu(resp
->min_power_cap
);
255 dom_info
->max_power_cap
= le32_to_cpu(resp
->max_power_cap
);
256 dom_info
->power_cap_step
= le32_to_cpu(resp
->power_cap_step
);
257 ret
= scmi_powercap_validate(dom_info
->min_power_cap
,
258 dom_info
->max_power_cap
,
259 dom_info
->power_cap_step
,
260 dom_info
->powercap_cap_config
);
263 "Platform reported inconsistent CAP config for domain %d - %s\n",
264 dom_info
->id
, dom_info
->name
);
268 dom_info
->sustainable_power
=
269 le32_to_cpu(resp
->sustainable_power
);
270 dom_info
->accuracy
= le32_to_cpu(resp
->accuracy
);
272 dom_info
->parent_id
= le32_to_cpu(resp
->parent_id
);
273 if (dom_info
->parent_id
!= SCMI_POWERCAP_ROOT_ZONE_ID
&&
274 (dom_info
->parent_id
>= pinfo
->num_domains
||
275 dom_info
->parent_id
== dom_info
->id
)) {
277 "Platform reported inconsistent parent ID for domain %d - %s\n",
278 dom_info
->id
, dom_info
->name
);
284 ph
->xops
->xfer_put(ph
, t
);
287 * If supported overwrite short name with the extended one;
288 * on error just carry on and use already provided short name.
290 if (!ret
&& SUPPORTS_EXTENDED_NAMES(flags
))
291 ph
->hops
->extended_name_get(ph
, POWERCAP_DOMAIN_NAME_GET
,
292 domain
, NULL
, dom_info
->name
,
298 static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle
*ph
)
300 struct powercap_info
*pi
= ph
->get_priv(ph
);
302 return pi
->num_domains
;
305 static const struct scmi_powercap_info
*
306 scmi_powercap_dom_info_get(const struct scmi_protocol_handle
*ph
, u32 domain_id
)
308 struct powercap_info
*pi
= ph
->get_priv(ph
);
310 if (domain_id
>= pi
->num_domains
)
313 return pi
->powercaps
+ domain_id
;
316 static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle
*ph
,
317 u32 domain_id
, u32
*power_cap
)
322 ret
= ph
->xops
->xfer_get_init(ph
, POWERCAP_CAP_GET
, sizeof(u32
),
327 put_unaligned_le32(domain_id
, t
->tx
.buf
);
328 ret
= ph
->xops
->do_xfer(ph
, t
);
330 *power_cap
= get_unaligned_le32(t
->rx
.buf
);
332 ph
->xops
->xfer_put(ph
, t
);
337 static int __scmi_powercap_cap_get(const struct scmi_protocol_handle
*ph
,
338 const struct scmi_powercap_info
*dom
,
341 if (dom
->fc_info
&& dom
->fc_info
[POWERCAP_FC_CAP
].get_addr
) {
342 *power_cap
= ioread32(dom
->fc_info
[POWERCAP_FC_CAP
].get_addr
);
343 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP
, POWERCAP_CAP_GET
,
344 dom
->id
, *power_cap
, 0);
348 return scmi_powercap_xfer_cap_get(ph
, dom
->id
, power_cap
);
351 static int scmi_powercap_cap_get(const struct scmi_protocol_handle
*ph
,
352 u32 domain_id
, u32
*power_cap
)
354 const struct scmi_powercap_info
*dom
;
359 dom
= scmi_powercap_dom_info_get(ph
, domain_id
);
363 return __scmi_powercap_cap_get(ph
, dom
, power_cap
);
366 static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle
*ph
,
367 const struct scmi_powercap_info
*pc
,
368 u32 power_cap
, bool ignore_dresp
)
372 struct scmi_msg_powercap_set_cap_or_pai
*msg
;
374 ret
= ph
->xops
->xfer_get_init(ph
, POWERCAP_CAP_SET
,
375 sizeof(*msg
), 0, &t
);
380 msg
->domain
= cpu_to_le32(pc
->id
);
382 cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC
, pc
->async_powercap_cap_set
) |
383 FIELD_PREP(CAP_SET_IGNORE_DRESP
, ignore_dresp
));
384 msg
->value
= cpu_to_le32(power_cap
);
386 if (!pc
->async_powercap_cap_set
|| ignore_dresp
) {
387 ret
= ph
->xops
->do_xfer(ph
, t
);
389 ret
= ph
->xops
->do_xfer_with_response(ph
, t
);
391 struct scmi_msg_resp_powercap_cap_set_complete
*resp
;
394 if (le32_to_cpu(resp
->domain
) == pc
->id
)
396 "Powercap ID %d CAP set async to %u\n",
398 get_unaligned_le32(&resp
->power_cap
));
404 ph
->xops
->xfer_put(ph
, t
);
408 static int __scmi_powercap_cap_set(const struct scmi_protocol_handle
*ph
,
409 struct powercap_info
*pi
, u32 domain_id
,
410 u32 power_cap
, bool ignore_dresp
)
413 const struct scmi_powercap_info
*pc
;
415 pc
= scmi_powercap_dom_info_get(ph
, domain_id
);
416 if (!pc
|| !pc
->powercap_cap_config
)
420 (power_cap
< pc
->min_power_cap
|| power_cap
> pc
->max_power_cap
))
423 if (pc
->fc_info
&& pc
->fc_info
[POWERCAP_FC_CAP
].set_addr
) {
424 struct scmi_fc_info
*fci
= &pc
->fc_info
[POWERCAP_FC_CAP
];
426 iowrite32(power_cap
, fci
->set_addr
);
427 ph
->hops
->fastchannel_db_ring(fci
->set_db
);
428 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP
, POWERCAP_CAP_SET
,
429 domain_id
, power_cap
, 0);
432 ret
= scmi_powercap_xfer_cap_set(ph
, pc
, power_cap
,
436 /* Save the last explicitly set non-zero powercap value */
437 if (PROTOCOL_REV_MAJOR(pi
->version
) >= 0x2 && !ret
&& power_cap
)
438 pi
->states
[domain_id
].last_pcap
= power_cap
;
443 static int scmi_powercap_cap_set(const struct scmi_protocol_handle
*ph
,
444 u32 domain_id
, u32 power_cap
,
447 struct powercap_info
*pi
= ph
->get_priv(ph
);
450 * Disallow zero as a possible explicitly requested powercap:
451 * there are enable/disable operations for this.
456 /* Just log the last set request if acting on a disabled domain */
457 if (PROTOCOL_REV_MAJOR(pi
->version
) >= 0x2 &&
458 !pi
->states
[domain_id
].enabled
) {
459 pi
->states
[domain_id
].last_pcap
= power_cap
;
463 return __scmi_powercap_cap_set(ph
, pi
, domain_id
,
464 power_cap
, ignore_dresp
);
467 static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle
*ph
,
468 u32 domain_id
, u32
*pai
)
473 ret
= ph
->xops
->xfer_get_init(ph
, POWERCAP_PAI_GET
, sizeof(u32
),
478 put_unaligned_le32(domain_id
, t
->tx
.buf
);
479 ret
= ph
->xops
->do_xfer(ph
, t
);
481 *pai
= get_unaligned_le32(t
->rx
.buf
);
483 ph
->xops
->xfer_put(ph
, t
);
488 static int scmi_powercap_pai_get(const struct scmi_protocol_handle
*ph
,
489 u32 domain_id
, u32
*pai
)
491 struct scmi_powercap_info
*dom
;
492 struct powercap_info
*pi
= ph
->get_priv(ph
);
494 if (!pai
|| domain_id
>= pi
->num_domains
)
497 dom
= pi
->powercaps
+ domain_id
;
498 if (dom
->fc_info
&& dom
->fc_info
[POWERCAP_FC_PAI
].get_addr
) {
499 *pai
= ioread32(dom
->fc_info
[POWERCAP_FC_PAI
].get_addr
);
500 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP
, POWERCAP_PAI_GET
,
505 return scmi_powercap_xfer_pai_get(ph
, domain_id
, pai
);
508 static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle
*ph
,
509 u32 domain_id
, u32 pai
)
513 struct scmi_msg_powercap_set_cap_or_pai
*msg
;
515 ret
= ph
->xops
->xfer_get_init(ph
, POWERCAP_PAI_SET
,
516 sizeof(*msg
), 0, &t
);
521 msg
->domain
= cpu_to_le32(domain_id
);
522 msg
->flags
= cpu_to_le32(0);
523 msg
->value
= cpu_to_le32(pai
);
525 ret
= ph
->xops
->do_xfer(ph
, t
);
527 ph
->xops
->xfer_put(ph
, t
);
531 static int scmi_powercap_pai_set(const struct scmi_protocol_handle
*ph
,
532 u32 domain_id
, u32 pai
)
534 const struct scmi_powercap_info
*pc
;
536 pc
= scmi_powercap_dom_info_get(ph
, domain_id
);
537 if (!pc
|| !pc
->powercap_pai_config
|| !pai
||
538 pai
< pc
->min_pai
|| pai
> pc
->max_pai
)
541 if (pc
->fc_info
&& pc
->fc_info
[POWERCAP_FC_PAI
].set_addr
) {
542 struct scmi_fc_info
*fci
= &pc
->fc_info
[POWERCAP_FC_PAI
];
544 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP
, POWERCAP_PAI_SET
,
546 iowrite32(pai
, fci
->set_addr
);
547 ph
->hops
->fastchannel_db_ring(fci
->set_db
);
551 return scmi_powercap_xfer_pai_set(ph
, domain_id
, pai
);
554 static int scmi_powercap_measurements_get(const struct scmi_protocol_handle
*ph
,
555 u32 domain_id
, u32
*average_power
,
560 struct scmi_msg_resp_powercap_meas_get
*resp
;
561 const struct scmi_powercap_info
*pc
;
563 pc
= scmi_powercap_dom_info_get(ph
, domain_id
);
564 if (!pc
|| !pc
->powercap_monitoring
|| !pai
|| !average_power
)
567 ret
= ph
->xops
->xfer_get_init(ph
, POWERCAP_MEASUREMENTS_GET
,
568 sizeof(u32
), sizeof(*resp
), &t
);
573 put_unaligned_le32(domain_id
, t
->tx
.buf
);
574 ret
= ph
->xops
->do_xfer(ph
, t
);
576 *average_power
= le32_to_cpu(resp
->power
);
577 *pai
= le32_to_cpu(resp
->pai
);
580 ph
->xops
->xfer_put(ph
, t
);
585 scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle
*ph
,
586 u32 domain_id
, u32
*power_thresh_low
,
587 u32
*power_thresh_high
)
589 struct powercap_info
*pi
= ph
->get_priv(ph
);
591 if (!power_thresh_low
|| !power_thresh_high
||
592 domain_id
>= pi
->num_domains
)
595 *power_thresh_low
= THRESH_LOW(pi
, domain_id
);
596 *power_thresh_high
= THRESH_HIGH(pi
, domain_id
);
602 scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle
*ph
,
603 u32 domain_id
, u32 power_thresh_low
,
604 u32 power_thresh_high
)
607 struct powercap_info
*pi
= ph
->get_priv(ph
);
609 if (domain_id
>= pi
->num_domains
||
610 power_thresh_low
> power_thresh_high
)
613 /* Anything to do ? */
614 if (THRESH_LOW(pi
, domain_id
) == power_thresh_low
&&
615 THRESH_HIGH(pi
, domain_id
) == power_thresh_high
)
618 pi
->states
[domain_id
].thresholds
=
619 (FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low
) |
620 FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high
));
622 /* Update thresholds if notification already enabled */
623 if (pi
->states
[domain_id
].meas_notif_enabled
)
624 ret
= scmi_powercap_notify(ph
, domain_id
,
625 POWERCAP_MEASUREMENTS_NOTIFY
,
631 static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle
*ph
,
632 u32 domain_id
, bool enable
)
636 struct powercap_info
*pi
= ph
->get_priv(ph
);
638 if (PROTOCOL_REV_MAJOR(pi
->version
) < 0x2)
641 if (enable
== pi
->states
[domain_id
].enabled
)
645 /* Cannot enable with a zero powercap. */
646 if (!pi
->states
[domain_id
].last_pcap
)
649 ret
= __scmi_powercap_cap_set(ph
, pi
, domain_id
,
650 pi
->states
[domain_id
].last_pcap
,
653 ret
= __scmi_powercap_cap_set(ph
, pi
, domain_id
, 0, true);
660 * Update our internal state to reflect final platform state: the SCMI
661 * server could have ignored a disable request and kept enforcing some
662 * powercap limit requested by other agents.
664 ret
= scmi_powercap_cap_get(ph
, domain_id
, &power_cap
);
666 pi
->states
[domain_id
].enabled
= !!power_cap
;
671 static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle
*ph
,
672 u32 domain_id
, bool *enable
)
676 struct powercap_info
*pi
= ph
->get_priv(ph
);
679 if (PROTOCOL_REV_MAJOR(pi
->version
) < 0x2)
683 * Report always real platform state; platform could have ignored
684 * a previous disable request. Default true on any error.
686 ret
= scmi_powercap_cap_get(ph
, domain_id
, &power_cap
);
688 *enable
= !!power_cap
;
690 /* Update internal state with current real platform state */
691 pi
->states
[domain_id
].enabled
= *enable
;
696 static const struct scmi_powercap_proto_ops powercap_proto_ops
= {
697 .num_domains_get
= scmi_powercap_num_domains_get
,
698 .info_get
= scmi_powercap_dom_info_get
,
699 .cap_get
= scmi_powercap_cap_get
,
700 .cap_set
= scmi_powercap_cap_set
,
701 .cap_enable_set
= scmi_powercap_cap_enable_set
,
702 .cap_enable_get
= scmi_powercap_cap_enable_get
,
703 .pai_get
= scmi_powercap_pai_get
,
704 .pai_set
= scmi_powercap_pai_set
,
705 .measurements_get
= scmi_powercap_measurements_get
,
706 .measurements_threshold_set
= scmi_powercap_measurements_threshold_set
,
707 .measurements_threshold_get
= scmi_powercap_measurements_threshold_get
,
710 static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle
*ph
,
711 u32 domain
, struct scmi_fc_info
**p_fc
)
713 struct scmi_fc_info
*fc
;
715 fc
= devm_kcalloc(ph
->dev
, POWERCAP_FC_MAX
, sizeof(*fc
), GFP_KERNEL
);
719 ph
->hops
->fastchannel_init(ph
, POWERCAP_DESCRIBE_FASTCHANNEL
,
720 POWERCAP_CAP_SET
, 4, domain
,
721 &fc
[POWERCAP_FC_CAP
].set_addr
,
722 &fc
[POWERCAP_FC_CAP
].set_db
,
723 &fc
[POWERCAP_FC_CAP
].rate_limit
);
725 ph
->hops
->fastchannel_init(ph
, POWERCAP_DESCRIBE_FASTCHANNEL
,
726 POWERCAP_CAP_GET
, 4, domain
,
727 &fc
[POWERCAP_FC_CAP
].get_addr
, NULL
,
728 &fc
[POWERCAP_FC_CAP
].rate_limit
);
730 ph
->hops
->fastchannel_init(ph
, POWERCAP_DESCRIBE_FASTCHANNEL
,
731 POWERCAP_PAI_SET
, 4, domain
,
732 &fc
[POWERCAP_FC_PAI
].set_addr
,
733 &fc
[POWERCAP_FC_PAI
].set_db
,
734 &fc
[POWERCAP_FC_PAI
].rate_limit
);
736 ph
->hops
->fastchannel_init(ph
, POWERCAP_DESCRIBE_FASTCHANNEL
,
737 POWERCAP_PAI_GET
, 4, domain
,
738 &fc
[POWERCAP_FC_PAI
].get_addr
, NULL
,
739 &fc
[POWERCAP_FC_PAI
].rate_limit
);
744 static int scmi_powercap_notify(const struct scmi_protocol_handle
*ph
,
745 u32 domain
, int message_id
, bool enable
)
750 switch (message_id
) {
751 case POWERCAP_CAP_NOTIFY
:
753 struct scmi_msg_powercap_notify_cap
*notify
;
755 ret
= ph
->xops
->xfer_get_init(ph
, message_id
,
756 sizeof(*notify
), 0, &t
);
761 notify
->domain
= cpu_to_le32(domain
);
762 notify
->notify_enable
= cpu_to_le32(enable
? BIT(0) : 0);
765 case POWERCAP_MEASUREMENTS_NOTIFY
:
768 struct scmi_msg_powercap_notify_thresh
*notify
;
771 * Note that we have to pick the most recently configured
772 * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
773 * enable request and we fail, complaining, if no thresholds
774 * were ever set, since this is an indication the API has been
777 ret
= scmi_powercap_measurements_threshold_get(ph
, domain
,
782 if (enable
&& !low
&& !high
) {
784 "Invalid Measurements Notify thresholds: %u/%u\n",
789 ret
= ph
->xops
->xfer_get_init(ph
, message_id
,
790 sizeof(*notify
), 0, &t
);
795 notify
->domain
= cpu_to_le32(domain
);
796 notify
->notify_enable
= cpu_to_le32(enable
? BIT(0) : 0);
797 notify
->power_thresh_low
= cpu_to_le32(low
);
798 notify
->power_thresh_high
= cpu_to_le32(high
);
805 ret
= ph
->xops
->do_xfer(ph
, t
);
807 ph
->xops
->xfer_put(ph
, t
);
812 scmi_powercap_notify_supported(const struct scmi_protocol_handle
*ph
,
813 u8 evt_id
, u32 src_id
)
815 bool supported
= false;
816 const struct scmi_powercap_info
*dom_info
;
817 struct powercap_info
*pi
= ph
->get_priv(ph
);
819 if (evt_id
>= ARRAY_SIZE(evt_2_cmd
) || src_id
>= pi
->num_domains
)
822 dom_info
= pi
->powercaps
+ src_id
;
823 if (evt_id
== SCMI_EVENT_POWERCAP_CAP_CHANGED
)
824 supported
= dom_info
->notify_powercap_cap_change
;
825 else if (evt_id
== SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED
)
826 supported
= dom_info
->notify_powercap_measurement_change
;
832 scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle
*ph
,
833 u8 evt_id
, u32 src_id
, bool enable
)
836 struct powercap_info
*pi
= ph
->get_priv(ph
);
838 if (evt_id
>= ARRAY_SIZE(evt_2_cmd
) || src_id
>= pi
->num_domains
)
841 cmd_id
= evt_2_cmd
[evt_id
];
842 ret
= scmi_powercap_notify(ph
, src_id
, cmd_id
, enable
);
844 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
845 evt_id
, src_id
, ret
);
846 else if (cmd_id
== POWERCAP_MEASUREMENTS_NOTIFY
)
848 * On success save the current notification enabled state, so
849 * as to be able to properly update the notification thresholds
850 * when they are modified on a domain for which measurement
851 * notifications were currently enabled.
853 * This is needed because the SCMI Notification core machinery
854 * and API does not support passing per-notification custom
855 * arguments at callback registration time.
857 * Note that this can be done here with a simple flag since the
858 * SCMI core Notifications code takes care of keeping proper
859 * per-domain enables refcounting, so that this helper function
860 * will be called only once (for enables) when the first user
861 * registers a callback on this domain and once more (disable)
862 * when the last user de-registers its callback.
864 pi
->states
[src_id
].meas_notif_enabled
= enable
;
870 scmi_powercap_fill_custom_report(const struct scmi_protocol_handle
*ph
,
871 u8 evt_id
, ktime_t timestamp
,
872 const void *payld
, size_t payld_sz
,
873 void *report
, u32
*src_id
)
878 case SCMI_EVENT_POWERCAP_CAP_CHANGED
:
880 const struct scmi_powercap_cap_changed_notify_payld
*p
= payld
;
881 struct scmi_powercap_cap_changed_report
*r
= report
;
883 if (sizeof(*p
) != payld_sz
)
886 r
->timestamp
= timestamp
;
887 r
->agent_id
= le32_to_cpu(p
->agent_id
);
888 r
->domain_id
= le32_to_cpu(p
->domain_id
);
889 r
->power_cap
= le32_to_cpu(p
->power_cap
);
890 r
->pai
= le32_to_cpu(p
->pai
);
891 *src_id
= r
->domain_id
;
895 case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED
:
897 const struct scmi_powercap_meas_changed_notify_payld
*p
= payld
;
898 struct scmi_powercap_meas_changed_report
*r
= report
;
900 if (sizeof(*p
) != payld_sz
)
903 r
->timestamp
= timestamp
;
904 r
->agent_id
= le32_to_cpu(p
->agent_id
);
905 r
->domain_id
= le32_to_cpu(p
->domain_id
);
906 r
->power
= le32_to_cpu(p
->power
);
907 *src_id
= r
->domain_id
;
919 scmi_powercap_get_num_sources(const struct scmi_protocol_handle
*ph
)
921 struct powercap_info
*pi
= ph
->get_priv(ph
);
926 return pi
->num_domains
;
929 static const struct scmi_event powercap_events
[] = {
931 .id
= SCMI_EVENT_POWERCAP_CAP_CHANGED
,
933 sizeof(struct scmi_powercap_cap_changed_notify_payld
),
935 sizeof(struct scmi_powercap_cap_changed_report
),
938 .id
= SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED
,
940 sizeof(struct scmi_powercap_meas_changed_notify_payld
),
942 sizeof(struct scmi_powercap_meas_changed_report
),
946 static const struct scmi_event_ops powercap_event_ops
= {
947 .is_notify_supported
= scmi_powercap_notify_supported
,
948 .get_num_sources
= scmi_powercap_get_num_sources
,
949 .set_notify_enabled
= scmi_powercap_set_notify_enabled
,
950 .fill_custom_report
= scmi_powercap_fill_custom_report
,
953 static const struct scmi_protocol_events powercap_protocol_events
= {
954 .queue_sz
= SCMI_PROTO_QUEUE_SZ
,
955 .ops
= &powercap_event_ops
,
956 .evts
= powercap_events
,
957 .num_events
= ARRAY_SIZE(powercap_events
),
961 scmi_powercap_protocol_init(const struct scmi_protocol_handle
*ph
)
965 struct powercap_info
*pinfo
;
967 ret
= ph
->xops
->version_get(ph
, &version
);
971 dev_dbg(ph
->dev
, "Powercap Version %d.%d\n",
972 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
974 pinfo
= devm_kzalloc(ph
->dev
, sizeof(*pinfo
), GFP_KERNEL
);
978 ret
= scmi_powercap_attributes_get(ph
, pinfo
);
982 pinfo
->powercaps
= devm_kcalloc(ph
->dev
, pinfo
->num_domains
,
983 sizeof(*pinfo
->powercaps
),
985 if (!pinfo
->powercaps
)
988 pinfo
->states
= devm_kcalloc(ph
->dev
, pinfo
->num_domains
,
989 sizeof(*pinfo
->states
), GFP_KERNEL
);
994 * Note that any failure in retrieving any domain attribute leads to
995 * the whole Powercap protocol initialization failure: this way the
996 * reported Powercap domains are all assured, when accessed, to be well
997 * formed and correlated by sane parent-child relationship (if any).
999 for (domain
= 0; domain
< pinfo
->num_domains
; domain
++) {
1000 ret
= scmi_powercap_domain_attributes_get(ph
, pinfo
, domain
);
1004 if (pinfo
->powercaps
[domain
].fastchannels
)
1005 scmi_powercap_domain_init_fc(ph
, domain
,
1006 &pinfo
->powercaps
[domain
].fc_info
);
1008 /* Grab initial state when disable is supported. */
1009 if (PROTOCOL_REV_MAJOR(version
) >= 0x2) {
1010 ret
= __scmi_powercap_cap_get(ph
,
1011 &pinfo
->powercaps
[domain
],
1012 &pinfo
->states
[domain
].last_pcap
);
1016 pinfo
->states
[domain
].enabled
=
1017 !!pinfo
->states
[domain
].last_pcap
;
1021 pinfo
->version
= version
;
1022 return ph
->set_priv(ph
, pinfo
, version
);
1025 static const struct scmi_protocol scmi_powercap
= {
1026 .id
= SCMI_PROTOCOL_POWERCAP
,
1027 .owner
= THIS_MODULE
,
1028 .instance_init
= &scmi_powercap_protocol_init
,
1029 .ops
= &powercap_proto_ops
,
1030 .events
= &powercap_protocol_events
,
1031 .supported_version
= SCMI_PROTOCOL_SUPPORTED_VERSION
,
1034 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap
, scmi_powercap
)