// +FHDR------------------------------------------------------------
//                 Copyright (c) 2022 SmartLogic.
//                       ALL RIGHTS RESERVED
// -----------------------------------------------------------------
// Filename      : msg_transfer_queue.c
// Author        : xianfeng.du
// Created On    : 2022-06-25
// Last Modified :
// -----------------------------------------------------------------
// Description:
//
//
// -FHDR------------------------------------------------------------

#include <stddef.h>
#include "ucp_printf.h"
#include "ucp_utility.h"
#include "ucp_tick.h"
#include "spu_hw_queue.h"
#include "pet_sm_mgt.h"
#include "msg_transfer_mem.h"
#include "msg_transfer_mbuffer.h"

ALWAYS_INLINE void* get_mbuf_ptr(uint32_t base, uint32_t size, uint16_t idx)
{
    void *mbuf = (void *)(base + (size * idx));
    return mbuf;
}

ALWAYS_INLINE int32_t msg_queue_ul_block_init(uint8_t inst_id, uint8_t que_id)
{
    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueLocalInfo_t* ch = (MsgQueueLocalInfo_t*)&pMsgQueueLocalMgt->localUlQueue[inst_id][que_id];
    ch->availableSize = ch->bufSize - MSG_MBUF_HEAD_SIZE;
    ch->offset = 0;
    ch->msgCnt = 0;

    return SUCCESS;
}

ALWAYS_INLINE uint8_t* msg_queue_ul_alloc_buf(uint8_t inst_id, uint8_t que_id, uint16_t* buf_id)
{
    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueLocalInfo_t* ch = (MsgQueueLocalInfo_t*)&pMsgQueueLocalMgt->localUlQueue[inst_id][que_id];

    PetSmLocalMgt_t* pPetSmLocalMgt = get_pet_sm_local_mgt();
    MsgQueueCommonInfo_t* chCommon = pPetSmLocalMgt->pUlQueue[inst_id][que_id];

    uint32_t alloc = atomic_fetch_add(&chCommon->alloc, 1);
    uint16_t idx = alloc & ch->ringMask;
    MsgMemBufAttr_t *mbuf = (MsgMemBufAttr_t *)get_mbuf_ptr(ch->bufBase, ch->bufSize, idx);
    if (NULL == mbuf)
    {
        UCP_PRINT_ERROR("msg_queue_ul_alloc_buf: mbuf ERROR!");
		return NULL;
    }
    uint8_t *buf = (uint8_t *)&mbuf[1];
    *buf_id = idx;

    return buf;
}

ALWAYS_INLINE int32_t msg_queue_ul_put_buf(uint8_t inst_id, uint8_t que_id)
{
    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueLocalInfo_t* ch = (MsgQueueLocalInfo_t*)&pMsgQueueLocalMgt->localUlQueue[inst_id][que_id];
    if (ch->msgCnt == 0) {//ch->offset
        return SUCCESS;
    }

    MsgMemBufAttr_t *mbuf = (MsgMemBufAttr_t *)get_mbuf_ptr(ch->bufBase, ch->bufSize, ch->idx);
    do_write(&mbuf->msgSize, ch->offset);

    uint32_t value = (inst_id << 24) + (que_id << 16) + ch->idx;
    int32_t ret = ecs_hw_que_send(ECS_RFM_SPU0_HW_QUEUE, value);

    return ret;
}

ALWAYS_INLINE uint8_t* msg_queue_dl_get_buf(uint8_t inst_id, uint8_t que_id)
{
    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    MsgQueueLocalInfo_t* ch = (MsgQueueLocalInfo_t*)&pMsgQueueLocalMgt->localDlQueue[inst_id][que_id];

    PetSmLocalMgt_t* pPetSmLocalMgt = get_pet_sm_local_mgt();
    MsgQueueCommonInfo_t* chCommon = pPetSmLocalMgt->pDlQueue[inst_id][que_id];

    ch->in = do_read(&chCommon->in);
    //UCP_PRINT_LOG("ucp_queue_dl_get_buf_start,qNo[0x%08x],chCommon_addr[0x%08x],in[0x%08x],out[0x%08x]",que_id,(uint32_t)chCommon,ch->in,ch->out);

    uint32_t avail = ch->in - ch->out;
    if (0 == avail) {
        //UCP_PRINT_LOG("No new msg[%1u]: in = 0x%08x out=0x%08x\n", qNo, ch->in, ch->out);
        return NULL;
    }

    uint16_t idx = ch->out & ch->ringMask;
    MsgMemBufAttr_t *mbuf = (MsgMemBufAttr_t *)get_mbuf_ptr(ch->bufBase, ch->bufSize, idx);
    uint8_t *buf = (uint8_t *)&mbuf[1];
    ch->out++;
    do_write(&chCommon->out, ch->out);//only for debug

    return buf;
}

void msg_transfer_queue_init(void)
{
    UCP_PRINT_EMPTY("start initializing msg queue local memory");

    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    PetSmLocalMgt_t* pPetSmLocalMgt = get_pet_sm_local_mgt();
    pMsgQueueLocalMgt->localSyncInfo.queueCfgFlag = do_read_byte(&pPetSmLocalMgt->pSyncInfo->queueCfgFlag);

    MsgQueueLocalInfo_t* ch;
    MsgQueueCommonInfo_t* chCommon;

    uint32_t i,j;
    for (i = 0; i < MAX_INSTANCE_NUM; i++) {
        for (j = 0; j < UCP4008_TRAFFIC_MAX_NUM; j++) {
            memcpy_ucp((void *)&pMsgQueueLocalMgt->localQueueCfg[i][j], (void *)pPetSmLocalMgt->pQueueCfg[i][j], sizeof(MsgQueueCfg_t));

            ch = (MsgQueueLocalInfo_t *)&pMsgQueueLocalMgt->localDlQueue[i][j];
            chCommon = pPetSmLocalMgt->pDlQueue[i][j];
            memcpy_ucp(ch, chCommon, sizeof(MsgQueueCommonInfo_t));

            ch = (MsgQueueLocalInfo_t*)&pMsgQueueLocalMgt->localUlQueue[i][j];
            chCommon = pPetSmLocalMgt->pUlQueue[i][j];
            memcpy_ucp(ch, chCommon, sizeof(MsgQueueCommonInfo_t));
        }
    }

    return;
}

void msg_transfer_queue_recfg(void)
{
    PetSmLocalMgt_t* pPetSmLocalMgt = get_pet_sm_local_mgt();
    uint8_t flag = do_read_byte(&pPetSmLocalMgt->pSyncInfo->queueCfgFlag);

    MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();
    if (flag == pMsgQueueLocalMgt->localSyncInfo.queueCfgFlag) {
        return;
    }

    msg_transfer_queue_init();

    //need to notify other cores by hw_queue

    return;
}

