linux/drivers/firmware/arm_scmi/base.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * System Control and Management Interface (SCMI) Base Protocol
   4 *
   5 * Copyright (C) 2018-2021 ARM Ltd.
   6 */
   7
   8#define pr_fmt(fmt) "SCMI Notifications BASE - " fmt
   9
  10#include <linux/module.h>
  11#include <linux/scmi_protocol.h>
  12
  13#include "common.h"
  14#include "notify.h"
  15
  16#define SCMI_BASE_NUM_SOURCES           1
  17#define SCMI_BASE_MAX_CMD_ERR_COUNT     1024
  18
  19enum scmi_base_protocol_cmd {
  20        BASE_DISCOVER_VENDOR = 0x3,
  21        BASE_DISCOVER_SUB_VENDOR = 0x4,
  22        BASE_DISCOVER_IMPLEMENT_VERSION = 0x5,
  23        BASE_DISCOVER_LIST_PROTOCOLS = 0x6,
  24        BASE_DISCOVER_AGENT = 0x7,
  25        BASE_NOTIFY_ERRORS = 0x8,
  26        BASE_SET_DEVICE_PERMISSIONS = 0x9,
  27        BASE_SET_PROTOCOL_PERMISSIONS = 0xa,
  28        BASE_RESET_AGENT_CONFIGURATION = 0xb,
  29};
  30
  31struct scmi_msg_resp_base_attributes {
  32        u8 num_protocols;
  33        u8 num_agents;
  34        __le16 reserved;
  35};
  36
  37struct scmi_msg_resp_base_discover_agent {
  38        __le32 agent_id;
  39        u8 name[SCMI_MAX_STR_SIZE];
  40};
  41
  42
  43struct scmi_msg_base_error_notify {
  44        __le32 event_control;
  45#define BASE_TP_NOTIFY_ALL      BIT(0)
  46};
  47
  48struct scmi_base_error_notify_payld {
  49        __le32 agent_id;
  50        __le32 error_status;
  51#define IS_FATAL_ERROR(x)       ((x) & BIT(31))
  52#define ERROR_CMD_COUNT(x)      FIELD_GET(GENMASK(9, 0), (x))
  53        __le64 msg_reports[SCMI_BASE_MAX_CMD_ERR_COUNT];
  54};
  55
  56/**
  57 * scmi_base_attributes_get() - gets the implementation details
  58 *      that are associated with the base protocol.
  59 *
  60 * @ph: SCMI protocol handle
  61 *
  62 * Return: 0 on success, else appropriate SCMI error.
  63 */
  64static int scmi_base_attributes_get(const struct scmi_protocol_handle *ph)
  65{
  66        int ret;
  67        struct scmi_xfer *t;
  68        struct scmi_msg_resp_base_attributes *attr_info;
  69        struct scmi_revision_info *rev = ph->get_priv(ph);
  70
  71        ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
  72                                      0, sizeof(*attr_info), &t);
  73        if (ret)
  74                return ret;
  75
  76        ret = ph->xops->do_xfer(ph, t);
  77        if (!ret) {
  78                attr_info = t->rx.buf;
  79                rev->num_protocols = attr_info->num_protocols;
  80                rev->num_agents = attr_info->num_agents;
  81        }
  82
  83        ph->xops->xfer_put(ph, t);
  84
  85        return ret;
  86}
  87
  88/**
  89 * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string.
  90 *
  91 * @ph: SCMI protocol handle
  92 * @sub_vendor: specify true if sub-vendor ID is needed
  93 *
  94 * Return: 0 on success, else appropriate SCMI error.
  95 */
  96static int
  97scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor)
  98{
  99        u8 cmd;
 100        int ret, size;
 101        char *vendor_id;
 102        struct scmi_xfer *t;
 103        struct scmi_revision_info *rev = ph->get_priv(ph);
 104
 105
 106        if (sub_vendor) {
 107                cmd = BASE_DISCOVER_SUB_VENDOR;
 108                vendor_id = rev->sub_vendor_id;
 109                size = ARRAY_SIZE(rev->sub_vendor_id);
 110        } else {
 111                cmd = BASE_DISCOVER_VENDOR;
 112                vendor_id = rev->vendor_id;
 113                size = ARRAY_SIZE(rev->vendor_id);
 114        }
 115
 116        ret = ph->xops->xfer_get_init(ph, cmd, 0, size, &t);
 117        if (ret)
 118                return ret;
 119
 120        ret = ph->xops->do_xfer(ph, t);
 121        if (!ret)
 122                memcpy(vendor_id, t->rx.buf, size);
 123
 124        ph->xops->xfer_put(ph, t);
 125
 126        return ret;
 127}
 128
 129/**
 130 * scmi_base_implementation_version_get() - gets a vendor-specific
 131 *      implementation 32-bit version. The format of the version number is
 132 *      vendor-specific
 133 *
 134 * @ph: SCMI protocol handle
 135 *
 136 * Return: 0 on success, else appropriate SCMI error.
 137 */
 138static int
 139scmi_base_implementation_version_get(const struct scmi_protocol_handle *ph)
 140{
 141        int ret;
 142        __le32 *impl_ver;
 143        struct scmi_xfer *t;
 144        struct scmi_revision_info *rev = ph->get_priv(ph);
 145
 146        ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_IMPLEMENT_VERSION,
 147                                      0, sizeof(*impl_ver), &t);
 148        if (ret)
 149                return ret;
 150
 151        ret = ph->xops->do_xfer(ph, t);
 152        if (!ret) {
 153                impl_ver = t->rx.buf;
 154                rev->impl_ver = le32_to_cpu(*impl_ver);
 155        }
 156
 157        ph->xops->xfer_put(ph, t);
 158
 159        return ret;
 160}
 161
 162/**
 163 * scmi_base_implementation_list_get() - gets the list of protocols it is
 164 *      OSPM is allowed to access
 165 *
 166 * @ph: SCMI protocol handle
 167 * @protocols_imp: pointer to hold the list of protocol identifiers
 168 *
 169 * Return: 0 on success, else appropriate SCMI error.
 170 */
 171static int
 172scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph,
 173                                  u8 *protocols_imp)
 174{
 175        u8 *list;
 176        int ret, loop;
 177        struct scmi_xfer *t;
 178        __le32 *num_skip, *num_ret;
 179        u32 tot_num_ret = 0, loop_num_ret;
 180        struct device *dev = ph->dev;
 181
 182        ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_LIST_PROTOCOLS,
 183                                      sizeof(*num_skip), 0, &t);
 184        if (ret)
 185                return ret;
 186
 187        num_skip = t->tx.buf;
 188        num_ret = t->rx.buf;
 189        list = t->rx.buf + sizeof(*num_ret);
 190
 191        do {
 192                /* Set the number of protocols to be skipped/already read */
 193                *num_skip = cpu_to_le32(tot_num_ret);
 194
 195                ret = ph->xops->do_xfer(ph, t);
 196                if (ret)
 197                        break;
 198
 199                loop_num_ret = le32_to_cpu(*num_ret);
 200                if (tot_num_ret + loop_num_ret > MAX_PROTOCOLS_IMP) {
 201                        dev_err(dev, "No. of Protocol > MAX_PROTOCOLS_IMP");
 202                        break;
 203                }
 204
 205                for (loop = 0; loop < loop_num_ret; loop++)
 206                        protocols_imp[tot_num_ret + loop] = *(list + loop);
 207
 208                tot_num_ret += loop_num_ret;
 209
 210                ph->xops->reset_rx_to_maxsz(ph, t);
 211        } while (loop_num_ret);
 212
 213        ph->xops->xfer_put(ph, t);
 214
 215        return ret;
 216}
 217
 218/**
 219 * scmi_base_discover_agent_get() - discover the name of an agent
 220 *
 221 * @ph: SCMI protocol handle
 222 * @id: Agent identifier
 223 * @name: Agent identifier ASCII string
 224 *
 225 * An agent id of 0 is reserved to identify the platform itself.
 226 * Generally operating system is represented as "OSPM"
 227 *
 228 * Return: 0 on success, else appropriate SCMI error.
 229 */
 230static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph,
 231                                        int id, char *name)
 232{
 233        int ret;
 234        struct scmi_msg_resp_base_discover_agent *agent_info;
 235        struct scmi_xfer *t;
 236
 237        ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_AGENT,
 238                                      sizeof(__le32), sizeof(*agent_info), &t);
 239        if (ret)
 240                return ret;
 241
 242        put_unaligned_le32(id, t->tx.buf);
 243
 244        ret = ph->xops->do_xfer(ph, t);
 245        if (!ret) {
 246                agent_info = t->rx.buf;
 247                strlcpy(name, agent_info->name, SCMI_MAX_STR_SIZE);
 248        }
 249
 250        ph->xops->xfer_put(ph, t);
 251
 252        return ret;
 253}
 254
 255static int scmi_base_error_notify(const struct scmi_protocol_handle *ph,
 256                                  bool enable)
 257{
 258        int ret;
 259        u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0;
 260        struct scmi_xfer *t;
 261        struct scmi_msg_base_error_notify *cfg;
 262
 263        ret = ph->xops->xfer_get_init(ph, BASE_NOTIFY_ERRORS,
 264                                      sizeof(*cfg), 0, &t);
 265        if (ret)
 266                return ret;
 267
 268        cfg = t->tx.buf;
 269        cfg->event_control = cpu_to_le32(evt_cntl);
 270
 271        ret = ph->xops->do_xfer(ph, t);
 272
 273        ph->xops->xfer_put(ph, t);
 274        return ret;
 275}
 276
 277static int scmi_base_set_notify_enabled(const struct scmi_protocol_handle *ph,
 278                                        u8 evt_id, u32 src_id, bool enable)
 279{
 280        int ret;
 281
 282        ret = scmi_base_error_notify(ph, enable);
 283        if (ret)
 284                pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret);
 285
 286        return ret;
 287}
 288
 289static void *scmi_base_fill_custom_report(const struct scmi_protocol_handle *ph,
 290                                          u8 evt_id, ktime_t timestamp,
 291                                          const void *payld, size_t payld_sz,
 292                                          void *report, u32 *src_id)
 293{
 294        int i;
 295        const struct scmi_base_error_notify_payld *p = payld;
 296        struct scmi_base_error_report *r = report;
 297
 298        /*
 299         * BaseError notification payload is variable in size but
 300         * up to a maximum length determined by the struct ponted by p.
 301         * Instead payld_sz is the effective length of this notification
 302         * payload so cannot be greater of the maximum allowed size as
 303         * pointed by p.
 304         */
 305        if (evt_id != SCMI_EVENT_BASE_ERROR_EVENT || sizeof(*p) < payld_sz)
 306                return NULL;
 307
 308        r->timestamp = timestamp;
 309        r->agent_id = le32_to_cpu(p->agent_id);
 310        r->fatal = IS_FATAL_ERROR(le32_to_cpu(p->error_status));
 311        r->cmd_count = ERROR_CMD_COUNT(le32_to_cpu(p->error_status));
 312        for (i = 0; i < r->cmd_count; i++)
 313                r->reports[i] = le64_to_cpu(p->msg_reports[i]);
 314        *src_id = 0;
 315
 316        return r;
 317}
 318
 319static const struct scmi_event base_events[] = {
 320        {
 321                .id = SCMI_EVENT_BASE_ERROR_EVENT,
 322                .max_payld_sz = sizeof(struct scmi_base_error_notify_payld),
 323                .max_report_sz = sizeof(struct scmi_base_error_report) +
 324                                  SCMI_BASE_MAX_CMD_ERR_COUNT * sizeof(u64),
 325        },
 326};
 327
 328static const struct scmi_event_ops base_event_ops = {
 329        .set_notify_enabled = scmi_base_set_notify_enabled,
 330        .fill_custom_report = scmi_base_fill_custom_report,
 331};
 332
 333static const struct scmi_protocol_events base_protocol_events = {
 334        .queue_sz = 4 * SCMI_PROTO_QUEUE_SZ,
 335        .ops = &base_event_ops,
 336        .evts = base_events,
 337        .num_events = ARRAY_SIZE(base_events),
 338        .num_sources = SCMI_BASE_NUM_SOURCES,
 339};
 340
 341static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
 342{
 343        int id, ret;
 344        u8 *prot_imp;
 345        u32 version;
 346        char name[SCMI_MAX_STR_SIZE];
 347        struct device *dev = ph->dev;
 348        struct scmi_revision_info *rev = scmi_revision_area_get(ph);
 349
 350        ret = ph->xops->version_get(ph, &version);
 351        if (ret)
 352                return ret;
 353
 354        prot_imp = devm_kcalloc(dev, MAX_PROTOCOLS_IMP, sizeof(u8), GFP_KERNEL);
 355        if (!prot_imp)
 356                return -ENOMEM;
 357
 358        rev->major_ver = PROTOCOL_REV_MAJOR(version),
 359        rev->minor_ver = PROTOCOL_REV_MINOR(version);
 360        ph->set_priv(ph, rev);
 361
 362        scmi_base_attributes_get(ph);
 363        scmi_base_vendor_id_get(ph, false);
 364        scmi_base_vendor_id_get(ph, true);
 365        scmi_base_implementation_version_get(ph);
 366        scmi_base_implementation_list_get(ph, prot_imp);
 367
 368        scmi_setup_protocol_implemented(ph, prot_imp);
 369
 370        dev_info(dev, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n",
 371                 rev->major_ver, rev->minor_ver, rev->vendor_id,
 372                 rev->sub_vendor_id, rev->impl_ver);
 373        dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
 374                rev->num_agents);
 375
 376        for (id = 0; id < rev->num_agents; id++) {
 377                scmi_base_discover_agent_get(ph, id, name);
 378                dev_dbg(dev, "Agent %d: %s\n", id, name);
 379        }
 380
 381        return 0;
 382}
 383
 384static const struct scmi_protocol scmi_base = {
 385        .id = SCMI_PROTOCOL_BASE,
 386        .owner = NULL,
 387        .instance_init = &scmi_base_protocol_init,
 388        .ops = NULL,
 389        .events = &base_protocol_events,
 390};
 391
 392DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)
 393