Mention branches and keyring.
[releases.git] / arm_scmi / powercap.c
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
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,
34 };
35
36 enum {
37         POWERCAP_FC_CAP,
38         POWERCAP_FC_PAI,
39         POWERCAP_FC_MAX,
40 };
41
42 struct 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
70 struct 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
78 struct scmi_msg_resp_powercap_cap_set_complete {
79         __le32 domain;
80         __le32 power_cap;
81 };
82
83 struct scmi_msg_resp_powercap_meas_get {
84         __le32 power;
85         __le32 pai;
86 };
87
88 struct scmi_msg_powercap_notify_cap {
89         __le32 domain;
90         __le32 notify_enable;
91 };
92
93 struct scmi_msg_powercap_notify_thresh {
94         __le32 domain;
95         __le32 notify_enable;
96         __le32 power_thresh_low;
97         __le32 power_thresh_high;
98 };
99
100 struct scmi_powercap_cap_changed_notify_payld {
101         __le32 agent_id;
102         __le32 domain_id;
103         __le32 power_cap;
104         __le32 pai;
105 };
106
107 struct scmi_powercap_meas_changed_notify_payld {
108         __le32 agent_id;
109         __le32 domain_id;
110         __le32 power;
111 };
112
113 struct 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
124 struct powercap_info {
125         u32 version;
126         int num_domains;
127         struct scmi_powercap_state *states;
128         struct scmi_powercap_info *powercaps;
129 };
130
131 static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
132         POWERCAP_CAP_NOTIFY,
133         POWERCAP_MEASUREMENTS_NOTIFY,
134 };
135
136 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
137                                 u32 domain, int message_id, bool enable);
138
139 static int
140 scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
141                              struct powercap_info *pi)
142 {
143         int ret;
144         struct scmi_xfer *t;
145
146         ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
147                                       sizeof(u32), &t);
148         if (ret)
149                 return ret;
150
151         ret = ph->xops->do_xfer(ph, t);
152         if (!ret) {
153                 u32 attributes;
154
155                 attributes = get_unaligned_le32(t->rx.buf);
156                 pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
157         }
158
159         ph->xops->xfer_put(ph, t);
160         return ret;
161 }
162
163 static inline int
164 scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
165                        unsigned int step_val, bool configurable)
166 {
167         if (!min_val || !max_val)
168                 return -EPROTO;
169
170         if ((configurable && min_val == max_val) ||
171             (!configurable && min_val != max_val))
172                 return -EPROTO;
173
174         if (min_val != max_val && !step_val)
175                 return -EPROTO;
176
177         return 0;
178 }
179
180 static int
181 scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
182                                     struct powercap_info *pinfo, u32 domain)
183 {
184         int ret;
185         u32 flags;
186         struct scmi_xfer *t;
187         struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
188         struct scmi_msg_resp_powercap_domain_attributes *resp;
189
190         ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
191                                       sizeof(domain), sizeof(*resp), &t);
192         if (ret)
193                 return ret;
194
195         put_unaligned_le32(domain, t->tx.buf);
196         resp = t->rx.buf;
197
198         ret = ph->xops->do_xfer(ph, t);
199         if (!ret) {
200                 flags = le32_to_cpu(resp->attributes);
201
202                 dom_info->id = domain;
203                 dom_info->notify_powercap_cap_change =
204                         SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
205                 dom_info->notify_powercap_measurement_change =
206                         SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
207                 dom_info->async_powercap_cap_set =
208                         SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
209                 dom_info->powercap_cap_config =
210                         SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
211                 dom_info->powercap_monitoring =
212                         SUPPORTS_POWERCAP_MONITORING(flags);
213                 dom_info->powercap_pai_config =
214                         SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
215                 dom_info->powercap_scale_mw =
216                         SUPPORTS_POWER_UNITS_MW(flags);
217                 dom_info->powercap_scale_uw =
218                         SUPPORTS_POWER_UNITS_UW(flags);
219                 dom_info->fastchannels =
220                         SUPPORTS_POWERCAP_FASTCHANNELS(flags);
221
222                 strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
223
224                 dom_info->min_pai = le32_to_cpu(resp->min_pai);
225                 dom_info->max_pai = le32_to_cpu(resp->max_pai);
226                 dom_info->pai_step = le32_to_cpu(resp->pai_step);
227                 ret = scmi_powercap_validate(dom_info->min_pai,
228                                              dom_info->max_pai,
229                                              dom_info->pai_step,
230                                              dom_info->powercap_pai_config);
231                 if (ret) {
232                         dev_err(ph->dev,
233                                 "Platform reported inconsistent PAI config for domain %d - %s\n",
234                                 dom_info->id, dom_info->name);
235                         goto clean;
236                 }
237
238                 dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
239                 dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
240                 dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
241                 ret = scmi_powercap_validate(dom_info->min_power_cap,
242                                              dom_info->max_power_cap,
243                                              dom_info->power_cap_step,
244                                              dom_info->powercap_cap_config);
245                 if (ret) {
246                         dev_err(ph->dev,
247                                 "Platform reported inconsistent CAP config for domain %d - %s\n",
248                                 dom_info->id, dom_info->name);
249                         goto clean;
250                 }
251
252                 dom_info->sustainable_power =
253                         le32_to_cpu(resp->sustainable_power);
254                 dom_info->accuracy = le32_to_cpu(resp->accuracy);
255
256                 dom_info->parent_id = le32_to_cpu(resp->parent_id);
257                 if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
258                     (dom_info->parent_id >= pinfo->num_domains ||
259                      dom_info->parent_id == dom_info->id)) {
260                         dev_err(ph->dev,
261                                 "Platform reported inconsistent parent ID for domain %d - %s\n",
262                                 dom_info->id, dom_info->name);
263                         ret = -ENODEV;
264                 }
265         }
266
267 clean:
268         ph->xops->xfer_put(ph, t);
269
270         /*
271          * If supported overwrite short name with the extended one;
272          * on error just carry on and use already provided short name.
273          */
274         if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
275                 ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
276                                             domain, NULL, dom_info->name,
277                                             SCMI_MAX_STR_SIZE);
278
279         return ret;
280 }
281
282 static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
283 {
284         struct powercap_info *pi = ph->get_priv(ph);
285
286         return pi->num_domains;
287 }
288
289 static const struct scmi_powercap_info *
290 scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
291 {
292         struct powercap_info *pi = ph->get_priv(ph);
293
294         if (domain_id >= pi->num_domains)
295                 return NULL;
296
297         return pi->powercaps + domain_id;
298 }
299
300 static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
301                                       u32 domain_id, u32 *power_cap)
302 {
303         int ret;
304         struct scmi_xfer *t;
305
306         ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
307                                       sizeof(u32), &t);
308         if (ret)
309                 return ret;
310
311         put_unaligned_le32(domain_id, t->tx.buf);
312         ret = ph->xops->do_xfer(ph, t);
313         if (!ret)
314                 *power_cap = get_unaligned_le32(t->rx.buf);
315
316         ph->xops->xfer_put(ph, t);
317
318         return ret;
319 }
320
321 static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
322                                    const struct scmi_powercap_info *dom,
323                                    u32 *power_cap)
324 {
325         if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
326                 *power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
327                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
328                                    dom->id, *power_cap, 0);
329                 return 0;
330         }
331
332         return scmi_powercap_xfer_cap_get(ph, dom->id, power_cap);
333 }
334
335 static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
336                                  u32 domain_id, u32 *power_cap)
337 {
338         const struct scmi_powercap_info *dom;
339
340         if (!power_cap)
341                 return -EINVAL;
342
343         dom = scmi_powercap_dom_info_get(ph, domain_id);
344         if (!dom)
345                 return -EINVAL;
346
347         return __scmi_powercap_cap_get(ph, dom, power_cap);
348 }
349
350 static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
351                                       const struct scmi_powercap_info *pc,
352                                       u32 power_cap, bool ignore_dresp)
353 {
354         int ret;
355         struct scmi_xfer *t;
356         struct scmi_msg_powercap_set_cap_or_pai *msg;
357
358         ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
359                                       sizeof(*msg), 0, &t);
360         if (ret)
361                 return ret;
362
363         msg = t->tx.buf;
364         msg->domain = cpu_to_le32(pc->id);
365         msg->flags =
366                 cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, pc->async_powercap_cap_set) |
367                             FIELD_PREP(CAP_SET_IGNORE_DRESP, ignore_dresp));
368         msg->value = cpu_to_le32(power_cap);
369
370         if (!pc->async_powercap_cap_set || ignore_dresp) {
371                 ret = ph->xops->do_xfer(ph, t);
372         } else {
373                 ret = ph->xops->do_xfer_with_response(ph, t);
374                 if (!ret) {
375                         struct scmi_msg_resp_powercap_cap_set_complete *resp;
376
377                         resp = t->rx.buf;
378                         if (le32_to_cpu(resp->domain) == pc->id)
379                                 dev_dbg(ph->dev,
380                                         "Powercap ID %d CAP set async to %u\n",
381                                         pc->id,
382                                         get_unaligned_le32(&resp->power_cap));
383                         else
384                                 ret = -EPROTO;
385                 }
386         }
387
388         ph->xops->xfer_put(ph, t);
389         return ret;
390 }
391
392 static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
393                                    struct powercap_info *pi, u32 domain_id,
394                                    u32 power_cap, bool ignore_dresp)
395 {
396         int ret = -EINVAL;
397         const struct scmi_powercap_info *pc;
398
399         pc = scmi_powercap_dom_info_get(ph, domain_id);
400         if (!pc || !pc->powercap_cap_config)
401                 return ret;
402
403         if (power_cap &&
404             (power_cap < pc->min_power_cap || power_cap > pc->max_power_cap))
405                 return ret;
406
407         if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
408                 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
409
410                 iowrite32(power_cap, fci->set_addr);
411                 ph->hops->fastchannel_db_ring(fci->set_db);
412                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
413                                    domain_id, power_cap, 0);
414                 ret = 0;
415         } else {
416                 ret = scmi_powercap_xfer_cap_set(ph, pc, power_cap,
417                                                  ignore_dresp);
418         }
419
420         /* Save the last explicitly set non-zero powercap value */
421         if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 && !ret && power_cap)
422                 pi->states[domain_id].last_pcap = power_cap;
423
424         return ret;
425 }
426
427 static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
428                                  u32 domain_id, u32 power_cap,
429                                  bool ignore_dresp)
430 {
431         struct powercap_info *pi = ph->get_priv(ph);
432
433         /*
434          * Disallow zero as a possible explicitly requested powercap:
435          * there are enable/disable operations for this.
436          */
437         if (!power_cap)
438                 return -EINVAL;
439
440         /* Just log the last set request if acting on a disabled domain */
441         if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 &&
442             !pi->states[domain_id].enabled) {
443                 pi->states[domain_id].last_pcap = power_cap;
444                 return 0;
445         }
446
447         return __scmi_powercap_cap_set(ph, pi, domain_id,
448                                        power_cap, ignore_dresp);
449 }
450
451 static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
452                                       u32 domain_id, u32 *pai)
453 {
454         int ret;
455         struct scmi_xfer *t;
456
457         ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
458                                       sizeof(u32), &t);
459         if (ret)
460                 return ret;
461
462         put_unaligned_le32(domain_id, t->tx.buf);
463         ret = ph->xops->do_xfer(ph, t);
464         if (!ret)
465                 *pai = get_unaligned_le32(t->rx.buf);
466
467         ph->xops->xfer_put(ph, t);
468
469         return ret;
470 }
471
472 static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
473                                  u32 domain_id, u32 *pai)
474 {
475         struct scmi_powercap_info *dom;
476         struct powercap_info *pi = ph->get_priv(ph);
477
478         if (!pai || domain_id >= pi->num_domains)
479                 return -EINVAL;
480
481         dom = pi->powercaps + domain_id;
482         if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
483                 *pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
484                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
485                                    domain_id, *pai, 0);
486                 return 0;
487         }
488
489         return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
490 }
491
492 static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
493                                       u32 domain_id, u32 pai)
494 {
495         int ret;
496         struct scmi_xfer *t;
497         struct scmi_msg_powercap_set_cap_or_pai *msg;
498
499         ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
500                                       sizeof(*msg), 0, &t);
501         if (ret)
502                 return ret;
503
504         msg = t->tx.buf;
505         msg->domain = cpu_to_le32(domain_id);
506         msg->flags = cpu_to_le32(0);
507         msg->value = cpu_to_le32(pai);
508
509         ret = ph->xops->do_xfer(ph, t);
510
511         ph->xops->xfer_put(ph, t);
512         return ret;
513 }
514
515 static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
516                                  u32 domain_id, u32 pai)
517 {
518         const struct scmi_powercap_info *pc;
519
520         pc = scmi_powercap_dom_info_get(ph, domain_id);
521         if (!pc || !pc->powercap_pai_config || !pai ||
522             pai < pc->min_pai || pai > pc->max_pai)
523                 return -EINVAL;
524
525         if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
526                 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
527
528                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
529                                    domain_id, pai, 0);
530                 iowrite32(pai, fci->set_addr);
531                 ph->hops->fastchannel_db_ring(fci->set_db);
532                 return 0;
533         }
534
535         return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
536 }
537
538 static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
539                                           u32 domain_id, u32 *average_power,
540                                           u32 *pai)
541 {
542         int ret;
543         struct scmi_xfer *t;
544         struct scmi_msg_resp_powercap_meas_get *resp;
545         const struct scmi_powercap_info *pc;
546
547         pc = scmi_powercap_dom_info_get(ph, domain_id);
548         if (!pc || !pc->powercap_monitoring || !pai || !average_power)
549                 return -EINVAL;
550
551         ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
552                                       sizeof(u32), sizeof(*resp), &t);
553         if (ret)
554                 return ret;
555
556         resp = t->rx.buf;
557         put_unaligned_le32(domain_id, t->tx.buf);
558         ret = ph->xops->do_xfer(ph, t);
559         if (!ret) {
560                 *average_power = le32_to_cpu(resp->power);
561                 *pai = le32_to_cpu(resp->pai);
562         }
563
564         ph->xops->xfer_put(ph, t);
565         return ret;
566 }
567
568 static int
569 scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
570                                          u32 domain_id, u32 *power_thresh_low,
571                                          u32 *power_thresh_high)
572 {
573         struct powercap_info *pi = ph->get_priv(ph);
574
575         if (!power_thresh_low || !power_thresh_high ||
576             domain_id >= pi->num_domains)
577                 return -EINVAL;
578
579         *power_thresh_low =  THRESH_LOW(pi, domain_id);
580         *power_thresh_high = THRESH_HIGH(pi, domain_id);
581
582         return 0;
583 }
584
585 static int
586 scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
587                                          u32 domain_id, u32 power_thresh_low,
588                                          u32 power_thresh_high)
589 {
590         int ret = 0;
591         struct powercap_info *pi = ph->get_priv(ph);
592
593         if (domain_id >= pi->num_domains ||
594             power_thresh_low > power_thresh_high)
595                 return -EINVAL;
596
597         /* Anything to do ? */
598         if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
599             THRESH_HIGH(pi, domain_id) == power_thresh_high)
600                 return ret;
601
602         pi->states[domain_id].thresholds =
603                 (FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
604                  FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
605
606         /* Update thresholds if notification already enabled */
607         if (pi->states[domain_id].meas_notif_enabled)
608                 ret = scmi_powercap_notify(ph, domain_id,
609                                            POWERCAP_MEASUREMENTS_NOTIFY,
610                                            true);
611
612         return ret;
613 }
614
615 static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
616                                         u32 domain_id, bool enable)
617 {
618         int ret;
619         u32 power_cap;
620         struct powercap_info *pi = ph->get_priv(ph);
621
622         if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
623                 return -EINVAL;
624
625         if (enable == pi->states[domain_id].enabled)
626                 return 0;
627
628         if (enable) {
629                 /* Cannot enable with a zero powercap. */
630                 if (!pi->states[domain_id].last_pcap)
631                         return -EINVAL;
632
633                 ret = __scmi_powercap_cap_set(ph, pi, domain_id,
634                                               pi->states[domain_id].last_pcap,
635                                               true);
636         } else {
637                 ret = __scmi_powercap_cap_set(ph, pi, domain_id, 0, true);
638         }
639
640         if (ret)
641                 return ret;
642
643         /*
644          * Update our internal state to reflect final platform state: the SCMI
645          * server could have ignored a disable request and kept enforcing some
646          * powercap limit requested by other agents.
647          */
648         ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
649         if (!ret)
650                 pi->states[domain_id].enabled = !!power_cap;
651
652         return ret;
653 }
654
655 static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
656                                         u32 domain_id, bool *enable)
657 {
658         int ret;
659         u32 power_cap;
660         struct powercap_info *pi = ph->get_priv(ph);
661
662         *enable = true;
663         if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
664                 return 0;
665
666         /*
667          * Report always real platform state; platform could have ignored
668          * a previous disable request. Default true on any error.
669          */
670         ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
671         if (!ret)
672                 *enable = !!power_cap;
673
674         /* Update internal state with current real platform state */
675         pi->states[domain_id].enabled = *enable;
676
677         return 0;
678 }
679
680 static const struct scmi_powercap_proto_ops powercap_proto_ops = {
681         .num_domains_get = scmi_powercap_num_domains_get,
682         .info_get = scmi_powercap_dom_info_get,
683         .cap_get = scmi_powercap_cap_get,
684         .cap_set = scmi_powercap_cap_set,
685         .cap_enable_set = scmi_powercap_cap_enable_set,
686         .cap_enable_get = scmi_powercap_cap_enable_get,
687         .pai_get = scmi_powercap_pai_get,
688         .pai_set = scmi_powercap_pai_set,
689         .measurements_get = scmi_powercap_measurements_get,
690         .measurements_threshold_set = scmi_powercap_measurements_threshold_set,
691         .measurements_threshold_get = scmi_powercap_measurements_threshold_get,
692 };
693
694 static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
695                                          u32 domain, struct scmi_fc_info **p_fc)
696 {
697         struct scmi_fc_info *fc;
698
699         fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
700         if (!fc)
701                 return;
702
703         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
704                                    POWERCAP_CAP_SET, 4, domain,
705                                    &fc[POWERCAP_FC_CAP].set_addr,
706                                    &fc[POWERCAP_FC_CAP].set_db);
707
708         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
709                                    POWERCAP_CAP_GET, 4, domain,
710                                    &fc[POWERCAP_FC_CAP].get_addr, NULL);
711
712         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
713                                    POWERCAP_PAI_SET, 4, domain,
714                                    &fc[POWERCAP_FC_PAI].set_addr,
715                                    &fc[POWERCAP_FC_PAI].set_db);
716
717         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
718                                    POWERCAP_PAI_GET, 4, domain,
719                                    &fc[POWERCAP_FC_PAI].get_addr, NULL);
720
721         *p_fc = fc;
722 }
723
724 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
725                                 u32 domain, int message_id, bool enable)
726 {
727         int ret;
728         struct scmi_xfer *t;
729
730         switch (message_id) {
731         case POWERCAP_CAP_NOTIFY:
732         {
733                 struct scmi_msg_powercap_notify_cap *notify;
734
735                 ret = ph->xops->xfer_get_init(ph, message_id,
736                                               sizeof(*notify), 0, &t);
737                 if (ret)
738                         return ret;
739
740                 notify = t->tx.buf;
741                 notify->domain = cpu_to_le32(domain);
742                 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
743                 break;
744         }
745         case POWERCAP_MEASUREMENTS_NOTIFY:
746         {
747                 u32 low, high;
748                 struct scmi_msg_powercap_notify_thresh *notify;
749
750                 /*
751                  * Note that we have to pick the most recently configured
752                  * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
753                  * enable request and we fail, complaining, if no thresholds
754                  * were ever set, since this is an indication the API has been
755                  * used wrongly.
756                  */
757                 ret = scmi_powercap_measurements_threshold_get(ph, domain,
758                                                                &low, &high);
759                 if (ret)
760                         return ret;
761
762                 if (enable && !low && !high) {
763                         dev_err(ph->dev,
764                                 "Invalid Measurements Notify thresholds: %u/%u\n",
765                                 low, high);
766                         return -EINVAL;
767                 }
768
769                 ret = ph->xops->xfer_get_init(ph, message_id,
770                                               sizeof(*notify), 0, &t);
771                 if (ret)
772                         return ret;
773
774                 notify = t->tx.buf;
775                 notify->domain = cpu_to_le32(domain);
776                 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
777                 notify->power_thresh_low = cpu_to_le32(low);
778                 notify->power_thresh_high = cpu_to_le32(high);
779                 break;
780         }
781         default:
782                 return -EINVAL;
783         }
784
785         ret = ph->xops->do_xfer(ph, t);
786
787         ph->xops->xfer_put(ph, t);
788         return ret;
789 }
790
791 static int
792 scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
793                                  u8 evt_id, u32 src_id, bool enable)
794 {
795         int ret, cmd_id;
796         struct powercap_info *pi = ph->get_priv(ph);
797
798         if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
799                 return -EINVAL;
800
801         cmd_id = evt_2_cmd[evt_id];
802         ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
803         if (ret)
804                 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
805                          evt_id, src_id, ret);
806         else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
807                 /*
808                  * On success save the current notification enabled state, so
809                  * as to be able to properly update the notification thresholds
810                  * when they are modified on a domain for which measurement
811                  * notifications were currently enabled.
812                  *
813                  * This is needed because the SCMI Notification core machinery
814                  * and API does not support passing per-notification custom
815                  * arguments at callback registration time.
816                  *
817                  * Note that this can be done here with a simple flag since the
818                  * SCMI core Notifications code takes care of keeping proper
819                  * per-domain enables refcounting, so that this helper function
820                  * will be called only once (for enables) when the first user
821                  * registers a callback on this domain and once more (disable)
822                  * when the last user de-registers its callback.
823                  */
824                 pi->states[src_id].meas_notif_enabled = enable;
825
826         return ret;
827 }
828
829 static void *
830 scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
831                                  u8 evt_id, ktime_t timestamp,
832                                  const void *payld, size_t payld_sz,
833                                  void *report, u32 *src_id)
834 {
835         void *rep = NULL;
836
837         switch (evt_id) {
838         case SCMI_EVENT_POWERCAP_CAP_CHANGED:
839         {
840                 const struct scmi_powercap_cap_changed_notify_payld *p = payld;
841                 struct scmi_powercap_cap_changed_report *r = report;
842
843                 if (sizeof(*p) != payld_sz)
844                         break;
845
846                 r->timestamp = timestamp;
847                 r->agent_id = le32_to_cpu(p->agent_id);
848                 r->domain_id = le32_to_cpu(p->domain_id);
849                 r->power_cap = le32_to_cpu(p->power_cap);
850                 r->pai = le32_to_cpu(p->pai);
851                 *src_id = r->domain_id;
852                 rep = r;
853                 break;
854         }
855         case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
856         {
857                 const struct scmi_powercap_meas_changed_notify_payld *p = payld;
858                 struct scmi_powercap_meas_changed_report *r = report;
859
860                 if (sizeof(*p) != payld_sz)
861                         break;
862
863                 r->timestamp = timestamp;
864                 r->agent_id = le32_to_cpu(p->agent_id);
865                 r->domain_id = le32_to_cpu(p->domain_id);
866                 r->power = le32_to_cpu(p->power);
867                 *src_id = r->domain_id;
868                 rep = r;
869                 break;
870         }
871         default:
872                 break;
873         }
874
875         return rep;
876 }
877
878 static int
879 scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
880 {
881         struct powercap_info *pi = ph->get_priv(ph);
882
883         if (!pi)
884                 return -EINVAL;
885
886         return pi->num_domains;
887 }
888
889 static const struct scmi_event powercap_events[] = {
890         {
891                 .id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
892                 .max_payld_sz =
893                         sizeof(struct scmi_powercap_cap_changed_notify_payld),
894                 .max_report_sz =
895                         sizeof(struct scmi_powercap_cap_changed_report),
896         },
897         {
898                 .id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
899                 .max_payld_sz =
900                         sizeof(struct scmi_powercap_meas_changed_notify_payld),
901                 .max_report_sz =
902                         sizeof(struct scmi_powercap_meas_changed_report),
903         },
904 };
905
906 static const struct scmi_event_ops powercap_event_ops = {
907         .get_num_sources = scmi_powercap_get_num_sources,
908         .set_notify_enabled = scmi_powercap_set_notify_enabled,
909         .fill_custom_report = scmi_powercap_fill_custom_report,
910 };
911
912 static const struct scmi_protocol_events powercap_protocol_events = {
913         .queue_sz = SCMI_PROTO_QUEUE_SZ,
914         .ops = &powercap_event_ops,
915         .evts = powercap_events,
916         .num_events = ARRAY_SIZE(powercap_events),
917 };
918
919 static int
920 scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
921 {
922         int domain, ret;
923         u32 version;
924         struct powercap_info *pinfo;
925
926         ret = ph->xops->version_get(ph, &version);
927         if (ret)
928                 return ret;
929
930         dev_dbg(ph->dev, "Powercap Version %d.%d\n",
931                 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
932
933         pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
934         if (!pinfo)
935                 return -ENOMEM;
936
937         ret = scmi_powercap_attributes_get(ph, pinfo);
938         if (ret)
939                 return ret;
940
941         pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
942                                         sizeof(*pinfo->powercaps),
943                                         GFP_KERNEL);
944         if (!pinfo->powercaps)
945                 return -ENOMEM;
946
947         pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
948                                      sizeof(*pinfo->states), GFP_KERNEL);
949         if (!pinfo->states)
950                 return -ENOMEM;
951
952         /*
953          * Note that any failure in retrieving any domain attribute leads to
954          * the whole Powercap protocol initialization failure: this way the
955          * reported Powercap domains are all assured, when accessed, to be well
956          * formed and correlated by sane parent-child relationship (if any).
957          */
958         for (domain = 0; domain < pinfo->num_domains; domain++) {
959                 ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
960                 if (ret)
961                         return ret;
962
963                 if (pinfo->powercaps[domain].fastchannels)
964                         scmi_powercap_domain_init_fc(ph, domain,
965                                                      &pinfo->powercaps[domain].fc_info);
966
967                 /* Grab initial state when disable is supported. */
968                 if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
969                         ret = __scmi_powercap_cap_get(ph,
970                                                       &pinfo->powercaps[domain],
971                                                       &pinfo->states[domain].last_pcap);
972                         if (ret)
973                                 return ret;
974
975                         pinfo->states[domain].enabled =
976                                 !!pinfo->states[domain].last_pcap;
977                 }
978         }
979
980         pinfo->version = version;
981         return ph->set_priv(ph, pinfo, version);
982 }
983
984 static const struct scmi_protocol scmi_powercap = {
985         .id = SCMI_PROTOCOL_POWERCAP,
986         .owner = THIS_MODULE,
987         .instance_init = &scmi_powercap_protocol_init,
988         .ops = &powercap_proto_ops,
989         .events = &powercap_protocol_events,
990         .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
991 };
992
993 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)