/**
*
* This function sets up the TX channel of a DMA engine to be ready for packet
* transmission
*
* @param    AxiDmaInstPtr is the instance pointer to the DMA engine.
*
* @return   XST_SUCCESS if the setup is successful, XST_FAILURE otherwise.
*
* @note     None.
*
******************************************************************************/
static int TxSetup(XAxiDma * AxiDmaInstPtr)
{
	XAxiDma_BdRing *TxRingPtr;
	XAxiDma_Bd BdTemplate;
	int Delay = 0;
	int Coalesce = 1;
	int Status;
	u32 BdCount;

	TxRingPtr = XAxiDma_GetTxRing(&AxiDma);

	/* Disable all TX interrupts before TxBD space setup */

	XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);

	/* Set TX delay and coalesce */
	XAxiDma_BdRingSetCoalesce(TxRingPtr, Coalesce, Delay);

	/* Setup TxBD space  */
	BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
					TX_BD_SPACE_HIGH - TX_BD_SPACE_BASE + 1);

	Status = XAxiDma_BdRingCreate(TxRingPtr, TX_BD_SPACE_BASE,
				     TX_BD_SPACE_BASE,
				     XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "failed create BD ring in txsetup\r\n");

		return XST_FAILURE;
	}

	/*
	 * We create an all-zero BD as the template.
	 */
	XAxiDma_BdClear(&BdTemplate);

	Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "failed bdring clone in txsetup %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Start the TX channel */
	Status = XAxiDma_BdRingStart(TxRingPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "failed start bdring txsetup %d\r\n", Status);

		return XST_FAILURE;
	}

	return XST_SUCCESS;
}
/*
*
* This function sets up RX channel of the DMA engine to be ready for packet
* reception
*
* @param	AxiDmaInstPtr is the pointer to the instance of the DMA engine.
*
* @return	- XST_SUCCESS if the setup is successful.
*		- XST_FAILURE if fails.
*
* @note		None.
*
******************************************************************************/
static int RxSetup(XAxiDma * AxiDmaInstPtr)
{
	XAxiDma_BdRing *RxRingPtr;
	int Status;
	XAxiDma_Bd BdTemplate;
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	int BdCount;
	int FreeBdCount;
	u32 RxBufferPtr;
	u32 RxBdSpacePtr;
	int Index;
	int RingIndex;

	RxBufferPtr = RX_BUFFER_BASE;
	RxBdSpacePtr = RX_BD_SPACE_BASE;

	for (RingIndex = 0;
			RingIndex < AxiDmaInstPtr->RxNumChannels; RingIndex++) {

		RxRingPtr = XAxiDma_GetRxIndexRing(&AxiDma, RingIndex);

		/* Disable all RX interrupts before RxBD space setup */
		XAxiDma_BdRingIntDisable(RxRingPtr,
						XAXIDMA_IRQ_ALL_MASK);

		/* Setup Rx BD space */
		BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
				RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1);

		Status = XAxiDma_BdRingCreate(RxRingPtr,
					RxBdSpacePtr,
					RxBdSpacePtr,
					XAXIDMA_BD_MINIMUM_ALIGNMENT,
					BdCount);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx bd create failed with %d\r\n",
				Status);
			return XST_FAILURE;
		}

		/*
	 	 * Setup a BD template for the Rx channel. Then copy it
	 	 * to every RX BD.
		 */
		XAxiDma_BdClear(&BdTemplate);
		Status = XAxiDma_BdRingClone(RxRingPtr,
						 &BdTemplate);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx bd clone failed with %d\r\n",
				Status);
			return XST_FAILURE;
		}

		/* Attach buffers to RxBD ring so we are ready to receive packets */
		FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);

		Status = XAxiDma_BdRingAlloc(RxRingPtr,
					FreeBdCount, &BdPtr);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx bd alloc failed with %d\r\n",
				Status);
			return XST_FAILURE;
		}

		BdCurPtr = BdPtr;

		for (Index = 0; Index < FreeBdCount; Index++) {

			Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr);
			if (Status != XST_SUCCESS) {
				xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n",
				(unsigned int)RxBufferPtr,
				(unsigned int)BdCurPtr, Status);

				return XST_FAILURE;
			}

			Status = XAxiDma_BdSetLength(BdCurPtr, HSIZE,
						RxRingPtr->MaxTransferLen);
			if (Status != XST_SUCCESS) {
				xil_printf("Rx set length %d on BD %x failed %d\r\n",
			    	MAX_PKT_LEN, (unsigned int)BdCurPtr, Status);

				return XST_FAILURE;
			}

			/* Receive BDs do not need to set anything for the control
		 	 * The hardware will set the SOF/EOF bits per stream status
		 	 */
			XAxiDma_BdSetCtrl(BdCurPtr, 0);
			XAxiDma_BdSetId(BdCurPtr, RxBufferPtr);
			XAxiDma_BdSetARCache(BdCurPtr, ARCACHE);
			XAxiDma_BdSetARUser(BdCurPtr, ARUSER);
			XAxiDma_BdSetVSize(BdCurPtr, VSIZE);
			XAxiDma_BdSetStride(BdCurPtr, STRIDE);

			RxBufferPtr += MAX_PKT_LEN;
			BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
		}

		/*
	 	 * Set the coalescing threshold, so only one receive interrupt
	 	 * occurs for this example
	 	 *
	 	 * If you would like to have multiple interrupts to happen, change
	 	 * the COALESCING_COUNT to be a smaller value
	 	 */
		Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, COALESCING_COUNT,
				DELAY_TIMER_COUNT);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx set coalesce failed with %d\r\n", Status);
			return XST_FAILURE;
		}

		Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx ToHw failed with %d\r\n", Status);
			return XST_FAILURE;
		}

		/* Enable all RX interrupts */
		XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);

		/* Start RX DMA channel */
		Status = XAxiDma_UpdateBdRingCDesc(RxRingPtr);
		if (Status != XST_SUCCESS) {
			xil_printf("Failed bd start %x\r\n", Status);
			return XST_FAILURE;
		}

		RxBdSpacePtr += BdCount * sizeof(XAxiDma_Bd);

	}

	for (RingIndex = 0;
			RingIndex < AxiDmaInstPtr->RxNumChannels; RingIndex++) {
		RxRingPtr = XAxiDma_GetRxIndexRing(&AxiDma, RingIndex);
		Status = XAxiDma_StartBdRingHw(RxRingPtr);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx start BD ring failed with %d\r\n", Status);
			return XST_FAILURE;
		}
	}

	return XST_SUCCESS;
}
/**
*
* This function sets up RX channel of the DMA engine to be ready for packet
* reception
*
* @param    AxiDmaInstPtr is the pointer to the instance of the DMA engine.
*
* @return   XST_SUCCESS if the setup is successful, XST_FAILURE otherwise.
*
* @note     None.
*
******************************************************************************/
static int RxSetup(XAxiDma * AxiDmaInstPtr)
{
	XAxiDma_BdRing *RxRingPtr;
	int Delay = 0;
	int Coalesce = 1;
	int Status;
	XAxiDma_Bd BdTemplate;
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	u32 BdCount;
	u32 FreeBdCount;
	u32 RxBufferPtr;
	int i;

	RxRingPtr = XAxiDma_GetRxRing(&AxiDma);

	/* Disable all RX interrupts before RxBD space setup */

	XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);

	/* Set delay and coalescing */
	XAxiDma_BdRingSetCoalesce(RxRingPtr, Coalesce, Delay);

	/* Setup Rx BD space */
	BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
					RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1);

	Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE,
				     RX_BD_SPACE_BASE,
				     XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);

	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "RX create BD ring failed %d\r\n", Status);

		return XST_FAILURE;
	}

	/*
	 * Setup an all-zero BD as the template for the Rx channel.
	 */
	XAxiDma_BdClear(&BdTemplate);

	Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "RX clone BD failed %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Attach buffers to RxBD ring so we are ready to receive packets */

	FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);

	Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "RX alloc BD failed %d\r\n", Status);

		return XST_FAILURE;
	}

	BdCurPtr = BdPtr;
	RxBufferPtr = RX_BUFFER_BASE;
	for (i = 0; i < FreeBdCount; i++) {
		Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr);

		if (Status != XST_SUCCESS) {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "Set buffer addr %x on BD %x failed %d\r\n",
			    (unsigned int)RxBufferPtr,
			    (unsigned int)BdCurPtr, Status);

			return XST_FAILURE;
		}

		Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN);
		if (Status != XST_SUCCESS) {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "Rx set length %d on BD %x failed %d\r\n",
			    MAX_PKT_LEN, (unsigned int)BdCurPtr, Status);

			return XST_FAILURE;
		}

		/* Receive BDs do not need to set anything for the control
		 * The hardware will set the SOF/EOF bits per stream status 
		 */
		XAxiDma_BdSetCtrl(BdCurPtr, 0);
		XAxiDma_BdSetId(BdCurPtr, RxBufferPtr);
	
		RxBufferPtr += MAX_PKT_LEN;
		BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
	}

	/* Clear the receive buffer, so we can verify data
	 */
	memset((void *)RX_BUFFER_BASE, 0, MAX_PKT_LEN); 

	Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "RX submit hw failed %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Start RX DMA channel */
	Status = XAxiDma_BdRingStart(RxRingPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "RX start hw failed %d\r\n", Status);

		return XST_FAILURE;
	}

	return XST_SUCCESS;
}
/*
*
* This function sets up the TX channel of a DMA engine to be ready for packet
* transmission.
*
* @param	AxiDmaInstPtr is the pointer to the instance of the DMA engine.
*
* @return	- XST_SUCCESS if the setup is successful.
*		- XST_FAILURE otherwise.
*
* @note		None.
*
******************************************************************************/
static int TxSetup(XAxiDma * AxiDmaInstPtr)
{
	XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(&AxiDma);
	XAxiDma_Bd BdTemplate;
	int Status;
	u32 BdCount;

	u32 TxBdSpacePtr = TX_BD_SPACE_BASE;

	/* Disable all TX interrupts before TxBD space setup */
	XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);

	/* Setup TxBD space  */
	BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
			(u32)TX_BD_SPACE_HIGH - (u32)TX_BD_SPACE_BASE + 1);

	Status = XAxiDma_BdRingCreate(TxRingPtr, TxBdSpacePtr,
				TxBdSpacePtr,
			     XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);
	if (Status != XST_SUCCESS) {

		xil_printf("Failed create BD ring\r\n");
		return XST_FAILURE;
	}

	/*
	 * Like the RxBD space, we create a template and set all BDs to be the
	 * same as the template. The sender has to set up the BDs as needed.
	 */
	XAxiDma_BdClear(&BdTemplate);
	Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate);
	if (Status != XST_SUCCESS) {

		xil_printf("Failed clone BDs\r\n");
		return XST_FAILURE;
	}

	/*
	 * Set the coalescing threshold, so only one transmit interrupt
	 * occurs for this example
	 *
	 * If you would like to have multiple interrupts to happen, change
	 * the COALESCING_COUNT to be a smaller value
	 */
	Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, COALESCING_COUNT,
			DELAY_TIMER_COUNT);
	if (Status != XST_SUCCESS) {

		xil_printf("Failed set coalescing"
		" %d/%d\r\n",COALESCING_COUNT, DELAY_TIMER_COUNT);
		return XST_FAILURE;
	}

	/* Enable all TX interrupts */
	XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);

	/* Start the TX channel */
	Status = XAxiDma_UpdateBdRingCDesc(TxRingPtr);
		if (Status != XST_SUCCESS) {

			xil_printf("Failed bd start %x\r\n", Status);
			return XST_FAILURE;
	}

	Status = XAxiDma_StartBdRingHw(TxRingPtr);
	if (Status != XST_SUCCESS) {

		xil_printf("Failed bd start %x\r\n", Status);
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}