mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-25 01:58:13 +01:00 
			
		
		
		
	Add support for the Xilinx ML300 platform * Patch by Stephan Linz, 17 Feb 2004: Fix watchdog support for NIOS * Patch by Josh Fryman, 16 Feb 2004: Fix byte-swapping for cfi_flash.c for different bus widths * Patch by Jon Diekema, 14 Jeb 2004: Remove duplicate "FPGA Support" notes from the README file
		
			
				
	
	
		
			1345 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1345 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /******************************************************************************
 | |
| *
 | |
| *     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);
 | |
| }
 |