// +FHDR------------------------------------------------------------
//                 Copyright (c) 2022 SmartLogic.
//                       ALL RIGHTS RESERVED
// -----------------------------------------------------------------
// Filename      : spu_hw_queue.s.c
// Author        : lishuang.xie
// Created On    : 2023-02-06
// Last Modified :
// -----------------------------------------------------------------
// Description:
//
//
// -FHDR------------------------------------------------------------
#include "inter_vector.h"
#include "spu_hw_queue.h"
#include "ucp_utility.h"
#include "ucp_printf.h"
#include "hwque.h"

#define ECS_PALLADIUM_TEST

#ifdef ECS_PALLADIUM_TEST
typedef struct ECS_DEBUG_INFO_STRUCT
{
    uint32_t ecs_msg_OutQue_err;
    uint32_t ecs_msg_irq_num;
    uint32_t ecs_msg_OutQue_num;
    uint32_t ecs_msg_QutQue_ok;
    uint32_t ecs_msg_QueIsEmpty_num;
}ecs_debug_info;
ecs_debug_info  g_ecs_debug_info;       /* ecs/pet rfm debug info */
#endif

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
static uint32_t gu32_app_recv_que0 = 0;     // #24
static uint32_t gu32_app_recv_que1 = 0;
static uint32_t gu32_app_recv_que2 = 0;
static uint32_t gu32_app_recv_que3 = 0;
static uint32_t gu32_app_recv_que4 = 0;
static uint32_t gu32_app_recv_que5 = 0;
static uint32_t gu32_app_recv_que6 = 0;
static uint32_t gu32_app_recv_que7 = 0;
static uint32_t gu32_app_recv_que8 = 0;
static uint32_t gu32_app_recv_que9 = 0;
static uint32_t gu32_app_recv_que10 = 0;
static uint32_t gu32_app_recv_que11 = 0;
#endif

ecs_hw_que_info_withirq_t g_ecs_hw_que_info;            /* ecs/pet rfm hw_que info with irq  */
ecs_hw_que_info_noirq_t   gst_ecs_hw_que_info_noirq;    /* ecs/pet rfm hw_que info without irq*/

extern void ecs_hw_que_irq(void);

void ecs_hw_que_init(uint8_t core_id)
{
    int32_t i32ret = 0;
 
   /* communication init */
    do
    {
        i32ret = smart_hq_init(core_id);
    }
    while(i32ret != 0);
    UCP_PRINT_EMPTY("[ecs_hw_que_init]: smart_hq_init OK\r\n");
#ifdef ECS_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 28), core_id);
#endif

    return ;
}

void ecs_hw_que_init_withirq(uint8_t core_id, uint8_t que_id)
{
    int32_t ret = -1;
    int32_t que_dep   = -1;
    int32_t que_width = -1;
    int32_t que_used  = -1;
    int32_t que_cpuid = -1;
    int32_t apeId     = (int32_t)core_id;
    uint8_t u8_loop   = 0;

    memset(&g_ecs_hw_que_info, 0, sizeof(g_ecs_hw_que_info));
    g_ecs_hw_que_info.ecs_hq_id = que_id;

    UCP_PRINT_EMPTY("[ecs_withirq]: smart_hq_init OK\r\n");
#ifdef ECS_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 29), que_id);
#endif

    /* Band */
    ret = smart_que_bind(core_id, que_id);
    if (0 != ret)
    {
        UCP_PRINT_EMPTY("[ecs_withirq]: smart_que_bind error!(core_id=%d, que_id=%d)", core_id, que_id);
        debug_write(DBG_DDR_ERR_IDX(apeId, 23), ret);
        return ;
    }

    /* Get queue info*/
    ret = smart_get_que_info(que_id, &que_dep, &que_width, &que_used, &que_cpuid);
    if (0 != ret)
    {
        debug_write(DBG_DDR_ERR_IDX(apeId, 21), ret);
    }
    UCP_PRINT_EMPTY("[ecs_withirq]: que_id(%d),dep(%d),width(%d),used(%d),cpuid(%d)", que_id, que_dep,que_width,que_used,que_cpuid);
#ifdef ECS_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 30), 0x1);
#endif

    /* Get queue vector */
    g_ecs_hw_que_info.ecs_hq_vector = smart_get_hq_vector(core_id, que_id);
    if (0 >= g_ecs_hw_que_info.ecs_hq_vector)
    {
        UCP_PRINT_EMPTY("[ecs_withirq]: smart_get_hq_vector error!(core_id=%d)", core_id);
        debug_write(DBG_DDR_ERR_IDX(apeId, 17), g_ecs_hw_que_info.ecs_hq_vector);
        return ;
    }
    UCP_PRINT_EMPTY("[ecs_withirq]: hq_vector=%d (coreid=%d, quei=%d)", g_ecs_hw_que_info.ecs_hq_vector, core_id, que_id);
#ifdef ECS_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 31), g_ecs_hw_que_info.ecs_hq_vector);
#endif

    /* Set req */
    ret = smart_irq_request(g_ecs_hw_que_info.ecs_hq_vector, ecs_hw_que_irq);
    if (0 != ret)
    {
        UCP_PRINT_EMPTY("[ecs_withirq]: smart_irq_request error!(core_id=%d)", core_id);
        debug_write(DBG_DDR_ERR_IDX(apeId, 7), ret);
        return ;
    }
#ifdef ECS_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 30), 0x2);
#endif

    /* enable no-empty irq */
    for (u8_loop = 0; u8_loop < 8; u8_loop++)
    {
        ret = smart_enable_q_nempty(que_id);
        if (0 == ret)
        {
            break;
        }
    }
    debug_write(DBG_DDR_ERR_IDX(core_id, 48), u8_loop);
    if (0 != ret)
    {
        debug_write(DBG_DDR_ERR_IDX(core_id, 49), ret);
        return ;
    }
#ifdef ECS_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 30), 0x3);
#endif

    UCP_PRINT_EMPTY("[ecs_withirq]: OK \r\n");
    return ;
}

void ecs_hw_que_init_noirq(uint8_t core_id, uint8_t que_id)
{
    int32_t i32ret = 0;
    int32_t i32que_dep   = -1;
    int32_t i32que_width = -1;
    int32_t i32que_used  = -1;
    int32_t i32que_cpuid = -1;

    memset(&gst_ecs_hw_que_info_noirq, 0, sizeof(gst_ecs_hw_que_info_noirq));
    gst_ecs_hw_que_info_noirq.ecs_hq_id = que_id;

    /* Band */
    i32ret = smart_que_bind(core_id, que_id);
    if (0 != i32ret)
    {
        UCP_PRINT_EMPTY("[ecs_noirq]: smart_que_bind error!(core_id=%d, que_id=%d)", core_id, que_id);
        debug_write(DBG_DDR_ERR_IDX(core_id, 39), i32ret);
        return ;
    }

    /* Get queue info*/
    i32ret = smart_get_que_info(que_id, &i32que_dep, &i32que_width, &i32que_used, &i32que_cpuid);
    if (0 != i32ret)
    {
        debug_write(DBG_DDR_ERR_IDX(core_id, 40), i32ret);
    }
    UCP_PRINT_EMPTY("[ecs_noirq]: que_id(%d),dep(%d),width(%d),used(%d),cpuid(%d)", que_id, i32que_dep, i32que_width, i32que_used, i32que_cpuid);

    /* Get queue vector */
    gst_ecs_hw_que_info_noirq.ecs_hq_vector = smart_get_hq_vector(core_id, que_id);
    if (0 >= gst_ecs_hw_que_info_noirq.ecs_hq_vector)
    {
        UCP_PRINT_EMPTY("[ecs_noirq]: smart_get_hq_vector error!(core_id=%d)", core_id);
        debug_write(DBG_DDR_ERR_IDX(core_id, 17), gst_ecs_hw_que_info_noirq.ecs_hq_vector);
        return ;
    }
#ifdef ECS_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 32), que_id);
#endif

    return ;
}

uint32_t gu32_ecs_send_cnt = 0;
uint32_t gu32_ecs_recv_cnt = 0;

ALWAYS_INLINE int32_t ecs_hw_que_send(uint8_t u8dst_que_id, uint32_t u32value)
{
    int32_t i32ret = 0;
    int32_t core_id = get_core_id();

    i32ret = smart_in_que(u8dst_que_id, u32value);
    if (0 != i32ret)
    {
        //UCP_PRINT_ERROR("[ecs_hw_que_send]: error(smart_in_que) que_id = 0x%08x addr = 0x%08x\r\n", u8dst_que_id, u32value);
        debug_write(DBG_DDR_ERR_IDX(core_id, 41), i32ret);
        return i32ret;
    }
    gu32_ecs_send_cnt++;
    debug_write(DBG_DDR_ERR_IDX(core_id, 43), gu32_ecs_send_cnt);
    return 0;
}

ALWAYS_INLINE int32_t ecs_hw_que_recv(uint8_t u8dst_que_id, uint32_t *pu32value)
{
    int32_t i32ret = 0;
    int32_t core_id = get_core_id();

    /* is empty */
    i32ret = smart_que_is_empty(u8dst_que_id);
    if (0 != i32ret)
    {
        /* no message return */
#ifdef ECS_PALLADIUM_TEST
        debug_write(DBG_DDR_COMMON_IDX(core_id, 47), i32ret);
#endif
        return 1;
    }

    i32ret = smart_out_que(u8dst_que_id, pu32value);
    if (0 != i32ret)
    {
        //UCP_PRINT_ERROR("[ecs_hw_que_recv]: smart_out_que error... que_id = 0x%08x \r\n", u8dst_que_id);
        debug_write(DBG_DDR_ERR_IDX(core_id, 42), i32ret);
        return i32ret;
    }
    gu32_ecs_recv_cnt++;
    debug_write(DBG_DDR_ERR_IDX(core_id, 44), gu32_ecs_recv_cnt);
    debug_write(DBG_DDR_ERR_IDX(core_id, 45), *pu32value);
    return i32ret;
}

/*********************************************************/

/* irq */
void ecs_hw_que_irq(void)
{
    int32_t ret = -1;
    uint32_t idx = 0;
    uint32_t len = 0;
    ecs_msg_head *pmsg_head = NULL;
    int32_t core_id = get_core_id();

#ifdef ECS_PALLADIUM_TEST
    g_ecs_debug_info.ecs_msg_irq_num++;
#endif

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
    debug_write(OSP_DEBUG_HW_POT(core_id, 38), g_ecs_debug_info.ecs_msg_irq_num);
#endif

    ret = smart_que_is_empty(g_ecs_hw_que_info.ecs_hq_id);
    while(ret == 0)
    {
#ifdef ECS_PALLADIUM_TEST
        g_ecs_debug_info.ecs_msg_OutQue_num++;
#endif

        /* out queue */
        ret = smart_out_que(g_ecs_hw_que_info.ecs_hq_id, &idx);
        if (0 != ret)
        {
            UCP_PRINT_ERROR("[ecs_hw_que_irq]: smart_out_que error... que_id = 0x%08x \r\n", g_ecs_hw_que_info.ecs_hq_id);
#ifdef ECS_PALLADIUM_TEST
            g_ecs_debug_info.ecs_msg_OutQue_err++;
            debug_write(DBG_DDR_COMMON_IDX(core_id, 33), g_ecs_debug_info.ecs_msg_OutQue_err);
            debug_write(DBG_DDR_COMMON_IDX(core_id, 34), g_ecs_debug_info.ecs_msg_irq_num);
            debug_write(DBG_DDR_COMMON_IDX(core_id, 35), g_ecs_debug_info.ecs_msg_OutQue_num);
#endif
            debug_write(DBG_DDR_ERR_IDX(core_id, 28), ret);

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
            debug_write(OSP_DEBUG_HW_POT(core_id, 40), g_ecs_debug_info.ecs_msg_OutQue_err);
#endif
            return ;
        }

#ifdef ECS_PALLADIUM_TEST
        g_ecs_debug_info.ecs_msg_QutQue_ok++;
#endif

        UCP_PRINT_LOG("[ecs_hw_que_irq]: smart_out_que(0x%08x), addr = 0x%08x\r\n", g_ecs_hw_que_info.ecs_hq_id, idx);
        if (NULL != g_ecs_hw_que_info.irq_entry)
        {
            pmsg_head = (ecs_msg_head*)((uint32_t)idx - (uint32_t)ECS_MSG_HEAD_LEN);
            len = do_read((char*)(&pmsg_head->msg_size));
#ifdef ECS_PALLADIUM_TEST
            debug_write(DBG_DDR_COMMON_IDX(core_id, 36), g_ecs_debug_info.ecs_msg_irq_num);
            debug_write(DBG_DDR_COMMON_IDX(core_id, 37), g_ecs_debug_info.ecs_msg_OutQue_num);
#endif

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
            uint8_t src_core_id = do_read_byte((char*)(&pmsg_head->src_core_id));
            switch (src_core_id)
            {
                case 0:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 24), ++gu32_app_recv_que0);
                    break;
                }
                case 1:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 25), ++gu32_app_recv_que1);
                    break;
                }
                case 2:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 26), ++gu32_app_recv_que2);
                    break;
                }
                case 3:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 27), ++gu32_app_recv_que3);
                    break;
                }
                case 4:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 28), ++gu32_app_recv_que4);
                    break;
                }
                case 5:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 29), ++gu32_app_recv_que5);
                    break;
                }
                case 6:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 30), ++gu32_app_recv_que6);
                    break;
                }
                case 7:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 31), ++gu32_app_recv_que7);
                    break;
                }
                case 8:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 32), ++gu32_app_recv_que8);
                    break;
                }
                case 9:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 33), ++gu32_app_recv_que9);
                    break;
                }
                case 10:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 34), ++gu32_app_recv_que10);
                    break;
                }
                case 11:
                {
                    debug_write(OSP_DEBUG_HW_POT(core_id, 35), ++gu32_app_recv_que11);
                    break;
                }
                default:
                {
                    break;
                }
            }
            debug_write(OSP_DEBUG_HW_POT(core_id, 49), g_ecs_debug_info.ecs_msg_QutQue_ok);
#endif

            g_ecs_hw_que_info.irq_entry(idx, len);
        }
        ret = smart_que_is_empty(g_ecs_hw_que_info.ecs_hq_id);
    }

    return ;
}

void ecs_hw_que_irq_callback(ECS_HWQUE_IRQ_FUNC func)
{
    if (NULL == func)
    {
#ifdef ECS_PALLADIUM_TEST
        int32_t core_id = get_core_id();
        debug_write(DBG_DDR_COMMON_IDX(core_id, 38), 0xF0F0F0F0);
#endif
        return ;
    }
    g_ecs_hw_que_info.irq_entry = func;

    return ;
}

