mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-25 20:43:32 +00:00
483 lines
16 KiB
C
483 lines
16 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_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;
|
||
|
}
|