103cc9bd9SJerin Jacob /* SPDX-License-Identifier: BSD-3-Clause 203cc9bd9SJerin Jacob * Copyright(C) 2021 Marvell. 303cc9bd9SJerin Jacob */ 403cc9bd9SJerin Jacob 503cc9bd9SJerin Jacob #include <errno.h> 603cc9bd9SJerin Jacob #include <stdio.h> 703cc9bd9SJerin Jacob #include <stdlib.h> 803cc9bd9SJerin Jacob #include <string.h> 903cc9bd9SJerin Jacob 1003cc9bd9SJerin Jacob #include "roc_api.h" 1103cc9bd9SJerin Jacob #include "roc_priv.h" 1203cc9bd9SJerin Jacob 1303cc9bd9SJerin Jacob /* RCLK, SCLK in MHz */ 1403cc9bd9SJerin Jacob uint16_t dev_rclk_freq; 1503cc9bd9SJerin Jacob uint16_t dev_sclk_freq; 1603cc9bd9SJerin Jacob 1703cc9bd9SJerin Jacob static inline uint16_t 1803cc9bd9SJerin Jacob msgs_offset(void) 1903cc9bd9SJerin Jacob { 2003cc9bd9SJerin Jacob return PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); 2103cc9bd9SJerin Jacob } 2203cc9bd9SJerin Jacob 2303cc9bd9SJerin Jacob void 2403cc9bd9SJerin Jacob mbox_fini(struct mbox *mbox) 2503cc9bd9SJerin Jacob { 2603cc9bd9SJerin Jacob mbox->reg_base = 0; 2703cc9bd9SJerin Jacob mbox->hwbase = 0; 2803cc9bd9SJerin Jacob plt_free(mbox->dev); 2903cc9bd9SJerin Jacob mbox->dev = NULL; 3003cc9bd9SJerin Jacob } 3103cc9bd9SJerin Jacob 3203cc9bd9SJerin Jacob void 3303cc9bd9SJerin Jacob mbox_reset(struct mbox *mbox, int devid) 3403cc9bd9SJerin Jacob { 3503cc9bd9SJerin Jacob struct mbox_dev *mdev = &mbox->dev[devid]; 3603cc9bd9SJerin Jacob struct mbox_hdr *tx_hdr = 3703cc9bd9SJerin Jacob (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start); 3803cc9bd9SJerin Jacob struct mbox_hdr *rx_hdr = 3903cc9bd9SJerin Jacob (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start); 4003cc9bd9SJerin Jacob 4103cc9bd9SJerin Jacob mdev->msg_size = 0; 4203cc9bd9SJerin Jacob mdev->rsp_size = 0; 4303cc9bd9SJerin Jacob tx_hdr->msg_size = 0; 4403cc9bd9SJerin Jacob tx_hdr->num_msgs = 0; 4503cc9bd9SJerin Jacob rx_hdr->msg_size = 0; 4603cc9bd9SJerin Jacob rx_hdr->num_msgs = 0; 4703cc9bd9SJerin Jacob } 4803cc9bd9SJerin Jacob 4961deac72SHarman Kalra static int 5061deac72SHarman Kalra cn20k_mbox_setup(struct mbox *mbox, int direction) 5103cc9bd9SJerin Jacob { 5261deac72SHarman Kalra switch (direction) { 5361deac72SHarman Kalra case MBOX_DIR_AFPF: 5461deac72SHarman Kalra mbox->trigger = RVU_MBOX_AF_AFPFX_TRIGX(1); 5561deac72SHarman Kalra mbox->tr_shift = 4; 5661deac72SHarman Kalra break; 5761deac72SHarman Kalra case MBOX_DIR_AFPF_UP: 5861deac72SHarman Kalra mbox->trigger = RVU_MBOX_AF_AFPFX_TRIGX(0); 5961deac72SHarman Kalra mbox->tr_shift = 4; 6061deac72SHarman Kalra break; 6161deac72SHarman Kalra case MBOX_DIR_PFAF: 6261deac72SHarman Kalra mbox->trigger = RVU_MBOX_PF_PFAF_TRIGX(0); 6361deac72SHarman Kalra mbox->tr_shift = 0; 6461deac72SHarman Kalra break; 6561deac72SHarman Kalra case MBOX_DIR_PFAF_UP: 6661deac72SHarman Kalra mbox->trigger = RVU_MBOX_PF_PFAF_TRIGX(1); 6761deac72SHarman Kalra mbox->tr_shift = 0; 6861deac72SHarman Kalra break; 69*9bd368caSHarman Kalra case MBOX_DIR_PFVF: 70*9bd368caSHarman Kalra mbox->trigger = RVU_MBOX_PF_VFX_PFVF_TRIGX(1); 71*9bd368caSHarman Kalra mbox->tr_shift = 4; 72*9bd368caSHarman Kalra break; 73*9bd368caSHarman Kalra case MBOX_DIR_PFVF_UP: 74*9bd368caSHarman Kalra mbox->trigger = RVU_MBOX_PF_VFX_PFVF_TRIGX(0); 75*9bd368caSHarman Kalra mbox->tr_shift = 4; 76*9bd368caSHarman Kalra break; 77*9bd368caSHarman Kalra case MBOX_DIR_VFPF: 78*9bd368caSHarman Kalra mbox->trigger = RVU_MBOX_VF_VFPF_TRIGX(0); 79*9bd368caSHarman Kalra mbox->tr_shift = 0; 80*9bd368caSHarman Kalra break; 81*9bd368caSHarman Kalra case MBOX_DIR_VFPF_UP: 82*9bd368caSHarman Kalra mbox->trigger = RVU_MBOX_VF_VFPF_TRIGX(1); 83*9bd368caSHarman Kalra mbox->tr_shift = 0; 84*9bd368caSHarman Kalra break; 8561deac72SHarman Kalra default: 8661deac72SHarman Kalra return -ENODEV; 8761deac72SHarman Kalra } 8803cc9bd9SJerin Jacob 8961deac72SHarman Kalra return 0; 9061deac72SHarman Kalra } 9103cc9bd9SJerin Jacob 9261deac72SHarman Kalra static int 9361deac72SHarman Kalra mbox_setup(struct mbox *mbox, uintptr_t reg_base, int direction, int ndevs, uint64_t intr_offset) 9461deac72SHarman Kalra { 9503cc9bd9SJerin Jacob switch (direction) { 9603cc9bd9SJerin Jacob case MBOX_DIR_AFPF: 9703cc9bd9SJerin Jacob case MBOX_DIR_PFVF: 9803cc9bd9SJerin Jacob mbox->tx_start = MBOX_DOWN_TX_START; 9903cc9bd9SJerin Jacob mbox->rx_start = MBOX_DOWN_RX_START; 10003cc9bd9SJerin Jacob mbox->tx_size = MBOX_DOWN_TX_SIZE; 10103cc9bd9SJerin Jacob mbox->rx_size = MBOX_DOWN_RX_SIZE; 10203cc9bd9SJerin Jacob break; 10303cc9bd9SJerin Jacob case MBOX_DIR_PFAF: 10403cc9bd9SJerin Jacob case MBOX_DIR_VFPF: 10503cc9bd9SJerin Jacob mbox->tx_start = MBOX_DOWN_RX_START; 10603cc9bd9SJerin Jacob mbox->rx_start = MBOX_DOWN_TX_START; 10703cc9bd9SJerin Jacob mbox->tx_size = MBOX_DOWN_RX_SIZE; 10803cc9bd9SJerin Jacob mbox->rx_size = MBOX_DOWN_TX_SIZE; 10903cc9bd9SJerin Jacob break; 11003cc9bd9SJerin Jacob case MBOX_DIR_AFPF_UP: 11103cc9bd9SJerin Jacob case MBOX_DIR_PFVF_UP: 11203cc9bd9SJerin Jacob mbox->tx_start = MBOX_UP_TX_START; 11303cc9bd9SJerin Jacob mbox->rx_start = MBOX_UP_RX_START; 11403cc9bd9SJerin Jacob mbox->tx_size = MBOX_UP_TX_SIZE; 11503cc9bd9SJerin Jacob mbox->rx_size = MBOX_UP_RX_SIZE; 11603cc9bd9SJerin Jacob break; 11703cc9bd9SJerin Jacob case MBOX_DIR_PFAF_UP: 11803cc9bd9SJerin Jacob case MBOX_DIR_VFPF_UP: 11903cc9bd9SJerin Jacob mbox->tx_start = MBOX_UP_RX_START; 12003cc9bd9SJerin Jacob mbox->rx_start = MBOX_UP_TX_START; 12103cc9bd9SJerin Jacob mbox->tx_size = MBOX_UP_RX_SIZE; 12203cc9bd9SJerin Jacob mbox->rx_size = MBOX_UP_TX_SIZE; 12303cc9bd9SJerin Jacob break; 12403cc9bd9SJerin Jacob default: 12503cc9bd9SJerin Jacob return -ENODEV; 12603cc9bd9SJerin Jacob } 12703cc9bd9SJerin Jacob 12861deac72SHarman Kalra mbox->intr_offset = intr_offset; 12961deac72SHarman Kalra mbox->dev = plt_zmalloc(ndevs * sizeof(struct mbox_dev), ROC_ALIGN); 13061deac72SHarman Kalra if (!mbox->dev) { 13161deac72SHarman Kalra mbox_fini(mbox); 13261deac72SHarman Kalra return -ENOMEM; 13361deac72SHarman Kalra } 13461deac72SHarman Kalra mbox->ndevs = ndevs; 13561deac72SHarman Kalra 13661deac72SHarman Kalra mbox->reg_base = reg_base; 13761deac72SHarman Kalra if (roc_model_is_cn20k()) 13861deac72SHarman Kalra return cn20k_mbox_setup(mbox, direction); 13961deac72SHarman Kalra 14003cc9bd9SJerin Jacob switch (direction) { 14103cc9bd9SJerin Jacob case MBOX_DIR_AFPF: 14203cc9bd9SJerin Jacob case MBOX_DIR_AFPF_UP: 14303cc9bd9SJerin Jacob mbox->trigger = RVU_AF_AFPF_MBOX0; 14403cc9bd9SJerin Jacob mbox->tr_shift = 4; 14503cc9bd9SJerin Jacob break; 14603cc9bd9SJerin Jacob case MBOX_DIR_PFAF: 14703cc9bd9SJerin Jacob case MBOX_DIR_PFAF_UP: 14803cc9bd9SJerin Jacob mbox->trigger = RVU_PF_PFAF_MBOX1; 14903cc9bd9SJerin Jacob mbox->tr_shift = 0; 15003cc9bd9SJerin Jacob break; 15103cc9bd9SJerin Jacob case MBOX_DIR_PFVF: 15203cc9bd9SJerin Jacob case MBOX_DIR_PFVF_UP: 15303cc9bd9SJerin Jacob mbox->trigger = RVU_PF_VFX_PFVF_MBOX0; 15403cc9bd9SJerin Jacob mbox->tr_shift = 12; 15503cc9bd9SJerin Jacob break; 15603cc9bd9SJerin Jacob case MBOX_DIR_VFPF: 15703cc9bd9SJerin Jacob case MBOX_DIR_VFPF_UP: 15803cc9bd9SJerin Jacob mbox->trigger = RVU_VF_VFPF_MBOX1; 15903cc9bd9SJerin Jacob mbox->tr_shift = 0; 16003cc9bd9SJerin Jacob break; 16103cc9bd9SJerin Jacob default: 16203cc9bd9SJerin Jacob return -ENODEV; 16303cc9bd9SJerin Jacob } 16403cc9bd9SJerin Jacob 16561deac72SHarman Kalra return 0; 16603cc9bd9SJerin Jacob } 16761deac72SHarman Kalra 16861deac72SHarman Kalra int 16961deac72SHarman Kalra mbox_init(struct mbox *mbox, uintptr_t hwbase, uintptr_t reg_base, int direction, int ndevs, 17061deac72SHarman Kalra uint64_t intr_offset) 17161deac72SHarman Kalra { 17261deac72SHarman Kalra struct mbox_dev *mdev; 17361deac72SHarman Kalra char *var, *var_to; 17461deac72SHarman Kalra int devid, rc; 17561deac72SHarman Kalra 17661deac72SHarman Kalra rc = mbox_setup(mbox, reg_base, direction, ndevs, intr_offset); 17761deac72SHarman Kalra if (rc) { 17861deac72SHarman Kalra plt_err("Failed to setup the mailbox"); 17961deac72SHarman Kalra return rc; 18061deac72SHarman Kalra } 18161deac72SHarman Kalra 18261deac72SHarman Kalra mbox->hwbase = hwbase; 18303cc9bd9SJerin Jacob for (devid = 0; devid < ndevs; devid++) { 18403cc9bd9SJerin Jacob mdev = &mbox->dev[devid]; 18503cc9bd9SJerin Jacob mdev->mbase = (void *)(mbox->hwbase + (devid * MBOX_SIZE)); 18603cc9bd9SJerin Jacob plt_spinlock_init(&mdev->mbox_lock); 18703cc9bd9SJerin Jacob /* Init header to reset value */ 18803cc9bd9SJerin Jacob mbox_reset(mbox, devid); 18903cc9bd9SJerin Jacob } 19003cc9bd9SJerin Jacob 19103cc9bd9SJerin Jacob var = getenv("ROC_CN10K_MBOX_TIMEOUT"); 19203cc9bd9SJerin Jacob var_to = getenv("ROC_MBOX_TIMEOUT"); 19303cc9bd9SJerin Jacob 19403cc9bd9SJerin Jacob if (var) 19503cc9bd9SJerin Jacob mbox->rsp_tmo = atoi(var); 19603cc9bd9SJerin Jacob else if (var_to) 19703cc9bd9SJerin Jacob mbox->rsp_tmo = atoi(var_to); 19803cc9bd9SJerin Jacob else 19903cc9bd9SJerin Jacob mbox->rsp_tmo = MBOX_RSP_TIMEOUT; 20003cc9bd9SJerin Jacob 20103cc9bd9SJerin Jacob return 0; 20203cc9bd9SJerin Jacob } 20303cc9bd9SJerin Jacob 20403cc9bd9SJerin Jacob /** 20503cc9bd9SJerin Jacob * @internal 20603cc9bd9SJerin Jacob * Allocate a message response 20703cc9bd9SJerin Jacob */ 20803cc9bd9SJerin Jacob struct mbox_msghdr * 20903cc9bd9SJerin Jacob mbox_alloc_msg_rsp(struct mbox *mbox, int devid, int size, int size_rsp) 21003cc9bd9SJerin Jacob { 21103cc9bd9SJerin Jacob struct mbox_dev *mdev = &mbox->dev[devid]; 21203cc9bd9SJerin Jacob struct mbox_msghdr *msghdr = NULL; 21303cc9bd9SJerin Jacob 21403cc9bd9SJerin Jacob size = PLT_ALIGN(size, MBOX_MSG_ALIGN); 21503cc9bd9SJerin Jacob size_rsp = PLT_ALIGN(size_rsp, MBOX_MSG_ALIGN); 21603cc9bd9SJerin Jacob /* Check if there is space in mailbox */ 21703cc9bd9SJerin Jacob if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset()) 21803cc9bd9SJerin Jacob goto exit; 21903cc9bd9SJerin Jacob if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset()) 22003cc9bd9SJerin Jacob goto exit; 22103cc9bd9SJerin Jacob if (mdev->msg_size == 0) 22203cc9bd9SJerin Jacob mdev->num_msgs = 0; 22303cc9bd9SJerin Jacob mdev->num_msgs++; 22403cc9bd9SJerin Jacob 22503cc9bd9SJerin Jacob msghdr = (struct mbox_msghdr *)(((uintptr_t)mdev->mbase + 22603cc9bd9SJerin Jacob mbox->tx_start + msgs_offset() + 22703cc9bd9SJerin Jacob mdev->msg_size)); 22803cc9bd9SJerin Jacob 22903cc9bd9SJerin Jacob /* Clear the whole msg region */ 23003cc9bd9SJerin Jacob mbox_memset(msghdr, 0, sizeof(*msghdr) + size); 23103cc9bd9SJerin Jacob /* Init message header with reset values */ 23203cc9bd9SJerin Jacob msghdr->ver = MBOX_VERSION; 23303cc9bd9SJerin Jacob mdev->msg_size += size; 23403cc9bd9SJerin Jacob mdev->rsp_size += size_rsp; 23503cc9bd9SJerin Jacob msghdr->next_msgoff = mdev->msg_size + msgs_offset(); 23603cc9bd9SJerin Jacob exit: 23703cc9bd9SJerin Jacob 23803cc9bd9SJerin Jacob return msghdr; 23903cc9bd9SJerin Jacob } 24003cc9bd9SJerin Jacob 24103cc9bd9SJerin Jacob /** 24203cc9bd9SJerin Jacob * @internal 243fa4ee2d4SHarman Kalra * Synchronization between UP and DOWN messages 24403cc9bd9SJerin Jacob */ 245fa4ee2d4SHarman Kalra bool 246fa4ee2d4SHarman Kalra mbox_wait_for_zero(struct mbox *mbox, int devid) 247fa4ee2d4SHarman Kalra { 248fa4ee2d4SHarman Kalra uint64_t data; 249fa4ee2d4SHarman Kalra 250fa4ee2d4SHarman Kalra data = plt_read64((volatile void *)(mbox->reg_base + 251fa4ee2d4SHarman Kalra (mbox->trigger | (devid << mbox->tr_shift)))); 252fa4ee2d4SHarman Kalra 253fa4ee2d4SHarman Kalra /* If data is non-zero wait for ~1ms and return to caller 254fa4ee2d4SHarman Kalra * whether data has changed to zero or not after the wait. 255fa4ee2d4SHarman Kalra */ 256fa4ee2d4SHarman Kalra if (data) 257fa4ee2d4SHarman Kalra usleep(1000); 258fa4ee2d4SHarman Kalra else 259fa4ee2d4SHarman Kalra return true; 260fa4ee2d4SHarman Kalra 261fa4ee2d4SHarman Kalra data = plt_read64((volatile void *)(mbox->reg_base + 262fa4ee2d4SHarman Kalra (mbox->trigger | (devid << mbox->tr_shift)))); 263fa4ee2d4SHarman Kalra return data == 0; 264fa4ee2d4SHarman Kalra } 265fa4ee2d4SHarman Kalra 266fa4ee2d4SHarman Kalra static void 267fa4ee2d4SHarman Kalra mbox_msg_send_data(struct mbox *mbox, int devid, uint8_t data) 26803cc9bd9SJerin Jacob { 26903cc9bd9SJerin Jacob struct mbox_dev *mdev = &mbox->dev[devid]; 2705d8ff275SHarman Kalra struct mbox_hdr *tx_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start); 2715d8ff275SHarman Kalra struct mbox_hdr *rx_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start); 2725d8ff275SHarman Kalra uint64_t intr_val; 27303cc9bd9SJerin Jacob 27403cc9bd9SJerin Jacob /* Reset header for next messages */ 27503cc9bd9SJerin Jacob tx_hdr->msg_size = mdev->msg_size; 27603cc9bd9SJerin Jacob mdev->msg_size = 0; 27703cc9bd9SJerin Jacob mdev->rsp_size = 0; 27803cc9bd9SJerin Jacob mdev->msgs_acked = 0; 27903cc9bd9SJerin Jacob 28003cc9bd9SJerin Jacob /* num_msgs != 0 signals to the peer that the buffer has a number of 28103cc9bd9SJerin Jacob * messages. So this should be written after copying txmem 28203cc9bd9SJerin Jacob */ 28303cc9bd9SJerin Jacob tx_hdr->num_msgs = mdev->num_msgs; 28403cc9bd9SJerin Jacob rx_hdr->num_msgs = 0; 28503cc9bd9SJerin Jacob 28603cc9bd9SJerin Jacob /* Sync mbox data into memory */ 28703cc9bd9SJerin Jacob plt_wmb(); 28803cc9bd9SJerin Jacob 2895d8ff275SHarman Kalra /* Check for any pending interrupt */ 2905d8ff275SHarman Kalra intr_val = plt_read64( 2915d8ff275SHarman Kalra (volatile void *)(mbox->reg_base + (mbox->trigger | (devid << mbox->tr_shift)))); 2925d8ff275SHarman Kalra 2935d8ff275SHarman Kalra intr_val |= (uint64_t)data; 29403cc9bd9SJerin Jacob /* The interrupt should be fired after num_msgs is written 29503cc9bd9SJerin Jacob * to the shared memory 29603cc9bd9SJerin Jacob */ 2975d8ff275SHarman Kalra plt_write64(intr_val, (volatile void *)(mbox->reg_base + 298fa4ee2d4SHarman Kalra (mbox->trigger | (devid << mbox->tr_shift)))); 299fa4ee2d4SHarman Kalra } 300fa4ee2d4SHarman Kalra 301fa4ee2d4SHarman Kalra /** 302fa4ee2d4SHarman Kalra * @internal 303fa4ee2d4SHarman Kalra * Send a mailbox message 304fa4ee2d4SHarman Kalra */ 305fa4ee2d4SHarman Kalra void 306fa4ee2d4SHarman Kalra mbox_msg_send(struct mbox *mbox, int devid) 307fa4ee2d4SHarman Kalra { 308fa4ee2d4SHarman Kalra mbox_msg_send_data(mbox, devid, MBOX_DOWN_MSG); 309fa4ee2d4SHarman Kalra } 310fa4ee2d4SHarman Kalra 311fa4ee2d4SHarman Kalra /** 312fa4ee2d4SHarman Kalra * @internal 313fa4ee2d4SHarman Kalra * Send an UP mailbox message 314fa4ee2d4SHarman Kalra */ 315fa4ee2d4SHarman Kalra void 316fa4ee2d4SHarman Kalra mbox_msg_send_up(struct mbox *mbox, int devid) 317fa4ee2d4SHarman Kalra { 318fa4ee2d4SHarman Kalra mbox_msg_send_data(mbox, devid, MBOX_UP_MSG); 31903cc9bd9SJerin Jacob } 32003cc9bd9SJerin Jacob 32103cc9bd9SJerin Jacob /** 32203cc9bd9SJerin Jacob * @internal 32303cc9bd9SJerin Jacob * Wait and get mailbox response 32403cc9bd9SJerin Jacob */ 32503cc9bd9SJerin Jacob int 32603cc9bd9SJerin Jacob mbox_get_rsp(struct mbox *mbox, int devid, void **msg) 32703cc9bd9SJerin Jacob { 32803cc9bd9SJerin Jacob struct mbox_dev *mdev = &mbox->dev[devid]; 32903cc9bd9SJerin Jacob struct mbox_msghdr *msghdr; 33003cc9bd9SJerin Jacob uint64_t offset; 33103cc9bd9SJerin Jacob int rc; 33203cc9bd9SJerin Jacob 33303cc9bd9SJerin Jacob rc = mbox_wait_for_rsp(mbox, devid); 33403cc9bd9SJerin Jacob if (rc < 0) 33503cc9bd9SJerin Jacob return -EIO; 33603cc9bd9SJerin Jacob 33703cc9bd9SJerin Jacob plt_rmb(); 33803cc9bd9SJerin Jacob 33903cc9bd9SJerin Jacob offset = mbox->rx_start + 34003cc9bd9SJerin Jacob PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); 34103cc9bd9SJerin Jacob msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset); 34203cc9bd9SJerin Jacob if (msg != NULL) 34303cc9bd9SJerin Jacob *msg = msghdr; 34403cc9bd9SJerin Jacob 34503cc9bd9SJerin Jacob return msghdr->rc; 34603cc9bd9SJerin Jacob } 34703cc9bd9SJerin Jacob 34803cc9bd9SJerin Jacob /** 34903cc9bd9SJerin Jacob * Polling for given wait time to get mailbox response 35003cc9bd9SJerin Jacob */ 35103cc9bd9SJerin Jacob static int 35203cc9bd9SJerin Jacob mbox_poll(struct mbox *mbox, uint32_t wait) 35303cc9bd9SJerin Jacob { 35403cc9bd9SJerin Jacob uint32_t timeout = 0, sleep = 1; 35503cc9bd9SJerin Jacob uint32_t wait_us = wait * 1000; 35603cc9bd9SJerin Jacob uint64_t rsp_reg = 0; 35703cc9bd9SJerin Jacob uintptr_t reg_addr; 35803cc9bd9SJerin Jacob 35903cc9bd9SJerin Jacob reg_addr = mbox->reg_base + mbox->intr_offset; 36003cc9bd9SJerin Jacob do { 36103cc9bd9SJerin Jacob rsp_reg = plt_read64(reg_addr); 36203cc9bd9SJerin Jacob 36303cc9bd9SJerin Jacob if (timeout >= wait_us) 36403cc9bd9SJerin Jacob return -ETIMEDOUT; 36503cc9bd9SJerin Jacob 36603cc9bd9SJerin Jacob plt_delay_us(sleep); 36703cc9bd9SJerin Jacob timeout += sleep; 36803cc9bd9SJerin Jacob } while (!rsp_reg); 36903cc9bd9SJerin Jacob 37003cc9bd9SJerin Jacob plt_rmb(); 37103cc9bd9SJerin Jacob 37203cc9bd9SJerin Jacob /* Clear interrupt */ 37303cc9bd9SJerin Jacob plt_write64(rsp_reg, reg_addr); 37403cc9bd9SJerin Jacob 37503cc9bd9SJerin Jacob /* Reset mbox */ 37603cc9bd9SJerin Jacob mbox_reset(mbox, 0); 37703cc9bd9SJerin Jacob 37803cc9bd9SJerin Jacob return 0; 37903cc9bd9SJerin Jacob } 38003cc9bd9SJerin Jacob 38103cc9bd9SJerin Jacob /** 38203cc9bd9SJerin Jacob * @internal 38303cc9bd9SJerin Jacob * Wait and get mailbox response with timeout 38403cc9bd9SJerin Jacob */ 38503cc9bd9SJerin Jacob int 38603cc9bd9SJerin Jacob mbox_get_rsp_tmo(struct mbox *mbox, int devid, void **msg, uint32_t tmo) 38703cc9bd9SJerin Jacob { 38803cc9bd9SJerin Jacob struct mbox_dev *mdev = &mbox->dev[devid]; 38903cc9bd9SJerin Jacob struct mbox_msghdr *msghdr; 39003cc9bd9SJerin Jacob uint64_t offset; 39103cc9bd9SJerin Jacob int rc; 39203cc9bd9SJerin Jacob 39303cc9bd9SJerin Jacob rc = mbox_wait_for_rsp_tmo(mbox, devid, tmo); 39403cc9bd9SJerin Jacob if (rc != 1) 39503cc9bd9SJerin Jacob return -EIO; 39603cc9bd9SJerin Jacob 39703cc9bd9SJerin Jacob plt_rmb(); 39803cc9bd9SJerin Jacob 39903cc9bd9SJerin Jacob offset = mbox->rx_start + 40003cc9bd9SJerin Jacob PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); 40103cc9bd9SJerin Jacob msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset); 40203cc9bd9SJerin Jacob if (msg != NULL) 40303cc9bd9SJerin Jacob *msg = msghdr; 40403cc9bd9SJerin Jacob 40503cc9bd9SJerin Jacob return msghdr->rc; 40603cc9bd9SJerin Jacob } 40703cc9bd9SJerin Jacob 40803cc9bd9SJerin Jacob static int 40903cc9bd9SJerin Jacob mbox_wait(struct mbox *mbox, int devid, uint32_t rst_timo) 41003cc9bd9SJerin Jacob { 41103cc9bd9SJerin Jacob volatile struct mbox_dev *mdev = &mbox->dev[devid]; 41203cc9bd9SJerin Jacob uint32_t timeout = 0, sleep = 1; 41303cc9bd9SJerin Jacob 41403cc9bd9SJerin Jacob rst_timo = rst_timo * 1000; /* Milli seconds to micro seconds */ 415dfb5a7a7SHarman Kalra 416dfb5a7a7SHarman Kalra /* Waiting for mdev->msgs_acked tp become equal to mdev->num_msgs, 417dfb5a7a7SHarman Kalra * mdev->msgs_acked are incremented at process_msgs() in interrupt 418dfb5a7a7SHarman Kalra * thread context. 419dfb5a7a7SHarman Kalra */ 42003cc9bd9SJerin Jacob while (mdev->num_msgs > mdev->msgs_acked) { 42103cc9bd9SJerin Jacob plt_delay_us(sleep); 42203cc9bd9SJerin Jacob timeout += sleep; 42303cc9bd9SJerin Jacob if (timeout >= rst_timo) { 42403cc9bd9SJerin Jacob struct mbox_hdr *tx_hdr = 42503cc9bd9SJerin Jacob (struct mbox_hdr *)((uintptr_t)mdev->mbase + 42603cc9bd9SJerin Jacob mbox->tx_start); 42703cc9bd9SJerin Jacob struct mbox_hdr *rx_hdr = 42803cc9bd9SJerin Jacob (struct mbox_hdr *)((uintptr_t)mdev->mbase + 42903cc9bd9SJerin Jacob mbox->rx_start); 43003cc9bd9SJerin Jacob 43103cc9bd9SJerin Jacob plt_err("MBOX[devid: %d] message wait timeout %d, " 43203cc9bd9SJerin Jacob "num_msgs: %d, msgs_acked: %d " 43303cc9bd9SJerin Jacob "(tx/rx num_msgs: %d/%d), msg_size: %d, " 43403cc9bd9SJerin Jacob "rsp_size: %d", 43503cc9bd9SJerin Jacob devid, timeout, mdev->num_msgs, 43603cc9bd9SJerin Jacob mdev->msgs_acked, tx_hdr->num_msgs, 43703cc9bd9SJerin Jacob rx_hdr->num_msgs, mdev->msg_size, 43803cc9bd9SJerin Jacob mdev->rsp_size); 43903cc9bd9SJerin Jacob 44003cc9bd9SJerin Jacob return -EIO; 44103cc9bd9SJerin Jacob } 44203cc9bd9SJerin Jacob plt_rmb(); 44303cc9bd9SJerin Jacob } 44403cc9bd9SJerin Jacob return 0; 44503cc9bd9SJerin Jacob } 44603cc9bd9SJerin Jacob 44703cc9bd9SJerin Jacob int 44803cc9bd9SJerin Jacob mbox_wait_for_rsp_tmo(struct mbox *mbox, int devid, uint32_t tmo) 44903cc9bd9SJerin Jacob { 45003cc9bd9SJerin Jacob struct mbox_dev *mdev = &mbox->dev[devid]; 45103cc9bd9SJerin Jacob int rc = 0; 45203cc9bd9SJerin Jacob 45303cc9bd9SJerin Jacob /* Sync with mbox region */ 45403cc9bd9SJerin Jacob plt_rmb(); 45503cc9bd9SJerin Jacob 45603cc9bd9SJerin Jacob if (mbox->trigger == RVU_PF_VFX_PFVF_MBOX1 || 45703cc9bd9SJerin Jacob mbox->trigger == RVU_PF_VFX_PFVF_MBOX0) { 45803cc9bd9SJerin Jacob /* In case of VF, Wait a bit more to account round trip delay */ 45903cc9bd9SJerin Jacob tmo = tmo * 2; 46003cc9bd9SJerin Jacob } 46103cc9bd9SJerin Jacob 46203cc9bd9SJerin Jacob /* Wait message */ 46303cc9bd9SJerin Jacob if (plt_thread_is_intr()) 46403cc9bd9SJerin Jacob rc = mbox_poll(mbox, tmo); 46503cc9bd9SJerin Jacob else 46603cc9bd9SJerin Jacob rc = mbox_wait(mbox, devid, tmo); 46703cc9bd9SJerin Jacob 46803cc9bd9SJerin Jacob if (!rc) 46903cc9bd9SJerin Jacob rc = mdev->num_msgs; 47003cc9bd9SJerin Jacob 47103cc9bd9SJerin Jacob return rc; 47203cc9bd9SJerin Jacob } 47303cc9bd9SJerin Jacob 47403cc9bd9SJerin Jacob /** 47503cc9bd9SJerin Jacob * @internal 47603cc9bd9SJerin Jacob * Wait for the mailbox response 47703cc9bd9SJerin Jacob */ 47803cc9bd9SJerin Jacob int 47903cc9bd9SJerin Jacob mbox_wait_for_rsp(struct mbox *mbox, int devid) 48003cc9bd9SJerin Jacob { 48103cc9bd9SJerin Jacob return mbox_wait_for_rsp_tmo(mbox, devid, mbox->rsp_tmo); 48203cc9bd9SJerin Jacob } 48303cc9bd9SJerin Jacob 48403cc9bd9SJerin Jacob int 48503cc9bd9SJerin Jacob mbox_get_availmem(struct mbox *mbox, int devid) 48603cc9bd9SJerin Jacob { 48703cc9bd9SJerin Jacob struct mbox_dev *mdev = &mbox->dev[devid]; 48803cc9bd9SJerin Jacob int avail; 48903cc9bd9SJerin Jacob 49003cc9bd9SJerin Jacob plt_spinlock_lock(&mdev->mbox_lock); 49103cc9bd9SJerin Jacob avail = mbox->tx_size - mdev->msg_size - msgs_offset(); 49203cc9bd9SJerin Jacob plt_spinlock_unlock(&mdev->mbox_lock); 49303cc9bd9SJerin Jacob 49403cc9bd9SJerin Jacob return avail; 49503cc9bd9SJerin Jacob } 49603cc9bd9SJerin Jacob 49703cc9bd9SJerin Jacob int 49803cc9bd9SJerin Jacob send_ready_msg(struct mbox *mbox, uint16_t *pcifunc) 49903cc9bd9SJerin Jacob { 50003cc9bd9SJerin Jacob struct ready_msg_rsp *rsp; 50103cc9bd9SJerin Jacob int rc; 50203cc9bd9SJerin Jacob 50344a9307cSRakesh Kudurumalla mbox_alloc_msg_ready(mbox_get(mbox)); 50403cc9bd9SJerin Jacob 50503cc9bd9SJerin Jacob rc = mbox_process_msg(mbox, (void *)&rsp); 50644a9307cSRakesh Kudurumalla if (rc) { 50744a9307cSRakesh Kudurumalla mbox_put(mbox); 50803cc9bd9SJerin Jacob return rc; 50944a9307cSRakesh Kudurumalla } 51044a9307cSRakesh Kudurumalla mbox_put(mbox); 51103cc9bd9SJerin Jacob 51203cc9bd9SJerin Jacob if (rsp->hdr.ver != MBOX_VERSION) { 51303cc9bd9SJerin Jacob plt_err("Incompatible MBox versions(AF: 0x%04x Client: 0x%04x)", 51403cc9bd9SJerin Jacob rsp->hdr.ver, MBOX_VERSION); 51503cc9bd9SJerin Jacob return -EPIPE; 51603cc9bd9SJerin Jacob } 51703cc9bd9SJerin Jacob 51803cc9bd9SJerin Jacob if (pcifunc) 51903cc9bd9SJerin Jacob *pcifunc = rsp->hdr.pcifunc; 52003cc9bd9SJerin Jacob 52103cc9bd9SJerin Jacob /* Save rclk & sclk freq */ 52203cc9bd9SJerin Jacob if (!dev_rclk_freq || !dev_sclk_freq) { 52303cc9bd9SJerin Jacob dev_rclk_freq = rsp->rclk_freq; 52403cc9bd9SJerin Jacob dev_sclk_freq = rsp->sclk_freq; 52503cc9bd9SJerin Jacob } 52603cc9bd9SJerin Jacob return 0; 52703cc9bd9SJerin Jacob } 52803cc9bd9SJerin Jacob 52903cc9bd9SJerin Jacob int 53003cc9bd9SJerin Jacob reply_invalid_msg(struct mbox *mbox, int devid, uint16_t pcifunc, uint16_t id) 53103cc9bd9SJerin Jacob { 53203cc9bd9SJerin Jacob struct msg_rsp *rsp; 53303cc9bd9SJerin Jacob 53403cc9bd9SJerin Jacob rsp = (struct msg_rsp *)mbox_alloc_msg(mbox, devid, sizeof(*rsp)); 53503cc9bd9SJerin Jacob if (!rsp) 53603cc9bd9SJerin Jacob return -ENOMEM; 53703cc9bd9SJerin Jacob rsp->hdr.id = id; 53803cc9bd9SJerin Jacob rsp->hdr.sig = MBOX_RSP_SIG; 53903cc9bd9SJerin Jacob rsp->hdr.rc = MBOX_MSG_INVALID; 54003cc9bd9SJerin Jacob rsp->hdr.pcifunc = pcifunc; 54103cc9bd9SJerin Jacob 54203cc9bd9SJerin Jacob return 0; 54303cc9bd9SJerin Jacob } 54403cc9bd9SJerin Jacob 54503cc9bd9SJerin Jacob /** 54603cc9bd9SJerin Jacob * @internal 54703cc9bd9SJerin Jacob * Convert mail box ID to name 54803cc9bd9SJerin Jacob */ 54903cc9bd9SJerin Jacob const char * 55003cc9bd9SJerin Jacob mbox_id2name(uint16_t id) 55103cc9bd9SJerin Jacob { 55203cc9bd9SJerin Jacob switch (id) { 55303cc9bd9SJerin Jacob default: 55403cc9bd9SJerin Jacob return "INVALID ID"; 55503cc9bd9SJerin Jacob #define M(_name, _id, _1, _2, _3) \ 55603cc9bd9SJerin Jacob case _id: \ 55703cc9bd9SJerin Jacob return #_name; 55803cc9bd9SJerin Jacob MBOX_MESSAGES 55903cc9bd9SJerin Jacob MBOX_UP_CGX_MESSAGES 560d85c80b4SHarman Kalra MBOX_UP_REP_MESSAGES 56103cc9bd9SJerin Jacob #undef M 56203cc9bd9SJerin Jacob } 56303cc9bd9SJerin Jacob } 56403cc9bd9SJerin Jacob 56503cc9bd9SJerin Jacob int 56603cc9bd9SJerin Jacob mbox_id2size(uint16_t id) 56703cc9bd9SJerin Jacob { 56803cc9bd9SJerin Jacob switch (id) { 56903cc9bd9SJerin Jacob default: 57003cc9bd9SJerin Jacob return 0; 57103cc9bd9SJerin Jacob #define M(_1, _id, _2, _req_type, _3) \ 57203cc9bd9SJerin Jacob case _id: \ 57303cc9bd9SJerin Jacob return sizeof(struct _req_type); 57403cc9bd9SJerin Jacob MBOX_MESSAGES 57503cc9bd9SJerin Jacob MBOX_UP_CGX_MESSAGES 576d85c80b4SHarman Kalra MBOX_UP_REP_MESSAGES 57703cc9bd9SJerin Jacob #undef M 57803cc9bd9SJerin Jacob } 57903cc9bd9SJerin Jacob } 580