cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
rnpittman
Visitor
Visitor
6,009 Views
Registered: ‎06-18-2010

Zynq Ethernet Low Level Driver

I am writing a low level driver for the Zynq for doing raw ethernet without TCP/IP.  I have mostly gotten it to work except that it does not appear to be reusing the recieve BDs I have.  After it has used each BD once it will not use it again and I get the message that are no recieve buffers available.  Below is the code I have for recycling the recieve BDs.  If you can let me know what is wrong, I would appreciate it.  This code runs without error but it does not appear to have the desired effect.  BTW  I am able to recycle the transfer BDs by using similar code so I don't know why this does not work here.

 

bool

net_receive_ack(XEmacPs *EmacPsInstancePtr, XEmacPs_Bd *BdRxPtr, u32 *NumRxBuf)

{

int Status;

XEmacPs_Bd *BdRx2Ptr;

EthernetFrame *RxFrameBufPtr;

u32 num = *NumRxBuf;

 

RxFrameBufPtr = (

EthernetFrame *)(XEmacPs_BdGetBufAddr(*BdRxPtr)&(0xfffffffe));

 

Status = XEmacPs_BdRingFree(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),num, BdRxPtr);

if (Status != XST_SUCCESS) {

EmacPsUtilErrorTrap(

"Error freeing up RxBDs");

returnfalse;

}

 

Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), 1, &BdRx2Ptr);

if (Status != XST_SUCCESS) {

printf("Error allocating RxBD");

returnfalse;

}

XEmacPs_BdSetAddressRx(BdRx2Ptr, RxFrameBufPtr);

Status = XEmacPs_BdRingToHw(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),1, BdRx2Ptr);

if (Status != XST_SUCCESS) {

printf("Error committing RxBD to HW");

returnfalse;

}

 

FramesRxAck++;

printf("RxACK%d\r\n",FramesRxAck);

returntrue;

}

Tags (1)
0 Kudos
6 Replies
jdelorme
Visitor
Visitor
5,231 Views
Registered: ‎07-17-2013

Hi,

did you progress in your issue?

I am currently trying to use the emacps in standalonemode for sending and receiving sevral frames repetively but it doesn't works.

It is similar to your issue, the bd frees are not reused...

Can you share some updated code with me?

Regards,

Julien

0 Kudos
lupu
Visitor
Visitor
4,505 Views
Registered: ‎07-01-2015

rnpittman, Have you figured out how to reuse BDs after XEmacPs_BdRingFromHwRx(), XEmacPs_BdClearRxNew(), XEmacPs_BdRingFree(), XEmacPs_BdRingAlloc (), XEmacPs_BdRingToHw().
I tried to do like that, but once all BDs are retrieved the ramaning  frames coming to last BD. Not to first BD.
0 Kudos
ronnywebers
Advisor
Advisor
4,484 Views
Registered: ‎10-10-2014

did you reset ownership after processing (each) Bd so the Bd(s) becomes available again to the DMA controller ?

 

take a look at the doc for :

 

XEmacPs_BdClearRxNew

 

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
lupu
Visitor
Visitor
4,462 Views
Registered: ‎07-01-2015

thanks ronnywebers

 

I've found my mistake. I missed function to arrange BD address again  - XEmacPs_BdSetAddressRx();

 So, the application has a following BD related sequence:

//clear the BdTemplate
XEmacPs_BdClear(&BdTemplate);

//Create BdRing from 3 BDs
XEmacPs_BdRingCreate();

//Clone BDs from template BD
XEmacPs_BdRingClone();

//Allocate BDs
XEmacPs_BdRingAlloc();

//Configure three BDs one by one
//First BD address
XEmacPs_BdSetAddressRx();

//Second BD
Bd2RxPtr = XEmacPs_BdRingNext();
XEmacPs_BdSetAddressRx();

//Third BD
Bd3RxPtr = XEmacPs_BdRingNext();
XEmacPs_BdSetAddressRx();
XEmacPs_BdSetLast(Bd2RxPtr);

//Enqueue to HW
XEmacPs_BdRingToHw();

//Then start the device
XEmacPs_Start();

while (1) {}

In the Interrupt handler funtion XEmacPsRecvHandler(); performes a following code section:

NumRxBuf  = XEmacPs_BdRingFromHwRx();

XEmacPs_BdClearRxNew();

XEmacPs_BdRingFree();

XEmacPs_BdRingAlloc();

XEmacPs_BdSetAddressRx();

XEmacPs_BdRingToHw();

The BDs are rotated forever in the ring in spite of there are only three BDs.

0 Kudos
jeevakumar.s
Newbie
Newbie
3,906 Views
Registered: ‎04-18-2016

I am testing PS GEM0 in zynq 7030 custom module. I have modified the xilinx SDK ps emac dma single interrupt application for continuous receive the ethernet frames. After receiving some packets, i am facing the issue Receive bufer not available error code. Any one can give suggestion on this issue ?

0 Kudos
ronnywebers
Advisor
Advisor
3,889 Views
Registered: ‎10-10-2014

Hello @jeevakumar.s

 

I believe to remember that indeed the example contains some bugs, or is incomplete in the sence that it cannot handle, or was not written for continuous reception of packets.

 

It must have something to do with not returning the processed Bd's to 'hardware', which means they don't become available again for the ethernet dma controller. So when it runs out of Bd's, it just stops. 

 

at birds eye view, these are the steps to follow when processing received packets (and thus handling bd's from the rx interrupt). The exact sequence is critical and must be followed :

 

* XEmacPs_GetRxRing : to get a pointer to the BD ring

* XEmacPs_BdRingFromHwRx : returns a number of bd's (1 or more) that are available for post processing

 

then loop through each bd and process each packet :

----------- loop starts here ---------------

      * ... do whatever you want to do with your receive ethernet data. You might need to use 'XEmacPs_BdGetBufAddr' here

      * make sure you handle caching correctly before interpreting the data, or disable cache on the ethernet buffers. If you suspect issues with cache, try turning the cache of completely to see if everything works ok, then turn it back on.

      * XEmacPs_BdClearRxNew

      * XEmacPs_BdRingNext

 --------- loop ends here -----------------

 

after processing 1 or more Bd's, you can free them at once, and give them back to the DMA controller :

 

* XEmacPs_BdRingFree : free the processed bd's (1 or more, the exact amount which you processed above)

* XEmacPs_BdRingAlloc : reallocate bd's

* XEmacPs_BdRingToHw : enqueue them back to hw (= make them available again for the dma controller)

 

that's it.

 

So my guess is that you skip some step like 'XEmacPs_BdClearRxNew', or the free - alloc - toHw sequence.

 

Try to read the doc, it might take a few re-reads to grasp everything. you can also debug & step through the code, and keep an eye on the Bd rings to see wether they are made available again.

 

(to access the doc you go to your system.mss file in the bsp, double click on it, look for 'emacps' and click on 'documentation')

 

Especially read the section 'DMA", and the doc of each of the methods

 

DMA

The DMA engine uses buffer descriptors (BDs) to describe Ethernet frames. These BDs are typically chained together into a list the hardware follows when transferring data in and out of the packet buffers. Each BD describes a memory region containing either a full or partial Ethernet packet.

Interrupt coalescing is not suppoted from this built-in DMA engine.

This API requires the user to understand how the DMA operates. The following paragraphs provide some explanation, but the user is encouraged to read documentation in xemacps_bdring.h as well as study example code that accompanies this driver.

The API is designed to get BDs to and from the DMA engine in the most efficient means possible. The first step is to establish a memory region to contain all BDs for a specific channel. This is done with XEmacPs_BdRingCreate(). This function sets up a BD ring that hardware will follow as BDs are processed. The ring will consist of a user defined number of BDs which will all be partially initialized. For example on the transmit channel, the driver will initialize all BDs' so that they are configured for transmit. The more fields that can be permanently setup at initialization, then the fewer accesses will be needed to each BD while the DMA engine is in operation resulting in better throughput and CPU utilization. The best case initialization would require the user to set only a frame buffer address and length prior to submitting the BD to the engine.

BDs move through the engine with the help of functions XEmacPs_BdRingAlloc(), XEmacPs_BdRingToHw(), XEmacPs_BdRingFromHw(), and XEmacPs_BdRingFree(). All these functions handle BDs that are in place. That is, there are no copies of BDs kept anywhere and any BD the user interacts with is an actual BD from the same ring hardware accesses.

BDs in the ring go through a series of states as follows: 1. Idle. The driver controls BDs in this state. 2. The user has data to transfer. XEmacPs_BdRingAlloc() is called to reserve BD(s). Once allocated, the user may setup the BD(s) with frame buffer address, length, and other attributes. The user controls BDs in this state. 3. The user submits BDs to the DMA engine with XEmacPs_BdRingToHw. BDs in this state are either waiting to be processed by hardware, are in process, or have been processed. The DMA engine controls BDs in this state. 4. Processed BDs are retrieved with XEmacEpv_BdRingFromHw() by the user. Once retrieved, the user can examine each BD for the outcome of the DMA transfer. The user controls BDs in this state. After examining the BDs the user calls XEmacPs_BdRingFree() which places the BDs back into state 1.

Each of the four BD accessor functions operate on a set of BDs. A set is defined as a segment of the BD ring consisting of one or more BDs. The user views the set as a pointer to the first BD along with the number of BDs for that set. The set can be navigated by using macros XEmacPs_BdNext(). The user must exercise extreme caution when changing BDs in a set as there is nothing to prevent doing a mBdNext past the end of the set and modifying a BD out of bounds.

XEmacPs_BdRingAlloc() + XEmacPs_BdRingToHw(), as well as XEmacPs_BdRingFromHw() + XEmacPs_BdRingFree() are designed to be used in tandem. The same BD set retrieved with BdRingAlloc should be the same one provided to hardware with BdRingToHw. Same goes with BdRingFromHw and BdRIngFree.

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos