1// SPDX-License-Identifier: GPL-2.0
2/*
3 * System Control and Management Interface (SCMI) Powercap Protocol
4 *
5 * Copyright (C) 2022 ARM Ltd.
6 */
7
8#define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
9
10#include <linux/bitfield.h>
11#include <linux/io.h>
12#include <linux/module.h>
13#include <linux/scmi_protocol.h>
14
15#include <trace/events/scmi.h>
16
17#include "protocols.h"
18#include "notify.h"
19
20/* Updated only after ALL the mandatory features for that version are merged */
21#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
22
23enum 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,
34};
35
36enum {
37 POWERCAP_FC_CAP,
38 POWERCAP_FC_PAI,
39 POWERCAP_FC_MAX,
40};
41
42struct scmi_msg_resp_powercap_domain_attributes {
43 __le32 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];
59 __le32 min_pai;
60 __le32 max_pai;
61 __le32 pai_step;
62 __le32 min_power_cap;
63 __le32 max_power_cap;
64 __le32 power_cap_step;
65 __le32 sustainable_power;
66 __le32 accuracy;
67 __le32 parent_id;
68};
69
70struct scmi_msg_powercap_set_cap_or_pai {
71 __le32 domain;
72 __le32 flags;
73#define CAP_SET_ASYNC BIT(1)
74#define CAP_SET_IGNORE_DRESP BIT(0)
75 __le32 value;
76};
77
78struct scmi_msg_resp_powercap_cap_set_complete {
79 __le32 domain;
80 __le32 power_cap;
81};
82
83struct scmi_msg_resp_powercap_meas_get {
84 __le32 power;
85 __le32 pai;
86};
87
88struct scmi_msg_powercap_notify_cap {
89 __le32 domain;
90 __le32 notify_enable;
91};
92
93struct scmi_msg_powercap_notify_thresh {
94 __le32 domain;
95 __le32 notify_enable;
96 __le32 power_thresh_low;
97 __le32 power_thresh_high;
98};
99
100struct scmi_powercap_cap_changed_notify_payld {
101 __le32 agent_id;
102 __le32 domain_id;
103 __le32 power_cap;
104 __le32 pai;
105};
106
107struct scmi_powercap_meas_changed_notify_payld {
108 __le32 agent_id;
109 __le32 domain_id;
110 __le32 power;
111};
112
113struct scmi_powercap_state {
114 bool enabled;
115 u32 last_pcap;
116 bool meas_notif_enabled;
117 u64 thresholds;
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))
122};
123
124struct powercap_info {
125 u32 version;
126 int num_domains;
127 bool notify_cap_cmd;
128 bool notify_measurements_cmd;
129 struct scmi_powercap_state *states;
130 struct scmi_powercap_info *powercaps;
131};
132
133static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
134 POWERCAP_CAP_NOTIFY,
135 POWERCAP_MEASUREMENTS_NOTIFY,
136};
137
138static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
139 u32 domain, int message_id, bool enable);
140
141static int
142scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
143 struct powercap_info *pi)
144{
145 int ret;
146 struct scmi_xfer *t;
147
148 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
149 sizeof(u32), &t);
150 if (ret)
151 return ret;
152
153 ret = ph->xops->do_xfer(ph, t);
154 if (!ret) {
155 u32 attributes;
156
157 attributes = get_unaligned_le32(p: t->rx.buf);
158 pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
159 }
160
161 ph->xops->xfer_put(ph, t);
162
163 if (!ret) {
164 if (!ph->hops->protocol_msg_check(ph,
165 POWERCAP_CAP_NOTIFY, NULL))
166 pi->notify_cap_cmd = true;
167
168 if (!ph->hops->protocol_msg_check(ph,
169 POWERCAP_MEASUREMENTS_NOTIFY,
170 NULL))
171 pi->notify_measurements_cmd = true;
172 }
173
174 return ret;
175}
176
177static inline int
178scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
179 unsigned int step_val, bool configurable)
180{
181 if (!min_val || !max_val)
182 return -EPROTO;
183
184 if ((configurable && min_val == max_val) ||
185 (!configurable && min_val != max_val))
186 return -EPROTO;
187
188 if (min_val != max_val && !step_val)
189 return -EPROTO;
190
191 return 0;
192}
193
194static int
195scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
196 struct powercap_info *pinfo, u32 domain)
197{
198 int ret;
199 u32 flags;
200 struct scmi_xfer *t;
201 struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
202 struct scmi_msg_resp_powercap_domain_attributes *resp;
203
204 ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
205 sizeof(domain), sizeof(*resp), &t);
206 if (ret)
207 return ret;
208
209 put_unaligned_le32(val: domain, p: t->tx.buf);
210 resp = t->rx.buf;
211
212 ret = ph->xops->do_xfer(ph, t);
213 if (!ret) {
214 flags = le32_to_cpu(resp->attributes);
215
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);
237
238 strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
239
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(min_val: dom_info->min_pai,
244 max_val: dom_info->max_pai,
245 step_val: dom_info->pai_step,
246 configurable: dom_info->powercap_pai_config);
247 if (ret) {
248 dev_err(ph->dev,
249 "Platform reported inconsistent PAI config for domain %d - %s\n",
250 dom_info->id, dom_info->name);
251 goto clean;
252 }
253
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(min_val: dom_info->min_power_cap,
258 max_val: dom_info->max_power_cap,
259 step_val: dom_info->power_cap_step,
260 configurable: dom_info->powercap_cap_config);
261 if (ret) {
262 dev_err(ph->dev,
263 "Platform reported inconsistent CAP config for domain %d - %s\n",
264 dom_info->id, dom_info->name);
265 goto clean;
266 }
267
268 dom_info->sustainable_power =
269 le32_to_cpu(resp->sustainable_power);
270 dom_info->accuracy = le32_to_cpu(resp->accuracy);
271
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)) {
276 dev_err(ph->dev,
277 "Platform reported inconsistent parent ID for domain %d - %s\n",
278 dom_info->id, dom_info->name);
279 ret = -ENODEV;
280 }
281 }
282
283clean:
284 ph->xops->xfer_put(ph, t);
285
286 /*
287 * If supported overwrite short name with the extended one;
288 * on error just carry on and use already provided short name.
289 */
290 if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
291 ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
292 domain, NULL, dom_info->name,
293 SCMI_MAX_STR_SIZE);
294
295 return ret;
296}
297
298static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
299{
300 struct powercap_info *pi = ph->get_priv(ph);
301
302 return pi->num_domains;
303}
304
305static const struct scmi_powercap_info *
306scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
307{
308 struct powercap_info *pi = ph->get_priv(ph);
309
310 if (domain_id >= pi->num_domains)
311 return NULL;
312
313 return pi->powercaps + domain_id;
314}
315
316static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
317 u32 domain_id, u32 *power_cap)
318{
319 int ret;
320 struct scmi_xfer *t;
321
322 ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
323 sizeof(u32), &t);
324 if (ret)
325 return ret;
326
327 put_unaligned_le32(val: domain_id, p: t->tx.buf);
328 ret = ph->xops->do_xfer(ph, t);
329 if (!ret)
330 *power_cap = get_unaligned_le32(p: t->rx.buf);
331
332 ph->xops->xfer_put(ph, t);
333
334 return ret;
335}
336
337static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
338 const struct scmi_powercap_info *dom,
339 u32 *power_cap)
340{
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(protocol_id: SCMI_PROTOCOL_POWERCAP, msg_id: POWERCAP_CAP_GET,
344 res_id: dom->id, val1: *power_cap, val2: 0);
345 return 0;
346 }
347
348 return scmi_powercap_xfer_cap_get(ph, domain_id: dom->id, power_cap);
349}
350
351static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
352 u32 domain_id, u32 *power_cap)
353{
354 const struct scmi_powercap_info *dom;
355
356 if (!power_cap)
357 return -EINVAL;
358
359 dom = scmi_powercap_dom_info_get(ph, domain_id);
360 if (!dom)
361 return -EINVAL;
362
363 return __scmi_powercap_cap_get(ph, dom, power_cap);
364}
365
366static 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)
369{
370 int ret;
371 struct scmi_xfer *t;
372 struct scmi_msg_powercap_set_cap_or_pai *msg;
373
374 ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
375 sizeof(*msg), 0, &t);
376 if (ret)
377 return ret;
378
379 msg = t->tx.buf;
380 msg->domain = cpu_to_le32(pc->id);
381 msg->flags =
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);
385
386 if (!pc->async_powercap_cap_set || ignore_dresp) {
387 ret = ph->xops->do_xfer(ph, t);
388 } else {
389 ret = ph->xops->do_xfer_with_response(ph, t);
390 if (!ret) {
391 struct scmi_msg_resp_powercap_cap_set_complete *resp;
392
393 resp = t->rx.buf;
394 if (le32_to_cpu(resp->domain) == pc->id)
395 dev_dbg(ph->dev,
396 "Powercap ID %d CAP set async to %u\n",
397 pc->id,
398 get_unaligned_le32(&resp->power_cap));
399 else
400 ret = -EPROTO;
401 }
402 }
403
404 ph->xops->xfer_put(ph, t);
405 return ret;
406}
407
408static 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)
411{
412 int ret = -EINVAL;
413 const struct scmi_powercap_info *pc;
414
415 pc = scmi_powercap_dom_info_get(ph, domain_id);
416 if (!pc || !pc->powercap_cap_config)
417 return ret;
418
419 if (power_cap &&
420 (power_cap < pc->min_power_cap || power_cap > pc->max_power_cap))
421 return ret;
422
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];
425
426 iowrite32(power_cap, fci->set_addr);
427 ph->hops->fastchannel_db_ring(fci->set_db);
428 trace_scmi_fc_call(protocol_id: SCMI_PROTOCOL_POWERCAP, msg_id: POWERCAP_CAP_SET,
429 res_id: domain_id, val1: power_cap, val2: 0);
430 ret = 0;
431 } else {
432 ret = scmi_powercap_xfer_cap_set(ph, pc, power_cap,
433 ignore_dresp);
434 }
435
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;
439
440 return ret;
441}
442
443static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
444 u32 domain_id, u32 power_cap,
445 bool ignore_dresp)
446{
447 struct powercap_info *pi = ph->get_priv(ph);
448
449 /*
450 * Disallow zero as a possible explicitly requested powercap:
451 * there are enable/disable operations for this.
452 */
453 if (!power_cap)
454 return -EINVAL;
455
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;
460 return 0;
461 }
462
463 return __scmi_powercap_cap_set(ph, pi, domain_id,
464 power_cap, ignore_dresp);
465}
466
467static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
468 u32 domain_id, u32 *pai)
469{
470 int ret;
471 struct scmi_xfer *t;
472
473 ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
474 sizeof(u32), &t);
475 if (ret)
476 return ret;
477
478 put_unaligned_le32(val: domain_id, p: t->tx.buf);
479 ret = ph->xops->do_xfer(ph, t);
480 if (!ret)
481 *pai = get_unaligned_le32(p: t->rx.buf);
482
483 ph->xops->xfer_put(ph, t);
484
485 return ret;
486}
487
488static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
489 u32 domain_id, u32 *pai)
490{
491 struct scmi_powercap_info *dom;
492 struct powercap_info *pi = ph->get_priv(ph);
493
494 if (!pai || domain_id >= pi->num_domains)
495 return -EINVAL;
496
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(protocol_id: SCMI_PROTOCOL_POWERCAP, msg_id: POWERCAP_PAI_GET,
501 res_id: domain_id, val1: *pai, val2: 0);
502 return 0;
503 }
504
505 return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
506}
507
508static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
509 u32 domain_id, u32 pai)
510{
511 int ret;
512 struct scmi_xfer *t;
513 struct scmi_msg_powercap_set_cap_or_pai *msg;
514
515 ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
516 sizeof(*msg), 0, &t);
517 if (ret)
518 return ret;
519
520 msg = t->tx.buf;
521 msg->domain = cpu_to_le32(domain_id);
522 msg->flags = cpu_to_le32(0);
523 msg->value = cpu_to_le32(pai);
524
525 ret = ph->xops->do_xfer(ph, t);
526
527 ph->xops->xfer_put(ph, t);
528 return ret;
529}
530
531static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
532 u32 domain_id, u32 pai)
533{
534 const struct scmi_powercap_info *pc;
535
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)
539 return -EINVAL;
540
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];
543
544 trace_scmi_fc_call(protocol_id: SCMI_PROTOCOL_POWERCAP, msg_id: POWERCAP_PAI_SET,
545 res_id: domain_id, val1: pai, val2: 0);
546 iowrite32(pai, fci->set_addr);
547 ph->hops->fastchannel_db_ring(fci->set_db);
548 return 0;
549 }
550
551 return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
552}
553
554static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
555 u32 domain_id, u32 *average_power,
556 u32 *pai)
557{
558 int ret;
559 struct scmi_xfer *t;
560 struct scmi_msg_resp_powercap_meas_get *resp;
561 const struct scmi_powercap_info *pc;
562
563 pc = scmi_powercap_dom_info_get(ph, domain_id);
564 if (!pc || !pc->powercap_monitoring || !pai || !average_power)
565 return -EINVAL;
566
567 ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
568 sizeof(u32), sizeof(*resp), &t);
569 if (ret)
570 return ret;
571
572 resp = t->rx.buf;
573 put_unaligned_le32(val: domain_id, p: t->tx.buf);
574 ret = ph->xops->do_xfer(ph, t);
575 if (!ret) {
576 *average_power = le32_to_cpu(resp->power);
577 *pai = le32_to_cpu(resp->pai);
578 }
579
580 ph->xops->xfer_put(ph, t);
581 return ret;
582}
583
584static int
585scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
586 u32 domain_id, u32 *power_thresh_low,
587 u32 *power_thresh_high)
588{
589 struct powercap_info *pi = ph->get_priv(ph);
590
591 if (!power_thresh_low || !power_thresh_high ||
592 domain_id >= pi->num_domains)
593 return -EINVAL;
594
595 *power_thresh_low = THRESH_LOW(pi, domain_id);
596 *power_thresh_high = THRESH_HIGH(pi, domain_id);
597
598 return 0;
599}
600
601static int
602scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
603 u32 domain_id, u32 power_thresh_low,
604 u32 power_thresh_high)
605{
606 int ret = 0;
607 struct powercap_info *pi = ph->get_priv(ph);
608
609 if (domain_id >= pi->num_domains ||
610 power_thresh_low > power_thresh_high)
611 return -EINVAL;
612
613 /* Anything to do ? */
614 if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
615 THRESH_HIGH(pi, domain_id) == power_thresh_high)
616 return ret;
617
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));
621
622 /* Update thresholds if notification already enabled */
623 if (pi->states[domain_id].meas_notif_enabled)
624 ret = scmi_powercap_notify(ph, domain: domain_id,
625 message_id: POWERCAP_MEASUREMENTS_NOTIFY,
626 enable: true);
627
628 return ret;
629}
630
631static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
632 u32 domain_id, bool enable)
633{
634 int ret;
635 u32 power_cap;
636 struct powercap_info *pi = ph->get_priv(ph);
637
638 if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
639 return -EINVAL;
640
641 if (enable == pi->states[domain_id].enabled)
642 return 0;
643
644 if (enable) {
645 /* Cannot enable with a zero powercap. */
646 if (!pi->states[domain_id].last_pcap)
647 return -EINVAL;
648
649 ret = __scmi_powercap_cap_set(ph, pi, domain_id,
650 power_cap: pi->states[domain_id].last_pcap,
651 ignore_dresp: true);
652 } else {
653 ret = __scmi_powercap_cap_set(ph, pi, domain_id, power_cap: 0, ignore_dresp: true);
654 }
655
656 if (ret)
657 return ret;
658
659 /*
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.
663 */
664 ret = scmi_powercap_cap_get(ph, domain_id, power_cap: &power_cap);
665 if (!ret)
666 pi->states[domain_id].enabled = !!power_cap;
667
668 return ret;
669}
670
671static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
672 u32 domain_id, bool *enable)
673{
674 int ret;
675 u32 power_cap;
676 struct powercap_info *pi = ph->get_priv(ph);
677
678 *enable = true;
679 if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
680 return 0;
681
682 /*
683 * Report always real platform state; platform could have ignored
684 * a previous disable request. Default true on any error.
685 */
686 ret = scmi_powercap_cap_get(ph, domain_id, power_cap: &power_cap);
687 if (!ret)
688 *enable = !!power_cap;
689
690 /* Update internal state with current real platform state */
691 pi->states[domain_id].enabled = *enable;
692
693 return 0;
694}
695
696static 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,
708};
709
710static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
711 u32 domain, struct scmi_fc_info **p_fc)
712{
713 struct scmi_fc_info *fc;
714
715 fc = devm_kcalloc(dev: ph->dev, n: POWERCAP_FC_MAX, size: sizeof(*fc), GFP_KERNEL);
716 if (!fc)
717 return;
718
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);
724
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);
729
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);
735
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);
740
741 *p_fc = fc;
742}
743
744static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
745 u32 domain, int message_id, bool enable)
746{
747 int ret;
748 struct scmi_xfer *t;
749
750 switch (message_id) {
751 case POWERCAP_CAP_NOTIFY:
752 {
753 struct scmi_msg_powercap_notify_cap *notify;
754
755 ret = ph->xops->xfer_get_init(ph, message_id,
756 sizeof(*notify), 0, &t);
757 if (ret)
758 return ret;
759
760 notify = t->tx.buf;
761 notify->domain = cpu_to_le32(domain);
762 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
763 break;
764 }
765 case POWERCAP_MEASUREMENTS_NOTIFY:
766 {
767 u32 low, high;
768 struct scmi_msg_powercap_notify_thresh *notify;
769
770 /*
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
775 * used wrongly.
776 */
777 ret = scmi_powercap_measurements_threshold_get(ph, domain_id: domain,
778 power_thresh_low: &low, power_thresh_high: &high);
779 if (ret)
780 return ret;
781
782 if (enable && !low && !high) {
783 dev_err(ph->dev,
784 "Invalid Measurements Notify thresholds: %u/%u\n",
785 low, high);
786 return -EINVAL;
787 }
788
789 ret = ph->xops->xfer_get_init(ph, message_id,
790 sizeof(*notify), 0, &t);
791 if (ret)
792 return ret;
793
794 notify = t->tx.buf;
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);
799 break;
800 }
801 default:
802 return -EINVAL;
803 }
804
805 ret = ph->xops->do_xfer(ph, t);
806
807 ph->xops->xfer_put(ph, t);
808 return ret;
809}
810
811static bool
812scmi_powercap_notify_supported(const struct scmi_protocol_handle *ph,
813 u8 evt_id, u32 src_id)
814{
815 bool supported = false;
816 const struct scmi_powercap_info *dom_info;
817 struct powercap_info *pi = ph->get_priv(ph);
818
819 if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
820 return false;
821
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;
827
828 return supported;
829}
830
831static int
832scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
833 u8 evt_id, u32 src_id, bool enable)
834{
835 int ret, cmd_id;
836 struct powercap_info *pi = ph->get_priv(ph);
837
838 if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
839 return -EINVAL;
840
841 cmd_id = evt_2_cmd[evt_id];
842 ret = scmi_powercap_notify(ph, domain: src_id, message_id: cmd_id, enable);
843 if (ret)
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)
847 /*
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.
852 *
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.
856 *
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.
863 */
864 pi->states[src_id].meas_notif_enabled = enable;
865
866 return ret;
867}
868
869static void *
870scmi_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)
874{
875 void *rep = NULL;
876
877 switch (evt_id) {
878 case SCMI_EVENT_POWERCAP_CAP_CHANGED:
879 {
880 const struct scmi_powercap_cap_changed_notify_payld *p = payld;
881 struct scmi_powercap_cap_changed_report *r = report;
882
883 if (sizeof(*p) != payld_sz)
884 break;
885
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;
892 rep = r;
893 break;
894 }
895 case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
896 {
897 const struct scmi_powercap_meas_changed_notify_payld *p = payld;
898 struct scmi_powercap_meas_changed_report *r = report;
899
900 if (sizeof(*p) != payld_sz)
901 break;
902
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;
908 rep = r;
909 break;
910 }
911 default:
912 break;
913 }
914
915 return rep;
916}
917
918static int
919scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
920{
921 struct powercap_info *pi = ph->get_priv(ph);
922
923 if (!pi)
924 return -EINVAL;
925
926 return pi->num_domains;
927}
928
929static const struct scmi_event powercap_events[] = {
930 {
931 .id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
932 .max_payld_sz =
933 sizeof(struct scmi_powercap_cap_changed_notify_payld),
934 .max_report_sz =
935 sizeof(struct scmi_powercap_cap_changed_report),
936 },
937 {
938 .id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
939 .max_payld_sz =
940 sizeof(struct scmi_powercap_meas_changed_notify_payld),
941 .max_report_sz =
942 sizeof(struct scmi_powercap_meas_changed_report),
943 },
944};
945
946static 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,
951};
952
953static 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),
958};
959
960static int
961scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
962{
963 int domain, ret;
964 u32 version;
965 struct powercap_info *pinfo;
966
967 ret = ph->xops->version_get(ph, &version);
968 if (ret)
969 return ret;
970
971 dev_dbg(ph->dev, "Powercap Version %d.%d\n",
972 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
973
974 pinfo = devm_kzalloc(dev: ph->dev, size: sizeof(*pinfo), GFP_KERNEL);
975 if (!pinfo)
976 return -ENOMEM;
977
978 ret = scmi_powercap_attributes_get(ph, pi: pinfo);
979 if (ret)
980 return ret;
981
982 pinfo->powercaps = devm_kcalloc(dev: ph->dev, n: pinfo->num_domains,
983 size: sizeof(*pinfo->powercaps),
984 GFP_KERNEL);
985 if (!pinfo->powercaps)
986 return -ENOMEM;
987
988 pinfo->states = devm_kcalloc(dev: ph->dev, n: pinfo->num_domains,
989 size: sizeof(*pinfo->states), GFP_KERNEL);
990 if (!pinfo->states)
991 return -ENOMEM;
992
993 /*
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).
998 */
999 for (domain = 0; domain < pinfo->num_domains; domain++) {
1000 ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
1001 if (ret)
1002 return ret;
1003
1004 if (pinfo->powercaps[domain].fastchannels)
1005 scmi_powercap_domain_init_fc(ph, domain,
1006 p_fc: &pinfo->powercaps[domain].fc_info);
1007
1008 /* Grab initial state when disable is supported. */
1009 if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
1010 ret = __scmi_powercap_cap_get(ph,
1011 dom: &pinfo->powercaps[domain],
1012 power_cap: &pinfo->states[domain].last_pcap);
1013 if (ret)
1014 return ret;
1015
1016 pinfo->states[domain].enabled =
1017 !!pinfo->states[domain].last_pcap;
1018 }
1019 }
1020
1021 pinfo->version = version;
1022 return ph->set_priv(ph, pinfo, version);
1023}
1024
1025static 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,
1032};
1033
1034DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
1035

source code of linux/drivers/firmware/arm_scmi/powercap.c