123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344 |
- /******************************************************************************
- *
- * Author: Xilinx, Inc.
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- *
- * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
- * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
- * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD,
- * XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
- * FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING
- * ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
- * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
- * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY
- * WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM
- * CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.
- *
- *
- * Xilinx hardware products are not intended for use in life support
- * appliances, devices, or systems. Use in such applications is
- * expressly prohibited.
- *
- *
- * (c) Copyright 2002-2004 Xilinx Inc.
- * All rights reserved.
- *
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ******************************************************************************/
- /*****************************************************************************/
- /**
- *
- * @file xemac_intr_dma.c
- *
- * Contains functions used in interrupt mode when configured with scatter-gather
- * DMA.
- *
- * The interrupt handler, XEmac_IntrHandlerDma(), must be connected by the user
- * to the interrupt controller.
- *
- * <pre>
- * MODIFICATION HISTORY:
- *
- * Ver Who Date Changes
- * ----- ---- -------- ---------------------------------------------------------
- * 1.00a rpm 07/31/01 First release
- * 1.00b rpm 02/20/02 Repartitioned files and functions
- * 1.00c rpm 12/05/02 New version includes support for simple DMA and the delay
- * argument to SgSend
- * 1.00c rpm 02/03/03 The XST_DMA_SG_COUNT_EXCEEDED return code was removed
- * from SetPktThreshold in the internal DMA driver. Also
- * avoided compiler warnings by initializing Result in the
- * interrupt service routines.
- * 1.00c rpm 03/26/03 Fixed a problem in the interrupt service routines where
- * the interrupt status was toggled clear after a call to
- * ErrorHandler, but if ErrorHandler reset the device the
- * toggle actually asserted the interrupt because the
- * reset had cleared it.
- * </pre>
- *
- ******************************************************************************/
- /***************************** Include Files *********************************/
- #include "xbasic_types.h"
- #include "xemac_i.h"
- #include "xio.h"
- #include "xbuf_descriptor.h"
- #include "xdma_channel.h"
- #include "xipif_v1_23_b.h" /* Uses v1.23b of the IPIF */
- /************************** Constant Definitions *****************************/
- /**************************** Type Definitions *******************************/
- /***************** Macros (Inline Functions) Definitions *********************/
- /************************** Variable Definitions *****************************/
- /************************** Function Prototypes ******************************/
- static void HandleDmaRecvIntr(XEmac * InstancePtr);
- static void HandleDmaSendIntr(XEmac * InstancePtr);
- static void HandleEmacDmaIntr(XEmac * InstancePtr);
- /*****************************************************************************/
- /**
- *
- * Send an Ethernet frame using scatter-gather DMA. The caller attaches the
- * frame to one or more buffer descriptors, then calls this function once for
- * each descriptor. The caller is responsible for allocating and setting up the
- * descriptor. An entire Ethernet frame may or may not be contained within one
- * descriptor. This function simply inserts the descriptor into the scatter-
- * gather engine's transmit list. The caller is responsible for providing mutual
- * exclusion to guarantee that a frame is contiguous in the transmit list. The
- * buffer attached to the descriptor must be word-aligned.
- *
- * The driver updates the descriptor with the device control register before
- * being inserted into the transmit list. If this is the last descriptor in
- * the frame, the inserts are committed, which means the descriptors for this
- * frame are now available for transmission.
- *
- * It is assumed that the upper layer software supplies a correctly formatted
- * Ethernet frame, including the destination and source addresses, the
- * type/length field, and the data field. It is also assumed that upper layer
- * software does not append FCS at the end of the frame.
- *
- * The buffer attached to the descriptor must be word-aligned on the front end.
- *
- * This call is non-blocking. Notification of error or successful transmission
- * is done asynchronously through the send or error callback function.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param BdPtr is the address of a descriptor to be inserted into the transmit
- * ring.
- * @param Delay indicates whether to start the scatter-gather DMA channel
- * immediately, or whether to wait. This allows the user to build up a
- * list of more than one descriptor before starting the transmission of
- * the packets, which allows the application to keep up with DMA and have
- * a constant stream of frames being transmitted. Use XEM_SGDMA_NODELAY or
- * XEM_SGDMA_DELAY, defined in xemac.h, as the value of this argument. If
- * the user chooses to delay and build a list, the user must call this
- * function with the XEM_SGDMA_NODELAY option or call XEmac_Start() to
- * kick off the tranmissions.
- *
- * @return
- *
- * - XST_SUCCESS if the buffer was successfull sent
- * - XST_DEVICE_IS_STOPPED if the Ethernet MAC has not been started yet
- * - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
- * - XST_DMA_SG_LIST_FULL if the descriptor list for the DMA channel is full
- * - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
- * the list because a locked descriptor exists at the insert point
- * - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
- * list, the DMA channel believes there are no new descriptors to commit. If
- * this is ever encountered, there is likely a thread mutual exclusion problem
- * on transmit.
- *
- * @note
- *
- * This function is not thread-safe. The user must provide mutually exclusive
- * access to this function if there are to be multiple threads that can call it.
- *
- * @internal
- *
- * A status that should never be returned from this function, although
- * the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
- * requires a list to be created, and this function requires the device to be
- * started.
- *
- ******************************************************************************/
- XStatus
- XEmac_SgSend(XEmac * InstancePtr, XBufDescriptor * BdPtr, int Delay)
- {
- XStatus Result;
- u32 BdControl;
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(BdPtr != NULL);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- /*
- * Be sure the device is configured for scatter-gather DMA, then be sure
- * it is started.
- */
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- /*
- * Set some descriptor control word defaults (source address increment
- * and local destination address) and the destination address
- * (the FIFO). These are the same for every transmit descriptor.
- */
- BdControl = XBufDescriptor_GetControl(BdPtr);
- XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_SEND_BD_MASK);
- XBufDescriptor_SetDestAddress(BdPtr,
- InstancePtr->BaseAddress +
- XEM_PFIFO_TXDATA_OFFSET);
- /*
- * Put the descriptor in the send list. The DMA component accesses data
- * here that can also be modified in interrupt context, so a critical
- * section is required.
- */
- XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);
- Result = XDmaChannel_PutDescriptor(&InstancePtr->SendChannel, BdPtr);
- if (Result != XST_SUCCESS) {
- XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
- return Result;
- }
- /*
- * If this is the last buffer in the frame, commit the inserts and start
- * the DMA engine if necessary
- */
- if (XBufDescriptor_IsLastControl(BdPtr)) {
- Result = XDmaChannel_CommitPuts(&InstancePtr->SendChannel);
- if (Result != XST_SUCCESS) {
- XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
- return Result;
- }
- if (Delay == XEM_SGDMA_NODELAY) {
- /*
- * Start the DMA channel. Ignore the return status since we know the
- * list exists and has at least one entry and we don't care if the
- * channel is already started. The DMA component accesses data here
- * that can be modified at interrupt or task levels, so a critical
- * section is required.
- */
- (void) XDmaChannel_SgStart(&InstancePtr->SendChannel);
- }
- }
- XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
- return XST_SUCCESS;
- }
- /*****************************************************************************/
- /**
- *
- * Add a descriptor, with an attached empty buffer, into the receive descriptor
- * list. The buffer attached to the descriptor must be word-aligned. This is
- * used by the upper layer software during initialization when first setting up
- * the receive descriptors, and also during reception of frames to replace
- * filled buffers with empty buffers. This function can be called when the
- * device is started or stopped. Note that it does start the scatter-gather DMA
- * engine. Although this is not necessary during initialization, it is not a
- * problem during initialization because the MAC receiver is not yet started.
- *
- * The buffer attached to the descriptor must be word-aligned on both the front
- * end and the back end.
- *
- * Notification of received frames are done asynchronously through the receive
- * callback function.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param BdPtr is a pointer to the buffer descriptor that will be added to the
- * descriptor list.
- *
- * @return
- *
- * - XST_SUCCESS if a descriptor was successfully returned to the driver
- * - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
- * - XST_DMA_SG_LIST_FULL if the receive descriptor list is full
- * - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
- * the list because a locked descriptor exists at the insert point.
- * - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
- * list, the DMA channel believes there are no new descriptors to commit.
- *
- * @internal
- *
- * A status that should never be returned from this function, although
- * the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
- * requires a list to be created, and this function requires the device to be
- * started.
- *
- ******************************************************************************/
- XStatus
- XEmac_SgRecv(XEmac * InstancePtr, XBufDescriptor * BdPtr)
- {
- XStatus Result;
- u32 BdControl;
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(BdPtr != NULL);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- /*
- * Be sure the device is configured for scatter-gather DMA
- */
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- /*
- * Set some descriptor control word defaults (destination address increment
- * and local source address) and the source address (the FIFO). These are
- * the same for every receive descriptor.
- */
- BdControl = XBufDescriptor_GetControl(BdPtr);
- XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_RECV_BD_MASK);
- XBufDescriptor_SetSrcAddress(BdPtr,
- InstancePtr->BaseAddress +
- XEM_PFIFO_RXDATA_OFFSET);
- /*
- * Put the descriptor into the channel's descriptor list and commit.
- * Although this function is likely called within interrupt context, there
- * is the possibility that the upper layer software queues it to a task.
- * In this case, a critical section is needed here to protect shared data
- * in the DMA component.
- */
- XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);
- Result = XDmaChannel_PutDescriptor(&InstancePtr->RecvChannel, BdPtr);
- if (Result != XST_SUCCESS) {
- XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
- return Result;
- }
- Result = XDmaChannel_CommitPuts(&InstancePtr->RecvChannel);
- if (Result != XST_SUCCESS) {
- XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
- return Result;
- }
- /*
- * Start the DMA channel. Ignore the return status since we know the list
- * exists and has at least one entry and we don't care if the channel is
- * already started. The DMA component accesses data here that can be
- * modified at interrupt or task levels, so a critical section is required.
- */
- (void) XDmaChannel_SgStart(&InstancePtr->RecvChannel);
- XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
- return XST_SUCCESS;
- }
- /*****************************************************************************/
- /**
- *
- * The interrupt handler for the Ethernet driver when configured with scatter-
- * gather DMA.
- *
- * Get the interrupt status from the IpIf to determine the source of the
- * interrupt. The source can be: MAC, Recv Packet FIFO, Send Packet FIFO, Recv
- * DMA channel, or Send DMA channel. The packet FIFOs only interrupt during
- * "deadlock" conditions.
- *
- * @param InstancePtr is a pointer to the XEmac instance that just interrupted.
- *
- * @return
- *
- * None.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- void
- XEmac_IntrHandlerDma(void *InstancePtr)
- {
- u32 IntrStatus;
- XEmac *EmacPtr = (XEmac *) InstancePtr;
- EmacPtr->Stats.TotalIntrs++;
- /*
- * Get the interrupt status from the IPIF. There is no clearing of
- * interrupts in the IPIF. Interrupts must be cleared at the source.
- */
- IntrStatus = XIIF_V123B_READ_DIPR(EmacPtr->BaseAddress);
- /*
- * See which type of interrupt is being requested, and service it
- */
- if (IntrStatus & XEM_IPIF_RECV_DMA_MASK) { /* Receive DMA interrupt */
- EmacPtr->Stats.RecvInterrupts++;
- HandleDmaRecvIntr(EmacPtr);
- }
- if (IntrStatus & XEM_IPIF_SEND_DMA_MASK) { /* Send DMA interrupt */
- EmacPtr->Stats.XmitInterrupts++;
- HandleDmaSendIntr(EmacPtr);
- }
- if (IntrStatus & XEM_IPIF_EMAC_MASK) { /* MAC interrupt */
- EmacPtr->Stats.EmacInterrupts++;
- HandleEmacDmaIntr(EmacPtr);
- }
- if (IntrStatus & XEM_IPIF_RECV_FIFO_MASK) { /* Receive FIFO interrupt */
- EmacPtr->Stats.RecvInterrupts++;
- XEmac_CheckFifoRecvError(EmacPtr);
- }
- if (IntrStatus & XEM_IPIF_SEND_FIFO_MASK) { /* Send FIFO interrupt */
- EmacPtr->Stats.XmitInterrupts++;
- XEmac_CheckFifoSendError(EmacPtr);
- }
- if (IntrStatus & XIIF_V123B_ERROR_MASK) {
- /*
- * An error occurred internal to the IPIF. This is more of a debug and
- * integration issue rather than a production error. Don't do anything
- * other than clear it, which provides a spot for software to trap
- * on the interrupt and begin debugging.
- */
- XIIF_V123B_WRITE_DISR(EmacPtr->BaseAddress,
- XIIF_V123B_ERROR_MASK);
- }
- }
- /*****************************************************************************/
- /**
- *
- * Set the packet count threshold for this device. The device must be stopped
- * before setting the threshold. The packet count threshold is used for interrupt
- * coalescing, which reduces the frequency of interrupts from the device to the
- * processor. In this case, the scatter-gather DMA engine only interrupts when
- * the packet count threshold is reached, instead of interrupting for each packet.
- * A packet is a generic term used by the scatter-gather DMA engine, and is
- * equivalent to an Ethernet frame in our case.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param Direction indicates the channel, send or receive, from which the
- * threshold register is read.
- * @param Threshold is the value of the packet threshold count used during
- * interrupt coalescing. A value of 0 disables the use of packet threshold
- * by the hardware.
- *
- * @return
- *
- * - XST_SUCCESS if the threshold was successfully set
- * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
- * - XST_DEVICE_IS_STARTED if the device has not been stopped
- * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
- * asserts would also catch this error.
- *
- * @note
- *
- * The packet threshold could be set to larger than the number of descriptors
- * allocated to the DMA channel. In this case, the wait bound will take over
- * and always indicate data arrival. There was a check in this function that
- * returned an error if the treshold was larger than the number of descriptors,
- * but that was removed because users would then have to set the threshold
- * only after they set descriptor space, which is an order dependency that
- * caused confustion.
- *
- ******************************************************************************/
- XStatus
- XEmac_SetPktThreshold(XEmac * InstancePtr, u32 Direction, u8 Threshold)
- {
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- /*
- * Be sure device is configured for scatter-gather DMA and has been stopped
- */
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) {
- return XST_DEVICE_IS_STARTED;
- }
- /*
- * Based on the direction, set the packet threshold in the
- * corresponding DMA channel component. Default to the receive
- * channel threshold register (if an invalid Direction is passed).
- */
- switch (Direction) {
- case XEM_SEND:
- return XDmaChannel_SetPktThreshold(&InstancePtr->SendChannel,
- Threshold);
- case XEM_RECV:
- return XDmaChannel_SetPktThreshold(&InstancePtr->RecvChannel,
- Threshold);
- default:
- return XST_INVALID_PARAM;
- }
- }
- /*****************************************************************************/
- /**
- *
- * Get the value of the packet count threshold for this driver/device. The packet
- * count threshold is used for interrupt coalescing, which reduces the frequency
- * of interrupts from the device to the processor. In this case, the
- * scatter-gather DMA engine only interrupts when the packet count threshold is
- * reached, instead of interrupting for each packet. A packet is a generic term
- * used by the scatter-gather DMA engine, and is equivalent to an Ethernet frame
- * in our case.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param Direction indicates the channel, send or receive, from which the
- * threshold register is read.
- * @param ThreshPtr is a pointer to the byte into which the current value of the
- * packet threshold register will be copied. An output parameter. A value
- * of 0 indicates the use of packet threshold by the hardware is disabled.
- *
- * @return
- *
- * - XST_SUCCESS if the packet threshold was retrieved successfully
- * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
- * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
- * asserts would also catch this error.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- XStatus
- XEmac_GetPktThreshold(XEmac * InstancePtr, u32 Direction, u8 * ThreshPtr)
- {
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
- XASSERT_NONVOID(ThreshPtr != NULL);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- /*
- * Based on the direction, return the packet threshold set in the
- * corresponding DMA channel component. Default to the value in
- * the receive channel threshold register (if an invalid Direction
- * is passed).
- */
- switch (Direction) {
- case XEM_SEND:
- *ThreshPtr =
- XDmaChannel_GetPktThreshold(&InstancePtr->SendChannel);
- break;
- case XEM_RECV:
- *ThreshPtr =
- XDmaChannel_GetPktThreshold(&InstancePtr->RecvChannel);
- break;
- default:
- return XST_INVALID_PARAM;
- }
- return XST_SUCCESS;
- }
- /*****************************************************************************/
- /**
- *
- * Set the packet wait bound timer for this driver/device. The device must be
- * stopped before setting the timer value. The packet wait bound is used during
- * interrupt coalescing to trigger an interrupt when not enough packets have been
- * received to reach the packet count threshold. A packet is a generic term used
- * by the scatter-gather DMA engine, and is equivalent to an Ethernet frame in
- * our case. The timer is in milliseconds.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param Direction indicates the channel, send or receive, from which the
- * threshold register is read.
- * @param TimerValue is the value of the packet wait bound used during interrupt
- * coalescing. It is in milliseconds in the range 0 - 1023. A value of 0
- * disables the packet wait bound timer.
- *
- * @return
- *
- * - XST_SUCCESS if the packet wait bound was set successfully
- * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
- * - XST_DEVICE_IS_STARTED if the device has not been stopped
- * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
- * asserts would also catch this error.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- XStatus
- XEmac_SetPktWaitBound(XEmac * InstancePtr, u32 Direction, u32 TimerValue)
- {
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
- XASSERT_NONVOID(TimerValue <= XEM_SGDMA_MAX_WAITBOUND);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- /*
- * Be sure device is configured for scatter-gather DMA and has been stopped
- */
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) {
- return XST_DEVICE_IS_STARTED;
- }
- /*
- * Based on the direction, set the packet wait bound in the
- * corresponding DMA channel component. Default to the receive
- * channel wait bound register (if an invalid Direction is passed).
- */
- switch (Direction) {
- case XEM_SEND:
- XDmaChannel_SetPktWaitBound(&InstancePtr->SendChannel,
- TimerValue);
- break;
- case XEM_RECV:
- XDmaChannel_SetPktWaitBound(&InstancePtr->RecvChannel,
- TimerValue);
- break;
- default:
- return XST_INVALID_PARAM;
- }
- return XST_SUCCESS;
- }
- /*****************************************************************************/
- /**
- *
- * Get the packet wait bound timer for this driver/device. The packet wait bound
- * is used during interrupt coalescing to trigger an interrupt when not enough
- * packets have been received to reach the packet count threshold. A packet is a
- * generic term used by the scatter-gather DMA engine, and is equivalent to an
- * Ethernet frame in our case. The timer is in milliseconds.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param Direction indicates the channel, send or receive, from which the
- * threshold register is read.
- * @param WaitPtr is a pointer to the byte into which the current value of the
- * packet wait bound register will be copied. An output parameter. Units
- * are in milliseconds in the range 0 - 1023. A value of 0 indicates the
- * packet wait bound timer is disabled.
- *
- * @return
- *
- * - XST_SUCCESS if the packet wait bound was retrieved successfully
- * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
- * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
- * asserts would also catch this error.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- XStatus
- XEmac_GetPktWaitBound(XEmac * InstancePtr, u32 Direction, u32 * WaitPtr)
- {
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
- XASSERT_NONVOID(WaitPtr != NULL);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- /*
- * Based on the direction, return the packet wait bound set in the
- * corresponding DMA channel component. Default to the value in
- * the receive channel wait bound register (if an invalid Direction
- * is passed).
- */
- switch (Direction) {
- case XEM_SEND:
- *WaitPtr =
- XDmaChannel_GetPktWaitBound(&InstancePtr->SendChannel);
- break;
- case XEM_RECV:
- *WaitPtr =
- XDmaChannel_GetPktWaitBound(&InstancePtr->RecvChannel);
- break;
- default:
- return XST_INVALID_PARAM;
- }
- return XST_SUCCESS;
- }
- /*****************************************************************************/
- /**
- *
- * Give the driver the memory space to be used for the scatter-gather DMA
- * receive descriptor list. This function should only be called once, during
- * initialization of the Ethernet driver. The memory space must be big enough
- * to hold some number of descriptors, depending on the needs of the system.
- * The xemac.h file defines minimum and default numbers of descriptors
- * which can be used to allocate this memory space.
- *
- * The memory space must be word-aligned. An assert will occur if asserts are
- * turned on and the memory is not word-aligned.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param MemoryPtr is a pointer to the word-aligned memory.
- * @param ByteCount is the length, in bytes, of the memory space.
- *
- * @return
- *
- * - XST_SUCCESS if the space was initialized successfully
- * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
- * - XST_DMA_SG_LIST_EXISTS if this list space has already been created
- *
- * @note
- *
- * If the device is configured for scatter-gather DMA, this function must be
- * called AFTER the XEmac_Initialize() function because the DMA channel
- * components must be initialized before the memory space is set.
- *
- ******************************************************************************/
- XStatus
- XEmac_SetSgRecvSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
- {
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(MemoryPtr != NULL);
- XASSERT_NONVOID(ByteCount != 0);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- return XDmaChannel_CreateSgList(&InstancePtr->RecvChannel, MemoryPtr,
- ByteCount);
- }
- /*****************************************************************************/
- /**
- *
- * Give the driver the memory space to be used for the scatter-gather DMA
- * transmit descriptor list. This function should only be called once, during
- * initialization of the Ethernet driver. The memory space must be big enough
- * to hold some number of descriptors, depending on the needs of the system.
- * The xemac.h file defines minimum and default numbers of descriptors
- * which can be used to allocate this memory space.
- *
- * The memory space must be word-aligned. An assert will occur if asserts are
- * turned on and the memory is not word-aligned.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param MemoryPtr is a pointer to the word-aligned memory.
- * @param ByteCount is the length, in bytes, of the memory space.
- *
- * @return
- *
- * - XST_SUCCESS if the space was initialized successfully
- * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
- * - XST_DMA_SG_LIST_EXISTS if this list space has already been created
- *
- * @note
- *
- * If the device is configured for scatter-gather DMA, this function must be
- * called AFTER the XEmac_Initialize() function because the DMA channel
- * components must be initialized before the memory space is set.
- *
- ******************************************************************************/
- XStatus
- XEmac_SetSgSendSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
- {
- XASSERT_NONVOID(InstancePtr != NULL);
- XASSERT_NONVOID(MemoryPtr != NULL);
- XASSERT_NONVOID(ByteCount != 0);
- XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- if (!XEmac_mIsSgDma(InstancePtr)) {
- return XST_NOT_SGDMA;
- }
- return XDmaChannel_CreateSgList(&InstancePtr->SendChannel, MemoryPtr,
- ByteCount);
- }
- /*****************************************************************************/
- /**
- *
- * Set the callback function for handling received frames in scatter-gather DMA
- * mode. The upper layer software should call this function during
- * initialization. The callback is called once per frame received. The head of
- * a descriptor list is passed in along with the number of descriptors in the
- * list. Before leaving the callback, the upper layer software should attach a
- * new buffer to each descriptor in the list.
- *
- * The callback is invoked by the driver within interrupt context, so it needs
- * to do its job quickly. Sending the received frame up the protocol stack
- * should be done at task-level. If there are other potentially slow operations
- * within the callback, these too should be done at task-level.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param CallBackRef is a reference pointer to be passed back to the adapter in
- * the callback. This helps the adapter correlate the callback to a
- * particular driver.
- * @param FuncPtr is the pointer to the callback function.
- *
- * @return
- *
- * None.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- void
- XEmac_SetSgRecvHandler(XEmac * InstancePtr, void *CallBackRef,
- XEmac_SgHandler FuncPtr)
- {
- /*
- * Asserted IsDmaSg here instead of run-time check because there is really
- * no ill-effects of setting these when not configured for scatter-gather.
- */
- XASSERT_VOID(InstancePtr != NULL);
- XASSERT_VOID(FuncPtr != NULL);
- XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
- XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- InstancePtr->SgRecvHandler = FuncPtr;
- InstancePtr->SgRecvRef = CallBackRef;
- }
- /*****************************************************************************/
- /**
- *
- * Set the callback function for handling confirmation of transmitted frames in
- * scatter-gather DMA mode. The upper layer software should call this function
- * during initialization. The callback is called once per frame sent. The head
- * of a descriptor list is passed in along with the number of descriptors in
- * the list. The callback is responsible for freeing buffers attached to these
- * descriptors.
- *
- * The callback is invoked by the driver within interrupt context, so it needs
- * to do its job quickly. If there are potentially slow operations within the
- * callback, these should be done at task-level.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- * @param CallBackRef is a reference pointer to be passed back to the adapter in
- * the callback. This helps the adapter correlate the callback to a
- * particular driver.
- * @param FuncPtr is the pointer to the callback function.
- *
- * @return
- *
- * None.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- void
- XEmac_SetSgSendHandler(XEmac * InstancePtr, void *CallBackRef,
- XEmac_SgHandler FuncPtr)
- {
- /*
- * Asserted IsDmaSg here instead of run-time check because there is really
- * no ill-effects of setting these when not configured for scatter-gather.
- */
- XASSERT_VOID(InstancePtr != NULL);
- XASSERT_VOID(FuncPtr != NULL);
- XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
- XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
- InstancePtr->SgSendHandler = FuncPtr;
- InstancePtr->SgSendRef = CallBackRef;
- }
- /*****************************************************************************/
- /*
- *
- * Handle an interrupt from the DMA receive channel. DMA interrupts are:
- *
- * - DMA error. DMA encountered a bus error or timeout. This is a fatal error
- * that requires reset of the channel. The driver calls the error handler
- * of the upper layer software with an error code indicating the device should
- * be reset.
- * - Packet count threshold reached. For scatter-gather operations, indicates
- * the threshold for the number of packets not serviced by software has been
- * reached. The driver behaves as follows:
- * - Get the value of the packet counter, which tells us how many packets
- * are ready to be serviced
- * - For each packet
- * - For each descriptor, remove it from the scatter-gather list
- * - Check for the last descriptor in the frame, and if set
- * - Bump frame statistics
- * - Call the scatter-gather receive callback function
- * - Decrement the packet counter by one
- * Note that there are no receive errors reported in the status word of
- * the buffer descriptor. If receive errors occur, the MAC drops the
- * packet, and we only find out about the errors through various error
- * count registers.
- * - Packet wait bound reached. For scatter-gather, indicates the time to wait
- * for the next packet has expired. The driver follows the same logic as when
- * the packet count threshold interrupt is received.
- * - Scatter-gather end acknowledge. Hardware has reached the end of the
- * descriptor list. The driver follows the same logic as when the packet count
- * threshold interrupt is received. In addition, the driver restarts the DMA
- * scatter-gather channel in case there are newly inserted descriptors.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- *
- * @return
- *
- * Although the function returns void, there are asynchronous errors that can
- * be generated (by calling the ErrorHandler) from this function. These are:
- * - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from the
- * DMA channel, but there was not one ready for software.
- * - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a fatal
- * error that requires reset.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- static void
- HandleDmaRecvIntr(XEmac * InstancePtr)
- {
- u32 IntrStatus;
- /*
- * Read the interrupt status
- */
- IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->RecvChannel);
- /*
- * For packet threshold or wait bound interrupts, process desciptors. Also
- * process descriptors on a SG end acknowledgement, which means the end of
- * the descriptor list has been reached by the hardware. For receive, this
- * is potentially trouble since it means the descriptor list is full,
- * unless software can process enough packets quickly enough so the
- * hardware has room to put new packets.
- */
- if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
- XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
- XStatus Result = XST_SUCCESS;
- u32 NumFrames;
- u32 NumProcessed;
- u32 NumBuffers;
- u32 NumBytes;
- u32 IsLast;
- XBufDescriptor *FirstBdPtr;
- XBufDescriptor *BdPtr;
- /*
- * Get the number of unserviced packets
- */
- NumFrames = XDmaChannel_GetPktCount(&InstancePtr->RecvChannel);
- for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
- IsLast = FALSE;
- FirstBdPtr = NULL;
- NumBuffers = 0;
- NumBytes = 0;
- /*
- * For each packet, get the descriptor from the list. On the
- * last one in the frame, make the callback to the upper layer.
- */
- while (!IsLast) {
- Result =
- XDmaChannel_GetDescriptor(&InstancePtr->
- RecvChannel,
- &BdPtr);
- if (Result != XST_SUCCESS) {
- /*
- * An error getting a buffer descriptor from the list.
- * This should not happen, but if it does, report it to
- * the error callback and break out of the loops to service
- * other interrupts.
- */
- InstancePtr->ErrorHandler(InstancePtr->
- ErrorRef,
- Result);
- break;
- }
- /*
- * Keep a pointer to the first descriptor in the list, as it
- * will be passed to the upper layers in a bit. By the fact
- * that we received this packet means no errors occurred, so
- * no need to check the device status word for errors.
- */
- if (FirstBdPtr == NULL) {
- FirstBdPtr = BdPtr;
- }
- NumBytes += XBufDescriptor_GetLength(BdPtr);
- /*
- * Check to see if this is the last descriptor in the frame,
- * and if so, set the IsLast flag to get out of the loop.
- */
- if (XBufDescriptor_IsLastStatus(BdPtr)) {
- IsLast = TRUE;
- }
- /*
- * Bump the number of buffers in this packet
- */
- NumBuffers++;
- } /* end while loop */
- /*
- * Check for error that occurred inside the while loop, and break
- * out of the for loop if there was one so other interrupts can
- * be serviced.
- */
- if (Result != XST_SUCCESS) {
- break;
- }
- InstancePtr->Stats.RecvFrames++;
- InstancePtr->Stats.RecvBytes += NumBytes;
- /*
- * Make the callback to the upper layers, passing it the first
- * descriptor in the packet and the number of descriptors in the
- * packet.
- */
- InstancePtr->SgRecvHandler(InstancePtr->SgRecvRef,
- FirstBdPtr, NumBuffers);
- /*
- * Decrement the packet count register to reflect the fact we
- * just processed a packet
- */
- XDmaChannel_DecrementPktCount(&InstancePtr->
- RecvChannel);
- } /* end for loop */
- /*
- * If the interrupt was an end-ack, check the descriptor list again to
- * see if it is empty. If not, go ahead and restart the scatter-gather
- * channel. This is to fix a possible race condition where, on receive,
- * the driver attempted to start a scatter-gather channel that was
- * already started, which resulted in no action from the XDmaChannel
- * component. But, just after the XDmaChannel component saw that the
- * hardware was already started, the hardware stopped because it
- * reached the end of the list. In that case, this interrupt is
- * generated and we can restart the hardware here.
- */
- if (IntrStatus & XDC_IXR_SG_END_MASK) {
- /*
- * Ignore the return status since we know the list exists and we
- * don't care if the list is empty or the channel is already started.
- */
- (void) XDmaChannel_SgStart(&InstancePtr->RecvChannel);
- }
- }
- /*
- * All interrupts are handled (except the error below) so acknowledge
- * (clear) the interrupts by writing the value read above back to the status
- * register. The packet count interrupt must be acknowledged after the
- * decrement, otherwise it will come right back. We clear the interrupts
- * before we handle the error interrupt because the ErrorHandler should
- * result in a reset, which clears the interrupt status register. So we
- * don't want to toggle the interrupt back on by writing the interrupt
- * status register with an old value after a reset.
- */
- XDmaChannel_SetIntrStatus(&InstancePtr->RecvChannel, IntrStatus);
- /*
- * Check for DMA errors and call the error callback function if an error
- * occurred (DMA bus or timeout error), which should result in a reset of
- * the device by the upper layer software.
- */
- if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
- InstancePtr->Stats.DmaErrors++;
- InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
- }
- }
- /*****************************************************************************/
- /*
- *
- * Handle an interrupt from the DMA send channel. DMA interrupts are:
- *
- * - DMA error. DMA encountered a bus error or timeout. This is a fatal error
- * that requires reset of the channel. The driver calls the error handler
- * of the upper layer software with an error code indicating the device should
- * be reset.
- * - Packet count threshold reached. For scatter-gather operations, indicates
- * the threshold for the number of packets not serviced by software has been
- * reached. The driver behaves as follows:
- * - Get the value of the packet counter, which tells us how many packets
- * are ready to be serviced
- * - For each packet
- * - For each descriptor, remove it from the scatter-gather list
- * - Check for the last descriptor in the frame, and if set
- * - Bump frame statistics
- * - Call the scatter-gather receive callback function
- * - Decrement the packet counter by one
- * Note that there are no receive errors reported in the status word of
- * the buffer descriptor. If receive errors occur, the MAC drops the
- * packet, and we only find out about the errors through various error
- * count registers.
- * - Packet wait bound reached. For scatter-gather, indicates the time to wait
- * for the next packet has expired. The driver follows the same logic as when
- * the packet count threshold interrupt is received.
- * - Scatter-gather end acknowledge. Hardware has reached the end of the
- * descriptor list. The driver follows the same logic as when the packet count
- * threshold interrupt is received. In addition, the driver restarts the DMA
- * scatter-gather channel in case there are newly inserted descriptors.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- *
- * @return
- *
- * Although the function returns void, there are asynchronous errors
- * that can be generated from this function. These are:
- * - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from
- * the DMA channel, but there was not one ready for software.
- * - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a
- * fatal error that requires reset.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- static void
- HandleDmaSendIntr(XEmac * InstancePtr)
- {
- u32 IntrStatus;
- /*
- * Read the interrupt status
- */
- IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->SendChannel);
- /*
- * For packet threshold or wait bound interrupt, process descriptors. Also
- * process descriptors on a SG end acknowledgement, which means the end of
- * the descriptor list has been reached by the hardware. For transmit,
- * this is a normal condition during times of light traffic. In fact, the
- * wait bound interrupt may be masked for transmit since the end-ack would
- * always occur before the wait bound expires.
- */
- if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
- XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
- XStatus Result = XST_SUCCESS;
- u32 NumFrames;
- u32 NumProcessed;
- u32 NumBuffers;
- u32 NumBytes;
- u32 IsLast;
- XBufDescriptor *FirstBdPtr;
- XBufDescriptor *BdPtr;
- /*
- * Get the number of unserviced packets
- */
- NumFrames = XDmaChannel_GetPktCount(&InstancePtr->SendChannel);
- for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
- IsLast = FALSE;
- FirstBdPtr = NULL;
- NumBuffers = 0;
- NumBytes = 0;
- /*
- * For each frame, traverse the descriptor list and look for
- * errors. On the last one in the frame, make the callback.
- */
- while (!IsLast) {
- Result =
- XDmaChannel_GetDescriptor(&InstancePtr->
- SendChannel,
- &BdPtr);
- if (Result != XST_SUCCESS) {
- /*
- * An error getting a buffer descriptor from the list.
- * This should not happen, but if it does, report it to
- * the error callback and break out of the loops to service
- * other interrupts
- */
- InstancePtr->ErrorHandler(InstancePtr->
- ErrorRef,
- Result);
- break;
- }
- /*
- * Keep a pointer to the first descriptor in the list and
- * check the device status for errors. The device status is
- * only available in the first descriptor of a packet.
- */
- if (FirstBdPtr == NULL) {
- u32 XmitStatus;
- FirstBdPtr = BdPtr;
- XmitStatus =
- XBufDescriptor_GetDeviceStatus
- (BdPtr);
- if (XmitStatus &
- XEM_TSR_EXCESS_DEFERRAL_MASK) {
- InstancePtr->Stats.
- XmitExcessDeferral++;
- }
- if (XmitStatus &
- XEM_TSR_LATE_COLLISION_MASK) {
- InstancePtr->Stats.
- XmitLateCollisionErrors++;
- }
- }
- NumBytes += XBufDescriptor_GetLength(BdPtr);
- /*
- * Check to see if this is the last descriptor in the frame,
- * and if so, set the IsLast flag to get out of the loop. The
- * transmit channel must check the last bit in the control
- * word, not the status word (the DMA engine does not update
- * the last bit in the status word for the transmit direction).
- */
- if (XBufDescriptor_IsLastControl(BdPtr)) {
- IsLast = TRUE;
- }
- /*
- * Bump the number of buffers in this packet
- */
- NumBuffers++;
- } /* end while loop */
- /*
- * Check for error that occurred inside the while loop, and break
- * out of the for loop if there was one so other interrupts can
- * be serviced.
- */
- if (Result != XST_SUCCESS) {
- break;
- }
- InstancePtr->Stats.XmitFrames++;
- InstancePtr->Stats.XmitBytes += NumBytes;
- /*
- * Make the callback to the upper layers, passing it the first
- * descriptor in the packet and the number of descriptors in the
- * packet.
- */
- InstancePtr->SgSendHandler(InstancePtr->SgSendRef,
- FirstBdPtr, NumBuffers);
- /*
- * Decrement the packet count register to reflect the fact we
- * just processed a packet
- */
- XDmaChannel_DecrementPktCount(&InstancePtr->
- SendChannel);
- } /* end for loop */
- /*
- * If the interrupt was an end-ack, check the descriptor list again to
- * see if it is empty. If not, go ahead and restart the scatter-gather
- * channel. This is to fix a possible race condition where, on transmit,
- * the driver attempted to start a scatter-gather channel that was
- * already started, which resulted in no action from the XDmaChannel
- * component. But, just after the XDmaChannel component saw that the
- * hardware was already started, the hardware stopped because it
- * reached the end of the list. In that case, this interrupt is
- * generated and we can restart the hardware here.
- */
- if (IntrStatus & XDC_IXR_SG_END_MASK) {
- /*
- * Ignore the return status since we know the list exists and we
- * don't care if the list is empty or the channel is already started.
- */
- (void) XDmaChannel_SgStart(&InstancePtr->SendChannel);
- }
- }
- /*
- * All interrupts are handled (except the error below) so acknowledge
- * (clear) the interrupts by writing the value read above back to the status
- * register. The packet count interrupt must be acknowledged after the
- * decrement, otherwise it will come right back. We clear the interrupts
- * before we handle the error interrupt because the ErrorHandler should
- * result in a reset, which clears the interrupt status register. So we
- * don't want to toggle the interrupt back on by writing the interrupt
- * status register with an old value after a reset.
- */
- XDmaChannel_SetIntrStatus(&InstancePtr->SendChannel, IntrStatus);
- /*
- * Check for DMA errors and call the error callback function if an error
- * occurred (DMA bus or timeout error), which should result in a reset of
- * the device by the upper layer software.
- */
- if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
- InstancePtr->Stats.DmaErrors++;
- InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
- }
- }
- /*****************************************************************************/
- /*
- *
- * Handle an interrupt from the Ethernet MAC when configured with scatter-gather
- * DMA. The only interrupts handled in this case are errors.
- *
- * @param InstancePtr is a pointer to the XEmac instance to be worked on.
- *
- * @return
- *
- * None.
- *
- * @note
- *
- * None.
- *
- ******************************************************************************/
- static void
- HandleEmacDmaIntr(XEmac * InstancePtr)
- {
- u32 IntrStatus;
- /*
- * When configured with DMA, the EMAC generates interrupts only when errors
- * occur. We clear the interrupts immediately so that any latched status
- * interrupt bits will reflect the true status of the device, and so any
- * pulsed interrupts (non-status) generated during the Isr will not be lost.
- */
- IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
- XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, IntrStatus);
- /*
- * Check the MAC for errors
- */
- XEmac_CheckEmacError(InstancePtr, IntrStatus);
- }
|