Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * System Control and Management Interface (SCMI) Powercap Protocol
0004  *
0005  * Copyright (C) 2022 ARM Ltd.
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      * If supported overwrite short name with the extended one;
0267      * on error just carry on and use already provided short name.
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     /* Anything to do ? */
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     /* Update thresholds if notification already enabled */
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          * Note that we have to pick the most recently configured
0637          * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
0638          * enable request and we fail, complaining, if no thresholds
0639          * were ever set, since this is an indication the API has been
0640          * used wrongly.
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          * On success save the current notification enabled state, so
0694          * as to be able to properly update the notification thresholds
0695          * when they are modified on a domain for which measurement
0696          * notifications were currently enabled.
0697          *
0698          * This is needed because the SCMI Notification core machinery
0699          * and API does not support passing per-notification custom
0700          * arguments at callback registration time.
0701          *
0702          * Note that this can be done here with a simple flag since the
0703          * SCMI core Notifications code takes care of keeping proper
0704          * per-domain enables refcounting, so that this helper function
0705          * will be called only once (for enables) when the first user
0706          * registers a callback on this domain and once more (disable)
0707          * when the last user de-registers its callback.
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      * Note that any failure in retrieving any domain attribute leads to
0834      * the whole Powercap protocol initialization failure: this way the
0835      * reported Powercap domains are all assured, when accessed, to be well
0836      * formed and correlated by sane parent-child relationship (if any).
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)