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

#include <stddef.h>
//#include <stdatomic.h>
#include "inter_vector.h"
#include "dw_pcie_ep.h"
#include "ucp_pcie_traffic.h"
#include "ucp_printf.h"
#include "ucp_drv_common.h"
#include "ucp_tick.h"

DwPcieEp_t gEp;

DwPcieEp_t* get_pcie_ep_dev(void)
{
	return (DwPcieEp_t *)&gEp;
}

static inline uint32_t dw_pcie_ep_get_bit(uint32_t *map, uint32_t pos) {
    return map[pos];//(*map) & (1U << pos);//
}

static inline void dw_pcie_ep_set_bit(uint32_t *map, uint32_t pos) {
    //*map |= (1U << pos);
	map[pos] = 1;
}

static inline void dw_pcie_ep_clear_bit(uint32_t *map, uint32_t pos) 
{
    //*map &= ~(1U << pos);
	map[pos] = 0;
}

uint32_t dw_pcie_dma_busy(DwPcieEpDma_t* dma, uint8_t ch) {
    return dw_pcie_ep_get_bit((uint32_t *)&dma->ch_map, (uint32_t)ch);
}

static inline void dw_pcie_dma_set_busy(DwPcieEpDma_t* dma, uint8_t ch) 
{
    dw_pcie_ep_set_bit((uint32_t *)&dma->ch_map, (uint32_t)ch);
	//PCIE_ERROR_LOG("called after dw_pcie_dma_set_busy  dma->ch_map = 0x%x\n", dma->ch_map);
}

static inline void dw_pcie_dma_clear_busy(DwPcieEpDma_t *dma, uint8_t ch) 
{
    dw_pcie_ep_clear_bit((uint32_t *)&dma->ch_map, (uint32_t)ch);
}


int32_t ucp_pcie_dma_chain_desc_init(PcieDmaBuffer_t* buffer, uint32_t length) 
{
	uint32_t size = length + 1;
	if (size > (MAX_NODE_NUM_DMA_CHAIN)){
		PCIE_DEBUG_LOG("ucp_pcie_dma_chain_desc_init failed! NoOfDesc[%d] is larger than MAX_NODE_NUM_DMA_CHAIN[%d]!\n", size, MAX_NODE_NUM_DMA_CHAIN);
		return -PCIE_EINVAL;
	}

	DwPcieDmaLinkListNode_t *ll_desc = (DwPcieDmaLinkListNode_t *)(buffer->buffer);
    for (int i = 0; i <= length; i++) {
        ll_desc[i].flags = 0;
    }
	//设置Link List Element，也就是Link list的最后一个元素	
    ll_desc[length].flags |= DW_PCIE_EP_DMA_LL_CB | DW_PCIE_EP_DMA_LL_LLP;
    ll_desc[length].src_addr = (uint64_t)(buffer->buffer);
    buffer->used = size;
    return PCIE_OK;
}

int32_t ucp_pcie_rdma_chain_desc_fill(PcieDmaBuffer_t* buffer, uint32_t idx,local_addr_t cpu_addr, pcie_addr_t pci_addr, uint32_t size) 
{
    uint32_t len = buffer->used;
    if (idx >= (len - 1)) {
        PCIE_DEBUG_LOG("ucp_pcie_fill_rdma_chain_desc failed !idx %d is larger than length %d!\n", idx, len-1);
        return -1;
    }
	
    DwPcieDmaLinkListNode_t *ll_desc = (DwPcieDmaLinkListNode_t *)(buffer->buffer);
    ll_desc[idx].size = size;
    ll_desc[idx].dst_addr = cpu_addr;
    ll_desc[idx].src_addr = pci_addr;
	
    return 0;
}

int32_t ucp_pcie_wdma_chain_desc_fill(PcieDmaBuffer_t* buffer, uint32_t idx,local_addr_t cpu_addr, pcie_addr_t pci_addr, uint32_t size) 
{
    uint32_t len = buffer->used;
    if (idx >= (len - 1)) {
        PCIE_DEBUG_LOG("ucp_pcie_fill_wdma_chain_desc failed !idx %d is larger than length %d!\n", idx, len-1);
        return -1;
    }
	
    DwPcieDmaLinkListNode_t *ll_desc = (DwPcieDmaLinkListNode_t *)(buffer->buffer);
    ll_desc[idx].size = size;
    ll_desc[idx].dst_addr = pci_addr;
    ll_desc[idx].src_addr = cpu_addr;
	
    return 0;
}

int32_t ucp_pcie_rdma_chain_start(uint8_t ch, DwPcieEpDmaChDesc_t* desc)
{
	DwPcieEp_t *ep = get_pcie_ep_dev();
	uint32_t rdma_busy = dw_pcie_dma_busy(&ep->rdma, ch);
    if (rdma_busy) 
	{
		PCIE_ERROR_LOG("error rdma chain is busy! ch = %d rdma_busy = %d \n", ch, rdma_busy);	
        return -PCIE_EBUSY;
    }
    dw_pcie_dma_set_busy(&ep->rdma, ch);

    //Mask may be configed by rc
    uint32_t int_mask = dw_pcie_read_rdma_status(DW_PCIE_DMA_UNR_INT_MASK_OFF);
    if (desc->local_irq_en) {
        int_mask &= ~(0x1 << ch);
        int_mask &= ~((0x1 << ch) << 16);
    }
    if (desc->remote_irq_en) {
        int_mask &= ~(0x1 << ch);
        int_mask &= ~((0x1 << ch) << 16);
    }
    dw_pcie_write_rdma_status(DW_PCIE_DMA_UNR_INT_MASK_OFF, int_mask);

    if (desc->ll == NULL) 
	{
		PCIE_ERROR_LOG("error rdma desc->ll is null NULL!\n");
        return -1;
    }
	
    //uint32_t ctrl1 = 0x4000008;//0x04000200;
    uint32_t status_msi_off = DW_PCIE_RDMA_STATUS_MSI_REG_OFF;
    uint32_t msg_data = dw_pcie_read_rdma_status(status_msi_off + DW_PCIE_DMA_STATUS_MSI_UNR_CH_DATA_OFF(ch));
    if (ch & 0x1) {
        msg_data = ((uint32_t)(desc->msg_data) << 16) | (msg_data & 0xffff);
    } else {
        msg_data = desc->msg_data | ((msg_data >> 16) << 16);
    }
    dw_pcie_write_rdma_status(status_msi_off + DW_PCIE_DMA_STATUS_MSI_UNR_CH_DATA_OFF(ch), msg_data);

    DwPcieDmaLinkListNode_t *ll_desc = (DwPcieDmaLinkListNode_t *)(desc->ll->buffer);
    uint32_t len = desc->ll->used;
    if (desc->local_irq_en) {
        ll_desc[len-2].flags |= DW_PCIE_EP_DMA_LL_LIE;
    }
    if (desc->remote_irq_en) {
        ll_desc[len-2].flags |= DW_PCIE_EP_DMA_LL_RIE;
    }

    uint32_t llaie_off = DW_PCIE_RDMA_UNR_LL_ERR_EN_OFF;
    uint32_t llaie = dw_pcie_read_rdma_status(llaie_off);
    //llaie |= ~((0x1 << ch) << 16);
    llaie |= ((0x1 << ch) << 16);
    dw_pcie_write_rdma_status(llaie_off, llaie);

   // UCP_PRINT_LOG("rdma_chain ll desc ll_desc->flags = 0x%x\n", ll_desc->flags);
	DMA_CH_CONTROL1_OFF_RD_0_REG_T rdrctr1 = {0};
     rdrctr1.b.LIE = 1;
     rdrctr1.b.CCS = 0;
     rdrctr1.b.LLE = 1;	
	 
    dw_pcie_write_rdma_ch(ch, DW_PCIE_DMA_CH_UNR_CTRL1_OFF, rdrctr1.v);//ctrl1);
    dw_pcie_write_rdma_ch(ch, DW_PCIE_DMA_CH_UNR_LLP_LOW_OFF, (local_addr_t)(desc->ll->bufByPcie));
    dw_pcie_write_rdma_ch(ch, DW_PCIE_DMA_CH_UNR_LLP_HIGH_OFF, (local_addr_t)0x0);
    dw_pcie_write_rdma_ctrl(DW_PCIE_DMA_UNR_DOORBELL_OFF, ch);
	return 0;
}

int32_t ucp_pcie_wdma_chain_start(uint8_t ch, DwPcieEpDmaChDesc_t* desc)
{
	DwPcieEp_t *ep = get_pcie_ep_dev();
	#if 1
    if (dw_pcie_dma_busy(&ep->wdma, ch)) 
	{
		PCIE_DEBUG_LOG("error wdma is busy!\n");
        return -PCIE_EBUSY;
    }
	#endif
    dw_pcie_dma_set_busy(&ep->wdma, ch);

    //Mask may be configed by rc
    uint32_t int_mask = dw_pcie_read_wdma_status(DW_PCIE_DMA_UNR_INT_MASK_OFF);
    if (desc->local_irq_en) {
        int_mask &= ~(0x1 << ch);
        int_mask &= ~((0x1 << ch) << 16);
    }
    if (desc->remote_irq_en) {
        int_mask &= ~(0x1 << ch);
        int_mask &= ~((0x1 << ch) << 16);
    }
    dw_pcie_write_wdma_status(DW_PCIE_DMA_UNR_INT_MASK_OFF, int_mask);

    if (desc->ll == NULL) {
		PCIE_DEBUG_LOG("error wdma desc->ll is null!\n");
        return -1;
    }

   // uint32_t ctrl1 = 0x4000008;//0x04000200;
    uint32_t status_msi_off = DW_PCIE_WDMA_STATUS_MSI_REG_OFF;
    uint32_t msg_data = dw_pcie_read_wdma_status(status_msi_off + DW_PCIE_DMA_STATUS_MSI_UNR_CH_DATA_OFF(ch));
    if (ch & 0x1) {
        msg_data = ((uint32_t)(desc->msg_data) << 16) | (msg_data & 0xffff);
    } else {
        msg_data = desc->msg_data | ((msg_data >> 16) << 16);
    }
    dw_pcie_write_wdma_status(status_msi_off + DW_PCIE_DMA_STATUS_MSI_UNR_CH_DATA_OFF(ch), msg_data);

    DwPcieDmaLinkListNode_t *ll_desc = (DwPcieDmaLinkListNode_t *)(desc->ll->buffer);
    uint32_t len = desc->ll->used;
    if (desc->local_irq_en) {
        ll_desc[len-2].flags |= DW_PCIE_EP_DMA_LL_LIE;
    }
    if (desc->remote_irq_en) {
        ll_desc[len-2].flags |= DW_PCIE_EP_DMA_LL_RIE;
    }

    uint32_t llaie_off = DW_PCIE_WDMA_UNR_LL_ERR_EN_OFF;
    uint32_t llaie = dw_pcie_read_wdma_status(llaie_off);
    //llaie |= ~((0x1 << ch) << 16);    
    llaie |= ((0x1 << ch) << 16);    
    dw_pcie_write_wdma_status(llaie_off, llaie);

	 DMA_CH_CONTROL1_OFF_WRCH_0_REG_T wrctr1 = {0};
	  wrctr1.b.LIE = 1;
	  wrctr1.b.CCS = 0;
	  wrctr1.b.LLE = 1;  

    dw_pcie_write_wdma_ch(ch, DW_PCIE_DMA_CH_UNR_CTRL1_OFF, wrctr1.v);//ctrl1);
    dw_pcie_write_wdma_ch(ch, DW_PCIE_DMA_CH_UNR_LLP_LOW_OFF, (local_addr_t)(desc->ll->bufByPcie));
    dw_pcie_write_wdma_ch(ch, DW_PCIE_DMA_CH_UNR_LLP_HIGH_OFF, (local_addr_t)0x0);

    dw_pcie_write_wdma_ctrl(DW_PCIE_DMA_UNR_DOORBELL_OFF, ch);
	
    return 0;
}

static int32_t pcie_rdma_ch_handler(uint8_t ch)
{
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info(); 
	pUcpPcieMemInfo->pDmaDlCh[ch]->state = UCP_DMA_STATE_FINISHED;

    return 0;
}
static int32_t pcie_wdma_ch_handler(uint8_t ch)
{
    //UCP_PRINT_LOG("ch = %u\n", ch);
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info(); 
	pUcpPcieMemInfo->pDmaUlCh[ch]->state = UCP_DMA_STATE_FINISHED;
    return 0;
}

static uint32_t dw_pcie_ep_rdma_ch_get_err_status(uint8_t ch) {
    uint32_t flags = 0;
    uint32_t err_offset = DW_PCIE_RDMA_UNR_INT_ERR_OFF;
    uint32_t err = dw_pcie_read_rdma_status(err_offset);
    uint32_t app_err = err & 0xffff;
    if (app_err & (1 << ch)) {
        flags |= DW_PCIE_DMA_APP_ERR;
    }
    uint32_t linklist_err = err >> 16;
    if (linklist_err & (1 << ch)) {
        flags |= DW_PCIE_DMA_LINKLIST_ERR;
    }

    {
        err = dw_pcie_read_rdma_status(DW_PCIE_RDMA_UNR_INT_ERR1_OFF);
        uint32_t req_err = err & 0xff;
        if (req_err & (1 << ch)) {
            flags |= DW_PCIE_DMA_UNSUPPORTED_REQ_ERR;
        }
        uint32_t cpl_abort_err = (err >> 8) & 0xff;
        if (cpl_abort_err & (1 << ch)) {
            flags |= DW_PCIE_DMA_CPL_ABORT_ERR;
        }
        uint32_t cpl_timeout_err = (err >> 16) & 0xff;
        if (cpl_timeout_err & (1 << ch)) {
            flags |= DW_PCIE_DMA_CPL_TIMEOUT_ERR;
        }
        uint32_t data_poision_err = (err >> 24) & 0xff;
        if (data_poision_err & (1 << ch)) {
            flags |= DW_PCIE_DMA_DATA_POISION_ERR;
        }
    }
    return flags;
}

static uint32_t dw_pcie_ep_wdma_ch_get_err_status(uint8_t ch) {
    uint32_t flags = 0;
    uint32_t err_offset = DW_PCIE_WDMA_UNR_INT_ERR_OFF;
    uint32_t err = dw_pcie_read_wdma_status(err_offset);
    uint32_t app_err = err & 0xffff;
    if (app_err & (1 << ch)) {
        flags |= DW_PCIE_DMA_APP_ERR;
    }
    uint32_t linklist_err = err >> 16;
    if (linklist_err & (1 << ch)) {
        flags |= DW_PCIE_DMA_LINKLIST_ERR;
    }

    return flags;
}



int32_t dw_pcie_ep_rdma_ch_finish(uint8_t ch, uint32_t *remain, uint32_t *err_flags) 
{
    int32_t ret = PCIE_OK;
    volatile uint32_t status = 0;
    volatile uint32_t clear = 0;
		
	int counter = 0;
    do {
        status = DW_PCIE_DMA_CH_STATUS(dw_pcie_read_rdma_ch(ch, DW_PCIE_DMA_CH_UNR_CTRL1_OFF));
		counter++;
		if(counter > LOOPMAXTIMES)
		{
			PCIE_ERROR_LOG("rdma ch states is still running and exceed the max retry times!\n");
			break;
		}	
    } while(status != DW_PCIE_DMA_CH_HALTED && status != DW_PCIE_DMA_CH_STOPPED);//(status == DW_PCIE_DMA_CH_RUNNING); //


	//read dma remain transfer size 
	*remain = dw_pcie_read_rdma_ch(ch, DW_PCIE_DMA_CH_UNR_SIZE_OFF);	
    if (status == DW_PCIE_DMA_CH_HALTED) {
        *err_flags = dw_pcie_ep_rdma_ch_get_err_status(ch);
		clear = dw_pcie_read_rdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF);
    	//clear &= ~((1 << ch) << 16);
    	clear |= ((1 << ch) << 16);
		dw_pcie_write_rdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF, clear);
        ret = -PCIE_EABORT;
		PCIE_DEBUG_LOG("rdma DMA ch[0x%x] About status = 0x%x\n",ch, status);			
    } else {
        *err_flags = 0;
		clear = dw_pcie_read_rdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF);
    	//clear &= ~(1 << ch);		
		clear |= (1 << ch); 			
		dw_pcie_write_rdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF, clear);
    }
	
	DwPcieEp_t* ep = get_pcie_ep_dev();
    dw_pcie_dma_clear_busy((DwPcieEpDma_t *)&ep->rdma, ch);

    return ret;
}

static int32_t dw_pcie_ep_wdma_ch_finish(uint8_t ch, uint32_t *remain, uint32_t *err_flags) 
{
    int32_t ret = PCIE_OK;
    volatile uint32_t status = 0;
    volatile uint32_t clear = 0;
	int counter = 0;//防止死循环
    do {
        status = DW_PCIE_DMA_CH_STATUS(dw_pcie_read_wdma_ch(ch, DW_PCIE_DMA_CH_UNR_CTRL1_OFF));
		counter++;
		if(counter > LOOPMAXTIMES)
		{
			PCIE_DEBUG_LOG("wdma ch states is still running and exceed the max retry times!\n");		
			break;
		}
    } while(status != DW_PCIE_DMA_CH_HALTED && status != DW_PCIE_DMA_CH_STOPPED);//(status == DW_PCIE_DMA_CH_RUNNING); 
	
	*remain = dw_pcie_read_wdma_ch(ch, DW_PCIE_DMA_CH_UNR_SIZE_OFF);
    if (status == DW_PCIE_DMA_CH_HALTED) {
        *err_flags = dw_pcie_ep_wdma_ch_get_err_status(ch);
		clear = dw_pcie_read_wdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF);
		//clear &= ~((1 << ch) << 16);
    	clear |= ((1 << ch) << 16);
        dw_pcie_write_wdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF, clear);		
        ret = -PCIE_EABORT;
		PCIE_DEBUG_LOG("wdma DMA ch[0x%x] About status = 0x%x\n",ch, status);					
    } else {
        *err_flags = 0;
		clear = dw_pcie_read_wdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF);
    	//clear &= ~(1 << ch);		
    	clear |= (1 << ch);		
        dw_pcie_write_wdma_status(DW_PCIE_DMA_UNR_INT_CLEAR_OFF, clear);	
    }

	DwPcieEp_t* ep = get_pcie_ep_dev();
    dw_pcie_dma_clear_busy((DwPcieEpDma_t *)&ep->wdma, ch);	
    return ret;
}

static int32_t dw_pcie_ep_rdma_local_int_handler(uint8_t ch) 
{
    int32_t ret = 0;
    uint32_t remain = 0;
    uint32_t err_flags = 0;
    ret = dw_pcie_ep_rdma_ch_finish(ch, &remain, &err_flags);
	if(ret != PCIE_OK)
	{
		PCIE_ERROR_LOG("dw_pcie_ep_rdma_ch_finish error! ret = %d\n", ret);
		//return ret;
	}	
    DwPcieEp_t* ep = get_pcie_ep_dev();
    if (ep->rdma.local_int_handler != NULL) 
	{
    	ret = ep->rdma.local_int_handler(ch);
    }
	
    return ret;
}

static int32_t dw_pcie_ep_wdma_local_int_handler(uint8_t ch) 
{
    int32_t ret = 0;
    uint32_t remain = 0;
    uint32_t err_flags = 0;
    ret = dw_pcie_ep_wdma_ch_finish(ch, &remain, &err_flags);
	if(ret != PCIE_OK)
	{
		PCIE_ERROR_LOG("dw_pcie_ep_wdma_ch_finish error! ret = %d\n", ret);
		//return ret;
	}
    DwPcieEp_t* ep = get_pcie_ep_dev();
    if (ep->wdma.local_int_handler != NULL) {
    	ret = ep->wdma.local_int_handler(ch);
    }
	
    return ret;
}

static int32_t pcie_dma_handler()//uint32_t irq
{
	uint32_t i = 0;
	uint32_t temp = 0;	
	uint32_t pcie_ip_rdma_int_status = 0;
	//dw_pcie_read_dma_int_reg(PCIE_PIC_INTR_OFFSET);
	uint32_t edma_int = dw_pcie_read_dma_int_reg(PCIE_EDMA_INTR_OFFSET);

	//smart_irq_disable(DMA_PIC_INT_NUM);//中断服务程序中，先禁止中断

	//[5:0]dma write channel int
	edma_int = edma_int & 0xfff;
	int counter = 0;//防止死循环
	while(1) {
		counter++;
		if(counter > LOOPMAXTIMES)
		{
			PCIE_ERROR_LOG("pcie_dma_handler loop error! counter = %d\n", counter);			
			break;
		}
	
		for(i=0; i<MAX_CH_NUM_DW_DMA; i++) 
		{
			temp = (edma_int >> i) & 0x1;
			if (temp) 
			{
				dw_pcie_ep_wdma_local_int_handler(i);
			}
		}

		pcie_ip_rdma_int_status = dw_pcie_read_dma_reg(DMA_READ_INT_STATUS_OFF);
		pcie_ip_rdma_int_status = pcie_ip_rdma_int_status&0xFF;
		//[11:6]dma read channel int	
		edma_int = edma_int >> MAX_CH_NUM_DW_DMA;
		//PCIE_DEBUG_LOG("pcie_dma_handler pcie_ip_rdma_int_status = %d, edma_int = %d\n", pcie_ip_rdma_int_status, edma_int);
		for(i=0; i<MAX_CH_NUM_DW_DMA; i++) 
		{
			temp = (edma_int >> i) & 0x1;
			if (temp) 
			{
				dw_pcie_ep_rdma_local_int_handler(i);
			}
		}

		edma_int = dw_pcie_read_dma_int_reg(PCIE_EDMA_INTR_OFFSET);
		edma_int = edma_int & 0xfff;		
		if (0 == edma_int) 
		{
			break;
		}
		else
		{
			PCIE_DEBUG_LOG("pcie_dma_handler intrupt not cleared! edma_int = 0x%x\n", edma_int);			
		}
	}
    //clear_irq(irq);
	//smart_irq_enable(DMA_PIC_INT_NUM);//中断服务程序中，先禁止中断

	return 0;
}

int32_t register_int_handler(uint32_t vector, irq_handler handler)
{
	int apeId = get_core_id(); // Get_ApcId(); //
	PCIE_DEBUG_LOG("register_int_handler apeId = %d\n", apeId);
	int ret  = 0;
    ret = smart_irq_init(apeId);
	if (0 != ret)
	{
		PCIE_DEBUG_LOG("smart_irq_init failed ret = %d\n", ret);
	}	
	//smart_irq_init(apeId);
	smart_irq_request(vector,handler);
	return 0;
}

//使能dbi配置只读寄存器
static void dw_pcie_dbi_ro_wr_en()
{
	uint32_t reg = PCIE_MISC_CONTROL_1_OFF;
	uint32_t val = dw_pcie_read_dbi_reg(reg);
	val |= PCIE_DBI_RO_WR_EN;
	dw_pcie_write_dbi_reg(reg, val);
}

//禁止dbi配置只读寄存器
static void dw_pcie_dbi_ro_wr_en_dis()
{
	uint32_t reg = PCIE_MISC_CONTROL_1_OFF;
	int val = dw_pcie_read_dbi_reg(reg);
	val &= ~PCIE_DBI_RO_WR_EN;
	dw_pcie_write_dbi_reg(reg, val);
}

//找到空闲的位图的索引号
int32_t dw_pcie_get_free_iatu_index(unsigned char *bitmap)
{
	int index = 0;
	int ret = -1;
	for(index = 0; index < 256; index++)
	{
		ret = dw_pcie_ep_get_bit((uint32_t *)bitmap, index);
		if(!ret)
		{
			return index;
		}
	}
	return ret;
}

//设置已经使用的位图的索引号
void dw_pcie_set_iatu_index(unsigned char *bitmap, int index)
{
	dw_pcie_ep_set_bit((uint32_t *)bitmap, index);
}

//配置bar空间
int dw_pcie_ep_set_bar(DwPcieEp_t* ep)
{
//	int type = 0;
	int retries = 0;
	int val = 0;
	int region = 0;
	int ret = 0;
	
	//set iatu 
	region = dw_pcie_get_free_iatu_index(ep->ib_window_map);
	dw_pcie_write_iatu_reg(region, PCIE_ATU_UNR_LOWER_TARGET, ep->bar[BAR_1].phy_addr);
	val = dw_pcie_read_iatu_reg(region, PCIE_ATU_UNR_LOWER_TARGET);
	dw_pcie_write_iatu_reg(region, PCIE_ATU_UNR_UPPER_TARGET, 0x00000000);
	dw_pcie_write_iatu_reg(region, PCIE_ATU_UNR_REGION_CTRL1, ep->bar[BAR_1].mem_tpye);//bar type is memory
	dw_pcie_write_iatu_reg(region, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_ENABLE|PCIE_ATU_BAR_MODE_ENABLE|(ep->bar[BAR_1].number << 8));
	/* 确保ATU 在做其它配置前生效        */
	for(retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++)
	{
		val = dw_pcie_read_iatu_reg(region, PCIE_ATU_UNR_REGION_CTRL2);
		if(val & PCIE_ATU_ENABLE)
		{
			ret = PCIE_OK;
			break;
		}
		delay_us(LINK_WAIT_IATU);
		ret = -PCIE_EBUSY;
	}
	if(ret == PCIE_OK)
	{
		dw_pcie_set_iatu_index(ep->ib_window_map, region);
		//配置bar size 和bar类型，此处需要先使能设置只读寄存器
		dw_pcie_dbi_ro_wr_en();
		dw_pcie_write_shandow_reg(PCIE_BASE_ADDRESSS_1, (ep->bar[BAR_1].size - 1));
		dw_pcie_write_dbi_reg(PCIE_BASE_ADDRESSS_1, ep->bar[BAR_1].addr_type);
		dw_pcie_dbi_ro_wr_en_dis();
	}
	else
	{
		PCIE_DEBUG_LOG("set iatu failed! the iatu is busy!\n");
		//return ret;
	}
	return ret;
}



uint32_t pcie_getMsgLAdd(int interrupt_num)
{
	uint32_t val;
	uint32_t offset;
	
	offset = BAR0_BASE_OF_DBI + MSIX_TABLE_OFF +interrupt_num * PCI_MSIX_ENTRY_SIZE 
		+ PCI_MSIX_ENTRY_LOWER_ADDR;
	val = dw_pcie_read_dbi_reg(offset);
	return val;
}
uint32_t pcie_getMsgHAdd(int interrupt_num)
{
	uint32_t val;
	uint32_t offset;
	
	offset = BAR0_BASE_OF_DBI + MSIX_TABLE_OFF +interrupt_num * PCI_MSIX_ENTRY_SIZE + 
		PCI_MSIX_ENTRY_UPPER_ADDR;
	val = dw_pcie_read_dbi_reg(offset);

	return val;
}

uint32_t pcie_getMsgData(int interrupt_num)
{
	uint32_t val;
	uint32_t offset;
	
	offset = BAR0_BASE_OF_DBI + MSIX_TABLE_OFF +interrupt_num * PCI_MSIX_ENTRY_SIZE + 
		PCI_MSIX_ENTRY_DATA;
	val = dw_pcie_read_dbi_reg(offset);
	
	return val;	

}


//wdma的描述符由本端配置基础寄存器，地址寄存器由对端配置
int pci_endpoint_dma_write_init(int islocalirq)
{
	DMA_WRITE_ENGINE_EN_REG_T wengen = {0};
	wengen.b.DMA_WRITE_ENGINE = 1;
	dw_pcie_write_dma_reg(DMA_WRITE_ENGINE_EN_OFF, wengen.v);//0x1);  /*0x2BC000c*/
	if(islocalirq)
	{

	}
	else
	{
	
		dw_pcie_write_dma_reg(DMA_WRITE_DONE_IMWR_LOW_OFF, pcie_getMsgLAdd(DMA_WRITE_DONE_MSIX_NUM_CH0)); 
		dw_pcie_write_dma_reg(DMA_WRITE_DONE_IMWR_HIGH_OFF, pcie_getMsgHAdd(DMA_WRITE_DONE_MSIX_NUM_CH0));
		dw_pcie_write_dma_reg(DMA_WRITE_ABORT_IMWR_LOW_OFF, pcie_getMsgLAdd(DMA_WRITE_ABORT_MSIX_NUM_CH0));
		dw_pcie_write_dma_reg(DMA_WRITE_ABORT_IMWR_HIGH_OFF, pcie_getMsgHAdd(DMA_WRITE_ABORT_MSIX_NUM_CH0));
		dw_pcie_write_dma_reg(DMA_WRITE_CH01_IMWR_DATA_OFF, pcie_getMsgData(DMA_WRITE_DONE_MSIX_NUM_CH0));
	}
	DMA_WRITE_CHANNEL_ARB_WEIGHT_LOW_REG_T  wcharbwgtlow = {0};
	wcharbwgtlow.b.WRITE_CHANNEL0_WEIGHT = 1;
	wcharbwgtlow.b.WRITE_CHANNEL1_WEIGHT = 1;
	wcharbwgtlow.b.WRITE_CHANNEL2_WEIGHT = 1;
	wcharbwgtlow.b.WRITE_CHANNEL3_WEIGHT = 1;		
	dw_pcie_write_dma_reg(DMA_WRITE_CHANNEL_ARB_WEIGHT_LOW_OFF, wcharbwgtlow.v);//0x8421);
	DMA_WRITE_CHANNEL_ARB_WEIGHT_HIGH_REG_T  wcharbwgthigh = {0};
	wcharbwgthigh.b.WRITE_CHANNEL4_WEIGHT = 1;//0x1f
	wcharbwgthigh.b.WRITE_CHANNEL5_WEIGHT = 1;
	wcharbwgthigh.b.WRITE_CHANNEL6_WEIGHT = 1;
	wcharbwgthigh.b.WRITE_CHANNEL7_WEIGHT = 1;		
	dw_pcie_write_dma_reg(DMA_WRITE_CHANNEL_ARB_WEIGHT_HIGH_OFF, wcharbwgthigh.v);//0x843f);


	DMA_WRITE_INT_MASK_REG_T wrintmask = {0};
	if(islocalirq)
	{
		wrintmask.v = 0;
		dw_pcie_write_dma_reg(DMA_WRITE_INT_MASK_OFF, wrintmask.v);//0);
	}	
	else
	{
		/*disable channel 0 writedone lcoal int*/		
		wrintmask.b.WR_DONE_INT_MASK = 1;
		dw_pcie_write_dma_reg(DMA_WRITE_INT_MASK_OFF, wrintmask.v);//1);
	}
	DMA_WRITE_LINKED_LIST_ERR_EN_REG_T wrllerren = {0};
	wrllerren.b.WR_CHANNEL_LLRAIE = 0xf;
	wrllerren.b.WR_CHANNEL_LLLAIE = 0xf;	
	dw_pcie_write_dma_reg(DMA_WRITE_LINKED_LIST_ERR_EN_OFF, wrllerren.v);//0xf000f);

	return PCIE_OK;
}


/* no remote irq make this func can be called when peset come, x86-driver-install is no needed   */
int pci_endpoint_dma_read_init(int islocalirq)
{
	//使能wdma传输引擎
	DMA_READ_ENGINE_EN_REG_T rengen = {0};
	rengen.b.DMA_READ_ENGINE = 1;
	
	dw_pcie_write_dma_reg(DMA_READ_ENGINE_EN_OFF, rengen.v);//0x1);/*0x2BC002c*/
	if(islocalirq)
	{
		
	}
	else
	{
		/*we just set DMA_CH_CONTROL1_OFF_RDCH_0 to 0x308 can not stop readdone remote irq, why?*/
		dw_pcie_write_dma_reg(DMA_READ_DONE_IMWR_LOW_OFF, pcie_getMsgLAdd(DMA_READ_DONE_MSIX_NUM_CH0));
		dw_pcie_write_dma_reg(DMA_READ_DONE_IMWR_HIGH_OFF, pcie_getMsgHAdd(DMA_READ_DONE_MSIX_NUM_CH0));
		dw_pcie_write_dma_reg(DMA_READ_ABORT_IMWR_LOW_OFF, pcie_getMsgLAdd(DMA_READ_BAORT_MSIX_NUM_CH0));
		dw_pcie_write_dma_reg(DMA_READ_ABORT_IMWR_HIGH_OFF, pcie_getMsgHAdd(DMA_READ_BAORT_MSIX_NUM_CH0));
		dw_pcie_write_dma_reg(DMA_READ_CH01_IMWR_DATA_OFF, pcie_getMsgData(DMA_READ_DONE_MSIX_NUM_CH0));
	}
	DMA_READ_CHANNEL_ARB_WEIGHT_LOW_REG_T  rcharbwgtlow = {0};
	rcharbwgtlow.b.READ_CHANNEL0_WEIGHT = 1;
	rcharbwgtlow.b.READ_CHANNEL1_WEIGHT = 1;
	rcharbwgtlow.b.READ_CHANNEL2_WEIGHT = 1;
	rcharbwgtlow.b.READ_CHANNEL3_WEIGHT = 1;	
	dw_pcie_write_dma_reg(DMA_READ_CHANNEL_ARB_WEIGHT_LOW_OFF, rcharbwgtlow.v);//0x8421);
	
	DMA_READ_CHANNEL_ARB_WEIGHT_HIGH_REG_T  rcharbwgthigh = {0};
	rcharbwgthigh.b.READ_CHANNEL4_WEIGHT = 1;//0x1f
	rcharbwgthigh.b.READ_CHANNEL5_WEIGHT = 1;
	rcharbwgthigh.b.READ_CHANNEL6_WEIGHT = 1;
	rcharbwgthigh.b.READ_CHANNEL7_WEIGHT = 1;	
	dw_pcie_write_dma_reg(DMA_READ_CHANNEL_ARB_WEIGHT_HIGH_OFF, rcharbwgthigh.v);//0x843f);

	DMA_READ_INT_MASK_REG_T rdintmask = {0};	
	if(islocalirq)
	{
		dw_pcie_write_dma_reg(DMA_READ_INT_MASK_OFF, rdintmask.v);//0x0);
	}
	else
	{
		dw_pcie_write_dma_reg(DMA_READ_INT_MASK_OFF, 0x1);
	}
	DMA_READ_LINKED_LIST_ERR_EN_REG_T rllerren = {0};
	rllerren.b.RD_CHANNEL_LLRAIE = 0xf;
	rllerren.b.RD_CHANNEL_LLLAIE = 0xf;	
	dw_pcie_write_dma_reg(DMA_READ_LINKED_LIST_ERR_EN_OFF, rllerren.v);//0xf000f);

	return PCIE_OK;
}


//ep初始化
void pcie_ep_drv_init(void)
{
	DwPcieEp_t* ep = get_pcie_ep_dev();

	ep->rdma.num_channels = MAX_CH_NUM_DW_DMA;	
	//ep->rdma.ch_map = 0;
	memset(ep->rdma.ch_map, 0x00, sizeof(ep->rdma.ch_map));
	ep->rdma.irq_vec = DMA_PIC_INT_NUM;		
	ep->rdma.local_int_handler = pcie_rdma_ch_handler;
	
	ep->wdma.num_channels = MAX_CH_NUM_DW_DMA;	
	//ep->wdma.ch_map = 0;
	memset(ep->wdma.ch_map, 0x00, sizeof(ep->wdma.ch_map));
	
	ep->wdma.irq_vec = DMA_PIC_INT_NUM;		
	ep->wdma.local_int_handler = pcie_wdma_ch_handler;	

	pci_endpoint_dma_read_init(1);
	pci_endpoint_dma_write_init(1);

	PCIE_DEBUG_LOG("dw_pcie_ep_init, write intrrpt counter\n");	
	//debug_write(0x00, 0x00);
	
	register_int_handler(DMA_PIC_INT_NUM, (irq_handler)pcie_dma_handler);
	#if 0
    //配置bar空间
	ep->bar[BAR_1].number = BAR_1;
	ep->bar[BAR_1].addr_type = PCI_BASE_ADDRESS_MEM_TYPE_32;//32位地址
	UcpPcieEpMemInfo_t* pUcpPcieMemInfo = get_ucp_pcie_mem_info();	
	ep->bar[BAR_1].phy_addr = (uint32_t)pUcpPcieMemInfo->pUcpMemBar;
	ep->bar[BAR_1].mem_tpye = PCIE_ATU_TYPE_MEM;//memory空间
	ep->bar[BAR_1].size = MAX_MEM_BAR_SIZE;
	ep->num_ob_window = 2;
	ep->num_ib_window = 6;
	memset(ep->ib_window_map, 0x00, 64);
	memset(ep->ob_window_map, 0x00, 64);
	dw_pcie_ep_set_bar(ep);
	#endif
	return;
}



//dma 重配
void pcie_ep_dma_recfg(void)
{
	pci_endpoint_dma_read_init(1);
	pci_endpoint_dma_write_init(1);
	PCIE_ERROR_LOG("pcie_ep_dma_recfg, finished!\n");		
	return;
}

