0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
0009
0010 #include <linux/bitfield.h>
0011 #include <linux/io.h>
0012 #include <linux/module.h>
0013 #include <linux/scmi_protocol.h>
0014
0015 #include <trace/events/scmi.h>
0016
0017 #include "protocols.h"
0018 #include "notify.h"
0019
0020 enum scmi_powercap_protocol_cmd {
0021 POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
0022 POWERCAP_CAP_GET = 0x4,
0023 POWERCAP_CAP_SET = 0x5,
0024 POWERCAP_PAI_GET = 0x6,
0025 POWERCAP_PAI_SET = 0x7,
0026 POWERCAP_DOMAIN_NAME_GET = 0x8,
0027 POWERCAP_MEASUREMENTS_GET = 0x9,
0028 POWERCAP_CAP_NOTIFY = 0xa,
0029 POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
0030 POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
0031 };
0032
0033 enum {
0034 POWERCAP_FC_CAP,
0035 POWERCAP_FC_PAI,
0036 POWERCAP_FC_MAX,
0037 };
0038
0039 struct scmi_msg_resp_powercap_domain_attributes {
0040 __le32 attributes;
0041 #define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(x) ((x) & BIT(31))
0042 #define SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(x) ((x) & BIT(30))
0043 #define SUPPORTS_ASYNC_POWERCAP_CAP_SET(x) ((x) & BIT(29))
0044 #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(28))
0045 #define SUPPORTS_POWERCAP_CAP_CONFIGURATION(x) ((x) & BIT(27))
0046 #define SUPPORTS_POWERCAP_MONITORING(x) ((x) & BIT(26))
0047 #define SUPPORTS_POWERCAP_PAI_CONFIGURATION(x) ((x) & BIT(25))
0048 #define SUPPORTS_POWERCAP_FASTCHANNELS(x) ((x) & BIT(22))
0049 #define POWERCAP_POWER_UNIT(x) \
0050 (FIELD_GET(GENMASK(24, 23), (x)))
0051 #define SUPPORTS_POWER_UNITS_MW(x) \
0052 (POWERCAP_POWER_UNIT(x) == 0x2)
0053 #define SUPPORTS_POWER_UNITS_UW(x) \
0054 (POWERCAP_POWER_UNIT(x) == 0x1)
0055 u8 name[SCMI_SHORT_NAME_MAX_SIZE];
0056 __le32 min_pai;
0057 __le32 max_pai;
0058 __le32 pai_step;
0059 __le32 min_power_cap;
0060 __le32 max_power_cap;
0061 __le32 power_cap_step;
0062 __le32 sustainable_power;
0063 __le32 accuracy;
0064 __le32 parent_id;
0065 };
0066
0067 struct scmi_msg_powercap_set_cap_or_pai {
0068 __le32 domain;
0069 __le32 flags;
0070 #define CAP_SET_ASYNC BIT(1)
0071 #define CAP_SET_IGNORE_DRESP BIT(0)
0072 __le32 value;
0073 };
0074
0075 struct scmi_msg_resp_powercap_cap_set_complete {
0076 __le32 domain;
0077 __le32 power_cap;
0078 };
0079
0080 struct scmi_msg_resp_powercap_meas_get {
0081 __le32 power;
0082 __le32 pai;
0083 };
0084
0085 struct scmi_msg_powercap_notify_cap {
0086 __le32 domain;
0087 __le32 notify_enable;
0088 };
0089
0090 struct scmi_msg_powercap_notify_thresh {
0091 __le32 domain;
0092 __le32 notify_enable;
0093 __le32 power_thresh_low;
0094 __le32 power_thresh_high;
0095 };
0096
0097 struct scmi_powercap_cap_changed_notify_payld {
0098 __le32 agent_id;
0099 __le32 domain_id;
0100 __le32 power_cap;
0101 __le32 pai;
0102 };
0103
0104 struct scmi_powercap_meas_changed_notify_payld {
0105 __le32 agent_id;
0106 __le32 domain_id;
0107 __le32 power;
0108 };
0109
0110 struct scmi_powercap_state {
0111 bool meas_notif_enabled;
0112 u64 thresholds;
0113 #define THRESH_LOW(p, id) \
0114 (lower_32_bits((p)->states[(id)].thresholds))
0115 #define THRESH_HIGH(p, id) \
0116 (upper_32_bits((p)->states[(id)].thresholds))
0117 };
0118
0119 struct powercap_info {
0120 u32 version;
0121 int num_domains;
0122 struct scmi_powercap_state *states;
0123 struct scmi_powercap_info *powercaps;
0124 };
0125
0126 static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
0127 POWERCAP_CAP_NOTIFY,
0128 POWERCAP_MEASUREMENTS_NOTIFY,
0129 };
0130
0131 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
0132 u32 domain, int message_id, bool enable);
0133
0134 static int
0135 scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
0136 struct powercap_info *pi)
0137 {
0138 int ret;
0139 struct scmi_xfer *t;
0140
0141 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
0142 sizeof(u32), &t);
0143 if (ret)
0144 return ret;
0145
0146 ret = ph->xops->do_xfer(ph, t);
0147 if (!ret) {
0148 u32 attributes;
0149
0150 attributes = get_unaligned_le32(t->rx.buf);
0151 pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
0152 }
0153
0154 ph->xops->xfer_put(ph, t);
0155 return ret;
0156 }
0157
0158 static inline int
0159 scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
0160 unsigned int step_val, bool configurable)
0161 {
0162 if (!min_val || !max_val)
0163 return -EPROTO;
0164
0165 if ((configurable && min_val == max_val) ||
0166 (!configurable && min_val != max_val))
0167 return -EPROTO;
0168
0169 if (min_val != max_val && !step_val)
0170 return -EPROTO;
0171
0172 return 0;
0173 }
0174
0175 static int
0176 scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
0177 struct powercap_info *pinfo, u32 domain)
0178 {
0179 int ret;
0180 u32 flags;
0181 struct scmi_xfer *t;
0182 struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
0183 struct scmi_msg_resp_powercap_domain_attributes *resp;
0184
0185 ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
0186 sizeof(domain), sizeof(*resp), &t);
0187 if (ret)
0188 return ret;
0189
0190 put_unaligned_le32(domain, t->tx.buf);
0191 resp = t->rx.buf;
0192
0193 ret = ph->xops->do_xfer(ph, t);
0194 if (!ret) {
0195 flags = le32_to_cpu(resp->attributes);
0196
0197 dom_info->id = domain;
0198 dom_info->notify_powercap_cap_change =
0199 SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
0200 dom_info->notify_powercap_measurement_change =
0201 SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
0202 dom_info->async_powercap_cap_set =
0203 SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
0204 dom_info->powercap_cap_config =
0205 SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
0206 dom_info->powercap_monitoring =
0207 SUPPORTS_POWERCAP_MONITORING(flags);
0208 dom_info->powercap_pai_config =
0209 SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
0210 dom_info->powercap_scale_mw =
0211 SUPPORTS_POWER_UNITS_MW(flags);
0212 dom_info->powercap_scale_uw =
0213 SUPPORTS_POWER_UNITS_UW(flags);
0214 dom_info->fastchannels =
0215 SUPPORTS_POWERCAP_FASTCHANNELS(flags);
0216
0217 strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
0218
0219 dom_info->min_pai = le32_to_cpu(resp->min_pai);
0220 dom_info->max_pai = le32_to_cpu(resp->max_pai);
0221 dom_info->pai_step = le32_to_cpu(resp->pai_step);
0222 ret = scmi_powercap_validate(dom_info->min_pai,
0223 dom_info->max_pai,
0224 dom_info->pai_step,
0225 dom_info->powercap_pai_config);
0226 if (ret) {
0227 dev_err(ph->dev,
0228 "Platform reported inconsistent PAI config for domain %d - %s\n",
0229 dom_info->id, dom_info->name);
0230 goto clean;
0231 }
0232
0233 dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
0234 dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
0235 dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
0236 ret = scmi_powercap_validate(dom_info->min_power_cap,
0237 dom_info->max_power_cap,
0238 dom_info->power_cap_step,
0239 dom_info->powercap_cap_config);
0240 if (ret) {
0241 dev_err(ph->dev,
0242 "Platform reported inconsistent CAP config for domain %d - %s\n",
0243 dom_info->id, dom_info->name);
0244 goto clean;
0245 }
0246
0247 dom_info->sustainable_power =
0248 le32_to_cpu(resp->sustainable_power);
0249 dom_info->accuracy = le32_to_cpu(resp->accuracy);
0250
0251 dom_info->parent_id = le32_to_cpu(resp->parent_id);
0252 if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
0253 (dom_info->parent_id >= pinfo->num_domains ||
0254 dom_info->parent_id == dom_info->id)) {
0255 dev_err(ph->dev,
0256 "Platform reported inconsistent parent ID for domain %d - %s\n",
0257 dom_info->id, dom_info->name);
0258 ret = -ENODEV;
0259 }
0260 }
0261
0262 clean:
0263 ph->xops->xfer_put(ph, t);
0264
0265
0266
0267
0268
0269 if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
0270 ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
0271 domain, dom_info->name,
0272 SCMI_MAX_STR_SIZE);
0273
0274 return ret;
0275 }
0276
0277 static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
0278 {
0279 struct powercap_info *pi = ph->get_priv(ph);
0280
0281 return pi->num_domains;
0282 }
0283
0284 static const struct scmi_powercap_info *
0285 scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
0286 {
0287 struct powercap_info *pi = ph->get_priv(ph);
0288
0289 if (domain_id >= pi->num_domains)
0290 return NULL;
0291
0292 return pi->powercaps + domain_id;
0293 }
0294
0295 static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
0296 u32 domain_id, u32 *power_cap)
0297 {
0298 int ret;
0299 struct scmi_xfer *t;
0300
0301 ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
0302 sizeof(u32), &t);
0303 if (ret)
0304 return ret;
0305
0306 put_unaligned_le32(domain_id, t->tx.buf);
0307 ret = ph->xops->do_xfer(ph, t);
0308 if (!ret)
0309 *power_cap = get_unaligned_le32(t->rx.buf);
0310
0311 ph->xops->xfer_put(ph, t);
0312
0313 return ret;
0314 }
0315
0316 static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
0317 u32 domain_id, u32 *power_cap)
0318 {
0319 struct scmi_powercap_info *dom;
0320 struct powercap_info *pi = ph->get_priv(ph);
0321
0322 if (!power_cap || domain_id >= pi->num_domains)
0323 return -EINVAL;
0324
0325 dom = pi->powercaps + domain_id;
0326 if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
0327 *power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
0328 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
0329 domain_id, *power_cap, 0);
0330 return 0;
0331 }
0332
0333 return scmi_powercap_xfer_cap_get(ph, domain_id, power_cap);
0334 }
0335
0336 static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
0337 const struct scmi_powercap_info *pc,
0338 u32 power_cap, bool ignore_dresp)
0339 {
0340 int ret;
0341 struct scmi_xfer *t;
0342 struct scmi_msg_powercap_set_cap_or_pai *msg;
0343
0344 ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
0345 sizeof(*msg), 0, &t);
0346 if (ret)
0347 return ret;
0348
0349 msg = t->tx.buf;
0350 msg->domain = cpu_to_le32(pc->id);
0351 msg->flags =
0352 cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, !!pc->async_powercap_cap_set) |
0353 FIELD_PREP(CAP_SET_IGNORE_DRESP, !!ignore_dresp));
0354 msg->value = cpu_to_le32(power_cap);
0355
0356 if (!pc->async_powercap_cap_set || ignore_dresp) {
0357 ret = ph->xops->do_xfer(ph, t);
0358 } else {
0359 ret = ph->xops->do_xfer_with_response(ph, t);
0360 if (!ret) {
0361 struct scmi_msg_resp_powercap_cap_set_complete *resp;
0362
0363 resp = t->rx.buf;
0364 if (le32_to_cpu(resp->domain) == pc->id)
0365 dev_dbg(ph->dev,
0366 "Powercap ID %d CAP set async to %u\n",
0367 pc->id,
0368 get_unaligned_le32(&resp->power_cap));
0369 else
0370 ret = -EPROTO;
0371 }
0372 }
0373
0374 ph->xops->xfer_put(ph, t);
0375 return ret;
0376 }
0377
0378 static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
0379 u32 domain_id, u32 power_cap,
0380 bool ignore_dresp)
0381 {
0382 const struct scmi_powercap_info *pc;
0383
0384 pc = scmi_powercap_dom_info_get(ph, domain_id);
0385 if (!pc || !pc->powercap_cap_config || !power_cap ||
0386 power_cap < pc->min_power_cap ||
0387 power_cap > pc->max_power_cap)
0388 return -EINVAL;
0389
0390 if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
0391 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
0392
0393 iowrite32(power_cap, fci->set_addr);
0394 ph->hops->fastchannel_db_ring(fci->set_db);
0395 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
0396 domain_id, power_cap, 0);
0397 return 0;
0398 }
0399
0400 return scmi_powercap_xfer_cap_set(ph, pc, power_cap, ignore_dresp);
0401 }
0402
0403 static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
0404 u32 domain_id, u32 *pai)
0405 {
0406 int ret;
0407 struct scmi_xfer *t;
0408
0409 ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
0410 sizeof(u32), &t);
0411 if (ret)
0412 return ret;
0413
0414 put_unaligned_le32(domain_id, t->tx.buf);
0415 ret = ph->xops->do_xfer(ph, t);
0416 if (!ret)
0417 *pai = get_unaligned_le32(t->rx.buf);
0418
0419 ph->xops->xfer_put(ph, t);
0420
0421 return ret;
0422 }
0423
0424 static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
0425 u32 domain_id, u32 *pai)
0426 {
0427 struct scmi_powercap_info *dom;
0428 struct powercap_info *pi = ph->get_priv(ph);
0429
0430 if (!pai || domain_id >= pi->num_domains)
0431 return -EINVAL;
0432
0433 dom = pi->powercaps + domain_id;
0434 if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
0435 *pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
0436 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
0437 domain_id, *pai, 0);
0438 return 0;
0439 }
0440
0441 return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
0442 }
0443
0444 static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
0445 u32 domain_id, u32 pai)
0446 {
0447 int ret;
0448 struct scmi_xfer *t;
0449 struct scmi_msg_powercap_set_cap_or_pai *msg;
0450
0451 ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
0452 sizeof(*msg), 0, &t);
0453 if (ret)
0454 return ret;
0455
0456 msg = t->tx.buf;
0457 msg->domain = cpu_to_le32(domain_id);
0458 msg->flags = cpu_to_le32(0);
0459 msg->value = cpu_to_le32(pai);
0460
0461 ret = ph->xops->do_xfer(ph, t);
0462
0463 ph->xops->xfer_put(ph, t);
0464 return ret;
0465 }
0466
0467 static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
0468 u32 domain_id, u32 pai)
0469 {
0470 const struct scmi_powercap_info *pc;
0471
0472 pc = scmi_powercap_dom_info_get(ph, domain_id);
0473 if (!pc || !pc->powercap_pai_config || !pai ||
0474 pai < pc->min_pai || pai > pc->max_pai)
0475 return -EINVAL;
0476
0477 if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
0478 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
0479
0480 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
0481 domain_id, pai, 0);
0482 iowrite32(pai, fci->set_addr);
0483 ph->hops->fastchannel_db_ring(fci->set_db);
0484 return 0;
0485 }
0486
0487 return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
0488 }
0489
0490 static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
0491 u32 domain_id, u32 *average_power,
0492 u32 *pai)
0493 {
0494 int ret;
0495 struct scmi_xfer *t;
0496 struct scmi_msg_resp_powercap_meas_get *resp;
0497 const struct scmi_powercap_info *pc;
0498
0499 pc = scmi_powercap_dom_info_get(ph, domain_id);
0500 if (!pc || !pc->powercap_monitoring || !pai || !average_power)
0501 return -EINVAL;
0502
0503 ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
0504 sizeof(u32), sizeof(*resp), &t);
0505 if (ret)
0506 return ret;
0507
0508 resp = t->rx.buf;
0509 put_unaligned_le32(domain_id, t->tx.buf);
0510 ret = ph->xops->do_xfer(ph, t);
0511 if (!ret) {
0512 *average_power = le32_to_cpu(resp->power);
0513 *pai = le32_to_cpu(resp->pai);
0514 }
0515
0516 ph->xops->xfer_put(ph, t);
0517 return ret;
0518 }
0519
0520 static int
0521 scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
0522 u32 domain_id, u32 *power_thresh_low,
0523 u32 *power_thresh_high)
0524 {
0525 struct powercap_info *pi = ph->get_priv(ph);
0526
0527 if (!power_thresh_low || !power_thresh_high ||
0528 domain_id >= pi->num_domains)
0529 return -EINVAL;
0530
0531 *power_thresh_low = THRESH_LOW(pi, domain_id);
0532 *power_thresh_high = THRESH_HIGH(pi, domain_id);
0533
0534 return 0;
0535 }
0536
0537 static int
0538 scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
0539 u32 domain_id, u32 power_thresh_low,
0540 u32 power_thresh_high)
0541 {
0542 int ret = 0;
0543 struct powercap_info *pi = ph->get_priv(ph);
0544
0545 if (domain_id >= pi->num_domains ||
0546 power_thresh_low > power_thresh_high)
0547 return -EINVAL;
0548
0549
0550 if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
0551 THRESH_HIGH(pi, domain_id) == power_thresh_high)
0552 return ret;
0553
0554 pi->states[domain_id].thresholds =
0555 (FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
0556 FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
0557
0558
0559 if (pi->states[domain_id].meas_notif_enabled)
0560 ret = scmi_powercap_notify(ph, domain_id,
0561 POWERCAP_MEASUREMENTS_NOTIFY,
0562 true);
0563
0564 return ret;
0565 }
0566
0567 static const struct scmi_powercap_proto_ops powercap_proto_ops = {
0568 .num_domains_get = scmi_powercap_num_domains_get,
0569 .info_get = scmi_powercap_dom_info_get,
0570 .cap_get = scmi_powercap_cap_get,
0571 .cap_set = scmi_powercap_cap_set,
0572 .pai_get = scmi_powercap_pai_get,
0573 .pai_set = scmi_powercap_pai_set,
0574 .measurements_get = scmi_powercap_measurements_get,
0575 .measurements_threshold_set = scmi_powercap_measurements_threshold_set,
0576 .measurements_threshold_get = scmi_powercap_measurements_threshold_get,
0577 };
0578
0579 static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
0580 u32 domain, struct scmi_fc_info **p_fc)
0581 {
0582 struct scmi_fc_info *fc;
0583
0584 fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
0585 if (!fc)
0586 return;
0587
0588 ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
0589 POWERCAP_CAP_SET, 4, domain,
0590 &fc[POWERCAP_FC_CAP].set_addr,
0591 &fc[POWERCAP_FC_CAP].set_db);
0592
0593 ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
0594 POWERCAP_CAP_GET, 4, domain,
0595 &fc[POWERCAP_FC_CAP].get_addr, NULL);
0596
0597 ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
0598 POWERCAP_PAI_SET, 4, domain,
0599 &fc[POWERCAP_FC_PAI].set_addr,
0600 &fc[POWERCAP_FC_PAI].set_db);
0601
0602 ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
0603 POWERCAP_PAI_GET, 4, domain,
0604 &fc[POWERCAP_FC_PAI].get_addr, NULL);
0605
0606 *p_fc = fc;
0607 }
0608
0609 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
0610 u32 domain, int message_id, bool enable)
0611 {
0612 int ret;
0613 struct scmi_xfer *t;
0614
0615 switch (message_id) {
0616 case POWERCAP_CAP_NOTIFY:
0617 {
0618 struct scmi_msg_powercap_notify_cap *notify;
0619
0620 ret = ph->xops->xfer_get_init(ph, message_id,
0621 sizeof(*notify), 0, &t);
0622 if (ret)
0623 return ret;
0624
0625 notify = t->tx.buf;
0626 notify->domain = cpu_to_le32(domain);
0627 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
0628 break;
0629 }
0630 case POWERCAP_MEASUREMENTS_NOTIFY:
0631 {
0632 u32 low, high;
0633 struct scmi_msg_powercap_notify_thresh *notify;
0634
0635
0636
0637
0638
0639
0640
0641
0642 ret = scmi_powercap_measurements_threshold_get(ph, domain,
0643 &low, &high);
0644 if (ret)
0645 return ret;
0646
0647 if (enable && !low && !high) {
0648 dev_err(ph->dev,
0649 "Invalid Measurements Notify thresholds: %u/%u\n",
0650 low, high);
0651 return -EINVAL;
0652 }
0653
0654 ret = ph->xops->xfer_get_init(ph, message_id,
0655 sizeof(*notify), 0, &t);
0656 if (ret)
0657 return ret;
0658
0659 notify = t->tx.buf;
0660 notify->domain = cpu_to_le32(domain);
0661 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
0662 notify->power_thresh_low = cpu_to_le32(low);
0663 notify->power_thresh_high = cpu_to_le32(high);
0664 break;
0665 }
0666 default:
0667 return -EINVAL;
0668 }
0669
0670 ret = ph->xops->do_xfer(ph, t);
0671
0672 ph->xops->xfer_put(ph, t);
0673 return ret;
0674 }
0675
0676 static int
0677 scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
0678 u8 evt_id, u32 src_id, bool enable)
0679 {
0680 int ret, cmd_id;
0681 struct powercap_info *pi = ph->get_priv(ph);
0682
0683 if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
0684 return -EINVAL;
0685
0686 cmd_id = evt_2_cmd[evt_id];
0687 ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
0688 if (ret)
0689 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
0690 evt_id, src_id, ret);
0691 else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709 pi->states[src_id].meas_notif_enabled = enable;
0710
0711 return ret;
0712 }
0713
0714 static void *
0715 scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
0716 u8 evt_id, ktime_t timestamp,
0717 const void *payld, size_t payld_sz,
0718 void *report, u32 *src_id)
0719 {
0720 void *rep = NULL;
0721
0722 switch (evt_id) {
0723 case SCMI_EVENT_POWERCAP_CAP_CHANGED:
0724 {
0725 const struct scmi_powercap_cap_changed_notify_payld *p = payld;
0726 struct scmi_powercap_cap_changed_report *r = report;
0727
0728 if (sizeof(*p) != payld_sz)
0729 break;
0730
0731 r->timestamp = timestamp;
0732 r->agent_id = le32_to_cpu(p->agent_id);
0733 r->domain_id = le32_to_cpu(p->domain_id);
0734 r->power_cap = le32_to_cpu(p->power_cap);
0735 r->pai = le32_to_cpu(p->pai);
0736 *src_id = r->domain_id;
0737 rep = r;
0738 break;
0739 }
0740 case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
0741 {
0742 const struct scmi_powercap_meas_changed_notify_payld *p = payld;
0743 struct scmi_powercap_meas_changed_report *r = report;
0744
0745 if (sizeof(*p) != payld_sz)
0746 break;
0747
0748 r->timestamp = timestamp;
0749 r->agent_id = le32_to_cpu(p->agent_id);
0750 r->domain_id = le32_to_cpu(p->domain_id);
0751 r->power = le32_to_cpu(p->power);
0752 *src_id = r->domain_id;
0753 rep = r;
0754 break;
0755 }
0756 default:
0757 break;
0758 }
0759
0760 return rep;
0761 }
0762
0763 static int
0764 scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
0765 {
0766 struct powercap_info *pi = ph->get_priv(ph);
0767
0768 if (!pi)
0769 return -EINVAL;
0770
0771 return pi->num_domains;
0772 }
0773
0774 static const struct scmi_event powercap_events[] = {
0775 {
0776 .id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
0777 .max_payld_sz =
0778 sizeof(struct scmi_powercap_cap_changed_notify_payld),
0779 .max_report_sz =
0780 sizeof(struct scmi_powercap_cap_changed_report),
0781 },
0782 {
0783 .id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
0784 .max_payld_sz =
0785 sizeof(struct scmi_powercap_meas_changed_notify_payld),
0786 .max_report_sz =
0787 sizeof(struct scmi_powercap_meas_changed_report),
0788 },
0789 };
0790
0791 static const struct scmi_event_ops powercap_event_ops = {
0792 .get_num_sources = scmi_powercap_get_num_sources,
0793 .set_notify_enabled = scmi_powercap_set_notify_enabled,
0794 .fill_custom_report = scmi_powercap_fill_custom_report,
0795 };
0796
0797 static const struct scmi_protocol_events powercap_protocol_events = {
0798 .queue_sz = SCMI_PROTO_QUEUE_SZ,
0799 .ops = &powercap_event_ops,
0800 .evts = powercap_events,
0801 .num_events = ARRAY_SIZE(powercap_events),
0802 };
0803
0804 static int
0805 scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
0806 {
0807 int domain, ret;
0808 u32 version;
0809 struct powercap_info *pinfo;
0810
0811 ret = ph->xops->version_get(ph, &version);
0812 if (ret)
0813 return ret;
0814
0815 dev_dbg(ph->dev, "Powercap Version %d.%d\n",
0816 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
0817
0818 pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
0819 if (!pinfo)
0820 return -ENOMEM;
0821
0822 ret = scmi_powercap_attributes_get(ph, pinfo);
0823 if (ret)
0824 return ret;
0825
0826 pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
0827 sizeof(*pinfo->powercaps),
0828 GFP_KERNEL);
0829 if (!pinfo->powercaps)
0830 return -ENOMEM;
0831
0832
0833
0834
0835
0836
0837
0838 for (domain = 0; domain < pinfo->num_domains; domain++) {
0839 ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
0840 if (ret)
0841 return ret;
0842
0843 if (pinfo->powercaps[domain].fastchannels)
0844 scmi_powercap_domain_init_fc(ph, domain,
0845 &pinfo->powercaps[domain].fc_info);
0846 }
0847
0848 pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
0849 sizeof(*pinfo->states), GFP_KERNEL);
0850 if (!pinfo->states)
0851 return -ENOMEM;
0852
0853 pinfo->version = version;
0854
0855 return ph->set_priv(ph, pinfo);
0856 }
0857
0858 static const struct scmi_protocol scmi_powercap = {
0859 .id = SCMI_PROTOCOL_POWERCAP,
0860 .owner = THIS_MODULE,
0861 .instance_init = &scmi_powercap_protocol_init,
0862 .ops = &powercap_proto_ops,
0863 .events = &powercap_protocol_events,
0864 };
0865
0866 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)