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

#include <string.h>
#include "ucp_drv_common.h"
#include "ucp_pcie_traffic.h"
#include "ucp_printf.h"
#include "ucp_utility.h"
#include "msg_transfer_mem.h"
#include "msg_transfer_mbuffer.h"
#include "msg_transfer_queue.h"
#include "msg_transfer_host.h"
#include "ucp_tick.h"

#define LOGBUFSIZE  1024
char log_buf[LOGBUFSIZE];

void no_debug_log(const char *fmt, ...)
{
}


#if 1
void debug_log(uint8_t level, const char *fmt, ...)
{ 
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info(); 
	uint32_t count = 0;
	if(level > pUcpPcieMemInfo->pUcpMemBar->command[PCI_ENDPOINT_UCPEP_CHECKSUM])//disable the log save to host
	{
		return;
	}
	va_list args; 
	va_start(args,fmt); 
	while(1)
	{
		count++;
		if(pUcpPcieMemInfo->pUcpMemBar->command[PCI_ENDPOINT_UCPEP_EP_ED] == 0)
		{
			vsnprintf(pUcpPcieMemInfo->pUcpMemBar->log_buf, LOGBUFSIZE, fmt, args); 
			pUcpPcieMemInfo->pUcpMemBar->command[PCI_ENDPOINT_UCPEP_EP_ED] = 1;
			break;
		}
		else
		{
		#if 1
			if(count > 200)
			{
				break;
			}
		#endif
			ucp_nop(100);
		}
	}
	va_end(args); 
}
#endif
void debug_dma_int(int32_t ch, int32_t direction)
{
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info(); 
	if (direction) {
		pUcpPcieMemInfo->pDmaDlCh[ch]->state = UCP_DMA_STATE_FINISHED;
	} else {
		pUcpPcieMemInfo->pDmaUlCh[ch]->state = UCP_DMA_STATE_FINISHED;
	}
	return;
}

static inline int32_t get_dl_dma_ch(void)
{
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
	int32_t ch = -1;
	int32_t k = 0;
	//volatile uint32_t status = 0;

    for (k = 0; k < MAX_CH_NUM_UCP_DMA; k++) 
	{
        if (pUcpPcieMemInfo->pDmaDlCh[k]->state == UCP_DMA_STATE_IDLE) 
		{
            ch =  k;
			break;
		}
	}
#if 0	
	if(ch < 0)
	{	
		for (k = 0; k < MAX_CH_NUM_UCP_DMA; k++)
		{
			status = DW_PCIE_DMA_CH_STATUS(dw_pcie_read_rdma_ch(k, DW_PCIE_DMA_CH_UNR_CTRL1_OFF));
			PCIE_ERROR_LOG("dl dma status dma[%d] = %d    pDmaDlCh->state = %d\n", k, status, pUcpPcieMemInfo->pDmaDlCh[k]->state);
		}
    }  
#endif	
    return ch;
}

static inline int32_t get_ul_dma_ch(void)
{
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
	int32_t ch = -1;
	int32_t k = 0;	
	//volatile uint32_t status = 0;

    for (k = 0; k < MAX_CH_NUM_UCP_DMA; k++) {
        if (pUcpPcieMemInfo->pDmaUlCh[k]->state == UCP_DMA_STATE_IDLE) 
		{
            ch =  k;
			break;
		}
	}
#if 0	
	if(ch < 0)
	{	
		for (k = 0; k < MAX_CH_NUM_UCP_DMA; k++)
		{
			status = DW_PCIE_DMA_CH_STATUS(dw_pcie_read_rdma_ch(k, DW_PCIE_DMA_CH_UNR_CTRL1_OFF));
			PCIE_DEBUG_LOG("ul dma status dma[%d] = %d\n", k, status);
		}
    }  
#endif	
    return ch;
}
#if 0
static inline uint32_t get_ul_desc_idx(uint32_t desc_idx, int8_t buf_idx)
{
	uint32_t idx = (desc_idx/MAX_MBUF_NUM)*MAX_MBUF_NUM + buf_idx;
	return idx;
}
#endif

static inline int32_t ucp_pcie_dl_worker(uint32_t inst_id)
{
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
	PcieTrafficCounter_t* pCnt = (PcieTrafficCounter_t *)&pUcpPcieMemInfo->pUcpMemBar->cnt;

#if 0	
	//MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();		
	uint32_t  clockBegin = 0;
	uint32_t  clockEnd = 0;
	uint32_t  clockCnt = 0;
    rdmcycle(&clockBegin);
#endif

    UcpPcieDmaCh_t* dma_ch;	
	int counter = 0;
	//int ret = 0;
	uint32_t q_idx = 0;
	uint32_t k = 0;
    uint32_t dl_finished[MAX_INSTANCE_NUM][MAX_Q_NUM_DL_TRAFFIC] = {0};//局部变量用来记录，是哪个业务queue已经完成了传输
    memset(dl_finished, 0, sizeof(dl_finished));
	int32_t dma_idx = 0;//DMA服务的上行队列的队列号
	uint32_t dma_trc_inst_id = 0;//用于记录DMA服务的小区号


	
	//判断DMA通道的状态，是否有DMA通道传输完成，DMA为6个通道
    for (dma_idx = 0; dma_idx < MAX_CH_NUM_UCP_DMA; dma_idx++) {
        dma_ch = pUcpPcieMemInfo->pDmaDlCh[dma_idx];
        if (dma_ch->state == UCP_DMA_STATE_FINISHED) {
			dma_trc_inst_id = dma_ch->served_traffic.served_traffic_insid;
            q_idx = dma_ch->served_traffic.served_traffic_queid;			
            //q_idx = dma_ch->served_traffic;
            *dma_ch->finished = 1;  //此处指向的是pCmplt的finished的地址
            dma_ch->state = UCP_DMA_STATE_IDLE;			
            dl_finished[dma_trc_inst_id][q_idx] = 1;
        }
    }

    uint32_t extInc = 0;
	uint32_t intInc = 0;
    uint32_t t_idx = 0;
	uint32_t i = 0;
    UcpPcieDmaThread_t* pDmaThread = NULL;	
	UcpPcieDmaComplete_t* pCmplt = NULL;	
	uint32_t num_rx_queues = MAX_Q_NUM_DL_TRAFFIC;//跟业务queue对应，共6个queue
	//按照传输队列判断，是否有队列已经传输完成，传输队列一共有6个
	for(i = 0; i < MAX_INSTANCE_NUM; i++)
	{	
	    for (k = 0; k < num_rx_queues; k++) {
			
	        if (0 == dl_finished[i][k]) {
	            continue;
	        }
	        
	        extInc = 0;
	        intInc = 0;
	        pDmaThread = (UcpPcieDmaThread_t *)&pUcpPcieMemInfo->pExtDlTraffic[i][k]->dma;
			//DMA->in是在DMA启动的时候进行加1，然后在此处是DMA传输完成后对out加1
	        while (pDmaThread->out != pDmaThread->in) {//如果不相等，表示该通道有DMA传输
	            t_idx = pDmaThread->out & pDmaThread->mask;
	            pCmplt = &pDmaThread->thread[t_idx];
	           //PCIE_ERROR_LOG("DL ExtCH[%d][%d] dmaThread.in = %d dmaThread.out = %d\n",inst_id, k, pDmaThread->in, pDmaThread->out);
	            //UCP_PRINT_LOG("DL finished = 0x%x extInc = 0x%x intInc = 0x%x\n", pCmplt->finished, pCmplt->extInc, pCmplt->intInc);
				//当前业务通道传输完成			
	            if (pCmplt->finished) {
	                extInc += pCmplt->extInc;
	                intInc += pCmplt->intInc;
	                pCmplt->finished = 0;
	                pDmaThread->out++;
	            } else {
	                break;
	            }
	        }
			//如果有已经完成的数据包，则将数据包放到应用的队列中
	        if (extInc > 0) {
	            pCnt->dlRxCounter[i][k] += extInc;//写入bar空间该通道接收到的数据包个数
	            //ucp_queue_dl_put_done(k, intInc);//队列中保存接收数据包计数		
				msg_queue_dl_put_done(i, k, intInc);
	            /*UCP_PRINT_LOG("DL After PutComplete int_dl_ch[%d][%d]: in = %d out = %d alloc = %d free = %d intInc = %d\n",
	                i, k, pMsgQueueLocalMgt->localDlQueue[i][k].in, pMsgQueueLocalMgt->localDlQueue[i][k].out,
					pMsgQueueLocalMgt->localDlQueue[i][k].alloc, pMsgQueueLocalMgt->localDlQueue[i][k].free, intInc);*/
	        }
	    }
	}
    //uint32_t dma_idx;
    uint32_t n =0;
	uint32_t N = 0;
    //uint32_t ext_size;	
    uint32_t freed = 0;
	uint32_t ext_idx = 0;
	//int8_t desc_idx;
	uint32_t pcieOffset = 0;
	uint32_t H = 0;
	uint32_t L = 0;		
	uint64_t dst_addr = 0;
    UcpExtTraffic_t* ext_ch = NULL;
    PcieTrafficDescriptor_t *desc_hdr = NULL;
    PcieTrafficDescriptor_t *desc = NULL;	
    MsgMemBufAttr_t* attr = NULL;
    DwPcieEpDmaChDesc_t rdma_desc_ch[MAX_CH_NUM_UCP_DMA] = {0};
	//判断是否有业务队列需要接收数据包，如果有需要接收的数据，则寻找一个空闲DMA读通道进行接收
	for (k = 0; k < num_rx_queues; k++) {
		ext_ch = pUcpPcieMemInfo->pExtDlTraffic[inst_id][k];
		PCIE_DEBUG_LOG("DL pUcpPcieMemInfo->pExtDlTraffic[[%d][%d] = 0x%x  ext_ch->epCntIng=%d \n",inst_id, k, pUcpPcieMemInfo->pExtDlTraffic[inst_id][k], ext_ch->epCntIng); 
		PCIE_DEBUG_LOG("DL pCnt->dlTxCounter[%d][%d]=%d  pCnt->dlRxCounter[%d][%d]=%d\n",inst_id, k, pCnt->dlTxCounter[inst_id][k], inst_id, k, pCnt->dlRxCounter[inst_id][k]);		
		N = pCnt->dlTxCounter[inst_id][k] - ext_ch->epCntIng;//计算要传输的数据包个数	
		PCIE_DEBUG_LOG("DL TRCCNT[%d][%d] = %d    N = %d\n", inst_id, k, pCnt->dlTxCounter[inst_id][k], N);
		if (0 == N) 
		{
			PCIE_DEBUG_LOG("DL no pkt need received! TRCCNT[[%d][%d] = %d epcntIng = %d\n", inst_id, k, pCnt->dlTxCounter[inst_id][k], ext_ch->epCntIng);			
			continue;
		}		
		if(N > pCnt->dlDescNum[inst_id][k])// MAX_THREAD_NUM_UCP_DMA)
		{
			N =  N&(pCnt->dlDescNum[inst_id][k]); //(MAX_THREAD_NUM_UCP_DMA);//如果单次传输的数据包个数大于DMA的描述符个数，则取模
			//如果取模后值为0，则说明是128的整数倍，则N需要设置为描述符的上限
			if(0 == N)
			{
				N = pCnt->dlDescNum[inst_id][k];//MAX_THREAD_NUM_UCP_DMA;
			}
		}
		
		PCIE_DEBUG_LOG("DL TRCCNT[%d][%d] = %d  N = %d\n", inst_id, k, pCnt->dlTxCounter[inst_id][k], N);
		//ext_mask = ext_ch->mask;
		//ext_size = ext_ch->mask + 1;
		//判断该通道是否有空闲的dma描述符可用
		freed = ext_ch->dma.size - (ext_ch->dma.in - ext_ch->dma.out);
		if (0 == freed) 
		{
			PCIE_ERROR_LOG("no freed dma thread! ext_ch[%d][%d] freed = %d, ext_ch->dma.size = %d, ext_ch->dma.in = %d, ext_ch->dma.out =%d \n",
				inst_id, k , freed, ext_ch->dma.size, ext_ch->dma.in, ext_ch->dma.out);
			continue;
		}

		dma_idx = get_dl_dma_ch();	
		if (dma_idx < 0) 
		{
			PCIE_DEBUG_LOG("dl no freed dma chanal! dma_idx = %d\n",dma_idx);			
			continue;
		}
		PCIE_DEBUG_LOG("DL DMA idx = 0x%x  dmaThreads.in = 0x%x  dmaTrheads.out = 0x%x\n", dma_idx, ext_ch->dma.in, ext_ch->dma.out);
		dma_ch = pUcpPcieMemInfo->pDmaDlCh[dma_idx];
		//dma_ch->served_traffic = k;
		ext_idx = ext_ch->epCntIng & ext_ch->mask;
		PCIE_DEBUG_LOG("DL DMA ext_idx = %d  ext_ch->mask = %d  ext_ch->epCntIng = %d\n", ext_idx, ext_ch->mask, ext_ch->epCntIng);
		
		desc_hdr = (PcieTrafficDescriptor_t *)&pUcpPcieMemInfo->pUcpMemBar->desc.dl[inst_id][k];
		pcieOffset = 0;//pUcpQueueMemInfo->pLocalIntDlTraffic[k]->offset;
		intInc = 0;

		counter = ucp_pcie_dma_chain_desc_init(pUcpPcieMemInfo->pRdmaChains[dma_idx], N);	
		#if 1
		if(counter < 0)
		{
			PCIE_ERROR_LOG("DL counter error counter = %d\n", counter);
			break;
		}
		#endif
		for (n = 0; n < N; n++) 
		{
			ext_ch->buf = (uint32_t *)msg_queue_dl_put_buf(inst_id, k);//ucp_queue_dl_put_buf(k);
			if (NULL != ext_ch->buf) 
			{
				ext_ch->offset = 0;
				/*UCP_PRINT_LOG("DL After PrePut buf = 0x%lx int_dl_ch[%d].alloc = %d\n", 
					(uint32_t)ext_ch->buf, k, pMsgQueueLocalMgt->localDlQueue[inst_id][k].alloc);*/
			} 
			else 
			{
				PCIE_ERROR_LOG("DL Change DMA chain num N = %d -->> n = %d,  k = %d\n", N, n, k);
				ucp_pcie_dma_chain_desc_init(pUcpPcieMemInfo->pRdmaChains[dma_idx], n);
				break;
			}			
			//ext_ch->lastEop = desc->eop;
			//intInc += desc->eop;
			intInc++; //此处的intInc和n是完全相同的，表示收到的数据包的个数

			
			/*desc_idx = pCnt->dlDescIdx[k][ext_idx];
			if (desc_idx < 0) {
				UCP_PRINT_ERROR("DL DESC[%u] error", ext_idx);
				break;
			}
			desc = (PcieTrafficDescriptor_t *)&desc_hdr[desc_idx];*/
			desc = (PcieTrafficDescriptor_t *)&desc_hdr[ext_idx]; //bar空间描述符，RC 写过来的要读取的数据包的源地址			
			H = desc->phyAddr >> 32;
			L = (uint32_t)desc->phyAddr;
			PCIE_DEBUG_LOG("DL DESC[%d]: desc = 0x%x  srcAddr=0x%x %x  (uint32_t)desc->length = %d\n", ext_idx, (uint32_t)desc, H, L, (uint32_t)desc->length);
			PCIE_DEBUG_LOG("DL DESC[%d]: len = %d  type = %d eop = %d\n", ext_idx, (uint32_t)desc->length, desc->type, desc->eop);
			ext_idx = (ext_idx + 1) & ext_ch->mask;//准备取下一个bar空间上的描述符

			dst_addr = (uint64_t)&ext_ch->buf[ext_ch->offset] + pcieOffset; //本地接收数据包的目的地址
			PCIE_DEBUG_LOG("DL tranfic dst_addr = 0x%x  desc->phyAddr = 0x%x\n", (uint32_t)dst_addr, (uint32_t)desc->phyAddr);	
			//PCIE_DEBUG_LOG("DL tranfic pUcpPcieMemInfo->pRdmaChains[dma_idx] = 0x%x \n", pUcpPcieMemInfo->pRdmaChains[dma_idx]);	
			ucp_pcie_rdma_chain_desc_fill(pUcpPcieMemInfo->pRdmaChains[dma_idx], n, dst_addr, (uint64_t)desc->phyAddr, desc->length);
			attr = MSG_MBUF_ATTR(ext_ch->buf);
			//PCIE_DEBUG_LOG("DL Data Msg: offset = %6u, nSeg = %2u\n", ext_ch->offset, attr->nSegs);
			//attr->msgSize = ext_ch->offset + desc->length;//external memory
			do_write(&attr->msgSize, ext_ch->offset + desc->length);
			ext_ch->offset += desc->length;
			//attr->msgType = desc->type;
			//attr->nSegs++;
			//attr->eop = desc->eop;
		}

		if (0 == n) 
		{
			PCIE_ERROR_LOG("received num is null n = %d\n",n);
			continue;
		}
		ext_ch->epCntIng += n;//通道接收到的数据包个数累计，desc是循环使用的，最大128
		t_idx = ext_ch->dma.in & ext_ch->dma.mask;
		ext_ch->dma.in++;//表示该通道有DMA传输已经启动
		//设置complete结构体
		pCmplt = &ext_ch->dma.thread[t_idx];//thread描述符，表示一次传输
		pCmplt->extInc = n; //接收数据包的个数，n和intInc是完全相等的
		pCmplt->intInc = intInc; //接收数据包的个数
		pCmplt->finished = 0;//本次传输刚启动
		//设置DMA通道状态结构体
		//dma_ch->served_traffic = k;
		dma_ch->served_traffic.served_traffic_insid = inst_id;		
		dma_ch->served_traffic.served_traffic_queid = k;
		dma_ch->served_traffic.thread_idx = t_idx; //记录所服务的thread idx 
		dma_ch->finished = &pCmplt->finished;
		dma_ch->state = UCP_DMA_STATE_WORKING;
        //设置对DMA通道
		rdma_desc_ch[dma_idx].ll = pUcpPcieMemInfo->pRdmaChains[dma_idx];
		rdma_desc_ch[dma_idx].local_irq_en = 1;
		rdma_desc_ch[dma_idx].remote_irq_en = 0;

        //启动DMA传输  
		PCIE_DEBUG_LOG("DL Start DMA %d for Traffic[%d][%d] datanum = %d ext_ch->dma.in = %d ext_ch->dma.out = %d dma_ch->state = %d \n", 
		dma_idx, inst_id, k, n, ext_ch->dma.in, ext_ch->dma.out, dma_ch->state);				
		ucp_pcie_rdma_chain_start(dma_idx, (DwPcieEpDmaChDesc_t *)&rdma_desc_ch[dma_idx]);
		//debug_dma_int(dma_idx, 1);
	}
#if 0	
    rdmcycle(&clockEnd);
    clockCnt = clockEnd - clockBegin;
    PCIE_DEBUG_LOG("dlworker end, startTime: %d endTime: %d, cycle:[%d]\n",clockBegin, clockEnd, clockCnt);
#endif
	return 0;
}

static inline int32_t ucp_pcie_ul_worker(uint32_t inst_id)
{
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
	PcieTrafficCounter_t* pCnt = (PcieTrafficCounter_t *)&pUcpPcieMemInfo->pUcpMemBar->cnt;
	
	MsgQueueLocalMgt_t* pMsgQueueLocalMgt = get_msg_queue_local_mgt();	

    UcpPcieDmaCh_t* dma_ch;
	uint32_t q_idx = 0;
	uint32_t dma_trc_inst_id = 0;
	uint32_t k = 0;
    uint32_t ul_finished[MAX_INSTANCE_NUM][MAX_Q_NUM_UL_TRAFFIC] = {0};
    memset(ul_finished, 0, sizeof(ul_finished));
	int32_t dma_idx = 0;
	int32_t ret = 0;
	
	//判断是否有上行DMA通道已经完成了传输
    for (dma_idx = 0; dma_idx < MAX_CH_NUM_UCP_DMA; dma_idx++) 
	{
        dma_ch = pUcpPcieMemInfo->pDmaUlCh[dma_idx];
		//UCP_PRINT_LOG("UL DMA 0x%x dma_ch->state = %d\n", dma_idx, dma_ch->state);
        if (dma_ch->state == UCP_DMA_STATE_FINISHED) 
		{
			dma_trc_inst_id = dma_ch->served_traffic.served_traffic_insid;
            q_idx = dma_ch->served_traffic.served_traffic_queid;
            *dma_ch->finished = 1;
            dma_ch->state = UCP_DMA_STATE_IDLE;
            ul_finished[dma_trc_inst_id][q_idx] = 1;			
           // UCP_PRINT_LOG("UL DMA 0x%x for traffic 0x%x finished\n", dma_idx, q_idx);
        }
    }

    uint32_t extInc = 0; 
	uint32_t intInc = 0;
    uint32_t t_idx = 0;	
    UcpPcieDmaThread_t* pDmaThread  = NULL;	
	UcpPcieDmaComplete_t* pCmplt = NULL;	
	uint32_t num_tx_queues = MAX_Q_NUM_UL_TRAFFIC;
	uint32_t i = 0;
	for(i = 0; i < MAX_INSTANCE_NUM; i++)
	{
		//如果有发送通道完成了DMA传输，则需要处理对应的数据包
	    for (k = 0; k < num_tx_queues; k++) 
		{
			//首先检查该通道上的数据包是否被RC已经取走
			//ucp_queue_ul_check_free(k, pCnt->ulRxCounter[k]);		
			//ucp_queue_ul_get_done(k, pCnt->ulRxCounter[k] - pMsgQueueLocalMgt->localUlQueue[k].free);
			msg_queue_ul_get_done(i, k, (pCnt->ulRxCounter[i][k] - pMsgQueueLocalMgt->localUlQueue[i][k].free));
			//检查该通道的DMA传输是否完成
			if (0 == ul_finished[i][k]) 
			{
	            //UCP_PRINT_LOG("UL check DMA finished ul_finished[%d][%d] = %d\n", inst_id, k, ul_finished[inst_id][k]);			
	            continue;
	        }
	        extInc = 0;
	        intInc = 0;
	        pDmaThread = (UcpPcieDmaThread_t *)&pUcpPcieMemInfo->pExtUlTraffic[i][k]->dma;
			//UCP_PRINT_LOG("pExtUlTraffic[%d][%d] pDmaThread->out= %d, pDmaThread->in =%d  pDmaThread = 0x%lx \n", i, k, pDmaThread->out, pDmaThread->in, pDmaThread);
	        while (pDmaThread->out != pDmaThread->in) {
	            t_idx = pDmaThread->out & pDmaThread->mask;
	            pCmplt = &pDmaThread->thread[t_idx];		
	           // UCP_PRINT_LOG("UL finished = 0x%x extInc = 0x%x intInc = 0x%x\n", pCmplt->finished, pCmplt->extInc, pCmplt->intInc);
	            if (pCmplt->finished) 
				{
	                extInc += pCmplt->extInc;
	                intInc += pCmplt->intInc;
	                pCmplt->finished = 0;
	                pDmaThread->out++;
	            } 
				else 
				{
	                break;
	            }
	        }
			
	        if (extInc > 0) 
			{
	            pCnt->ulTxCounter[i][k] += extInc;//通知RC，数据包已经传输完成
	            //ucp_queue_ul_get_done(k, intInc);//此处不应该立即去释放数据包，需要等对端取走后再去释放
	            PCIE_DEBUG_LOG("UL After PutComplete int_ul_ch[%d][%d]: in = %d out = %d alloc = %d free = %d\n", 
	                i, k, pMsgQueueLocalMgt->localUlQueue[i][k].in, pMsgQueueLocalMgt->localUlQueue[i][k].out,
					pMsgQueueLocalMgt->localUlQueue[i][k].alloc, pMsgQueueLocalMgt->localUlQueue[i][k].free);
	        }
	    }
	}
    //uint32_t dma_idx;
    uint32_t n = 0; 
    uint32_t N = 0;
    uint32_t int_num, ext_num = 0;	
    //uint32_t ext_size;	
    uint32_t freed = 0;
	uint32_t ext_idx = 0;
	//uint32_t desc_idx;
	//int8_t buf_idx;
	uint32_t pcieOffset = 0;
	uint32_t H = 0; 
	uint32_t L = 0;		
	uint64_t src_addr = 0;
    UcpExtTraffic_t* ext_ch = NULL;
	MsgQueueLocalInfo_t* int_ch = NULL; 
    PcieTrafficDescriptor_t *desc_hdr = NULL;
    PcieTrafficDescriptor_t *desc = NULL;	
	MsgMemBufAttr_t* attr  = NULL;
	DwPcieEpDmaChDesc_t wdma_desc_ch[MAX_CH_NUM_UCP_DMA] = {0};
	//检查是否有通道需要有数据发送，一共6个queue，逐个通道检查
	for (k = 0; k < num_tx_queues; k++, N = 0) {
		//ucp_queue_ul_update_in(k);
		msg_queue_ul_update_in(inst_id, k);
		ext_ch = pUcpPcieMemInfo->pExtUlTraffic[inst_id][k];
        int_ch = (MsgQueueLocalInfo_t *)&pMsgQueueLocalMgt->localUlQueue[inst_id][k];	//从queue中获取需要传输的数据包的个数       
        int_num = int_ch->in - int_ch->out;//本次要传输的数据包的个数 
        if(0 == int_num)
        {
			PCIE_DEBUG_LOG("UL no pkt need send! TRCCNT[[%d][%d] = %d epcntIng = %d\n", inst_id, k, pCnt->ulTxCounter[inst_id][k], ext_ch->epCntIng);			
			continue;        	
        }
		if(int_num > pCnt->ulDescNum[inst_id][k])//MAX_THREAD_NUM_UCP_DMA)
		{
			int_num = int_num & pCnt->ulDescNum[inst_id][k];//(MAX_THREAD_NUM_UCP_DMA);//如果单次传输的数据包个数大于DMA的描述符个数，则取模
			if(0 == int_num)
			{
				int_num = pCnt->ulDescNum[inst_id][k];//MAX_THREAD_NUM_UCP_DMA;
			}
		}        
		PCIE_DEBUG_LOG("UL localUlQueue[%d][%d] int_ch->in=%d int_ch->out=%d int_num= %d \n", inst_id, k, int_ch->in, int_ch->out, int_num);
		PCIE_DEBUG_LOG("UL pCnt->ulDescNum[%d][%d] = %d ext_ch->epCntIng=%d pCnt->ulRxCounter[%d][%d]=%d \n", 
			inst_id, k, pCnt->ulDescNum[inst_id][k], ext_ch->epCntIng, inst_id, k, pCnt->ulRxCounter[inst_id][k]);	
		N =  int_num;
		#if 0		
        ext_num = pCnt->ulDescNum[inst_id][k] - ((ext_ch->epCntIng - pCnt->ulRxCounter[inst_id][k]) & pCnt->ulDescNum[inst_id][k]);	//此处需要对描述符取模，否则如果一直发送，但是没有接收，则会导致DMA无法启动	
        N = (int_num < ext_num) ? int_num : ext_num; //此处是判断Bar空间上的传输描述符个数是否够本次传输，取出本次传输的数据包的个数
		if (0 == N) 
		{
			PCIE_DEBUG_LOG("UL not free bar desc N = %d\n", N);			
			continue;
		}
		#endif		
        PCIE_DEBUG_LOG("UL INT_CH[%d][%d] = 0x%x  N = %d in = %d out = %d ext_num = %d \n", inst_id, k, (uint32_t)int_ch, N, int_ch->in, int_ch->out, ext_num);
        PCIE_DEBUG_LOG("UL pCnt->ulRxCounter[%d][%d]= %d  pCnt->ulTxCounter[%d][%d] = %d\n", inst_id, k, pCnt->ulRxCounter[inst_id][k], inst_id, k, pCnt->ulTxCounter[inst_id][k]);

        freed = ext_ch->dma.size - ext_ch->dma.in + ext_ch->dma.out;
		if (0 == freed) {
			PCIE_DEBUG_LOG("UL not free dma desc k = %d  in = %d out = %d free = %d, freed = %d\n", 
				            k, int_ch->in, int_ch->out, int_ch->free, freed);
			continue;
		}
		dma_idx = get_ul_dma_ch();	
		if (dma_idx < 0) {
			PCIE_ERROR_LOG("UL get_ul_dma_ch failed! dma_idx = %d\n", dma_idx);					
			continue;
		}	

		//PCIE_DEBUG_LOG("UL DMA idx = 0x%x  dmaThreads.in = 0x%x  dmaTrheads.out = 0x%x\n", dma_idx, ext_ch->dma.in, ext_ch->dma.out);
		dma_ch = pUcpPcieMemInfo->pDmaUlCh[dma_idx];
		ext_idx = ext_ch->epCntIng & ext_ch->mask;
		//ext_size = ext_ch->mask + 1;
		desc_hdr = (PcieTrafficDescriptor_t *)&pUcpPcieMemInfo->pUcpMemBar->desc.ul[inst_id][k];
		pcieOffset = 0;//pUcpQueueMemInfo->pLocalIntUlTraffic[k]->offset;
		ret = ucp_pcie_dma_chain_desc_init(pUcpPcieMemInfo->pWdmaChains[dma_idx], N);	
		if(ret != PCIE_OK)
		{
			continue;
		}
		//将数据包的地址和size信息填充到DMA desc中
		for (n = 0; n < N; n++) {
		    ext_ch->buf = (uint32_t *)msg_queue_ul_get_buf(inst_id, k);//ucp_queue_ul_get_buf(k);	//每调用一次，自动加一，由queue保存当前的buffer地址
			if (NULL != ext_ch->buf) {
            	PCIE_DEBUG_LOG("UL After PreGet buf = 0x%x int_ul_ch[%d][%d].out = %d\n", (uint32_t)ext_ch->buf, inst_id, k, int_ch->out);
			} else {
				PCIE_DEBUG_LOG("uL Change DMA chain num %d -->> %d\n", N, n);
				ucp_pcie_dma_chain_desc_init(pUcpPcieMemInfo->pRdmaChains[dma_idx], n);
				break;
			}			
			desc = (PcieTrafficDescriptor_t *)&desc_hdr[ext_idx];				
			if(!desc->phyAddr)
			{
				PCIE_ERROR_LOG("dstAddr is null, not start this transfer! UL DESC[0x%x]: dstAddr= 0x%x %x\n", ext_idx, H, L);
				n = 0;//src addr is null not start this transfer
				break;
			}
            H = desc->phyAddr >> 32;
            L = (uint32_t)desc->phyAddr;
            PCIE_DEBUG_LOG("UL DESC[0x%x]: dstAddr= 0x%x %x\n", ext_idx, H, L);
			//给描述符填充数据包长度
			attr = MSG_MBUF_ATTR(ext_ch->buf);
			desc->length = do_read(&attr->msgSize);//本次传输的数据包的长度，此处需要考虑RC侧对应申请的memory的空间是否满足		
			if(desc->length == 0)
			{
				PCIE_DEBUG_LOG("UL ul_ch[%d][%d] buf=0x%x  desc->length = %d\n", inst_id, k, ext_ch->buf, desc->length);			
				continue;
			}
			ext_idx = (ext_idx + 1) & ext_ch->mask;//准备下一个描述符

			//给描述符填充源地址/目的地址/长度信息
            src_addr = (uint64_t)ext_ch->buf + pcieOffset;
			PCIE_DEBUG_LOG("UL src_addr = 0x%x  desc->phyAddr = 0x%x\n", (uint32_t)src_addr, (uint64_t)desc->phyAddr);
            PCIE_DEBUG_LOG("UL DESC[0x%x]: len = %d type = 0x%x\n", ext_idx, desc->length, desc->type);
            ucp_pcie_wdma_chain_desc_fill(pUcpPcieMemInfo->pWdmaChains[dma_idx], n, src_addr, desc->phyAddr, desc->length);
		}
		
		if (0 == n) {
			PCIE_ERROR_LOG("UL send packet num is null! n = %d\n", n);	
			continue;
		}		
		ext_ch->epCntIng += n;//N;
		t_idx = ext_ch->dma.in & ext_ch->dma.mask;
		ext_ch->dma.in++;
		pCmplt = &ext_ch->dma.thread[t_idx];
		pCmplt->extInc = n;//N;
		pCmplt->intInc = n;//N;
		pCmplt->finished = 0;
		dma_ch->served_traffic.served_traffic_insid = inst_id;		
		dma_ch->served_traffic.served_traffic_queid = k;
		dma_ch->served_traffic.thread_idx = t_idx;
		dma_ch->finished = &pCmplt->finished;
		dma_ch->state = UCP_DMA_STATE_WORKING;

        wdma_desc_ch[dma_idx].ll = pUcpPcieMemInfo->pWdmaChains[dma_idx];
        wdma_desc_ch[dma_idx].local_irq_en = 1;
        wdma_desc_ch[dma_idx].remote_irq_en = 0;

		PCIE_DEBUG_LOG("UL Start DMA[%d] for Traffic[%d][%d]  ext_ch->dma.in =%d ext_ch->dma = %d \n", dma_idx, inst_id, k, ext_ch->dma.in, ext_ch->dma);	
		ucp_pcie_wdma_chain_start(dma_idx, &wdma_desc_ch[dma_idx]);
		//debug_dma_int(dma_idx, 0);
	}

	return 0;
}

//心跳机制，如果ep发生了重启，rc则会定期重新触发pcie rescan重新扫描设备
void pcie_heart_beat(void)
{
	static int heartbeatCount = 0;
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();
	int heartBeatVal = pUcpPcieMemInfo->pUcpMemBar->command[PCI_ENDPOINT_UCPEP_EP_STATUS];
	if(heartBeatVal != PCI_UCPEP_EP_HEARTBEAT)
	{
		pUcpPcieMemInfo->pUcpMemBar->command[PCI_ENDPOINT_UCPEP_EP_STATUS] = PCI_UCPEP_EP_HEARTBEAT;
		heartbeatCount = 0;
		pUcpPcieMemInfo->pUcpMemBar->status.devEnable = 1;		
		PCIE_DEBUG_LOG("pcie link heartbeat OK!\n");
	}
	else
	{
		//do nothing
		heartbeatCount++;
		if(heartbeatCount > PCI_HEARTBEAT_MAXTIME)
		{
			PCIE_DEBUG_LOG("pcie link losted!\n");
			heartbeatCount = 0;
			pUcpPcieMemInfo->pUcpMemBar->status.devEnable = 0;
			ucp_pcie_reset();
		}
	}
}

void ucp_pcie_worker(void)
{
	//ucp_pcie_reset();
    //pcie_heart_beat();	
	for (uint32_t inst_id=0; inst_id<MAX_INSTANCE_NUM; inst_id++) {
	    ucp_pcie_dl_worker(inst_id);
	    ucp_pcie_ul_worker(inst_id);
	}
    return;
}

void ucp_testSpeed_pcie_worker(void)
{
    ucp_pcie_reset();
	for (uint32_t inst_id=0; inst_id<MAX_INSTANCE_NUM; inst_id++) 
	{
	    ucp_pcie_dl_worker(inst_id);
    	ucp_pcie_ul_worker(inst_id);
	}
	return;
}


