XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bdring.c
u32 XAxiDma_BdRingCreate(XAxiDma_BdRing *RingPtr, UINTPTR PhysAddr,
			UINTPTR VirtAddr, u32 Alignment, int BdCount)
{
	int i;
	UINTPTR BdVirtAddr;
	UINTPTR BdPhysAddr;

	if (BdCount <= 0) {

		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: non-positive BD"
				" number %d\r\n", BdCount);

		return XST_INVALID_PARAM;
	}

	/* In case there is a failure prior to creating list, make sure the
	 * following attributes are 0 to prevent calls to other SG functions
	 * from doing anything
	 */
	RingPtr->AllCnt = 0;
	RingPtr->FreeCnt = 0;
	RingPtr->HwCnt = 0;
	RingPtr->PreCnt = 0;
	RingPtr->PostCnt = 0;
	RingPtr->Cyclic = 0;

	/* Make sure Alignment parameter meets minimum requirements */
	if (Alignment < XAXIDMA_BD_MINIMUM_ALIGNMENT) {

		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: alignment too "
		"small %d, need to be at least %d\r\n", (int)Alignment,
			XAXIDMA_BD_MINIMUM_ALIGNMENT);

		return XST_INVALID_PARAM;
	}

	/* Make sure Alignment is a power of 2 */
	if ((Alignment - 1) & Alignment) {

		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: alignment not"
				" valid %d\r\n", (int)Alignment);

		return XST_INVALID_PARAM;
	}

	/* Make sure PhysAddr and VirtAddr are on same Alignment */
	if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) {

		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: Physical address"
		" %x and virtual address %x have different alignment\r\n",
			(unsigned int)PhysAddr, (unsigned int)VirtAddr);

		return XST_INVALID_PARAM;
	}

	/* Compute how many bytes will be between the start of adjacent BDs */
	RingPtr->Separation =
		(sizeof(XAxiDma_Bd) + (Alignment - 1)) & ~(Alignment - 1);

	/* Must make sure the ring doesn't span address 0x00000000. If it does,
	 * then the next/prev BD traversal macros will fail.
	 */
	if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) {

		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: BD space cross "
			"0x0\r\n");

		return XST_DMA_SG_LIST_ERROR;
	}

	/* Initial ring setup:
	 *  - Clear the entire space
	 *  - Setup each BD's next pointer with the physical address of the
	 *    next BD
	 *  - Put hardware information in each BD
	 */
	memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount));

	BdVirtAddr = VirtAddr;
	BdPhysAddr = PhysAddr + RingPtr->Separation;
	for (i = 1; i < BdCount; i++) {
		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_OFFSET,
				(BdPhysAddr & XAXIDMA_DESC_LSB_MASK));
		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_MSB_OFFSET,
				UPPER_32_BITS(BdPhysAddr));

		/* Put hardware information in the BDs
		 */
		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET,
				(u32)RingPtr->HasStsCntrlStrm);

		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_DRE_OFFSET,
		    (((u32)(RingPtr->HasDRE)) << XAXIDMA_BD_HAS_DRE_SHIFT) |
		    RingPtr->DataWidth);

		XAXIDMA_CACHE_FLUSH(BdVirtAddr);
		BdVirtAddr += RingPtr->Separation;
		BdPhysAddr += RingPtr->Separation;
	}

	/* At the end of the ring, link the last BD back to the top */
	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_OFFSET,
			(PhysAddr & XAXIDMA_DESC_LSB_MASK));
	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_MSB_OFFSET,
			UPPER_32_BITS(PhysAddr));


	/* Setup the last BD's hardware information */
	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET,
		(u32)RingPtr->HasStsCntrlStrm);

	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_DRE_OFFSET,
	    (((u32)(RingPtr->HasDRE)) << XAXIDMA_BD_HAS_DRE_SHIFT) |
	    RingPtr->DataWidth);

	/* Setup and initialize pointers and counters */
	RingPtr->RunState = AXIDMA_CHANNEL_HALTED;
	RingPtr->FirstBdAddr = VirtAddr;
	RingPtr->FirstBdPhysAddr = PhysAddr;
	RingPtr->LastBdAddr = BdVirtAddr;
	RingPtr->Length = RingPtr->LastBdAddr - RingPtr->FirstBdAddr +
		RingPtr->Separation;
	RingPtr->AllCnt = BdCount;
	RingPtr->FreeCnt = BdCount;
	RingPtr->FreeHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->PreHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->HwHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->HwTail = (XAxiDma_Bd *) VirtAddr;
	RingPtr->PostHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->BdaRestart = (XAxiDma_Bd *) VirtAddr;
	RingPtr->CyclicBd = (XAxiDma_Bd *) malloc(sizeof(XAxiDma_Bd));

	return XST_SUCCESS;
}
/*****************************************************************************/
/**
 * Using a memory segment allocated by the caller, This fundtion creates and
 * setup the BD ring.
 *
 * @param	RingPtr is the BD ring instance to be worked on.
 * @param	PhysAddr is the physical base address of application memory
 *		region.
 * @param	VirtAddr is the virtual base address of the application memory
 *		region.If address translation is not being utilized, then
 *		VirtAddr should be equivalent to PhysAddr.
 * @param	Alignment governs the byte alignment of individual BDs. This
 *		function will enforce a minimum alignment of
 *		XAXIDMA_BD_MINIMUM_ALIGNMENT bytes with no maximum as long as
 *		it is specified as a power of 2.
 * @param	BdCount is the number of BDs to setup in the application memory
 *		region. It is assumed the region is large enough to contain the
 *		BDs.Refer to the "SGDMA Ring Creation" section  in xaxidma.h
 *		for more information. The minimum valid value for this
 *		parameter is 1.
 *
 * @return
 *		- XST_SUCCESS if initialization was successful
 * 		- XST_NO_FEATURE if the provided instance is a non SGDMA type
 *		of DMA channel.
 *		- XST_INVALID_PARAM under any of the following conditions:
 *		1) BdCount is not positive
 *
 *		2) PhysAddr and/or VirtAddr are not aligned to the given
 *		Alignment parameter;
 *
 *		3) Alignment parameter does not meet minimum requirements or
 *		is not a power of 2 value.
 *
 *		- XST_DMA_SG_LIST_ERROR if the memory segment containing the
 *		list spans over address 0x00000000 in virtual address space.
 *
 * @note	This function can be used only when DMA is in SG mode
 *
 *****************************************************************************/
Using a memory segment allocated by the caller, This fundtion creates and
setup the BD ring.

@param       RingPtr is the BD ring instance to be worked on.
@param       PhysAddr is the physical base address of application memory
region.
@param       VirtAddr is the virtual base address of the application memory
region.If address translation is not being utilized, then
VirtAddr should be equivalent to PhysAddr.
@param       Alignment governs the byte alignment of individual BDs. This
function will enforce a minimum alignment of
XAXIDMA_BD_MINIMUM_ALIGNMENT bytes with no maximum as long as
it is specified as a power of 2.
@param       BdCount is the number of BDs to setup in the application memory
region. It is assumed the region is large enough to contain the
BDs.Refer to the "SGDMA Ring Creation" section  in xaxidma.h
for more information. The minimum valid value for this
parameter is 1.

@return
- XST_SUCCESS if initialization was successful
- XST_NO_FEATURE if the provided instance is a non SGDMA type
of DMA channel.
- XST_INVALID_PARAM under any of the following conditions:
1) BdCount is not positive

2) PhysAddr and/or VirtAddr are not aligned to the given
Alignment parameter.

3) Alignment parameter does not meet minimum requirements or
is not a power of 2 value.

- XST_DMA_SG_LIST_ERROR if the memory segment containing the
list spans over address 0x00000000 in virtual address space.

@note        This function can be used only when DMA is in SG mode
Using a memory segment allocated by the caller This fundtion creates and setup the BD ring . @param RingPtr is the BD ring instance to be worked on . @param PhysAddr is the physical base address of application memory region . @param VirtAddr is the virtual base address of the application memory region . If address translation is not being utilized then VirtAddr should be equivalent to PhysAddr . @param Alignment governs the byte alignment of individual BDs . This function will enforce a minimum alignment of XAXIDMA_BD_MINIMUM_ALIGNMENT bytes with no maximum as long as it is specified as a power of 2 . @param BdCount is the number of BDs to setup in the application memory region . It is assumed the region is large enough to contain the BDs . Refer to the " SGDMA Ring Creation " section in xaxidma . h for more information . The minimum valid value for this parameter is 1 . @return - XST_SUCCESS if initialization was successful - XST_NO_FEATURE if the provided instance is a non SGDMA type of DMA channel . - XST_INVALID_PARAM under any of the following conditions : 1 ) BdCount is not positive 2 ) PhysAddr and / or VirtAddr are not aligned to the given Alignment parameter . 3 ) Alignment parameter does not meet minimum requirements or is not a power of 2 value . - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans over address 0x00000000 in virtual address space . @note This function can be used only when DMA is in SG mode
u32 XAxiDma_BdRingCreate(XAxiDma_BdRing *RingPtr, UINTPTR PhysAddr,
			UINTPTR VirtAddr, u32 Alignment, int BdCount)
{
	int i;
	UINTPTR BdVirtAddr;
	UINTPTR BdPhysAddr;
	if (BdCount <= 0) {
		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: non-positive BD"
				" number %d\r\n", BdCount);
		return XST_INVALID_PARAM;
	}
	RingPtr->AllCnt = 0;
	RingPtr->FreeCnt = 0;
	RingPtr->HwCnt = 0;
	RingPtr->PreCnt = 0;
	RingPtr->PostCnt = 0;
	RingPtr->Cyclic = 0;
	if (Alignment < XAXIDMA_BD_MINIMUM_ALIGNMENT) {
		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: alignment too "
		"small %d, need to be at least %d\r\n", (int)Alignment,
			XAXIDMA_BD_MINIMUM_ALIGNMENT);
		return XST_INVALID_PARAM;
	}
	if ((Alignment - 1) & Alignment) {
		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: alignment not"
				" valid %d\r\n", (int)Alignment);
		return XST_INVALID_PARAM;
	}
	if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) {
		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: Physical address"
		" %x and virtual address %x have different alignment\r\n",
			(unsigned int)PhysAddr, (unsigned int)VirtAddr);
		return XST_INVALID_PARAM;
	}
	RingPtr->Separation =
		(sizeof(XAxiDma_Bd) + (Alignment - 1)) & ~(Alignment - 1);
	if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) {
		xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: BD space cross "
			"0x0\r\n");
		return XST_DMA_SG_LIST_ERROR;
	}
	memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount));
	BdVirtAddr = VirtAddr;
	BdPhysAddr = PhysAddr + RingPtr->Separation;
	for (i = 1; i < BdCount; i++) {
		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_OFFSET,
				(BdPhysAddr & XAXIDMA_DESC_LSB_MASK));
		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_MSB_OFFSET,
				UPPER_32_BITS(BdPhysAddr));
		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET,
				(u32)RingPtr->HasStsCntrlStrm);
		XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_DRE_OFFSET,
		    (((u32)(RingPtr->HasDRE)) << XAXIDMA_BD_HAS_DRE_SHIFT) |
		    RingPtr->DataWidth);
		XAXIDMA_CACHE_FLUSH(BdVirtAddr);
		BdVirtAddr += RingPtr->Separation;
		BdPhysAddr += RingPtr->Separation;
	}
	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_OFFSET,
			(PhysAddr & XAXIDMA_DESC_LSB_MASK));
	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_MSB_OFFSET,
			UPPER_32_BITS(PhysAddr));
	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET,
		(u32)RingPtr->HasStsCntrlStrm);
	XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_DRE_OFFSET,
	    (((u32)(RingPtr->HasDRE)) << XAXIDMA_BD_HAS_DRE_SHIFT) |
	    RingPtr->DataWidth);
	RingPtr->RunState = AXIDMA_CHANNEL_HALTED;
	RingPtr->FirstBdAddr = VirtAddr;
	RingPtr->FirstBdPhysAddr = PhysAddr;
	RingPtr->LastBdAddr = BdVirtAddr;
	RingPtr->Length = RingPtr->LastBdAddr - RingPtr->FirstBdAddr +
		RingPtr->Separation;
	RingPtr->AllCnt = BdCount;
	RingPtr->FreeCnt = BdCount;
	RingPtr->FreeHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->PreHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->HwHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->HwTail = (XAxiDma_Bd *) VirtAddr;
	RingPtr->PostHead = (XAxiDma_Bd *) VirtAddr;
	RingPtr->BdaRestart = (XAxiDma_Bd *) VirtAddr;
	RingPtr->CyclicBd = (XAxiDma_Bd *) malloc(sizeof(XAxiDma_Bd));
	return XST_SUCCESS;
}
u32 XAxiDma_BdRingCreate ( XAxiDma_BdRing * RingPtr , UINTPTR PhysAddr , UINTPTR VirtAddr , u32 Alignment , int BdCount ) { int i ; UINTPTR BdVirtAddr ; UINTPTR BdPhysAddr ; if ( BdCount <= 0 ) { xdbg_printf ( XDBG_DEBUG_ERROR , " " " \r \n " , BdCount ) ; return XST_INVALID_PARAM ; } RingPtr -> AllCnt = 0 ; RingPtr -> FreeCnt = 0 ; RingPtr -> HwCnt = 0 ; RingPtr -> PreCnt = 0 ; RingPtr -> PostCnt = 0 ; RingPtr -> Cyclic = 0 ; if ( Alignment < XAXIDMA_BD_MINIMUM_ALIGNMENT ) { xdbg_printf ( XDBG_DEBUG_ERROR , " " " \r \n " , ( int ) Alignment , XAXIDMA_BD_MINIMUM_ALIGNMENT ) ; return XST_INVALID_PARAM ; } if ( ( Alignment - 1 ) & Alignment ) { xdbg_printf ( XDBG_DEBUG_ERROR , " " " \r \n " , ( int ) Alignment ) ; return XST_INVALID_PARAM ; } if ( ( PhysAddr % Alignment ) || ( VirtAddr % Alignment ) ) { xdbg_printf ( XDBG_DEBUG_ERROR , " " " \r \n " , ( unsigned int ) PhysAddr , ( unsigned int ) VirtAddr ) ; return XST_INVALID_PARAM ; } RingPtr -> Separation = ( sizeof ( XAxiDma_Bd ) + ( Alignment - 1 ) ) & ~ ( Alignment - 1 ) ; if ( VirtAddr > ( VirtAddr + ( RingPtr -> Separation * BdCount ) - 1 ) ) { xdbg_printf ( XDBG_DEBUG_ERROR , " " " \r \n " ) ; return XST_DMA_SG_LIST_ERROR ; } memset ( ( void * ) VirtAddr , 0 , ( RingPtr -> Separation * BdCount ) ) ; BdVirtAddr = VirtAddr ; BdPhysAddr = PhysAddr + RingPtr -> Separation ; for ( i = 1 ; i < BdCount ; i ++ ) { XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_NDESC_OFFSET , ( BdPhysAddr & XAXIDMA_DESC_LSB_MASK ) ) ; XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_NDESC_MSB_OFFSET , UPPER_32_BITS ( BdPhysAddr ) ) ; XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_HAS_STSCNTRL_OFFSET , ( u32 ) RingPtr -> HasStsCntrlStrm ) ; XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_HAS_DRE_OFFSET , ( ( ( u32 ) ( RingPtr -> HasDRE ) ) << XAXIDMA_BD_HAS_DRE_SHIFT ) | RingPtr -> DataWidth ) ; XAXIDMA_CACHE_FLUSH ( BdVirtAddr ) ; BdVirtAddr += RingPtr -> Separation ; BdPhysAddr += RingPtr -> Separation ; } XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_NDESC_OFFSET , ( PhysAddr & XAXIDMA_DESC_LSB_MASK ) ) ; XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_NDESC_MSB_OFFSET , UPPER_32_BITS ( PhysAddr ) ) ; XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_HAS_STSCNTRL_OFFSET , ( u32 ) RingPtr -> HasStsCntrlStrm ) ; XAxiDma_BdWrite ( BdVirtAddr , XAXIDMA_BD_HAS_DRE_OFFSET , ( ( ( u32 ) ( RingPtr -> HasDRE ) ) << XAXIDMA_BD_HAS_DRE_SHIFT ) | RingPtr -> DataWidth ) ; RingPtr -> RunState = AXIDMA_CHANNEL_HALTED ; RingPtr -> FirstBdAddr = VirtAddr ; RingPtr -> FirstBdPhysAddr = PhysAddr ; RingPtr -> LastBdAddr = BdVirtAddr ; RingPtr -> Length = RingPtr -> LastBdAddr - RingPtr -> FirstBdAddr + RingPtr -> Separation ; RingPtr -> AllCnt = BdCount ; RingPtr -> FreeCnt = BdCount ; RingPtr -> FreeHead = ( XAxiDma_Bd * ) VirtAddr ; RingPtr -> PreHead = ( XAxiDma_Bd * ) VirtAddr ; RingPtr -> HwHead = ( XAxiDma_Bd * ) VirtAddr ; RingPtr -> HwTail = ( XAxiDma_Bd * ) VirtAddr ; RingPtr -> PostHead = ( XAxiDma_Bd * ) VirtAddr ; RingPtr -> BdaRestart = ( XAxiDma_Bd * ) VirtAddr ; RingPtr -> CyclicBd = ( XAxiDma_Bd * ) malloc ( sizeof ( XAxiDma_Bd ) ) ; return XST_SUCCESS ; }
Using a memory segment allocated by the caller, This fundtion creates and
 setup the BD ring.
Using a memory segment allocated by the caller This fundtion creates and setup the BD ring .
/* In case there is a failure prior to creating list, make sure the
	 * following attributes are 0 to prevent calls to other SG functions
	 * from doing anything
	 */ /* Make sure Alignment parameter meets minimum requirements */ /* Make sure Alignment is a power of 2 */ /* Make sure PhysAddr and VirtAddr are on same Alignment */ /* Compute how many bytes will be between the start of adjacent BDs */ /* Must make sure the ring doesn't span address 0x00000000. If it does,
	 * then the next/prev BD traversal macros will fail.
	 */ /* Initial ring setup:
	 *  - Clear the entire space
	 *  - Setup each BD's next pointer with the physical address of the
	 *    next BD
	 *  - Put hardware information in each BD
	 */ /* Put hardware information in the BDs
		 */ /* At the end of the ring, link the last BD back to the top */ /* Setup the last BD's hardware information */ /* Setup and initialize pointers and counters */