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

#include <assert.h>
#include <stddef.h>
#include "ucp_utility.h"
#include "ucp_printf.h"
#include "ucp_pcie_traffic.h"
#include "msg_transfer_host.h"
#include "dw_pcie_ep.h"

static inline void ucp_variables_init()
{
	uint32_t k = 0;
	uint32_t i = 0;
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
	//UcpQueueMemInfo_t* pUcpQueueMemInfo = get_ucp_queue_mem_info();	
	for(k = 0; k < MAX_INSTANCE_NUM; k++)
	{
	    for (i = 0; i < UCP4008_TRAFFIC_MAX_NUM; i++) {
	        memset(pUcpPcieMemInfo->pExtDlTraffic[k][i], 0, sizeof(UcpExtTraffic_t));
	        memset(pUcpPcieMemInfo->pExtUlTraffic[k][i], 0, sizeof(UcpExtTraffic_t));
	        //memset(pUcpQueueMemInfo->pLocalIntDlTraffic[i], 0, sizeof(UcpIntTraffic_t));
	        //memset(pUcpQueueMemInfo->pLocalIntUlTraffic[i], 0, sizeof(UcpIntTraffic_t));	
	        //memset_ucp(pUcpQueueMemInfo->pIntDlTraffic[i], 0, sizeof(UcpIntTraffic_t));
	        //memset_ucp(pUcpQueueMemInfo->pIntUlTraffic[i], 0, sizeof(UcpIntTraffic_t));
	    }
	}
    volatile UcpPcieDmaState_e   state;	
    for (i = 0; i < MAX_CH_NUM_UCP_DMA; i++) {
        do {
            state = pUcpPcieMemInfo->pDmaDlCh[i]->state;
        } while (UCP_DMA_STATE_WORKING == state);
        memset(pUcpPcieMemInfo->pDmaDlCh[i], 0, sizeof(UcpPcieDmaCh_t));
		
        do {
            state = pUcpPcieMemInfo->pDmaUlCh[i]->state;
        } while (UCP_DMA_STATE_WORKING == state);
        memset(pUcpPcieMemInfo->pDmaUlCh[i], 0, sizeof(UcpPcieDmaCh_t));
    }

    return;
}


static inline void ucp_counter_setup(void)
{
    uint32_t i = 0;
    uint32_t k = 0;

    UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
    PcieTrafficCounter_t* pCounter = (PcieTrafficCounter_t *)&pUcpPcieMemInfo->pUcpMemBar->cnt;
    //pUcpPcieMemInfo->pUcpMemBar->traffic[][].queue_cplane_info.
    for(k = 0; k < MAX_INSTANCE_NUM; k++)
    {
        for (i = 0; i < UCP4008_TRAFFIC_MAX_NUM; i++) {
            //configure dl counter 
            if(i == UCP4008_TRAFFIC_NR_eMBB_DATA)
            {
                pCounter->dlDescNum[k][i] = 
                pUcpPcieMemInfo->pUcpMemBar->traffic[k][CU_SPLIT].queue_cplane_info.tx_desc_num;//MAX_DESC_NUM;
            }
            else if(i == UCP4008_TRAFFIC_NR_eMBB_CTRL)
            {
                pCounter->dlDescNum[k][i] = 
                pUcpPcieMemInfo->pUcpMemBar->traffic[k][CU_SPLIT].queue_uplane_info.tx_desc_num;//MAX_DESC_NUM;
            }
            else if(i == UCP4008_TRAFFIC_OAM)
            {
                pCounter->dlDescNum[k][i] = 
                pUcpPcieMemInfo->pUcpMemBar->traffic[k][OAM].queue_uplane_info.tx_desc_num;//MAX_DESC_NUM;
            }
            else
            {
                pCounter->dlDescNum[k][i] = MAX_DESC_NUM;
            }
            //描述符的个数不能大于128
            if(pCounter->dlDescNum[k][i] > MAX_DESC_NUM)
            {
                pCounter->dlDescNum[k][i] = MAX_DESC_NUM;
            }
            pCounter->dlRxCounter[k][i] = 0;
            //pCounter->dlTxCounter[i] = 0;
            //assert(isPowerOf2(pCounter->dlDescNum[k][i]));

            //configure ul counter 
            if(i == UCP4008_TRAFFIC_NR_eMBB_DATA)
            {
                pCounter->ulDescNum[k][i] = 
                pUcpPcieMemInfo->pUcpMemBar->traffic[k][CU_SPLIT].queue_cplane_info.rx_desc_num;//MAX_DESC_NUM;
            }
            else if(i == UCP4008_TRAFFIC_NR_eMBB_CTRL)
            {
                pCounter->ulDescNum[k][i] = 
                pUcpPcieMemInfo->pUcpMemBar->traffic[k][CU_SPLIT].queue_uplane_info.rx_desc_num;//MAX_DESC_NUM;
            }
            else if(i == UCP4008_TRAFFIC_OAM)
            {
                pCounter->ulDescNum[k][i] = 
                pUcpPcieMemInfo->pUcpMemBar->traffic[k][OAM].queue_uplane_info.rx_desc_num;//MAX_DESC_NUM;
            }
            else
            {
                pCounter->ulDescNum[k][i] = MAX_DESC_NUM;
            }

            if(pCounter->ulDescNum[k][i] > MAX_DESC_NUM)
            {
                pCounter->ulDescNum[k][i] = MAX_DESC_NUM;
            }
            pCounter->ulTxCounter[k][i] = 0;	
            //pCounter->ulRxCounter[i] = 0;	
            //assert(isPowerOf2(pCounter->ulDescNum[k][i]));    
        }
    }
    return;
}

static inline void ucp_variables_setup(void)
{
    uint32_t i, j;
    uint32_t k = 0;

    UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
    UcpExtTraffic_t* pExtTraffic = NULL;
    uint32_t desc_mask = 0; //pUcpPcieMemInfo->pUcpMemBar->cnt.dlDescNum[][];
    for(k = 0; k < MAX_INSTANCE_NUM; k++)
    {
        for (i = 0; i < UCP4008_TRAFFIC_MAX_NUM; i++) {
            desc_mask = pUcpPcieMemInfo->pUcpMemBar->cnt.dlDescNum[k][i] - 1;
            pExtTraffic = pUcpPcieMemInfo->pExtDlTraffic[k][i];
            pExtTraffic->mask = desc_mask; //MAX_DESC_NUM - 1;
            pExtTraffic->epCntIng = 0;
            pExtTraffic->lastEop = 1;
            pExtTraffic->offset = 0;
            pExtTraffic->buf = NULL;
            pExtTraffic->dma.size = MAX_THREAD_NUM_UCP_DMA;
            assert(isPowerOf2(pExtTraffic->dma.size));//判断是否是2的幂次方
            pExtTraffic->dma.mask = MAX_THREAD_NUM_UCP_DMA - 1;
            pExtTraffic->dma.in = 0;
            pExtTraffic->dma.out = 0;
            for (j = 0; j < pExtTraffic->dma.size; j++) {
                pExtTraffic->dma.thread[j].finished = 0;
            }
        }
    }

    for(k = 0; k < MAX_INSTANCE_NUM; k++)
    {
        for (i = 0; i < UCP4008_TRAFFIC_MAX_NUM; i++) {
            desc_mask = pUcpPcieMemInfo->pUcpMemBar->cnt.ulDescNum[k][i] - 1;
            pExtTraffic = pUcpPcieMemInfo->pExtUlTraffic[k][i];
            pExtTraffic->mask = desc_mask; //MAX_DESC_NUM - 1;
            pExtTraffic->epCntIng = 0;
            pExtTraffic->lastEop = 1;
            pExtTraffic->offset = 0;
            pExtTraffic->buf = NULL;
            pExtTraffic->dma.size = MAX_THREAD_NUM_UCP_DMA;
            assert(isPowerOf2(pExtTraffic->dma.size));
            pExtTraffic->dma.mask = MAX_THREAD_NUM_UCP_DMA - 1;
            pExtTraffic->dma.in = 0;
            pExtTraffic->dma.out = 0;		
            for (j = 0; j < pExtTraffic->dma.size; j++) {
                pExtTraffic->dma.thread[j].finished = 0;
            }
        }
    }
    return;
}

void ucp_pcie_reset(void)
{
    //uint32_t i = 0;
    UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
    volatile PcieLinkStatus_t* pDevStatus = &pUcpPcieMemInfo->pUcpMemBar->status;	

    //RC set enable;
    if (pDevStatus->devEnable) {
        return;
    }
    pDevStatus->devReady = epInit;

    UCP_PRINT_LOG("UCP PCIE EP is initializing...\n");		
    ucp_variables_init(); //对DMA状态结构体初始化

    pDevStatus->devReady = epReady;	
    UCP_PRINT_LOG("UCP is waiting for enabling by RC ...\n");


    do {
        //devStatus = pUcpPcieMemInfo->pUcpMemBar->status.devEnable;
        pDevStatus->devReady = epReady;	
        //NOP;
        UCP_PRINT_LOG("UCP is waiting for enabling by RC ...\n");
        // delay_us(1000);

    } while(0 == pDevStatus->devEnable);
    UCP_PRINT_LOG("UCP has been enabled by RC !\n");
#if 0 //此处RC的配置还未设置下来，需要等RC配置完成后，再配置traffic和counter
    ucp_counter_setup();  //对DMA 的counter 结构体初始化
    UCP_PRINT_LOG("UCP PCIE EP Fucp_counter_setup end !\n");

    ucp_variables_setup();//对extTrafic变量进行初始化
    //ucp_queue_setup();
#endif
	pUcpPcieMemInfo->pUcpMemBar->command[PCI_ENDPOINT_UCPEP_RC_STATUS]=RC_NG;

    pDevStatus->devReady = epRunning;
    UCP_PRINT_LOG("UCP PCIE EP Finish checking reset !\n");
    return;
}

void ucp_pcie_reset_bar(void)
{
    ucp_counter_setup();  //对DMA 的counter 结构体初始化
    UCP_PRINT_EMPTY("UCP PCIE EP Fucp_counter_setup end !\n");
    ucp_variables_setup();//对extTrafic变量进行初始化
    //ucp_queue_setup();
}


//主机侧app发生了重启后，需要重新进行配置
int ucp_pcie_recfg_reset(void)
{
    uint32_t i = 0;
    int ret = FAILURE;
	int count = 0;
	int deadCount = 1000;
    UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
    volatile PcieLinkStatus_t* pDevStatus = &pUcpPcieMemInfo->pUcpMemBar->status;	

    //RC set enable;
    if (pDevStatus->devEnable) 
	{
		ret = SUCCESS;
        return ret;
    }
	else
	{
    	PCIE_ERROR_LOG("UCP PCIE EP enter recfg...\n");
	    volatile UcpPcieDmaState_e   state;	
	    for (i = 0; i < MAX_CH_NUM_UCP_DMA; i++) 
		{
			count = 0;
	        do 
			{
				count++;
	            state = pUcpPcieMemInfo->pDmaDlCh[i]->state;
				PCIE_ERROR_LOG("UCP PCIE EP wait for DL dma finish!\n");	
				ucp_nop(100);					
	        } while ((UCP_DMA_STATE_WORKING == state) && (count < deadCount));
	        memset(pUcpPcieMemInfo->pDmaDlCh[i], 0, sizeof(UcpPcieDmaCh_t));
			count = 0;
	        do 
			{
				count++;			
	            state = pUcpPcieMemInfo->pDmaUlCh[i]->state;
				PCIE_ERROR_LOG("UCP PCIE EP wait for UL dma finish!\n");				
				ucp_nop(100);		
	        } while ((UCP_DMA_STATE_WORKING == state) && (count < deadCount));
	        memset(pUcpPcieMemInfo->pDmaUlCh[i], 0, sizeof(UcpPcieDmaCh_t));
	    }
		//notify the RC that DMA had stoped
		pUcpPcieMemInfo->pUcpMemBar->command[PCI_ENDPOINT_UCPEP_DMA_STATUS] = 0;
		PCIE_ERROR_LOG("UCP PCIE EP DMA had sotpped!\n");		
	}
    pDevStatus->devReady = epInit;

    PCIE_DEBUG_LOG("UCP PCIE EP is initializing...\n");		
    ucp_variables_init(); //对DMA状态结构体初始化

    pDevStatus->devReady = epReady;	
    PCIE_DEBUG_LOG("UCP is waiting for enabling by RC ...\n");

    do {
        //devStatus = pUcpPcieMemInfo->pUcpMemBar->status.devEnable;
        pDevStatus->devReady = epReady;	
        //NOP;
        PCIE_ERROR_LOG("UCP is waiting for enabling by RC ...\n");
		ucp_nop(200);		
    } while(0 == pDevStatus->devEnable);
    PCIE_DEBUG_LOG("UCP has been enabled by RC !\n");
#if 0 //此处RC的配置还未设置下来，需要等RC配置完成后，再配置traffic和counter
    ucp_counter_setup();  //对DMA 的counter 结构体初始化
    UCP_PRINT_LOG("UCP PCIE EP Fucp_counter_setup end !\n");

    ucp_variables_setup();//对extTrafic变量进行初始化
    //ucp_queue_setup();
#endif
    pDevStatus->devReady = epRunning;
    PCIE_ERROR_LOG("UCP PCIE EP Finish checking reset !\n");

	ret = msg_transfer_reset_recfg(); 	
	//重新配置DMA
	//pcie_ep_drv_init();
    return ret;
}


