cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Observer
Observer
9,212 Views
Registered: ‎09-27-2014

Why I Cant Use XAxiDma_BdGetActualLength in Multichannel AXI DMA?

Hi.

I'm trying to run multichannel AXI DMA. My work is done on SDK default Example by some changes on code.

now I want to use XAxiDma_BdGetActualLength function to getthe received packet length. but this function always returns zero! 

plz, any one can help me?

 

 

My Code in Rx Callback:

/*
*
* This is the DMA RX callback function called by the RX interrupt handler.
* This function handles finished BDs by hardware, attaches new buffers to those
* BDs, and give them back to hardware to receive more incoming packets
*
* @param	RxRingPtr is a pointer to RX channel of the DMA engine.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void RxCallBack(XAxiDma *AxiDmaPtr)
{
	int BdCount;
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	u32 BdSts;
	int Index;
	int RingIndex;
	XAxiDma_BdRing *RxRingPtr;

	u8 *RxPacket;


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

		RxRingPtr = XAxiDma_GetRxIndexRing(AxiDmaPtr, RingIndex);
		BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);

		BdCurPtr = BdPtr;
		for (Index = 0; Index < BdCount; Index++) {

			/*
			 * Check the flags set by the hardware for status
			 * If error happens, processing stops, because the DMA engine
			 * is halted after this BD.
			 */
			BdSts = XAxiDma_BdGetSts(BdCurPtr);
			if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
			    (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {
				Error = 1;
				break;
			}

			//Consume RxPacket Here
			int PackLength=0;
			RxPacket = (u8 *) XAxiDma_BdGetBufAddr(BdCurPtr) ;
			/* Invalidate the DestBuffer before receiving the data, in case the
			 * Data Cache is enabled
			 */
			Xil_DCacheInvalidateRange((u32)RxPacket, MAX_PKT_LEN);

			PackLength=XAxiDma_BdGetActualLength(BdCurPtr,MAX_PKT_Mask);
			//look here  --@@--, PackLength is zero always
			//PackLength=512;



			/* Find the next processed BD */
			BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
			RxDone[RingIndex] += 1;
		}

		if(BdCount!=0)
		{
			//@@// added for test to free RX BDs
			/* Free all processed BDs for future transmission */
			int Status = XAxiDma_BdRingFree(RxRingPtr, BdCount, BdPtr);
			if (Status != XST_SUCCESS) {
				Error = 1;
			}
			/* Return processed BDs to RX channel so we are ready to receive new
			 * packets:
			 *    - Allocate all free RX BDs
			 *    - Pass the BDs to RX channel
			 */
			int FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
			Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
			if (Status != XST_SUCCESS) {
				xil_printf("bd alloc failed\r\n");
				return XST_FAILURE;
			}

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

		}

	}
}
0 Kudos
7 Replies
Highlighted
Xilinx Employee
Xilinx Employee
9,197 Views
Registered: ‎08-02-2011

Hmmm, can you try reading the length register directly to see what it's value is?
www.xilinx.com
0 Kudos
Highlighted
Observer
Observer
9,178 Views
Registered: ‎09-27-2014

How Can I read length register directly? Do you mean using XAxiDma_BdGetLength()?

 

If I use XAxiDma_BdGetLength() it will not return the length of received data according to doc of this function!

/*****************************************************************************/
/**
 * Retrieve the length field value from the given BD.  The returned value is
 * the same as what was written with XAxiDma_BdSetLength(). Note that in the
 * this value does not reflect the real length of received data.
 * See the comments of XAxiDma_BdSetLength() for more details. To obtain the
 * actual transfer length, use XAxiDma_BdGetActualLength().
 *
 * @param	BdPtr is the BD to operate on.
 * @param	LengthMask is the Maximum Transfer Length.
 *
 * @return	The length value set in the BD.
 *
 * @note
 *		C-style signature:
 *		u32 XAxiDma_BdGetLength(XAxiDma_Bd* BdPtr)
 *
 *****************************************************************************/
#define XAxiDma_BdGetLength(BdPtr, LengthMask)                \
	(XAxiDma_BdRead((BdPtr), XAXIDMA_BD_CTRL_LEN_OFFSET) & \
		LengthMask)
0 Kudos
Highlighted
Xilinx Employee
Xilinx Employee
9,171 Views
Registered: ‎08-02-2011

Sorry, I meant to read the address directly via something like Xil_In32
www.xilinx.com
0 Kudos
Highlighted
Observer
Observer
9,159 Views
Registered: ‎09-27-2014

as I faound the function XAxiDma_BdGetActualLength retrns this registers value! then why should I read this register directly?

 

this is the code for function XAxiDma_BdGetActualLength:

 

/*****************************************************************************/
/**
 * Get the actual transfer length of a BD. The BD has completed in hw.
 *
 * This function may not work if the BD is in cached memory.
 *
 * @param	BdPtr is the BD to check on
 * @param	LengthMask is the Maximum Transfer Length.
 *
 * @return	None
 *
 * @note
 *		C-style signature:
 *		int XAxiDma_BdGetActualLength(XAxiDma_Bd* BdPtr)
 *
 *****************************************************************************/
#define XAxiDma_BdGetActualLength(BdPtr, LengthMask)      \
	(XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STS_OFFSET) & \
		LengthMask)

 

 

So the value of register with address XAXIDMA_BD_STS_OFFSET will be returned.

XAXIDMA_BD_STS_OFFSET is defined in xaxidma_hw as below:

#define XAXIDMA_BD_STS_OFFSET		0x1C  /**< Status */
0 Kudos
Highlighted
Observer
Observer
9,111 Views
Registered: ‎09-27-2014

Plz Any body Help.

 

I see the status register value after receiving a packet but its value for received length is zero. Datas is correct but length report is not valid.

 

AxiDmaMultiChannelProblem.jpg

 

some definitions in xacidma_hw.h is as below:

/** @name Bitmasks of XAXIDMA_BD_STS_OFFSET register
 *  @{
 */
#define XAXIDMA_BD_STS_COMPLETE_MASK	0x80000000 /**< Completed */
#define XAXIDMA_BD_STS_DEC_ERR_MASK	0x40000000 /**< Decode error */
#define XAXIDMA_BD_STS_SLV_ERR_MASK	0x20000000 /**< Slave error */
#define XAXIDMA_BD_STS_INT_ERR_MASK	0x10000000 /**< Internal err */
#define XAXIDMA_BD_STS_ALL_ERR_MASK	0x70000000 /**< All errors */
#define XAXIDMA_BD_STS_RXSOF_MASK	0x08000000 /**< First rx pkt */
#define XAXIDMA_BD_STS_RXEOF_MASK	0x04000000 /**< Last rx pkt */
#define XAXIDMA_BD_STS_ALL_MASK		0xFC000000 /**< All status bits */
/*@}*/

I Set a breakpoint in place after receving a BD. as the fig shows the status register value is 0x8c000000.

this value indicates that :

1. this is BD is completed.

2. this is first packet and last packet of the current transfer

3. size of receiveed transfer is zero. here is my probelm!...

 

 

0 Kudos
Highlighted
Anonymous
Not applicable
6,507 Views

Hi everyone!

O have the same problem!

Did you (or someone else) resolve this issue?

Thank you and best regards!

0 Kudos
Highlighted
Adventurer
Adventurer
4,354 Views
Registered: ‎09-19-2016

If anyone is still trying to figure this out...

 

You can't use the function simply because Single channel (SC) Scatter Gather (SG) descriptor is different from Multi channel (MC) SG descriptor. Please take a look at page 39 of pg021. As you can see SC descriptor has field STATUS at 0x1C offset. If you take a look at S2MM status registers (page 48), you can see that bits [22:0] are reserved for Transferred bytes. That's what XAxiDma_BdGetActualLength() reads.

 

Now look at MC SG S2MM descriptor at page 61. At 0x1C offset you can see register that looks completely different from previously mentioned SC register. Bits [22:0] are used for other information such as TID, TDEST, TUSER, etc.So, when you use XAxiDma_BdGetActualLength() function on MC SG descriptor it will get you that information (TID, TDEST, TUSER...) and not what the function is supposed to return. It must be mentioned somewhere that the function can be used only for SC DMA. The closest you can get to length of MC transfer is to read HSIZE field (bits [15:0] at 0x18 offset of MC SG descriptor). However, that field is probably not what you expect, since it doesn't get updated by DMA while working (at least I think so).

 

All in all, MC DMA doesn't support the feature you are looking for. Please, let me know if I misunderstood this.  

0 Kudos