diff options
Diffstat (limited to 'board/xilinx/xilinx_enet/xemac_polled.c')
| -rw-r--r-- | board/xilinx/xilinx_enet/xemac_polled.c | 482 | 
1 files changed, 482 insertions, 0 deletions
| diff --git a/board/xilinx/xilinx_enet/xemac_polled.c b/board/xilinx/xilinx_enet/xemac_polled.c new file mode 100644 index 000000000..23768bca7 --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac_polled.c @@ -0,0 +1,482 @@ +/****************************************************************************** +* +*     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_polled.c +* +* Contains functions used when the driver is in polled mode. Use the +* XEmac_SetOptions() function to put the driver into polled mode. +* +* <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 +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xemac_i.h" +#include "xio.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 ******************************/ + +/*****************************************************************************/ +/** +* +* Send an Ethernet frame in polled mode.  The device/driver must be in polled +* mode before calling this function. The driver writes the frame directly to +* the MAC's packet FIFO, then enters a loop checking the device status for +* completion or error. Statistics are updated if an error occurs. The buffer +* to be sent must be word-aligned. +* +* 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. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param BufPtr is a pointer to a word-aligned buffer containing the Ethernet +*        frame to be sent. +* @param ByteCount is the size of the Ethernet frame. +* +* @return +* +* - XST_SUCCESS if the frame was sent successfully +* - XST_DEVICE_IS_STOPPED if the device has not yet been started +* - XST_NOT_POLLED if the device is not in polled mode +* - XST_FIFO_NO_ROOM if there is no room in the EMAC's length FIFO for this frame +* - XST_FIFO_ERROR if the FIFO was overrun or underrun. This error is critical +*   and requires the caller to reset the device. +* - XST_EMAC_COLLISION if the send failed due to excess deferral or late +*   collision +* +* @note +* +* There is the possibility that this function will not return if the hardware +* is broken (i.e., it never sets the status bit indicating that transmission is +* done). If this is of concern to the user, the user should provide protection +* from this problem - perhaps by using a different timer thread to monitor the +* PollSend thread. On a 10Mbps MAC, it takes about 1.21 msecs to transmit a +* maximum size Ethernet frame (1518 bytes). On a 100Mbps MAC, it takes about +* 121 usecs to transmit a maximum size Ethernet frame. +* +* @internal +* +* The EMAC uses FIFOs behind its length and status registers. For this reason, +* it is important to keep the length, status, and data FIFOs in sync when +* reading or writing to them. +* +******************************************************************************/ +XStatus +XEmac_PollSend(XEmac * InstancePtr, u8 * BufPtr, u32 ByteCount) +{ +	u32 IntrStatus; +	u32 XmitStatus; +	XStatus Result; + +	XASSERT_NONVOID(InstancePtr != NULL); +	XASSERT_NONVOID(BufPtr != NULL); +	XASSERT_NONVOID(ByteCount > XEM_HDR_SIZE);	/* send at least 1 byte */ +	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + +	/* +	 * Be sure the device is configured for polled mode and it is started +	 */ +	if (!InstancePtr->IsPolled) { +		return XST_NOT_POLLED; +	} + +	if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { +		return XST_DEVICE_IS_STOPPED; +	} + +	/* +	 * Check for overruns and underruns for the transmit status and length +	 * FIFOs and make sure the send packet FIFO is not deadlocked. Any of these +	 * conditions is bad enough that we do not want to continue. The upper layer +	 * software should reset the device to resolve the error. +	 */ +	IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); + +	/* +	 * Overrun errors +	 */ +	if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK | +			  XEM_EIR_XMIT_LFIFO_OVER_MASK)) { +		InstancePtr->Stats.XmitOverrunErrors++; +		InstancePtr->Stats.FifoErrors++; +		return XST_FIFO_ERROR; +	} + +	/* +	 * Underrun errors +	 */ +	if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK | +			  XEM_EIR_XMIT_LFIFO_UNDER_MASK)) { +		InstancePtr->Stats.XmitUnderrunErrors++; +		InstancePtr->Stats.FifoErrors++; +		return XST_FIFO_ERROR; +	} + +	if (XPF_V100B_IS_DEADLOCKED(&InstancePtr->SendFifo)) { +		InstancePtr->Stats.FifoErrors++; +		return XST_FIFO_ERROR; +	} + +	/* +	 * Before writing to the data FIFO, make sure the length FIFO is not +	 * full.  The data FIFO might not be full yet even though the length FIFO +	 * is. This avoids an overrun condition on the length FIFO and keeps the +	 * FIFOs in sync. +	 */ +	if (IntrStatus & XEM_EIR_XMIT_LFIFO_FULL_MASK) { +		/* +		 * Clear the latched LFIFO_FULL bit so next time around the most +		 * current status is represented +		 */ +		XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, +				      XEM_EIR_XMIT_LFIFO_FULL_MASK); +		return XST_FIFO_NO_ROOM; +	} + +	/* +	 * This is a non-blocking write. The packet FIFO returns an error if there +	 * is not enough room in the FIFO for this frame. +	 */ +	Result = +	    XPacketFifoV100b_Write(&InstancePtr->SendFifo, BufPtr, ByteCount); +	if (Result != XST_SUCCESS) { +		return Result; +	} + +	/* +	 * Loop on the MAC's status to wait for any pause to complete. +	 */ +	IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); + +	while ((IntrStatus & XEM_EIR_XMIT_PAUSE_MASK) != 0) { +		IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); +		/* +		   * Clear the pause status from the transmit status register +		 */ +		XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, +				      IntrStatus & XEM_EIR_XMIT_PAUSE_MASK); +	} + +	/* +	 * Set the MAC's transmit packet length register to tell it to transmit +	 */ +	XIo_Out32(InstancePtr->BaseAddress + XEM_TPLR_OFFSET, ByteCount); + +	/* +	 * Loop on the MAC's status to wait for the transmit to complete. The +	 * transmit status is in the FIFO when the XMIT_DONE bit is set. +	 */ +	do { +		IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); +	} +	while ((IntrStatus & XEM_EIR_XMIT_DONE_MASK) == 0); + +	XmitStatus = XIo_In32(InstancePtr->BaseAddress + XEM_TSR_OFFSET); + +	InstancePtr->Stats.XmitFrames++; +	InstancePtr->Stats.XmitBytes += ByteCount; + +	/* +	 * Check for various errors, bump statistics, and return an error status. +	 */ + +	/* +	 * Overrun errors +	 */ +	if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK | +			  XEM_EIR_XMIT_LFIFO_OVER_MASK)) { +		InstancePtr->Stats.XmitOverrunErrors++; +		InstancePtr->Stats.FifoErrors++; +		return XST_FIFO_ERROR; +	} + +	/* +	 * Underrun errors +	 */ +	if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK | +			  XEM_EIR_XMIT_LFIFO_UNDER_MASK)) { +		InstancePtr->Stats.XmitUnderrunErrors++; +		InstancePtr->Stats.FifoErrors++; +		return XST_FIFO_ERROR; +	} + +	/* +	 * Clear the interrupt status register of transmit statuses +	 */ +	XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, +			      IntrStatus & XEM_EIR_XMIT_ALL_MASK); + +	/* +	 * Collision errors are stored in the transmit status register +	 * instead of the interrupt status register +	 */ +	if (XmitStatus & XEM_TSR_EXCESS_DEFERRAL_MASK) { +		InstancePtr->Stats.XmitExcessDeferral++; +		return XST_EMAC_COLLISION_ERROR; +	} + +	if (XmitStatus & XEM_TSR_LATE_COLLISION_MASK) { +		InstancePtr->Stats.XmitLateCollisionErrors++; +		return XST_EMAC_COLLISION_ERROR; +	} + +	return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Receive an Ethernet frame in polled mode. The device/driver must be in polled +* mode before calling this function. The driver receives the frame directly +* from the MAC's packet FIFO. This is a non-blocking receive, in that if there +* is no frame ready to be received at the device, the function returns with an +* error. The MAC's error status is not checked, so statistics are not updated +* for polled receive. The buffer into which the frame will be received must be +* word-aligned. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param BufPtr is a pointer to a word-aligned buffer into which the received +*        Ethernet frame will be copied. +* @param ByteCountPtr is both an input and an output parameter. It is a pointer +*        to a 32-bit word that contains the size of the buffer on entry into the +*        function and the size the received frame on return from the function. +* +* @return +* +* - XST_SUCCESS if the frame was sent successfully +* - XST_DEVICE_IS_STOPPED if the device has not yet been started +* - XST_NOT_POLLED if the device is not in polled mode +* - XST_NO_DATA if there is no frame to be received from the FIFO +* - XST_BUFFER_TOO_SMALL if the buffer to receive the frame is too small for +*   the frame waiting in the FIFO. +* +* @note +* +* Input buffer must be big enough to hold the largest Ethernet frame. Buffer +* must also be 32-bit aligned. +* +* @internal +* +* The EMAC uses FIFOs behind its length and status registers. For this reason, +* it is important to keep the length, status, and data FIFOs in sync when +* reading or writing to them. +* +******************************************************************************/ +XStatus +XEmac_PollRecv(XEmac * InstancePtr, u8 * BufPtr, u32 * ByteCountPtr) +{ +	XStatus Result; +	u32 PktLength; +	u32 IntrStatus; + +	XASSERT_NONVOID(InstancePtr != NULL); +	XASSERT_NONVOID(BufPtr != NULL); +	XASSERT_NONVOID(ByteCountPtr != NULL); +	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + +	/* +	 * Be sure the device is configured for polled mode and it is started +	 */ +	if (!InstancePtr->IsPolled) { +		return XST_NOT_POLLED; +	} + +	if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { +		return XST_DEVICE_IS_STOPPED; +	} + +	/* +	 * Make sure the buffer is big enough to hold the maximum frame size. +	 * We need to do this because as soon as we read the MAC's packet length +	 * register, which is actually a FIFO, we remove that length from the +	 * FIFO.  We do not want to read the length FIFO without also reading the +	 * data FIFO since this would get the FIFOs out of sync.  So we have to +	 * make this restriction. +	 */ +	if (*ByteCountPtr < XEM_MAX_FRAME_SIZE) { +		return XST_BUFFER_TOO_SMALL; +	} + +	/* +	 * First check for packet FIFO deadlock and return an error if it has +	 * occurred. A reset by the caller is necessary to correct this problem. +	 */ +	if (XPF_V100B_IS_DEADLOCKED(&InstancePtr->RecvFifo)) { +		InstancePtr->Stats.FifoErrors++; +		return XST_FIFO_ERROR; +	} + +	/* +	 * Get the interrupt status to know what happened (whether an error occurred +	 * and/or whether frames have been received successfully). When clearing the +	 * intr status register, clear only statuses that pertain to receive. +	 */ +	IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); +	XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, +			      IntrStatus & XEM_EIR_RECV_ALL_MASK); + +	/* +	 * Check receive errors and bump statistics so the caller will have a clue +	 * as to why data may not have been received. We continue on if an error +	 * occurred since there still may be frames that were received successfully. +	 */ +	if (IntrStatus & (XEM_EIR_RECV_LFIFO_OVER_MASK | +			  XEM_EIR_RECV_DFIFO_OVER_MASK)) { +		InstancePtr->Stats.RecvOverrunErrors++; +		InstancePtr->Stats.FifoErrors++; +	} + +	if (IntrStatus & XEM_EIR_RECV_LFIFO_UNDER_MASK) { +		InstancePtr->Stats.RecvUnderrunErrors++; +		InstancePtr->Stats.FifoErrors++; +	} + +	/* +	 * General receive errors +	 */ +	if (IntrStatus & XEM_EIR_RECV_ERROR_MASK) { +		if (IntrStatus & XEM_EIR_RECV_MISSED_FRAME_MASK) { +			InstancePtr->Stats.RecvMissedFrameErrors = +			    XIo_In32(InstancePtr->BaseAddress + +				     XEM_RMFC_OFFSET); +		} + +		if (IntrStatus & XEM_EIR_RECV_COLLISION_MASK) { +			InstancePtr->Stats.RecvCollisionErrors = +			    XIo_In32(InstancePtr->BaseAddress + XEM_RCC_OFFSET); +		} + +		if (IntrStatus & XEM_EIR_RECV_FCS_ERROR_MASK) { +			InstancePtr->Stats.RecvFcsErrors = +			    XIo_In32(InstancePtr->BaseAddress + +				     XEM_RFCSEC_OFFSET); +		} + +		if (IntrStatus & XEM_EIR_RECV_LEN_ERROR_MASK) { +			InstancePtr->Stats.RecvLengthFieldErrors++; +		} + +		if (IntrStatus & XEM_EIR_RECV_SHORT_ERROR_MASK) { +			InstancePtr->Stats.RecvShortErrors++; +		} + +		if (IntrStatus & XEM_EIR_RECV_LONG_ERROR_MASK) { +			InstancePtr->Stats.RecvLongErrors++; +		} + +		if (IntrStatus & XEM_EIR_RECV_ALIGN_ERROR_MASK) { +			InstancePtr->Stats.RecvAlignmentErrors = +			    XIo_In32(InstancePtr->BaseAddress + +				     XEM_RAEC_OFFSET); +		} +	} + +	/* +	 * Before reading from the length FIFO, make sure the length FIFO is not +	 * empty. We could cause an underrun error if we try to read from an +	 * empty FIFO. +	 */ +	if ((IntrStatus & XEM_EIR_RECV_DONE_MASK) == 0) { +		return XST_NO_DATA; +	} + +	/* +	 * Determine, from the MAC, the length of the next packet available +	 * in the data FIFO (there should be a non-zero length here) +	 */ +	PktLength = XIo_In32(InstancePtr->BaseAddress + XEM_RPLR_OFFSET); +	if (PktLength == 0) { +		return XST_NO_DATA; +	} + +	/* +	 * Write the RECV_DONE bit in the status register to clear it. This bit +	 * indicates the RPLR is non-empty, and we know it's set at this point. +	 * We clear it so that subsequent entry into this routine will reflect the +	 * current status. This is done because the non-empty bit is latched in the +	 * IPIF, which means it may indicate a non-empty condition even though +	 * there is something in the FIFO. +	 */ +	XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_RECV_DONE_MASK); + +	/* +	 * We assume that the MAC never has a length bigger than the largest +	 * Ethernet frame, so no need to make another check here. +	 */ + +	/* +	 * This is a non-blocking read. The FIFO returns an error if there is +	 * not at least the requested amount of data in the FIFO. +	 */ +	Result = +	    XPacketFifoV100b_Read(&InstancePtr->RecvFifo, BufPtr, PktLength); +	if (Result != XST_SUCCESS) { +		return Result; +	} + +	InstancePtr->Stats.RecvFrames++; +	InstancePtr->Stats.RecvBytes += PktLength; + +	*ByteCountPtr = PktLength; + +	return XST_SUCCESS; +} |