dpdk/drivers/common/octeontx2/otx2_mbox.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(C) 2019 Marvell International Ltd.
   3 */
   4
   5#include <errno.h>
   6#include <stdio.h>
   7#include <stdlib.h>
   8#include <string.h>
   9
  10#include <rte_atomic.h>
  11#include <rte_cycles.h>
  12#include <rte_malloc.h>
  13
  14#include "otx2_mbox.h"
  15#include "otx2_dev.h"
  16
  17#define RVU_AF_AFPF_MBOX0       (0x02000)
  18#define RVU_AF_AFPF_MBOX1       (0x02008)
  19
  20#define RVU_PF_PFAF_MBOX0       (0xC00)
  21#define RVU_PF_PFAF_MBOX1       (0xC08)
  22
  23#define RVU_PF_VFX_PFVF_MBOX0   (0x0000)
  24#define RVU_PF_VFX_PFVF_MBOX1   (0x0008)
  25
  26#define RVU_VF_VFPF_MBOX0       (0x0000)
  27#define RVU_VF_VFPF_MBOX1       (0x0008)
  28
  29static inline uint16_t
  30msgs_offset(void)
  31{
  32        return RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
  33}
  34
  35void
  36otx2_mbox_fini(struct otx2_mbox *mbox)
  37{
  38        mbox->reg_base = 0;
  39        mbox->hwbase = 0;
  40        rte_free(mbox->dev);
  41        mbox->dev = NULL;
  42}
  43
  44void
  45otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
  46{
  47        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
  48        struct mbox_hdr *tx_hdr =
  49                (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
  50        struct mbox_hdr *rx_hdr =
  51                (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
  52
  53        rte_spinlock_lock(&mdev->mbox_lock);
  54        mdev->msg_size = 0;
  55        mdev->rsp_size = 0;
  56        tx_hdr->msg_size = 0;
  57        tx_hdr->num_msgs = 0;
  58        rx_hdr->msg_size = 0;
  59        rx_hdr->num_msgs = 0;
  60        rte_spinlock_unlock(&mdev->mbox_lock);
  61}
  62
  63int
  64otx2_mbox_init(struct otx2_mbox *mbox, uintptr_t hwbase, uintptr_t reg_base,
  65               int direction, int ndevs, uint64_t intr_offset)
  66{
  67        struct otx2_mbox_dev *mdev;
  68        int devid;
  69
  70        mbox->intr_offset = intr_offset;
  71        mbox->reg_base = reg_base;
  72        mbox->hwbase = hwbase;
  73
  74        switch (direction) {
  75        case MBOX_DIR_AFPF:
  76        case MBOX_DIR_PFVF:
  77                mbox->tx_start = MBOX_DOWN_TX_START;
  78                mbox->rx_start = MBOX_DOWN_RX_START;
  79                mbox->tx_size  = MBOX_DOWN_TX_SIZE;
  80                mbox->rx_size  = MBOX_DOWN_RX_SIZE;
  81                break;
  82        case MBOX_DIR_PFAF:
  83        case MBOX_DIR_VFPF:
  84                mbox->tx_start = MBOX_DOWN_RX_START;
  85                mbox->rx_start = MBOX_DOWN_TX_START;
  86                mbox->tx_size  = MBOX_DOWN_RX_SIZE;
  87                mbox->rx_size  = MBOX_DOWN_TX_SIZE;
  88                break;
  89        case MBOX_DIR_AFPF_UP:
  90        case MBOX_DIR_PFVF_UP:
  91                mbox->tx_start = MBOX_UP_TX_START;
  92                mbox->rx_start = MBOX_UP_RX_START;
  93                mbox->tx_size  = MBOX_UP_TX_SIZE;
  94                mbox->rx_size  = MBOX_UP_RX_SIZE;
  95                break;
  96        case MBOX_DIR_PFAF_UP:
  97        case MBOX_DIR_VFPF_UP:
  98                mbox->tx_start = MBOX_UP_RX_START;
  99                mbox->rx_start = MBOX_UP_TX_START;
 100                mbox->tx_size  = MBOX_UP_RX_SIZE;
 101                mbox->rx_size  = MBOX_UP_TX_SIZE;
 102                break;
 103        default:
 104                return -ENODEV;
 105        }
 106
 107        switch (direction) {
 108        case MBOX_DIR_AFPF:
 109        case MBOX_DIR_AFPF_UP:
 110                mbox->trigger = RVU_AF_AFPF_MBOX0;
 111                mbox->tr_shift = 4;
 112                break;
 113        case MBOX_DIR_PFAF:
 114        case MBOX_DIR_PFAF_UP:
 115                mbox->trigger = RVU_PF_PFAF_MBOX1;
 116                mbox->tr_shift = 0;
 117                break;
 118        case MBOX_DIR_PFVF:
 119        case MBOX_DIR_PFVF_UP:
 120                mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
 121                mbox->tr_shift = 12;
 122                break;
 123        case MBOX_DIR_VFPF:
 124        case MBOX_DIR_VFPF_UP:
 125                mbox->trigger = RVU_VF_VFPF_MBOX1;
 126                mbox->tr_shift = 0;
 127                break;
 128        default:
 129                return -ENODEV;
 130        }
 131
 132        mbox->dev = rte_zmalloc("mbox dev",
 133                                ndevs * sizeof(struct otx2_mbox_dev),
 134                                OTX2_ALIGN);
 135        if (!mbox->dev) {
 136                otx2_mbox_fini(mbox);
 137                return -ENOMEM;
 138        }
 139        mbox->ndevs = ndevs;
 140        for (devid = 0; devid < ndevs; devid++) {
 141                mdev = &mbox->dev[devid];
 142                mdev->mbase = (void *)(mbox->hwbase + (devid * MBOX_SIZE));
 143                rte_spinlock_init(&mdev->mbox_lock);
 144                /* Init header to reset value */
 145                otx2_mbox_reset(mbox, devid);
 146        }
 147
 148        return 0;
 149}
 150
 151/**
 152 * @internal
 153 * Allocate a message response
 154 */
 155struct mbox_msghdr *
 156otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, int size,
 157                        int size_rsp)
 158{
 159        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 160        struct mbox_msghdr *msghdr = NULL;
 161
 162        rte_spinlock_lock(&mdev->mbox_lock);
 163        size = RTE_ALIGN(size, MBOX_MSG_ALIGN);
 164        size_rsp = RTE_ALIGN(size_rsp, MBOX_MSG_ALIGN);
 165        /* Check if there is space in mailbox */
 166        if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset())
 167                goto exit;
 168        if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset())
 169                goto exit;
 170        if (mdev->msg_size == 0)
 171                mdev->num_msgs = 0;
 172        mdev->num_msgs++;
 173
 174        msghdr = (struct mbox_msghdr *)(((uintptr_t)mdev->mbase +
 175                        mbox->tx_start + msgs_offset() + mdev->msg_size));
 176
 177        /* Clear the whole msg region */
 178        otx2_mbox_memset(msghdr, 0, sizeof(*msghdr) + size);
 179        /* Init message header with reset values */
 180        msghdr->ver = OTX2_MBOX_VERSION;
 181        mdev->msg_size += size;
 182        mdev->rsp_size += size_rsp;
 183        msghdr->next_msgoff = mdev->msg_size + msgs_offset();
 184exit:
 185        rte_spinlock_unlock(&mdev->mbox_lock);
 186
 187        return msghdr;
 188}
 189
 190/**
 191 * @internal
 192 * Send a mailbox message
 193 */
 194void
 195otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
 196{
 197        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 198        struct mbox_hdr *tx_hdr =
 199                (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
 200        struct mbox_hdr *rx_hdr =
 201                (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
 202
 203        /* Reset header for next messages */
 204        tx_hdr->msg_size = mdev->msg_size;
 205        mdev->msg_size = 0;
 206        mdev->rsp_size = 0;
 207        mdev->msgs_acked = 0;
 208
 209        /* num_msgs != 0 signals to the peer that the buffer has a number of
 210         * messages. So this should be written after copying txmem
 211         */
 212        tx_hdr->num_msgs = mdev->num_msgs;
 213        rx_hdr->num_msgs = 0;
 214
 215        /* Sync mbox data into memory */
 216        rte_wmb();
 217
 218        /* The interrupt should be fired after num_msgs is written
 219         * to the shared memory
 220         */
 221        rte_write64(1, (volatile void *)(mbox->reg_base +
 222                (mbox->trigger | (devid << mbox->tr_shift))));
 223}
 224
 225/**
 226 * @internal
 227 * Wait and get mailbox response
 228 */
 229int
 230otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, void **msg)
 231{
 232        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 233        struct mbox_msghdr *msghdr;
 234        uint64_t offset;
 235        int rc;
 236
 237        rc = otx2_mbox_wait_for_rsp(mbox, devid);
 238        if (rc != 1)
 239                return -EIO;
 240
 241        rte_rmb();
 242
 243        offset = mbox->rx_start +
 244                RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
 245        msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
 246        if (msg != NULL)
 247                *msg = msghdr;
 248
 249        return msghdr->rc;
 250}
 251
 252/**
 253 * Polling for given wait time to get mailbox response
 254 */
 255static int
 256mbox_poll(struct otx2_mbox *mbox, uint32_t wait)
 257{
 258        uint32_t timeout = 0, sleep = 1;
 259        uint32_t wait_us = wait * 1000;
 260        uint64_t rsp_reg = 0;
 261        uintptr_t reg_addr;
 262
 263        reg_addr = mbox->reg_base + mbox->intr_offset;
 264        do {
 265                rsp_reg = otx2_read64(reg_addr);
 266
 267                if (timeout >= wait_us)
 268                        return -ETIMEDOUT;
 269
 270                rte_delay_us(sleep);
 271                timeout += sleep;
 272        } while (!rsp_reg);
 273
 274        rte_smp_rmb();
 275
 276        /* Clear interrupt */
 277        otx2_write64(rsp_reg, reg_addr);
 278
 279        /* Reset mbox */
 280        otx2_mbox_reset(mbox, 0);
 281
 282        return 0;
 283}
 284
 285/**
 286 * @internal
 287 * Wait and get mailbox response with timeout
 288 */
 289int
 290otx2_mbox_get_rsp_tmo(struct otx2_mbox *mbox, int devid, void **msg,
 291                      uint32_t tmo)
 292{
 293        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 294        struct mbox_msghdr *msghdr;
 295        uint64_t offset;
 296        int rc;
 297
 298        rc = otx2_mbox_wait_for_rsp_tmo(mbox, devid, tmo);
 299        if (rc != 1)
 300                return -EIO;
 301
 302        rte_rmb();
 303
 304        offset = mbox->rx_start +
 305                        RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
 306        msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
 307        if (msg != NULL)
 308                *msg = msghdr;
 309
 310        return msghdr->rc;
 311}
 312
 313static int
 314mbox_wait(struct otx2_mbox *mbox, int devid, uint32_t rst_timo)
 315{
 316        volatile struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 317        uint32_t timeout = 0, sleep = 1;
 318
 319        rst_timo  = rst_timo * 1000; /* Milli seconds to micro seconds */
 320        while (mdev->num_msgs > mdev->msgs_acked) {
 321                rte_delay_us(sleep);
 322                timeout += sleep;
 323                if (timeout >= rst_timo) {
 324                        struct mbox_hdr *tx_hdr =
 325                                (struct mbox_hdr *)((uintptr_t)mdev->mbase +
 326                                                        mbox->tx_start);
 327                        struct mbox_hdr *rx_hdr =
 328                                (struct mbox_hdr *)((uintptr_t)mdev->mbase +
 329                                                        mbox->rx_start);
 330
 331                        otx2_err("MBOX[devid: %d] message wait timeout %d, "
 332                                 "num_msgs: %d, msgs_acked: %d "
 333                                 "(tx/rx num_msgs: %d/%d), msg_size: %d, "
 334                                 "rsp_size: %d",
 335                                 devid, timeout, mdev->num_msgs,
 336                                 mdev->msgs_acked, tx_hdr->num_msgs,
 337                                 rx_hdr->num_msgs, mdev->msg_size,
 338                                 mdev->rsp_size);
 339
 340                        return -EIO;
 341                }
 342                rte_rmb();
 343        }
 344        return 0;
 345}
 346
 347int
 348otx2_mbox_wait_for_rsp_tmo(struct otx2_mbox *mbox, int devid, uint32_t tmo)
 349{
 350        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 351        int rc = 0;
 352
 353        /* Sync with mbox region */
 354        rte_rmb();
 355
 356        if (mbox->trigger == RVU_PF_VFX_PFVF_MBOX1 ||
 357                mbox->trigger == RVU_PF_VFX_PFVF_MBOX0) {
 358                /* In case of VF, Wait a bit more to account round trip delay */
 359                tmo = tmo * 2;
 360        }
 361
 362        /* Wait message */
 363        if (rte_thread_is_intr())
 364                rc = mbox_poll(mbox, tmo);
 365        else
 366                rc = mbox_wait(mbox, devid, tmo);
 367
 368        if (!rc)
 369                rc = mdev->num_msgs;
 370
 371        return rc;
 372}
 373
 374/**
 375 * @internal
 376 * Wait for the mailbox response
 377 */
 378int
 379otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
 380{
 381        return otx2_mbox_wait_for_rsp_tmo(mbox, devid, MBOX_RSP_TIMEOUT);
 382}
 383
 384int
 385otx2_mbox_get_availmem(struct otx2_mbox *mbox, int devid)
 386{
 387        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
 388        int avail;
 389
 390        rte_spinlock_lock(&mdev->mbox_lock);
 391        avail = mbox->tx_size - mdev->msg_size - msgs_offset();
 392        rte_spinlock_unlock(&mdev->mbox_lock);
 393
 394        return avail;
 395}
 396
 397int
 398otx2_send_ready_msg(struct otx2_mbox *mbox, uint16_t *pcifunc)
 399{
 400        struct ready_msg_rsp *rsp;
 401        int rc;
 402
 403        otx2_mbox_alloc_msg_ready(mbox);
 404
 405        otx2_mbox_msg_send(mbox, 0);
 406        rc = otx2_mbox_get_rsp(mbox, 0, (void *)&rsp);
 407        if (rc)
 408                return rc;
 409
 410        if (rsp->hdr.ver != OTX2_MBOX_VERSION) {
 411                otx2_err("Incompatible MBox versions(AF: 0x%04x DPDK: 0x%04x)",
 412                          rsp->hdr.ver, OTX2_MBOX_VERSION);
 413                return -EPIPE;
 414        }
 415
 416        if (pcifunc)
 417                *pcifunc = rsp->hdr.pcifunc;
 418
 419        return 0;
 420}
 421
 422int
 423otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, uint16_t pcifunc,
 424                       uint16_t id)
 425{
 426        struct msg_rsp *rsp;
 427
 428        rsp = (struct msg_rsp *)otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
 429        if (!rsp)
 430                return -ENOMEM;
 431        rsp->hdr.id = id;
 432        rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
 433        rsp->hdr.rc = MBOX_MSG_INVALID;
 434        rsp->hdr.pcifunc = pcifunc;
 435
 436        return 0;
 437}
 438
 439/**
 440 * @internal
 441 * Convert mail box ID to name
 442 */
 443const char *otx2_mbox_id2name(uint16_t id)
 444{
 445        switch (id) {
 446#define M(_name, _id, _1, _2, _3) case _id: return # _name;
 447        MBOX_MESSAGES
 448        MBOX_UP_CGX_MESSAGES
 449#undef M
 450        default :
 451                return "INVALID ID";
 452        }
 453}
 454
 455int otx2_mbox_id2size(uint16_t id)
 456{
 457        switch (id) {
 458#define M(_1, _id, _2, _req_type, _3) case _id: return sizeof(struct _req_type);
 459        MBOX_MESSAGES
 460        MBOX_UP_CGX_MESSAGES
 461#undef M
 462        default :
 463                return 0;
 464        }
 465}
 466