The xps_ll_temac core is a bit different from previous ethernet IP provided in the EDK. The xps_ll_temac core provides no direct bus attachment, but rather expects data to come through a local link connection. An additional core needs to be connected this local link interface along with a connection to a bus that can be accessed by the processor.
The EDK provides various such cores, xps_ll_fifo, and mpmc/sdma. The xps_ll_fifo core provides a fifo interface to the plbv46 bus and transfers data to the xps_ll_temac's local link interface. The dma cores transfer data directly out of memory into the local link interface.
Because fifo and dma functionality is not included directly in the xps_ll_temac, the lltemac driver also does not have any routines to transfer data. Instead the lltemac driver relies upon a second driver that can control, for example, the xps_ll_fifo or dma cores.
This guide will lay out the steps for porting your code from using the temac driver to the lltemac driver.
There are 2 primary differences between the temac driver and the lltemac driver.
What used to be a single main operation to initialize the plb_temac driver, is now broken out into multiple steps. For a system with the xps_ll_temac core, the lltemac driver along with the driver for the core attached to the xps_ll_temac's local link interface must both be initialized.
Here is an example of how a plb_temac instance might be initialized:
XTemac_Config *TemacCfg; XTemac TemacInst;
TemacCfg = XTemac_LookupConfig(XTEMAC_DEVICE_ID); XTemac_CfgInitialize(&TemacInst, TemacCfg, TemacCfg->BaseAddress);
Here is an example of the lltemac method, utilizing the llfifo driver:
XLlTemac_Config *TemacCfg; XLlTemac TemacInst; XLlFifo FifoInst;
TemacCfg = XLltemac_LookupConfig(XTEMAC_DEVICE_ID); XLlTemac_CfgInitialize(&TemacInst, TemacCfg, TemacCfg->BaseAddress);
if (XLlTemac_IsDma(&TemacInst)) { XLlDma_Initialize(&FifoInst, TemacCfg->LLDevBaseAddress); } else { XLlFifo_Initialize(&FifoInst, TemacCfg->LLDevBaseAddress); }
The temac driver handled the temac interrupts and provided a way to register callback routines using the XTemac_SetHandler() routine. The lltemac driver does not handle interrupts. Instead the application or O/S driver must register its own interrupt handlers.
Note that for data transfers, the application or O/S driver will want to handle the interrupts for the xps_ll_fifo or mpmc/sdma core and not use the tx or rx completion interrupts in the xps_ll_temac core. The xps_ll_temac rx and tx completion interrupts will trigger transfer completions at the wrong time, either before data has been transferred to the xps_ll_fifo or mpmc/smda core, or too late, after data has been transmitted out of the xps_ll_temac core when the driver only cares that the data is out of the xps_ll_fifo or mpmc/sdma core.
The only interrupts from the xps_ll_temac core the application or O/S driver may care about are the fifo overflow, or rx reject interrupts. These are informational interrupts and no action is necessary to recover.
Here is an example of how the application or O/S code might register a callback routine for dma receive:
void DmaRecvHandler(void *ref) { ... }
XTemac_SetHandler(&TemacInst, XTE_HANDLER_SGRECV, DmaRecvHandler, ref);
For the lltemac driver the handler must be registered with the O/S or with the Xilinx interrupt driver, xintc:
void DmaRecvHandler(XLlDma_BdRing *RxRingPtr) { ... }
// EDK puts local link attached core interrupt id into lltemac config // Call the xintc driver to set up the interrupt handler. XIntc_Connect(&IntcInst, TemacCfg->LLDmaRxIntr, (XinterruptHandler) DmaRecvHandler, RxRingPtr);
The plb_temac's fifo mode supported filling the fifos with multiple packets before transmitting data. The xps_ll_fifo, that comes with the EDK version 9.2 or later, does not support this feature. If your existing code uses plb_temac to stuff the fifos, then your algorithm for writing to the fifos may have to be modified. Your existing code may transfer one frame at a time. If this is the case, then your algorithm will be fine, and just the routine calls will need to be modified.
Note that the xps_ll_fifo core has internal buffer sizes fixed at 2K bytes, which prevents the use of jumbo frames in ethernet.
Here is an example of how the temac driver might be used to write packets using fifo mode:
// packet data in the variable, char *Frames[]; // number of bytes in the frame in, int FrameSizes[]; // number of frames in, int framesToSend;
ramesWritten = 0; for (index = 0; index < framesToSend && XTemac_FifoGetFreeBytes(&TemacInst, XTE_SEND) > FrameSizes[i]; index++) { XTemac_FifoWrite(&TemacInst, Frame, FrameSizes[i], XTE_END+_OF_PACKET); FramesWritten++; }
for (index = 0; index < FramesWritten; index++) { XTemac_FifoSend(&TemacInst, FrameSizes[i]); }
// Poll for completion XTemac_FifoQuerySendStatus(), or rely on interrupt handler
For the llfifo driver the following would be used instead:
// packet data in the variable, char *Frames[]; // number of bytes in the frame in, int FrameSizes[]; // number of frames in, int framesToSend;
for (index = 0; index < framesToSend; index++) { XLlFifo_Write(&FifoInst, Frames[i], FrameSizes[i]); XLlFifo_TxSetLen(&FifoInst, FrameSizes[i]);
// Poll for completion XllFifo_Status(), or rely on interrupt handler }
The new dma driver for the MPMC/SDMA soft core works nearly the same as the driver use in the plb_temac. A few differences to note are:
XCACHE_INVALIDATE_DCACHE_RANGE
, and XCACHE_FLUSH_DCACHE_RANGE
must be defined. Both of these macros take two parameters: a processor address and a length. Note that the O/S drivers provided by Xilinx for VxWorks and Linux already provide these macros in the xenv.h file.See the lltemac and temac driver examples for more details.
Just about everything that could be done with the temac driver can be done in some way using a combination of drivers: lltemac, llfifo, lldma.
The following is a list of routines in the temac driver and and the routines that would be used out of the lltemac, llfifo, lldma set instead.
plb_temac routine | replacement routine |
XTemac_CfgInitialize(Inst, Config, Virt) | XLltemac_CfgInitialize(Inst, Config, Virt) |
XTemac_FifoGetFreeBytes(Inst, Direction) | XLlfifo_RxOccupancy(Inst) or XLlfifo_TxVacancy(Inst) |
XTemac_FifoQueryRecvStatus(Inst) | XLlfifo_Status(Inst) |
XTemac_FifoQuerySendStatus(Inst, StatusPtr) | *StatusPtr = XLlfifo_Status(Inst) |
XTemac_FifoRead(Inst, Buf, Bytes, Eop) | XLlfifo_Read(Inst, Buf, Bytes) |
XTemac_FifoRecv(Inst, BytesPtr) | *BytesPtr = XLlfifo_RxGetLen(Inst) |
XTemac_FifoSend(Inst, Bytes) | XLlfifo_TxSetLen(Inst, Bytes) |
XTemac_FifoWrite(Inst, Buf, Bytes, Eop) | XLlfifo_Write(Inst, Buf, Bytes) |
XTemac_IntrFifoDisable(Inst, Direction) | XLlfifo_IntDisable(Inst, Mask) |
XTemac_IntrFifoEnable(Inst, Direction) | XLlfifo_IntEnable(Inst, Mask) |
XTemac_IntrSgCoalGet(Inst, Direction, ThreshPtr, TimerPtr) | XLldma_BdRingGetCoalesce(RingPtr, ThreshPtr, TimerPtr) |
XTemac_IntrSgCoalSet(Inst, Direction, Thresh, Timer) | XLldma_BdRingSetCoalesce(RingPtr, Thresh, Timer) |
XTemac_IntrSgDisable(Inst, Direction) | XLldma_mBdTringIntDisable(RingPtr, Mask) |
XTemac_IntrSgEnable(Inst, Direction) | XLldma_mBdRingIntEnable(RingPtr, Mask) |
XTemac_LookupConfig(id) | XLltemac_LookupConfig(id) |
XTemac_mGetPhysicalInterface(Inst) | XLltemac_GetPhysicalInterface(Inst) |
XTemac_mIsFifo(Inst) | XLltemac_IsFifo(Inst) |
XTemac_mIsRecvFrame(Inst) | XLlfifo_RxOccupancy(Inst) |
XTemac_mIsRecvFrameDropoped(Inst) | XLltemac_isRecvFrameDropped(Inst) |
XTemac_mIsRxCsum(Inst) | XLltemac_IsRxCsum(Inst) |
XTemac_mIsRxDre(Inst) | N/A |
XTemac_mIsSgDma(Inst) | XLltemac_IsDma(Inst) |
XTemac_mIsStarted(Inst) | XLltemac_IsStarted(Inst) |
XTemac_mIsTxCsum(Inst) | XLltemac_IsTxCsum(Inst) |
XTemac_mSgSendBdCsumEnable(BdPtr) | XLldma_mBdWrite((BdPtr), XLldma_BD_STSCTRL_USR0_OFFSET (XLldma_mBdRead((BdPtr), XLldma_BD_STSCTRL_USR0_OFFSET)) | 1 ) |
XTemac_mSgSendBdCsumDisable(BdPtr) | XLldma_mBdWrite((BdPtr), XLldma_BD_STSCTRL_USR0_OFFSET (XLldma_mBdRead((BdPtr), XLldma_BD_STSCTRL_USR0_OFFSET)) & 0xFFFFFFFE) |
XTemac_mSgSendBdCsumSetup(BdPtr, Start, Insert) | XLldma_mBdWrite((BdPtr), XLldma_BD_USR1_OFFSET, (Start) << 16 | (Insert)) |
XTemac_mSgSendBdCsumSeed(BdPtr, Seed) | XLldma_mBdWrite((BdPtr), XLldma_BD_USR2_OFFSET, Seed) |
XTemac_mSgRecvBdCsumGet(BdPtr) | XLldma_mBdRead((BdPtr), XLldma_BD_USR3_OFFSET) |
XTemac_mSgRecvBdNext(Inst, BdPtr) | XLldma_mBdRingNext(RingPtr, BdPtr) |
XTemac_mSgRecvBdPrev(Inst, BdPtr) | XLldma_mBdRingPrev(RingPtr, BdPtr) |
XTemac_mSgSendBdNext(Inst, BdPtr) | XLldma_mBdRingNext(RingPtr, BdPtr) |
XTemac_mSgSendBdPrev(Inst, BdPtr) | XLldma_mBdRingPrev(RingPtr, BdPtr) |
XTemac_Reset(Inst) | XLltemac_Reset(Inst) |
XTemac_SelfTest(Inst) | N/A |
XTemac_SetHandler(...) | N/A |
XTemac_SetOptions(Inst, Options) | XLltemac_SetOptions(Inst, Options) |
XTemac_SgAlloc(Inst, Direction, NumBd, BdPtr) | XLldma_BdRingAlloc(RingPtr, NumBd, BdPtr) |
XTemac_SgCheck(Inst, Direction) | XLldma_BdRingCheck(RingPtr) |
XTemac_SgCommit(Inst, Direction, NumBd, BdPtr) | XLldma_BdRingToHw(RingPtr, NumBd, BdPtr) |
XTemac_SgFree(Inst, Direction, NumBd, BdPtr) | XLldma_BdRingFree(RingPtr, NumBd, BdPtr) |
XTemac_SgGetProcessed(Inst, Direction, NumBd, BdPtr) | XLldma_BdRingFromHw(RingPtr, NumBd, BdPtr) |
XTemac_SgSetSpace(Inst, Direction, PhysAddr, VirtAddr, Alignment, BdCount, BdTemplate) | XLldma_BdRingCreate(RingPtr, PhysAddr, VirtAddr, Alignment, BdCount), XLldma_BdRingClone(RingPtr, BdTemplate) |
XTemac_SgUnAlloc(Inst, Direction, NumBd, BdPtr) | XLldma_BdRingUnAlloc(RingPtr, NumBd, BdPtr) |
XTemac_Start(Inst) | XLltemac_Start(Inst) |
XTemac_Stop(Inst) | XLltemac_Stop(Inst) |
XTemac_SetOptions(Inst, Options) | XLltemac_SetOptions(Inst, Options) |
XTemac_ClearOptions(Inst, Options) | XLltemac_ClearOptions(Inst, Options) |
XTemac_GetOptions(Inst) | XLltemac_GetOptions(Inst) |
XTemac_SetMacAddress(Inst, MacAddressPtr) | XLltemac_SetMacAddress(Inst, MacAddressPtr) |
XTemac_GetMacAddress(Inst, MacAddressPtr) | XLltemac_GetMacAddress(Inst, MacAddressPtr) |
XTemac_SetMaPauseAddress(Inst, AddressPtr) | XLltemac_SetMaPauseAddress(Inst, AddressPtr)lltemac |
XTemac_GetMaPauseAddress(Inst, AddressPtr) | XLltemac_GetMaPauseAddress(Inst, AddressPtr) |
XTemac_SendPausePacket(Inst, PauseValue) | XLltemac_SendPausePacket(Inst, PauseValue) |
XTemac_GetSgmiiStatus(Inst, SpeedPtr) | XLltemac_GetSgmiiStatus(Inst, SpeedPtr) |
XTemac_GetRgmiiStatus(Inst, SpeedPtr, FullDuplexPtr, LinkupPtr) | XLltemac_GetRgmiiStatus(Inst, SpeedPtr, FullDuplexPtr, LinkupPtr) |
XTemac_GetOperatingSpeed(Inst) | XLltemac_GetOperatingSpeed(Inst) |
XTemac_SetOperatingSpeed(Inst, speed) | XLltemac_SetOperatingSpeed(Inst, speed) |
XTemac_PhySetMdioDivisor(Inst, Divisor) | XLltemac_PhySetMdioDivisor(Inst, Divisor) |
XTemac_PhyRead(Inst, PhyAddr, RegNum, DataPtr) | XLltemac_PhyRead(Inst, PhyAddr, RegNum, DataPtr) |
XTemac_PhyWrite(Inst, PhyAddr, RegNum, Data) | XLltemac_PhyWrite(Inst, PhyAddr, RegNum, Data) |
XTemac_MulticastAdd(Inst, AddressPtr, Entry) | XLltemac_MulticastAdd(Inst, AddressPtr, Entry) |
XTemac_MulticastGet(Inst, AddressPtr, Entry) | XLltemac_MulticastGet(Inst, AddressPtr, Entry) |
XTemac_MulticastClear(Inst, Entry) | XLltemac_MulticastAdd(Inst, Entry) |
XTemac_GetSoftStats(Inst, StatsPtr) | N/A |
XTemac_ClearSoftStats(Inst) | N/A |
XTemac_SelfTest(Inst) | N/A |
Copyright © 1995-2009 Xilinx, Inc. All rights reserved.