dpdk/drivers/common/octeontx/octeontx_mbox.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2017 Cavium, Inc
   3 */
   4
   5#include <string.h>
   6
   7#include <rte_atomic.h>
   8#include <rte_common.h>
   9#include <rte_cycles.h>
  10#include <rte_io.h>
  11#include <rte_spinlock.h>
  12
  13#include "octeontx_mbox.h"
  14
  15/* Mbox operation timeout in seconds */
  16#define MBOX_WAIT_TIME_SEC      3
  17#define MAX_RAM_MBOX_LEN        ((SSOW_BAR4_LEN >> 1) - 8 /* Mbox header */)
  18
  19/* Mbox channel state */
  20enum {
  21        MBOX_CHAN_STATE_REQ = 1,
  22        MBOX_CHAN_STATE_RES = 0,
  23};
  24
  25/* Response messages */
  26enum {
  27        MBOX_RET_SUCCESS,
  28        MBOX_RET_INVALID,
  29        MBOX_RET_INTERNAL_ERR,
  30};
  31
  32struct mbox {
  33        int init_once;
  34        uint8_t ready;
  35        uint8_t *ram_mbox_base; /* Base address of mbox message stored in ram */
  36        uint8_t *reg; /* Store to this register triggers PF mbox interrupt */
  37        uint16_t tag_own; /* Last tag which was written to own channel */
  38        uint16_t domain; /* Domain */
  39        rte_spinlock_t lock;
  40};
  41
  42static struct mbox octeontx_mbox;
  43
  44/*
  45 * Structure used for mbox synchronization
  46 * This structure sits at the begin of Mbox RAM and used as main
  47 * synchronization point for channel communication
  48 */
  49struct mbox_ram_hdr {
  50        union {
  51                uint64_t u64;
  52                struct {
  53                        uint8_t chan_state : 1;
  54                        uint8_t coproc : 7;
  55                        uint8_t msg;
  56                        uint8_t vfid;
  57                        uint8_t res_code;
  58                        uint16_t tag;
  59                        uint16_t len;
  60                };
  61        };
  62};
  63
  64/* MBOX interface version message */
  65struct mbox_intf_ver {
  66        uint32_t platform:12;
  67        uint32_t major:10;
  68        uint32_t minor:10;
  69};
  70
  71RTE_LOG_REGISTER(octeontx_logtype_mbox, pmd.octeontx.mbox, NOTICE);
  72
  73static inline void
  74mbox_msgcpy(volatile uint8_t *d, volatile const uint8_t *s, uint16_t size)
  75{
  76        uint16_t i;
  77
  78        for (i = 0; i < size; i++)
  79                d[i] = s[i];
  80}
  81
  82static inline void
  83mbox_send_request(struct mbox *m, struct octeontx_mbox_hdr *hdr,
  84                        const void *txmsg, uint16_t txsize)
  85{
  86        struct mbox_ram_hdr old_hdr;
  87        struct mbox_ram_hdr new_hdr = { {0} };
  88        uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
  89        uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
  90
  91        /*
  92         * Initialize the channel with the tag left by last send.
  93         * On success full mbox send complete, PF increments the tag by one.
  94         * The sender can validate integrity of PF message with this scheme
  95         */
  96        old_hdr.u64 = rte_read64(ram_mbox_hdr);
  97        m->tag_own = (old_hdr.tag + 2) & (~0x1ul); /* next even number */
  98
  99        /* Copy msg body */
 100        if (txmsg)
 101                mbox_msgcpy(ram_mbox_msg, txmsg, txsize);
 102
 103        /* Prepare new hdr */
 104        new_hdr.chan_state = MBOX_CHAN_STATE_REQ;
 105        new_hdr.coproc = hdr->coproc;
 106        new_hdr.msg = hdr->msg;
 107        new_hdr.vfid = hdr->vfid;
 108        new_hdr.tag = m->tag_own;
 109        new_hdr.len = txsize;
 110
 111        /* Write the msg header */
 112        rte_write64(new_hdr.u64, ram_mbox_hdr);
 113        rte_smp_wmb();
 114        /* Notify PF about the new msg - write to MBOX reg generates PF IRQ */
 115        rte_write64(0, m->reg);
 116}
 117
 118static inline int
 119mbox_wait_response(struct mbox *m, struct octeontx_mbox_hdr *hdr,
 120                        void *rxmsg, uint16_t rxsize)
 121{
 122        int res = 0, wait;
 123        uint16_t len;
 124        struct mbox_ram_hdr rx_hdr;
 125        uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
 126        uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
 127
 128        /* Wait for response */
 129        wait = MBOX_WAIT_TIME_SEC * 1000 * 10;
 130        while (wait > 0) {
 131                rte_delay_us(100);
 132                rx_hdr.u64 = rte_read64(ram_mbox_hdr);
 133                if (rx_hdr.chan_state == MBOX_CHAN_STATE_RES)
 134                        break;
 135                --wait;
 136        }
 137
 138        hdr->res_code = rx_hdr.res_code;
 139        m->tag_own++;
 140
 141        /* Timeout */
 142        if (wait <= 0) {
 143                res = -ETIMEDOUT;
 144                goto error;
 145        }
 146
 147        /* Tag mismatch */
 148        if (m->tag_own != rx_hdr.tag) {
 149                res = -EINVAL;
 150                goto error;
 151        }
 152
 153        /* PF nacked the msg */
 154        if (rx_hdr.res_code != MBOX_RET_SUCCESS) {
 155                res = -EBADMSG;
 156                goto error;
 157        }
 158
 159        len = RTE_MIN(rx_hdr.len, rxsize);
 160        if (rxmsg)
 161                mbox_msgcpy(rxmsg, ram_mbox_msg, len);
 162
 163        return len;
 164
 165error:
 166        mbox_log_err("Failed to send mbox(%d/%d) coproc=%d msg=%d ret=(%d,%d)",
 167                        m->tag_own, rx_hdr.tag, hdr->coproc, hdr->msg, res,
 168                        hdr->res_code);
 169        return res;
 170}
 171
 172static inline int
 173mbox_send(struct mbox *m, struct octeontx_mbox_hdr *hdr, const void *txmsg,
 174                uint16_t txsize, void *rxmsg, uint16_t rxsize)
 175{
 176        int res = -EINVAL;
 177
 178        if (m->init_once == 0 || hdr == NULL ||
 179                txsize > MAX_RAM_MBOX_LEN || rxsize > MAX_RAM_MBOX_LEN) {
 180                mbox_log_err("Invalid init_once=%d hdr=%p txsz=%d rxsz=%d",
 181                                m->init_once, hdr, txsize, rxsize);
 182                return res;
 183        }
 184
 185        rte_spinlock_lock(&m->lock);
 186
 187        mbox_send_request(m, hdr, txmsg, txsize);
 188        res = mbox_wait_response(m, hdr, rxmsg, rxsize);
 189
 190        rte_spinlock_unlock(&m->lock);
 191        return res;
 192}
 193
 194int
 195octeontx_mbox_set_ram_mbox_base(uint8_t *ram_mbox_base, uint16_t domain)
 196{
 197        struct mbox *m = &octeontx_mbox;
 198
 199        if (m->init_once)
 200                return -EALREADY;
 201
 202        if (ram_mbox_base == NULL) {
 203                mbox_log_err("Invalid ram_mbox_base=%p", ram_mbox_base);
 204                return -EINVAL;
 205        }
 206
 207        m->ram_mbox_base = ram_mbox_base;
 208
 209        if (m->reg != NULL) {
 210                rte_spinlock_init(&m->lock);
 211                m->init_once = 1;
 212                m->domain = domain;
 213        }
 214
 215        return 0;
 216}
 217
 218int
 219octeontx_mbox_set_reg(uint8_t *reg, uint16_t domain)
 220{
 221        struct mbox *m = &octeontx_mbox;
 222
 223        if (m->init_once)
 224                return -EALREADY;
 225
 226        if (reg == NULL) {
 227                mbox_log_err("Invalid reg=%p", reg);
 228                return -EINVAL;
 229        }
 230
 231        m->reg = reg;
 232
 233        if (m->ram_mbox_base != NULL) {
 234                rte_spinlock_init(&m->lock);
 235                m->init_once = 1;
 236                m->domain = domain;
 237        }
 238
 239        return 0;
 240}
 241
 242int
 243octeontx_mbox_send(struct octeontx_mbox_hdr *hdr, void *txdata,
 244                                 uint16_t txlen, void *rxdata, uint16_t rxlen)
 245{
 246        struct mbox *m = &octeontx_mbox;
 247
 248        RTE_BUILD_BUG_ON(sizeof(struct mbox_ram_hdr) != 8);
 249        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 250                return -EINVAL;
 251
 252        return mbox_send(m, hdr, txdata, txlen, rxdata, rxlen);
 253}
 254
 255static int
 256octeontx_start_domain(void)
 257{
 258        struct octeontx_mbox_hdr hdr = {0};
 259        int result = -EINVAL;
 260
 261        hdr.coproc = NO_COPROC;
 262        hdr.msg = RM_START_APP;
 263
 264        result = octeontx_mbox_send(&hdr, NULL, 0, NULL, 0);
 265        if (result != 0) {
 266                mbox_log_err("Could not start domain. Err=%d. FuncErr=%d\n",
 267                             result, hdr.res_code);
 268                result = -EINVAL;
 269        }
 270
 271        return result;
 272}
 273
 274static int
 275octeontx_check_mbox_version(struct mbox_intf_ver *app_intf_ver,
 276                            struct mbox_intf_ver *intf_ver)
 277{
 278        struct mbox_intf_ver kernel_intf_ver = {0};
 279        struct octeontx_mbox_hdr hdr = {0};
 280        int result = 0;
 281
 282
 283        hdr.coproc = NO_COPROC;
 284        hdr.msg = RM_INTERFACE_VERSION;
 285
 286        result = octeontx_mbox_send(&hdr, app_intf_ver,
 287                                    sizeof(struct mbox_intf_ver),
 288                                    &kernel_intf_ver, sizeof(kernel_intf_ver));
 289        if (result != sizeof(kernel_intf_ver)) {
 290                mbox_log_err("Could not send interface version. Err=%d. FuncErr=%d\n",
 291                             result, hdr.res_code);
 292                result = -EINVAL;
 293        }
 294
 295        if (intf_ver)
 296                *intf_ver = kernel_intf_ver;
 297
 298        if (app_intf_ver->platform != kernel_intf_ver.platform ||
 299                        app_intf_ver->major != kernel_intf_ver.major ||
 300                        app_intf_ver->minor != kernel_intf_ver.minor)
 301                result = -EINVAL;
 302
 303        return result;
 304}
 305
 306int
 307octeontx_mbox_init(void)
 308{
 309        struct mbox_intf_ver MBOX_INTERFACE_VERSION = {
 310                .platform = 0x01,
 311                .major = 0x01,
 312                .minor = 0x03
 313        };
 314        struct mbox_intf_ver rm_intf_ver = {0};
 315        struct mbox *m = &octeontx_mbox;
 316        int ret;
 317
 318        if (m->ready)
 319                return 0;
 320
 321        ret = octeontx_start_domain();
 322        if (ret < 0) {
 323                m->init_once = 0;
 324                return ret;
 325        }
 326
 327        ret = octeontx_check_mbox_version(&MBOX_INTERFACE_VERSION,
 328                                          &rm_intf_ver);
 329        if (ret < 0) {
 330                mbox_log_err("MBOX version: Kernel(%d.%d.%d) != DPDK(%d.%d.%d)",
 331                             rm_intf_ver.platform, rm_intf_ver.major,
 332                             rm_intf_ver.minor, MBOX_INTERFACE_VERSION.platform,
 333                             MBOX_INTERFACE_VERSION.major,
 334                             MBOX_INTERFACE_VERSION.minor);
 335                m->init_once = 0;
 336                return -EINVAL;
 337        }
 338
 339        m->ready = 1;
 340        rte_mb();
 341
 342        return 0;
 343}
 344
 345uint16_t
 346octeontx_get_global_domain(void)
 347{
 348        struct mbox *m = &octeontx_mbox;
 349
 350        return m->domain;
 351}
 352