X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fcommon%2Focteontx2%2Fotx2_mbox.c;h=6df1e8ea63ea380ffc698603933dc3bbcac921f0;hb=b4fac34715f2;hp=c9cdbdbbc58443000f02c715dc839829c52ee3ad;hpb=371d3212cbed1067e6554a755b0dfd578a0e0e8b;p=dpdk.git diff --git a/drivers/common/octeontx2/otx2_mbox.c b/drivers/common/octeontx2/otx2_mbox.c index c9cdbdbbc5..6df1e8ea63 100644 --- a/drivers/common/octeontx2/otx2_mbox.c +++ b/drivers/common/octeontx2/otx2_mbox.c @@ -2,4 +2,464 @@ * Copyright(C) 2019 Marvell International Ltd. */ +#include +#include +#include +#include + +#include +#include +#include + #include "otx2_mbox.h" +#include "otx2_dev.h" + +#define RVU_AF_AFPF_MBOX0 (0x02000) +#define RVU_AF_AFPF_MBOX1 (0x02008) + +#define RVU_PF_PFAF_MBOX0 (0xC00) +#define RVU_PF_PFAF_MBOX1 (0xC08) + +#define RVU_PF_VFX_PFVF_MBOX0 (0x0000) +#define RVU_PF_VFX_PFVF_MBOX1 (0x0008) + +#define RVU_VF_VFPF_MBOX0 (0x0000) +#define RVU_VF_VFPF_MBOX1 (0x0008) + +static inline uint16_t +msgs_offset(void) +{ + return RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); +} + +void +otx2_mbox_fini(struct otx2_mbox *mbox) +{ + mbox->reg_base = 0; + mbox->hwbase = 0; + rte_free(mbox->dev); + mbox->dev = NULL; +} + +void +otx2_mbox_reset(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_hdr *tx_hdr = + (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start); + struct mbox_hdr *rx_hdr = + (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start); + + rte_spinlock_lock(&mdev->mbox_lock); + mdev->msg_size = 0; + mdev->rsp_size = 0; + tx_hdr->msg_size = 0; + tx_hdr->num_msgs = 0; + rx_hdr->msg_size = 0; + rx_hdr->num_msgs = 0; + rte_spinlock_unlock(&mdev->mbox_lock); +} + +int +otx2_mbox_init(struct otx2_mbox *mbox, uintptr_t hwbase, uintptr_t reg_base, + int direction, int ndevs, uint64_t intr_offset) +{ + struct otx2_mbox_dev *mdev; + int devid; + + mbox->intr_offset = intr_offset; + mbox->reg_base = reg_base; + mbox->hwbase = hwbase; + + switch (direction) { + case MBOX_DIR_AFPF: + case MBOX_DIR_PFVF: + mbox->tx_start = MBOX_DOWN_TX_START; + mbox->rx_start = MBOX_DOWN_RX_START; + mbox->tx_size = MBOX_DOWN_TX_SIZE; + mbox->rx_size = MBOX_DOWN_RX_SIZE; + break; + case MBOX_DIR_PFAF: + case MBOX_DIR_VFPF: + mbox->tx_start = MBOX_DOWN_RX_START; + mbox->rx_start = MBOX_DOWN_TX_START; + mbox->tx_size = MBOX_DOWN_RX_SIZE; + mbox->rx_size = MBOX_DOWN_TX_SIZE; + break; + case MBOX_DIR_AFPF_UP: + case MBOX_DIR_PFVF_UP: + mbox->tx_start = MBOX_UP_TX_START; + mbox->rx_start = MBOX_UP_RX_START; + mbox->tx_size = MBOX_UP_TX_SIZE; + mbox->rx_size = MBOX_UP_RX_SIZE; + break; + case MBOX_DIR_PFAF_UP: + case MBOX_DIR_VFPF_UP: + mbox->tx_start = MBOX_UP_RX_START; + mbox->rx_start = MBOX_UP_TX_START; + mbox->tx_size = MBOX_UP_RX_SIZE; + mbox->rx_size = MBOX_UP_TX_SIZE; + break; + default: + return -ENODEV; + } + + switch (direction) { + case MBOX_DIR_AFPF: + case MBOX_DIR_AFPF_UP: + mbox->trigger = RVU_AF_AFPF_MBOX0; + mbox->tr_shift = 4; + break; + case MBOX_DIR_PFAF: + case MBOX_DIR_PFAF_UP: + mbox->trigger = RVU_PF_PFAF_MBOX1; + mbox->tr_shift = 0; + break; + case MBOX_DIR_PFVF: + case MBOX_DIR_PFVF_UP: + mbox->trigger = RVU_PF_VFX_PFVF_MBOX0; + mbox->tr_shift = 12; + break; + case MBOX_DIR_VFPF: + case MBOX_DIR_VFPF_UP: + mbox->trigger = RVU_VF_VFPF_MBOX1; + mbox->tr_shift = 0; + break; + default: + return -ENODEV; + } + + mbox->dev = rte_zmalloc("mbox dev", + ndevs * sizeof(struct otx2_mbox_dev), + OTX2_ALIGN); + if (!mbox->dev) { + otx2_mbox_fini(mbox); + return -ENOMEM; + } + mbox->ndevs = ndevs; + for (devid = 0; devid < ndevs; devid++) { + mdev = &mbox->dev[devid]; + mdev->mbase = (void *)(mbox->hwbase + (devid * MBOX_SIZE)); + rte_spinlock_init(&mdev->mbox_lock); + /* Init header to reset value */ + otx2_mbox_reset(mbox, devid); + } + + return 0; +} + +/** + * @internal + * Allocate a message response + */ +struct mbox_msghdr * +otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, int size, + int size_rsp) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_msghdr *msghdr = NULL; + + rte_spinlock_lock(&mdev->mbox_lock); + size = RTE_ALIGN(size, MBOX_MSG_ALIGN); + size_rsp = RTE_ALIGN(size_rsp, MBOX_MSG_ALIGN); + /* Check if there is space in mailbox */ + if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset()) + goto exit; + if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset()) + goto exit; + if (mdev->msg_size == 0) + mdev->num_msgs = 0; + mdev->num_msgs++; + + msghdr = (struct mbox_msghdr *)(((uintptr_t)mdev->mbase + + mbox->tx_start + msgs_offset() + mdev->msg_size)); + + /* Clear the whole msg region */ + otx2_mbox_memset(msghdr, 0, sizeof(*msghdr) + size); + /* Init message header with reset values */ + msghdr->ver = OTX2_MBOX_VERSION; + mdev->msg_size += size; + mdev->rsp_size += size_rsp; + msghdr->next_msgoff = mdev->msg_size + msgs_offset(); +exit: + rte_spinlock_unlock(&mdev->mbox_lock); + + return msghdr; +} + +/** + * @internal + * Send a mailbox message + */ +void +otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_hdr *tx_hdr = + (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start); + struct mbox_hdr *rx_hdr = + (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start); + + /* Reset header for next messages */ + tx_hdr->msg_size = mdev->msg_size; + mdev->msg_size = 0; + mdev->rsp_size = 0; + mdev->msgs_acked = 0; + + /* num_msgs != 0 signals to the peer that the buffer has a number of + * messages. So this should be written after copying txmem + */ + tx_hdr->num_msgs = mdev->num_msgs; + rx_hdr->num_msgs = 0; + + /* Sync mbox data into memory */ + rte_wmb(); + + /* The interrupt should be fired after num_msgs is written + * to the shared memory + */ + rte_write64(1, (volatile void *)(mbox->reg_base + + (mbox->trigger | (devid << mbox->tr_shift)))); +} + +/** + * @internal + * Wait and get mailbox response + */ +int +otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, void **msg) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_msghdr *msghdr; + uint64_t offset; + int rc; + + rc = otx2_mbox_wait_for_rsp(mbox, devid); + if (rc != 1) + return -EIO; + + rte_rmb(); + + offset = mbox->rx_start + + RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); + msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset); + if (msg != NULL) + *msg = msghdr; + + return msghdr->rc; +} + +/** + * Polling for given wait time to get mailbox response + */ +static int +mbox_poll(struct otx2_mbox *mbox, uint32_t wait) +{ + uint32_t timeout = 0, sleep = 1; + uint32_t wait_us = wait * 1000; + uint64_t rsp_reg = 0; + uintptr_t reg_addr; + + reg_addr = mbox->reg_base + mbox->intr_offset; + do { + rsp_reg = otx2_read64(reg_addr); + + if (timeout >= wait_us) + return -ETIMEDOUT; + + rte_delay_us(sleep); + timeout += sleep; + } while (!rsp_reg); + + rte_smp_rmb(); + + /* Clear interrupt */ + otx2_write64(rsp_reg, reg_addr); + + /* Reset mbox */ + otx2_mbox_reset(mbox, 0); + + return 0; +} + +/** + * @internal + * Wait and get mailbox response with timeout + */ +int +otx2_mbox_get_rsp_tmo(struct otx2_mbox *mbox, int devid, void **msg, + uint32_t tmo) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_msghdr *msghdr; + uint64_t offset; + int rc; + + rc = otx2_mbox_wait_for_rsp_tmo(mbox, devid, tmo); + if (rc != 1) + return -EIO; + + rte_rmb(); + + offset = mbox->rx_start + + RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); + msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset); + if (msg != NULL) + *msg = msghdr; + + return msghdr->rc; +} + +static int +mbox_wait(struct otx2_mbox *mbox, int devid, uint32_t rst_timo) +{ + volatile struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + uint32_t timeout = 0, sleep = 1; + + rst_timo = rst_timo * 1000; /* Milli seconds to micro seconds */ + while (mdev->num_msgs > mdev->msgs_acked) { + rte_delay_us(sleep); + timeout += sleep; + if (timeout >= rst_timo) { + struct mbox_hdr *tx_hdr = + (struct mbox_hdr *)((uintptr_t)mdev->mbase + + mbox->tx_start); + struct mbox_hdr *rx_hdr = + (struct mbox_hdr *)((uintptr_t)mdev->mbase + + mbox->rx_start); + + otx2_err("MBOX[devid: %d] message wait timeout %d, " + "num_msgs: %d, msgs_acked: %d " + "(tx/rx num_msgs: %d/%d), msg_size: %d, " + "rsp_size: %d", + devid, timeout, mdev->num_msgs, + mdev->msgs_acked, tx_hdr->num_msgs, + rx_hdr->num_msgs, mdev->msg_size, + mdev->rsp_size); + + return -EIO; + } + rte_rmb(); + } + return 0; +} + +int +otx2_mbox_wait_for_rsp_tmo(struct otx2_mbox *mbox, int devid, uint32_t tmo) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + int rc = 0; + + /* Sync with mbox region */ + rte_rmb(); + + if (mbox->trigger == RVU_PF_VFX_PFVF_MBOX1 || + mbox->trigger == RVU_PF_VFX_PFVF_MBOX0) { + /* In case of VF, Wait a bit more to account round trip delay */ + tmo = tmo * 2; + } + + /* Wait message */ + if (rte_thread_is_intr()) + rc = mbox_poll(mbox, tmo); + else + rc = mbox_wait(mbox, devid, tmo); + + if (!rc) + rc = mdev->num_msgs; + + return rc; +} + +/** + * @internal + * Wait for the mailbox response + */ +int +otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid) +{ + return otx2_mbox_wait_for_rsp_tmo(mbox, devid, MBOX_RSP_TIMEOUT); +} + +int +otx2_mbox_get_availmem(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + int avail; + + rte_spinlock_lock(&mdev->mbox_lock); + avail = mbox->tx_size - mdev->msg_size - msgs_offset(); + rte_spinlock_unlock(&mdev->mbox_lock); + + return avail; +} + +int +otx2_send_ready_msg(struct otx2_mbox *mbox, uint16_t *pcifunc) +{ + struct ready_msg_rsp *rsp; + int rc; + + otx2_mbox_alloc_msg_ready(mbox); + + otx2_mbox_msg_send(mbox, 0); + rc = otx2_mbox_get_rsp(mbox, 0, (void *)&rsp); + if (rc) + return rc; + + if (rsp->hdr.ver != OTX2_MBOX_VERSION) { + otx2_err("Incompatible MBox versions(AF: 0x%04x DPDK: 0x%04x)", + rsp->hdr.ver, OTX2_MBOX_VERSION); + return -EPIPE; + } + + if (pcifunc) + *pcifunc = rsp->hdr.pcifunc; + + return 0; +} + +int +otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, uint16_t pcifunc, + uint16_t id) +{ + struct msg_rsp *rsp; + + rsp = (struct msg_rsp *)otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp)); + if (!rsp) + return -ENOMEM; + rsp->hdr.id = id; + rsp->hdr.sig = OTX2_MBOX_RSP_SIG; + rsp->hdr.rc = MBOX_MSG_INVALID; + rsp->hdr.pcifunc = pcifunc; + + return 0; +} + +/** + * @internal + * Convert mail box ID to name + */ +const char *otx2_mbox_id2name(uint16_t id) +{ + switch (id) { +#define M(_name, _id, _1, _2, _3) case _id: return # _name; + MBOX_MESSAGES + MBOX_UP_CGX_MESSAGES +#undef M + default : + return "INVALID ID"; + } +} + +int otx2_mbox_id2size(uint16_t id) +{ + switch (id) { +#define M(_1, _id, _2, _req_type, _3) case _id: return sizeof(struct _req_type); + MBOX_MESSAGES + MBOX_UP_CGX_MESSAGES +#undef M + default : + return 0; + } +}