|
@@ -0,0 +1,1344 @@
|
|
|
|
+/******************************************************************************
|
|
|
|
+*
|
|
|
|
+* 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);
|
|
|
|
+}
|