From 028ab6b598b628326116acd88e0f35aa9f526d12 Mon Sep 17 00:00:00 2001 From: wdenk Date: Mon, 23 Feb 2004 23:54:43 +0000 Subject: * Patch by Peter Ryser, 20 Feb 2004: 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 --- board/xilinx/xilinx_enet/emac_adapter.c | 153 ++++ board/xilinx/xilinx_enet/xemac.c | 844 ++++++++++++++++++ board/xilinx/xilinx_enet/xemac.h | 673 +++++++++++++++ board/xilinx/xilinx_enet/xemac_g.c | 60 ++ board/xilinx/xilinx_enet/xemac_i.h | 207 +++++ board/xilinx/xilinx_enet/xemac_intr.c | 402 +++++++++ board/xilinx/xilinx_enet/xemac_intr_dma.c | 1344 +++++++++++++++++++++++++++++ board/xilinx/xilinx_enet/xemac_l.h | 462 ++++++++++ board/xilinx/xilinx_enet/xemac_options.c | 318 +++++++ board/xilinx/xilinx_enet/xemac_polled.c | 482 +++++++++++ 10 files changed, 4945 insertions(+) create mode 100644 board/xilinx/xilinx_enet/emac_adapter.c create mode 100644 board/xilinx/xilinx_enet/xemac.c create mode 100644 board/xilinx/xilinx_enet/xemac.h create mode 100644 board/xilinx/xilinx_enet/xemac_g.c create mode 100644 board/xilinx/xilinx_enet/xemac_i.h create mode 100644 board/xilinx/xilinx_enet/xemac_intr.c create mode 100644 board/xilinx/xilinx_enet/xemac_intr_dma.c create mode 100644 board/xilinx/xilinx_enet/xemac_l.h create mode 100644 board/xilinx/xilinx_enet/xemac_options.c create mode 100644 board/xilinx/xilinx_enet/xemac_polled.c (limited to 'board/xilinx/xilinx_enet') diff --git a/board/xilinx/xilinx_enet/emac_adapter.c b/board/xilinx/xilinx_enet/emac_adapter.c new file mode 100644 index 0000000000..a3c37baab9 --- /dev/null +++ b/board/xilinx/xilinx_enet/emac_adapter.c @@ -0,0 +1,153 @@ +/****************************************************************************** +* +* 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. +* +******************************************************************************/ + +#include +#include +#include +#include "xparameters.h" +#include "xemac.h" + +#if defined(XPAR_EMAC_0_DEVICE_ID) +/* + * ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from + * PKTSIZE and PKTSIZE_ALIGN (include/net.h) + */ + +#define ENET_MAX_MTU PKTSIZE +#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN +#define ENET_ADDR_LENGTH 6 + +static XEmac Emac; +static char etherrxbuff[PKTSIZE_ALIGN]; /* Receive buffer */ + +/* hardcoded MAC address for the Xilinx EMAC Core */ +static u8 EMACAddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 }; + +static int initialized = 0; + +void +eth_halt(void) +{ + if (initialized) + (void) XEmac_Stop(&Emac); +} + +int +eth_init(bd_t * bis) +{ + u32 Options; + XStatus Result; + +#ifdef DEBUG + printf("EMAC Initialization Started\n\r"); +#endif + + Result = XEmac_Initialize(&Emac, XPAR_EMAC_0_DEVICE_ID); + if (Result != XST_SUCCESS) { + return 0; + } + + /* make sure the Emac is stopped before it is started */ + (void) XEmac_Stop(&Emac); + + memcpy(bis->bi_enetaddr, EMACAddr, 6); + Result = XEmac_SetMacAddress(&Emac, EMACAddr); + if (Result != XST_SUCCESS) { + return 0; + } + + Options = + (XEM_POLLED_OPTION | XEM_UNICAST_OPTION | XEM_BROADCAST_OPTION | + XEM_FDUPLEX_OPTION | XEM_INSERT_FCS_OPTION | + XEM_INSERT_PAD_OPTION); + Result = XEmac_SetOptions(&Emac, Options); + if (Result != XST_SUCCESS) { + return 0; + } + + Result = XEmac_Start(&Emac); + if (Result != XST_SUCCESS) { + return 0; + } +#ifdef DEBUG + printf("EMAC Initialization complete\n\r"); +#endif + + initialized = 1; + + return (0); +} + +/*-----------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------*/ +int +eth_send(volatile void *ptr, int len) +{ + XStatus Result; + + if (len > ENET_MAX_MTU) + len = ENET_MAX_MTU; + + Result = XEmac_PollSend(&Emac, (u8 *) ptr, len); + if (Result == XST_SUCCESS) { + return (1); + } else { + printf("Error while sending frame\n\r"); + return (0); + } + +} + +int +eth_rx(void) +{ + u32 RecvFrameLength; + XStatus Result; + + RecvFrameLength = PKTSIZE; + Result = XEmac_PollRecv(&Emac, (u8 *) etherrxbuff, &RecvFrameLength); + if (Result == XST_SUCCESS) { + NetReceive(etherrxbuff, RecvFrameLength); + return (1); + } else { + return (0); + } +} + +#endif diff --git a/board/xilinx/xilinx_enet/xemac.c b/board/xilinx/xilinx_enet/xemac.c new file mode 100644 index 0000000000..48b4ede704 --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac.c @@ -0,0 +1,844 @@ +/****************************************************************************** +* +* 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.c +* +* The XEmac driver. Functions in this file are the minimum required functions +* for this driver. See xemac.h for a detailed description of the driver. +* +*
+* 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.00b rpm  07/23/02 Removed the PHY reset from Initialize()
+* 1.00b rmm  09/23/02 Removed commented code in Initialize(). Recycled as
+*                     XEmac_mPhyReset macro in xemac_l.h.
+* 1.00c rpm  12/05/02 New version includes support for simple DMA
+* 1.00c rpm  12/12/02 Changed location of IsStarted assignment in XEmac_Start
+*                     to be sure the flag is set before the device and
+*                     interrupts are enabled.
+* 1.00c rpm  02/03/03 SelfTest was not clearing polled mode. Take driver out
+*                     of polled mode in XEmac_Reset() to fix this problem.
+* 1.00c rmm  05/13/03 Fixed diab compiler warnings relating to asserts.
+* 
+******************************************************************************/ + +/***************************** 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 *********************/ + +/************************** Function Prototypes ******************************/ + +static XStatus ConfigureDma(XEmac * InstancePtr); +static XStatus ConfigureFifo(XEmac * InstancePtr); +static void StubFifoHandler(void *CallBackRef); +static void StubErrorHandler(void *CallBackRef, XStatus ErrorCode); +static void StubSgHandler(void *CallBackRef, XBufDescriptor * BdPtr, + u32 NumBds); + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* +* Initialize a specific XEmac instance/driver. The initialization entails: +* - Initialize fields of the XEmac structure +* - Clear the Ethernet statistics for this device +* - Initialize the IPIF component with its register base address +* - Configure the FIFO components with their register base addresses. +* - If the device is configured with DMA, configure the DMA channel components +* with their register base addresses. At some later time, memory pools for +* the scatter-gather descriptor lists may be passed to the driver. +* - Reset the Ethernet MAC +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param DeviceId is the unique id of the device controlled by this XEmac +* instance. Passing in a device id associates the generic XEmac +* instance to a specific device, as chosen by the caller or application +* developer. +* +* @return +* +* - XST_SUCCESS if initialization was successful +* - XST_DEVICE_IS_STARTED if the device has already been started +* - XST_DEVICE_NOT_FOUND if device configuration information was not found for +* a device with the supplied device ID. +* +* @note +* +* None. +* +******************************************************************************/ +XStatus +XEmac_Initialize(XEmac * InstancePtr, u16 DeviceId) +{ + XStatus Result; + XEmac_Config *ConfigPtr; /* configuration information */ + + XASSERT_NONVOID(InstancePtr != NULL); + + /* + * If the device is started, disallow the initialize and return a status + * indicating it is started. This allows the user to stop the device + * and reinitialize, but prevents a user from inadvertently initializing + */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + /* + * Lookup the device configuration in the temporary CROM table. Use this + * configuration info down below when initializing this component. + */ + ConfigPtr = XEmac_LookupConfig(DeviceId); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + /* + * Set some default values + */ + InstancePtr->IsReady = 0; + InstancePtr->IsStarted = 0; + InstancePtr->IpIfDmaConfig = ConfigPtr->IpIfDmaConfig; + InstancePtr->HasMii = ConfigPtr->HasMii; + InstancePtr->HasMulticastHash = FALSE; + + /* Always default polled to false, let user configure this mode */ + InstancePtr->IsPolled = FALSE; + InstancePtr->FifoRecvHandler = StubFifoHandler; + InstancePtr->FifoSendHandler = StubFifoHandler; + InstancePtr->ErrorHandler = StubErrorHandler; + InstancePtr->SgRecvHandler = StubSgHandler; + InstancePtr->SgSendHandler = StubSgHandler; + + /* + * Clear the statistics for this driver + */ + XEmac_mClearStruct((u8 *) & InstancePtr->Stats, sizeof (XEmac_Stats)); + + /* + * Initialize the device register base addresses + */ + InstancePtr->BaseAddress = ConfigPtr->BaseAddress; + + /* + * Configure the send and receive FIFOs in the MAC + */ + Result = ConfigureFifo(InstancePtr); + if (Result != XST_SUCCESS) { + return Result; + } + + /* + * If the device is configured for DMA, configure the send and receive DMA + * channels in the MAC. + */ + if (XEmac_mIsDma(InstancePtr)) { + Result = ConfigureDma(InstancePtr); + if (Result != XST_SUCCESS) { + return Result; + } + } + + /* + * Indicate the component is now ready to use. Note that this is done before + * we reset the device and the PHY below, which may seem a bit odd. The + * choice was made to move it here rather than remove the asserts in various + * functions (e.g., Reset() and all functions that it calls). Applications + * that use multiple threads, one to initialize the XEmac driver and one + * waiting on the IsReady condition could have a problem with this sequence. + */ + InstancePtr->IsReady = XCOMPONENT_IS_READY; + + /* + * Reset the MAC to get it into its initial state. It is expected that + * device configuration by the user will take place after this + * initialization is done, but before the device is started. + */ + XEmac_Reset(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Start the Ethernet controller as follows: +* - If not in polled mode +* - Set the internal interrupt enable registers appropriately +* - Enable interrupts within the device itself. Note that connection of +* the driver's interrupt handler to the interrupt source (typically +* done using the interrupt controller component) is done by the higher +* layer software. +* - If the device is configured with scatter-gather DMA, start the DMA +* channels if the descriptor lists are not empty +* - Enable the transmitter +* - Enable the receiver +* +* The PHY is enabled after driver initialization. We assume the upper layer +* software has configured it and the EMAC appropriately before this function +* is called. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* - XST_SUCCESS if the device was started successfully +* - XST_NO_CALLBACK if a callback function has not yet been registered using +* the SetxxxHandler function. This is required if in interrupt mode. +* - XST_DEVICE_IS_STARTED if the device is already started +* - XST_DMA_SG_NO_LIST if configured for scatter-gather DMA and a descriptor +* list has not yet been created for the send or receive channel. +* +* @note +* +* The driver tries to match the hardware configuration. So if the hardware +* is configured with scatter-gather DMA, the driver expects to start the +* scatter-gather channels and expects that the user has set up the buffer +* descriptor lists already. If the user expects to use the driver in a mode +* different than how the hardware is configured, the user should modify the +* configuration table to reflect the mode to be used. Modifying the config +* table is a workaround for now until we get some experience with how users +* are intending to use the hardware in its different configurations. For +* example, if the hardware is built with scatter-gather DMA but the user is +* intending to use only simple DMA, the user either needs to modify the config +* table as a workaround or rebuild the hardware with only simple DMA. +* +* This function makes use of internal resources that are shared between the +* Start, Stop, and SetOptions functions. So if one task might be setting device +* options while another is trying to start the device, the user is required to +* provide protection of this shared data (typically using a semaphore). +* +******************************************************************************/ +XStatus +XEmac_Start(XEmac * InstancePtr) +{ + u32 ControlReg; + XStatus Result; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* + * If it is already started, return a status indicating so + */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + /* + * If not polled, enable interrupts + */ + if (!InstancePtr->IsPolled) { + /* + * Verify that the callbacks have been registered, then enable + * interrupts + */ + if (XEmac_mIsSgDma(InstancePtr)) { + if ((InstancePtr->SgRecvHandler == StubSgHandler) || + (InstancePtr->SgSendHandler == StubSgHandler)) { + return XST_NO_CALLBACK; + } + + /* Enable IPIF interrupts */ + XIIF_V123B_WRITE_DIER(InstancePtr->BaseAddress, + XEM_IPIF_DMA_DFT_MASK | + XIIF_V123B_ERROR_MASK); + XIIF_V123B_WRITE_IIER(InstancePtr->BaseAddress, + XEM_EIR_DFT_SG_MASK); + + /* Enable scatter-gather DMA interrupts */ + XDmaChannel_SetIntrEnable(&InstancePtr->RecvChannel, + XEM_DMA_SG_INTR_MASK); + XDmaChannel_SetIntrEnable(&InstancePtr->SendChannel, + XEM_DMA_SG_INTR_MASK); + } else { + if ((InstancePtr->FifoRecvHandler == StubFifoHandler) || + (InstancePtr->FifoSendHandler == StubFifoHandler)) { + return XST_NO_CALLBACK; + } + + /* Enable IPIF interrupts (used by simple DMA also) */ + XIIF_V123B_WRITE_DIER(InstancePtr->BaseAddress, + XEM_IPIF_FIFO_DFT_MASK | + XIIF_V123B_ERROR_MASK); + XIIF_V123B_WRITE_IIER(InstancePtr->BaseAddress, + XEM_EIR_DFT_FIFO_MASK); + } + + /* Enable the global IPIF interrupt output */ + XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress); + } + + /* + * Indicate that the device is started before we enable the transmitter + * or receiver. This needs to be done before because as soon as the + * receiver is enabled we may get an interrupt, and there are functions + * in the interrupt handling path that rely on the IsStarted flag. + */ + InstancePtr->IsStarted = XCOMPONENT_IS_STARTED; + + /* + * Enable the transmitter, and receiver (do a read/modify/write to preserve + * current settings). There is no critical section here since this register + * is not modified during interrupt context. + */ + ControlReg = XIo_In32(InstancePtr->BaseAddress + XEM_ECR_OFFSET); + ControlReg &= ~(XEM_ECR_XMIT_RESET_MASK | XEM_ECR_RECV_RESET_MASK); + ControlReg |= (XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK); + + XIo_Out32(InstancePtr->BaseAddress + XEM_ECR_OFFSET, ControlReg); + + /* + * If configured with scatter-gather DMA and not polled, restart the + * DMA channels in case there are buffers ready to be sent or received into. + * The DMA SgStart function uses data that can be modified during interrupt + * context, so a critical section is required here. + */ + if ((XEmac_mIsSgDma(InstancePtr)) && (!InstancePtr->IsPolled)) { + XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress); + + /* + * The only error we care about is if the list has not yet been + * created, or on receive, if no buffer descriptors have been + * added yet (the list is empty). Other errors are benign at this point. + */ + Result = XDmaChannel_SgStart(&InstancePtr->RecvChannel); + if ((Result == XST_DMA_SG_NO_LIST) + || (Result == XST_DMA_SG_LIST_EMPTY)) { + XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress); + return Result; + } + + Result = XDmaChannel_SgStart(&InstancePtr->SendChannel); + if (Result == XST_DMA_SG_NO_LIST) { + XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress); + return Result; + } + + XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Stop the Ethernet MAC as follows: +* - If the device is configured with scatter-gather DMA, stop the DMA +* channels (wait for acknowledgment of stop) +* - Disable the transmitter and receiver +* - Disable interrupts if not in polled mode (the higher layer software is +* responsible for disabling interrupts at the interrupt controller) +* +* The PHY is left enabled after a Stop is called. +* +* If the device is configured for scatter-gather DMA, the DMA engine stops at +* the next buffer descriptor in its list. The remaining descriptors in the list +* are not removed, so anything in the list will be transmitted or received when +* the device is restarted. The side effect of doing this is that the last +* buffer descriptor processed by the DMA engine before stopping may not be the +* last descriptor in the Ethernet frame. So when the device is restarted, a +* partial frame (i.e., a bad frame) may be transmitted/received. This is only a +* concern if a frame can span multiple buffer descriptors, which is dependent +* on the size of the network buffers. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* - XST_SUCCESS if the device was stopped successfully +* - XST_DEVICE_IS_STOPPED if the device is already stopped +* +* @note +* +* This function makes use of internal resources that are shared between the +* Start, Stop, and SetOptions functions. So if one task might be setting device +* options while another is trying to start the device, the user is required to +* provide protection of this shared data (typically using a semaphore). +* +******************************************************************************/ +XStatus +XEmac_Stop(XEmac * InstancePtr) +{ + u32 ControlReg; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* + * If the device is already stopped, do nothing but return a status + * indicating so + */ + if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STOPPED; + } + + /* + * If configured for scatter-gather DMA, stop the DMA channels. Ignore + * the XST_DMA_SG_IS_STOPPED return code. There is a critical section + * here between SgStart and SgStop, and SgStart can be called in interrupt + * context, so disable interrupts while calling SgStop. + */ + if (XEmac_mIsSgDma(InstancePtr)) { + XBufDescriptor *BdTemp; /* temporary descriptor pointer */ + + XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress); + + (void) XDmaChannel_SgStop(&InstancePtr->SendChannel, &BdTemp); + (void) XDmaChannel_SgStop(&InstancePtr->RecvChannel, &BdTemp); + + XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress); + } + + /* + * Disable the transmitter and receiver. There is no critical section + * here since this register is not modified during interrupt context. + */ + ControlReg = XIo_In32(InstancePtr->BaseAddress + XEM_ECR_OFFSET); + ControlReg &= ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK); + XIo_Out32(InstancePtr->BaseAddress + XEM_ECR_OFFSET, ControlReg); + + /* + * If not in polled mode, disable interrupts for IPIF (includes MAC and + * DMAs) + */ + if (!InstancePtr->IsPolled) { + XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress); + } + + InstancePtr->IsStarted = 0; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Reset the Ethernet MAC. This is a graceful reset in that the device is stopped +* first. Resets the DMA channels, the FIFOs, the transmitter, and the receiver. +* The PHY is not reset. Any frames in the scatter-gather descriptor lists will +* remain in the lists. The side effect of doing this is that after a reset and +* following a restart of the device, frames that were in the list before the +* reset may be transmitted or received. Reset must only be called after the +* driver has been initialized. +* +* The driver is also taken out of polled mode if polled mode was set. The user +* is responsbile for re-configuring the driver into polled mode after the +* reset if desired. +* +* The configuration after this reset is as follows: +* - Half duplex +* - Disabled transmitter and receiver +* - Enabled PHY (the PHY is not reset) +* - MAC transmitter does pad insertion, FCS insertion, and source address +* overwrite. +* - MAC receiver does not strip padding or FCS +* - Interframe Gap as recommended by IEEE Std. 802.3 (96 bit times) +* - Unicast addressing enabled +* - Broadcast addressing enabled +* - Multicast addressing disabled (addresses are preserved) +* - Promiscuous addressing disabled +* - Default packet threshold and packet wait bound register values for +* scatter-gather DMA operation +* - MAC address of all zeros +* - Non-polled mode +* +* The upper layer software is responsible for re-configuring (if necessary) +* and restarting the MAC after the reset. Note that the PHY is not reset. PHY +* control is left to the upper layer software. Note also that driver statistics +* are not cleared on reset. It is up to the upper layer software to clear the +* statistics if needed. +* +* When a reset is required due to an internal error, the driver notifies the +* upper layer software of this need through the ErrorHandler callback and +* specific status codes. The upper layer software is responsible for calling +* this Reset function and then re-configuring the device. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* None. +* +* @note +* +* None. +* +* @internal +* +* The reset is accomplished by setting the IPIF reset register. This takes +* care of resetting all hardware blocks, including the MAC. +* +******************************************************************************/ +void +XEmac_Reset(XEmac * InstancePtr) +{ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* + * Stop the device first + */ + (void) XEmac_Stop(InstancePtr); + + /* + * Take the driver out of polled mode + */ + InstancePtr->IsPolled = FALSE; + + /* + * Reset the entire IPIF at once. If we choose someday to reset each + * hardware block separately, the reset should occur in the direction of + * data flow. For example, for the send direction the reset order is DMA + * first, then FIFO, then the MAC transmitter. + */ + XIIF_V123B_RESET(InstancePtr->BaseAddress); + + if (XEmac_mIsSgDma(InstancePtr)) { + /* + * After reset, configure the scatter-gather DMA packet threshold and + * packet wait bound registers to default values. Ignore the return + * values of these functions since they only return error if the device + * is not stopped. + */ + (void) XEmac_SetPktThreshold(InstancePtr, XEM_SEND, + XEM_SGDMA_DFT_THRESHOLD); + (void) XEmac_SetPktThreshold(InstancePtr, XEM_RECV, + XEM_SGDMA_DFT_THRESHOLD); + (void) XEmac_SetPktWaitBound(InstancePtr, XEM_SEND, + XEM_SGDMA_DFT_WAITBOUND); + (void) XEmac_SetPktWaitBound(InstancePtr, XEM_RECV, + XEM_SGDMA_DFT_WAITBOUND); + } +} + +/*****************************************************************************/ +/** +* +* Set the MAC address for this driver/device. The address is a 48-bit value. +* The device must be stopped before calling this function. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param AddressPtr is a pointer to a 6-byte MAC address. +* +* @return +* +* - XST_SUCCESS if the MAC address was set successfully +* - XST_DEVICE_IS_STARTED if the device has not yet been stopped +* +* @note +* +* None. +* +******************************************************************************/ +XStatus +XEmac_SetMacAddress(XEmac * InstancePtr, u8 * AddressPtr) +{ + u32 MacAddr = 0; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(AddressPtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* + * The device must be stopped before setting the MAC address + */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + /* + * Set the device station address high and low registers + */ + MacAddr = (AddressPtr[0] << 8) | AddressPtr[1]; + XIo_Out32(InstancePtr->BaseAddress + XEM_SAH_OFFSET, MacAddr); + + MacAddr = (AddressPtr[2] << 24) | (AddressPtr[3] << 16) | + (AddressPtr[4] << 8) | AddressPtr[5]; + + XIo_Out32(InstancePtr->BaseAddress + XEM_SAL_OFFSET, MacAddr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Get the MAC address for this driver/device. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param BufferPtr is an output parameter, and is a pointer to a buffer into +* which the current MAC address will be copied. The buffer must be at +* least 6 bytes. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +void +XEmac_GetMacAddress(XEmac * InstancePtr, u8 * BufferPtr) +{ + u32 MacAddrHi; + u32 MacAddrLo; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(BufferPtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + MacAddrHi = XIo_In32(InstancePtr->BaseAddress + XEM_SAH_OFFSET); + MacAddrLo = XIo_In32(InstancePtr->BaseAddress + XEM_SAL_OFFSET); + + BufferPtr[0] = (u8) (MacAddrHi >> 8); + BufferPtr[1] = (u8) MacAddrHi; + BufferPtr[2] = (u8) (MacAddrLo >> 24); + BufferPtr[3] = (u8) (MacAddrLo >> 16); + BufferPtr[4] = (u8) (MacAddrLo >> 8); + BufferPtr[5] = (u8) MacAddrLo; +} + +/******************************************************************************/ +/** +* +* Configure DMA capabilities. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* - XST_SUCCESS if successful initialization of DMA +* +* @note +* +* None. +* +******************************************************************************/ +static XStatus +ConfigureDma(XEmac * InstancePtr) +{ + XStatus Result; + + /* + * Initialize the DMA channels with their base addresses. We assume + * scatter-gather DMA is the only possible configuration. Descriptor space + * will need to be set later by the upper layer. + */ + Result = XDmaChannel_Initialize(&InstancePtr->RecvChannel, + InstancePtr->BaseAddress + + XEM_DMA_RECV_OFFSET); + if (Result != XST_SUCCESS) { + return Result; + } + + Result = XDmaChannel_Initialize(&InstancePtr->SendChannel, + InstancePtr->BaseAddress + + XEM_DMA_SEND_OFFSET); + + return Result; +} + +/******************************************************************************/ +/** +* +* Configure the send and receive FIFO components with their base addresses +* and interrupt masks. Currently the base addresses are defined constants. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* XST_SUCCESS if successful initialization of the packet FIFOs +* +* @note +* +* None. +* +******************************************************************************/ +static XStatus +ConfigureFifo(XEmac * InstancePtr) +{ + XStatus Result; + + /* + * Return status from the packet FIFOs initialization is ignored since + * they always return success. + */ + Result = XPacketFifoV100b_Initialize(&InstancePtr->RecvFifo, + InstancePtr->BaseAddress + + XEM_PFIFO_RXREG_OFFSET, + InstancePtr->BaseAddress + + XEM_PFIFO_RXDATA_OFFSET); + if (Result != XST_SUCCESS) { + return Result; + } + + Result = XPacketFifoV100b_Initialize(&InstancePtr->SendFifo, + InstancePtr->BaseAddress + + XEM_PFIFO_TXREG_OFFSET, + InstancePtr->BaseAddress + + XEM_PFIFO_TXDATA_OFFSET); + return Result; +} + +/******************************************************************************/ +/** +* +* This is a stub for the scatter-gather send and recv callbacks. The stub +* is here in case the upper layers forget to set the handlers. +* +* @param CallBackRef is a pointer to the upper layer callback reference +* @param BdPtr is a pointer to the first buffer descriptor in a list +* @param NumBds is the number of descriptors in the list. +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +static void +StubSgHandler(void *CallBackRef, XBufDescriptor * BdPtr, u32 NumBds) +{ + XASSERT_VOID_ALWAYS(); +} + +/******************************************************************************/ +/** +* +* This is a stub for the non-DMA send and recv callbacks. The stub is here in +* case the upper layers forget to set the handlers. +* +* @param CallBackRef is a pointer to the upper layer callback reference +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +static void +StubFifoHandler(void *CallBackRef) +{ + XASSERT_VOID_ALWAYS(); +} + +/******************************************************************************/ +/** +* +* This is a stub for the asynchronous error callback. The stub is here in +* case the upper layers forget to set the handler. +* +* @param CallBackRef is a pointer to the upper layer callback reference +* @param ErrorCode is the Xilinx error code, indicating the cause of the error +* +* @return +* +* None. +* +* @note +* +* None. +* +******************************************************************************/ +static void +StubErrorHandler(void *CallBackRef, XStatus ErrorCode) +{ + XASSERT_VOID_ALWAYS(); +} + +/*****************************************************************************/ +/** +* +* Lookup the device configuration based on the unique device ID. The table +* EmacConfigTable contains the configuration info for each device in the system. +* +* @param DeviceId is the unique device ID of the device being looked up. +* +* @return +* +* A pointer to the configuration table entry corresponding to the given +* device ID, or NULL if no match is found. +* +* @note +* +* None. +* +******************************************************************************/ +XEmac_Config * +XEmac_LookupConfig(u16 DeviceId) +{ + XEmac_Config *CfgPtr = NULL; + int i; + + for (i = 0; i < XPAR_XEMAC_NUM_INSTANCES; i++) { + if (XEmac_ConfigTable[i].DeviceId == DeviceId) { + CfgPtr = &XEmac_ConfigTable[i]; + break; + } + } + + return CfgPtr; +} diff --git a/board/xilinx/xilinx_enet/xemac.h b/board/xilinx/xilinx_enet/xemac.h new file mode 100644 index 0000000000..ed704bf29b --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac.h @@ -0,0 +1,673 @@ +/****************************************************************************** +* +* 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.h +* +* The Xilinx Ethernet driver component. This component supports the Xilinx +* Ethernet 10/100 MAC (EMAC). +* +* The Xilinx Ethernet 10/100 MAC supports the following features: +* - Simple and scatter-gather DMA operations, as well as simple memory +* mapped direct I/O interface (FIFOs). +* - Media Independent Interface (MII) for connection to external +* 10/100 Mbps PHY transceivers. +* - MII management control reads and writes with MII PHYs +* - Independent internal transmit and receive FIFOs +* - CSMA/CD compliant operations for half-duplex modes +* - Programmable PHY reset signal +* - Unicast, broadcast, and promiscuous address filtering (no multicast yet) +* - Internal loopback +* - Automatic source address insertion or overwrite (programmable) +* - Automatic FCS insertion and stripping (programmable) +* - Automatic pad insertion and stripping (programmable) +* - Pause frame (flow control) detection in full-duplex mode +* - Programmable interframe gap +* - VLAN frame support. +* - Pause frame support +* +* The device driver supports all the features listed above. +* +* Driver Description +* +* The device driver enables higher layer software (e.g., an application) to +* communicate to the EMAC. The driver handles transmission and reception of +* Ethernet frames, as well as configuration of the controller. It does not +* handle protocol stack functionality such as Link Layer Control (LLC) or the +* Address Resolution Protocol (ARP). The protocol stack that makes use of the +* driver handles this functionality. This implies that the driver is simply a +* pass-through mechanism between a protocol stack and the EMAC. A single device +* driver can support multiple EMACs. +* +* The driver is designed for a zero-copy buffer scheme. That is, the driver will +* not copy buffers. This avoids potential throughput bottlenecks within the +* driver. +* +* Since the driver is a simple pass-through mechanism between a protocol stack +* and the EMAC, no assembly or disassembly of Ethernet frames is done at the +* driver-level. This assumes that the protocol stack passes a correctly +* formatted Ethernet frame to the driver for transmission, and that the driver +* does not validate the contents of an incoming frame +* +* PHY Communication +* +* The driver provides rudimentary read and write functions to allow the higher +* layer software to access the PHY. The EMAC provides MII registers for the +* driver to access. This management interface can be parameterized away in the +* FPGA implementation process. If this is the case, the PHY read and write +* functions of the driver return XST_NO_FEATURE. +* +* External loopback is usually supported at the PHY. It is up to the user to +* turn external loopback on or off at the PHY. The driver simply provides pass- +* through functions for configuring the PHY. The driver does not read, write, +* or reset the PHY on its own. All control of the PHY must be done by the user. +* +* Asynchronous Callbacks +* +* The driver services interrupts and passes Ethernet frames to the higher layer +* software through asynchronous callback functions. When using the driver +* directly (i.e., not with the RTOS protocol stack), the higher layer +* software must register its callback functions during initialization. The +* driver requires callback functions for received frames, for confirmation of +* transmitted frames, and for asynchronous errors. +* +* Interrupts +* +* The driver has no dependencies on the interrupt controller. The driver +* provides two interrupt handlers. XEmac_IntrHandlerDma() handles interrupts +* when the EMAC is configured with scatter-gather DMA. XEmac_IntrHandlerFifo() +* handles interrupts when the EMAC is configured for direct FIFO I/O or simple +* DMA. Either of these routines can be connected to the system interrupt +* controller by the user. +* +* Interrupt Frequency +* +* When the EMAC is configured with scatter-gather DMA, the frequency of +* interrupts can be controlled with the interrupt coalescing features of the +* scatter-gather DMA engine. The frequency of interrupts can be adjusted using +* the driver API functions for setting the packet count threshold and the packet +* wait bound values. +* +* 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. +* +* The packet wait bound is a timer value used during interrupt coalescing to +* trigger an interrupt when not enough packets have been received to reach the +* packet count threshold. +* +* These values can be tuned by the user to meet their needs. If there appear to +* be interrupt latency problems or delays in packet arrival that are longer than +* might be expected, the user should verify that the packet count threshold is +* set low enough to receive interrupts before the wait bound timer goes off. +* +* Device Reset +* +* Some errors that can occur in the device require a device reset. These errors +* are listed in the XEmac_SetErrorHandler() function header. The user's error +* handler is responsible for resetting the device and re-configuring it based on +* its needs (the driver does not save the current configuration). When +* integrating into an RTOS, these reset and re-configure obligations are +* taken care of by the Xilinx adapter software if it exists for that RTOS. +* +* Device Configuration +* +* The device can be configured in various ways during the FPGA implementation +* process. Configuration parameters are stored in the xemac_g.c files. +* A table is defined where each entry contains configuration information +* for an EMAC device. This information includes such things as the base address +* of the memory-mapped device, the base addresses of IPIF, DMA, and FIFO modules +* within the device, and whether the device has DMA, counter registers, +* multicast support, MII support, and flow control. +* +* The driver tries to use the features built into the device. So if, for +* example, the hardware is configured with scatter-gather DMA, the driver +* expects to start the scatter-gather channels and expects that the user has set +* up the buffer descriptor lists already. If the user expects to use the driver +* in a mode different than how the hardware is configured, the user should +* modify the configuration table to reflect the mode to be used. Modifying the +* configuration table is a workaround for now until we get some experience with +* how users are intending to use the hardware in its different configurations. +* For example, if the hardware is built with scatter-gather DMA but the user is +* intending to use only simple DMA, the user either needs to modify the config +* table as a workaround or rebuild the hardware with only simple DMA. The +* recommendation at this point is to build the hardware with the features you +* intend to use. If you're inclined to modify the table, do so before the call +* to XEmac_Initialize(). Here is a snippet of code that changes a device to +* simple DMA (the hardware needs to have DMA for this to work of course): +*
+*	 XEmac_Config *ConfigPtr;
+*
+*	 ConfigPtr = XEmac_LookupConfig(DeviceId);
+*	 ConfigPtr->IpIfDmaConfig = XEM_CFG_SIMPLE_DMA;
+* 
+* +* Simple DMA +* +* Simple DMA is supported through the FIFO functions, FifoSend and FifoRecv, of +* the driver (i.e., there is no separate interface for it). The driver makes use +* of the DMA engine for a simple DMA transfer if the device is configured with +* DMA, otherwise it uses the FIFOs directly. While the simple DMA interface is +* therefore transparent to the user, the caching of network buffers is not. +* If the device is configured with DMA and the FIFO interface is used, the user +* must ensure that the network buffers are not cached or are cache coherent, +* since DMA will be used to transfer to and from the Emac device. If the device +* is configured with DMA and the user really wants to use the FIFOs directly, +* the user should rebuild the hardware without DMA. If unable to do this, there +* is a workaround (described above in Device Configuration) to modify the +* configuration table of the driver to fake the driver into thinking the device +* has no DMA. A code snippet follows: +*
+*	 XEmac_Config *ConfigPtr;
+*
+*	 ConfigPtr = XEmac_LookupConfig(DeviceId);
+*	 ConfigPtr->IpIfDmaConfig = XEM_CFG_NO_DMA;
+* 
+* +* Asserts +* +* Asserts are used within all Xilinx drivers to enforce constraints on argument +* values. Asserts can be turned off on a system-wide basis by defining, at +* compile time, the NDEBUG identifier. By default, asserts are turned on and it +* is recommended that users leave asserts on during development. +* +* Building the driver +* +* The XEmac driver is composed of several source files. Why so many? This +* allows the user to build and link only those parts of the driver that are +* necessary. Since the EMAC hardware can be configured in various ways (e.g., +* with or without DMA), the driver too can be built with varying features. +* For the most part, this means that besides always linking in xemac.c, you +* link in only the driver functionality you want. Some of the choices you have +* are polled vs. interrupt, interrupt with FIFOs only vs. interrupt with DMA, +* self-test diagnostics, and driver statistics. Note that currently the DMA code +* must be linked in, even if you don't have DMA in the device. +* +* @note +* +* Xilinx drivers are typically composed of two components, one is the driver +* and the other is the adapter. The driver is independent of OS and processor +* and is intended to be highly portable. The adapter is OS-specific and +* facilitates communication between the driver and an OS. +*

+* This driver is intended to be RTOS and processor independent. It works +* with physical addresses only. Any needs for dynamic memory management, +* threads or thread mutual exclusion, virtual memory, or cache control must +* be satisfied by the layer above this driver. +* +*
+* 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.00b rpm  10/08/02 Replaced HasSgDma boolean with IpifDmaConfig enumerated
+*		      configuration parameter
+* 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
+*		      DMA interrupt service routines.
+* 
+* +******************************************************************************/ + +#ifndef XEMAC_H /* prevent circular inclusions */ +#define XEMAC_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xstatus.h" +#include "xparameters.h" +#include "xpacket_fifo_v1_00_b.h" /* Uses v1.00b of Packet Fifo */ +#include "xdma_channel.h" + +/************************** Constant Definitions *****************************/ + +/* + * Device information + */ +#define XEM_DEVICE_NAME "xemac" +#define XEM_DEVICE_DESC "Xilinx Ethernet 10/100 MAC" + +/** @name Configuration options + * + * Device configuration options (see the XEmac_SetOptions() and + * XEmac_GetOptions() for information on how to use these options) + * @{ + */ +/** + *
+ *   XEM_BROADCAST_OPTION	 Broadcast addressing on or off (default is on)
+ *   XEM_UNICAST_OPTION		 Unicast addressing on or off (default is on)
+ *   XEM_PROMISC_OPTION		 Promiscuous addressing on or off (default is off)
+ *   XEM_FDUPLEX_OPTION		 Full duplex on or off (default is off)
+ *   XEM_POLLED_OPTION		 Polled mode on or off (default is off)
+ *   XEM_LOOPBACK_OPTION	 Internal loopback on or off (default is off)
+ *   XEM_FLOW_CONTROL_OPTION	 Interpret pause frames in full duplex mode
+ *				 (default is off)
+ *   XEM_INSERT_PAD_OPTION	 Pad short frames on transmit (default is on)
+ *   XEM_INSERT_FCS_OPTION	 Insert FCS (CRC) on transmit (default is on)
+ *   XEM_INSERT_ADDR_OPTION	 Insert source address on transmit (default is on)
+ *   XEM_OVWRT_ADDR_OPTION	 Overwrite source address on transmit. This is
+ *				 only used if source address insertion is on.
+ *				 (default is on)
+ *   XEM_STRIP_PAD_FCS_OPTION	 Strip FCS and padding from received frames
+ *				 (default is off)
+  * 
+ */ +#define XEM_UNICAST_OPTION 0x00000001UL +#define XEM_BROADCAST_OPTION 0x00000002UL +#define XEM_PROMISC_OPTION 0x00000004UL +#define XEM_FDUPLEX_OPTION 0x00000008UL +#define XEM_POLLED_OPTION 0x00000010UL +#define XEM_LOOPBACK_OPTION 0x00000020UL +#define XEM_FLOW_CONTROL_OPTION 0x00000080UL +#define XEM_INSERT_PAD_OPTION 0x00000100UL +#define XEM_INSERT_FCS_OPTION 0x00000200UL +#define XEM_INSERT_ADDR_OPTION 0x00000400UL +#define XEM_OVWRT_ADDR_OPTION 0x00000800UL +#define XEM_STRIP_PAD_FCS_OPTION 0x00002000UL +/*@}*/ +/* + * Not supported yet: + * XEM_MULTICAST_OPTION Multicast addressing on or off (default is off) + */ +/* NOT SUPPORTED YET... */ +#define XEM_MULTICAST_OPTION 0x00000040UL + +/* + * Some default values for interrupt coalescing within the scatter-gather + * DMA engine. + */ +#define XEM_SGDMA_DFT_THRESHOLD 1 /* Default pkt threshold */ +#define XEM_SGDMA_MAX_THRESHOLD 255 /* Maximum pkt theshold */ +#define XEM_SGDMA_DFT_WAITBOUND 5 /* Default pkt wait bound (msec) */ +#define XEM_SGDMA_MAX_WAITBOUND 1023 /* Maximum pkt wait bound (msec) */ + +/* + * Direction identifiers. These are used for setting values like packet + * thresholds and wait bound for specific channels + */ +#define XEM_SEND 1 +#define XEM_RECV 2 + +/* + * Arguments to SgSend function to indicate whether to hold off starting + * the scatter-gather engine. + */ +#define XEM_SGDMA_NODELAY 0 /* start SG DMA immediately */ +#define XEM_SGDMA_DELAY 1 /* do not start SG DMA */ + +/* + * Constants to determine the configuration of the hardware device. They are + * used to allow the driver to verify it can operate with the hardware. + */ +#define XEM_CFG_NO_IPIF 0 /* Not supported by the driver */ +#define XEM_CFG_NO_DMA 1 /* No DMA */ +#define XEM_CFG_SIMPLE_DMA 2 /* Simple DMA */ +#define XEM_CFG_DMA_SG 3 /* DMA scatter gather */ + +/* + * The next few constants help upper layers determine the size of memory + * pools used for Ethernet buffers and descriptor lists. + */ +#define XEM_MAC_ADDR_SIZE 6 /* six-byte MAC address */ +#define XEM_MTU 1500 /* max size of Ethernet frame */ +#define XEM_HDR_SIZE 14 /* size of Ethernet header */ +#define XEM_HDR_VLAN_SIZE 18 /* size of Ethernet header with VLAN */ +#define XEM_TRL_SIZE 4 /* size of Ethernet trailer (FCS) */ +#define XEM_MAX_FRAME_SIZE (XEM_MTU + XEM_HDR_SIZE + XEM_TRL_SIZE) +#define XEM_MAX_VLAN_FRAME_SIZE (XEM_MTU + XEM_HDR_VLAN_SIZE + XEM_TRL_SIZE) + +/* + * Define a default number of send and receive buffers + */ +#define XEM_MIN_RECV_BUFS 32 /* minimum # of recv buffers */ +#define XEM_DFT_RECV_BUFS 64 /* default # of recv buffers */ + +#define XEM_MIN_SEND_BUFS 16 /* minimum # of send buffers */ +#define XEM_DFT_SEND_BUFS 32 /* default # of send buffers */ + +#define XEM_MIN_BUFFERS (XEM_MIN_RECV_BUFS + XEM_MIN_SEND_BUFS) +#define XEM_DFT_BUFFERS (XEM_DFT_RECV_BUFS + XEM_DFT_SEND_BUFS) + +/* + * Define the number of send and receive buffer descriptors, used for + * scatter-gather DMA + */ +#define XEM_MIN_RECV_DESC 16 /* minimum # of recv descriptors */ +#define XEM_DFT_RECV_DESC 32 /* default # of recv descriptors */ + +#define XEM_MIN_SEND_DESC 8 /* minimum # of send descriptors */ +#define XEM_DFT_SEND_DESC 16 /* default # of send descriptors */ + +/**************************** Type Definitions *******************************/ + +/** + * Ethernet statistics (see XEmac_GetStats() and XEmac_ClearStats()) + */ +typedef struct { + u32 XmitFrames; /**< Number of frames transmitted */ + u32 XmitBytes; /**< Number of bytes transmitted */ + u32 XmitLateCollisionErrors; + /**< Number of transmission failures + due to late collisions */ + u32 XmitExcessDeferral; /**< Number of transmission failures + due o excess collision deferrals */ + u32 XmitOverrunErrors; /**< Number of transmit overrun errors */ + u32 XmitUnderrunErrors; /**< Number of transmit underrun errors */ + u32 RecvFrames; /**< Number of frames received */ + u32 RecvBytes; /**< Number of bytes received */ + u32 RecvFcsErrors; /**< Number of frames discarded due + to FCS errors */ + u32 RecvAlignmentErrors; /**< Number of frames received with + alignment errors */ + u32 RecvOverrunErrors; /**< Number of frames discarded due + to overrun errors */ + u32 RecvUnderrunErrors; /**< Number of recv underrun errors */ + u32 RecvMissedFrameErrors; + /**< Number of frames missed by MAC */ + u32 RecvCollisionErrors; /**< Number of frames discarded due + to collisions */ + u32 RecvLengthFieldErrors; + /**< Number of frames discarded with + invalid length field */ + u32 RecvShortErrors; /**< Number of short frames discarded */ + u32 RecvLongErrors; /**< Number of long frames discarded */ + u32 DmaErrors; /**< Number of DMA errors since init */ + u32 FifoErrors; /**< Number of FIFO errors since init */ + u32 RecvInterrupts; /**< Number of receive interrupts */ + u32 XmitInterrupts; /**< Number of transmit interrupts */ + u32 EmacInterrupts; /**< Number of MAC (device) interrupts */ + u32 TotalIntrs; /**< Total interrupts */ +} XEmac_Stats; + +/** + * This typedef contains configuration information for a device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress; /**< Register base address */ + u32 HasCounters; /**< Does device have counters? */ + u8 IpIfDmaConfig; /**< IPIF/DMA hardware configuration */ + u32 HasMii; /**< Does device support MII? */ + +} XEmac_Config; + +/** @name Typedefs for callbacks + * Callback functions. + * @{ + */ +/** + * Callback when data is sent or received with scatter-gather DMA. + * + * @param CallBackRef is a callback reference passed in by the upper layer + * when setting the callback functions, and passed back to the upper + * layer when the callback is invoked. + * @param BdPtr is a pointer to the first buffer descriptor in a list of + * buffer descriptors. + * @param NumBds is the number of buffer descriptors in the list pointed + * to by BdPtr. + */ +typedef void (*XEmac_SgHandler) (void *CallBackRef, XBufDescriptor * BdPtr, + u32 NumBds); + +/** + * Callback when data is sent or received with direct FIFO communication or + * simple DMA. The user typically defines two callacks, one for send and one + * for receive. + * + * @param CallBackRef is a callback reference passed in by the upper layer + * when setting the callback functions, and passed back to the upper + * layer when the callback is invoked. + */ +typedef void (*XEmac_FifoHandler) (void *CallBackRef); + +/** + * Callback when an asynchronous error occurs. + * + * @param CallBackRef is a callback reference passed in by the upper layer + * when setting the callback functions, and passed back to the upper + * layer when the callback is invoked. + * @param ErrorCode is a Xilinx error code defined in xstatus.h. Also see + * XEmac_SetErrorHandler() for a description of possible errors. + */ +typedef void (*XEmac_ErrorHandler) (void *CallBackRef, XStatus ErrorCode); +/*@}*/ + +/** + * The XEmac driver instance data. The user is required to allocate a + * variable of this type for every EMAC device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + u32 BaseAddress; /* Base address (of IPIF) */ + u32 IsStarted; /* Device is currently started */ + u32 IsReady; /* Device is initialized and ready */ + u32 IsPolled; /* Device is in polled mode */ + u8 IpIfDmaConfig; /* IPIF/DMA hardware configuration */ + u32 HasMii; /* Does device support MII? */ + u32 HasMulticastHash; /* Does device support multicast hash table? */ + + XEmac_Stats Stats; + XPacketFifoV100b RecvFifo; /* FIFO used to receive frames */ + XPacketFifoV100b SendFifo; /* FIFO used to send frames */ + + /* + * Callbacks + */ + XEmac_FifoHandler FifoRecvHandler; /* for non-DMA/simple DMA interrupts */ + void *FifoRecvRef; + XEmac_FifoHandler FifoSendHandler; /* for non-DMA/simple DMA interrupts */ + void *FifoSendRef; + XEmac_ErrorHandler ErrorHandler; /* for asynchronous errors */ + void *ErrorRef; + + XDmaChannel RecvChannel; /* DMA receive channel driver */ + XDmaChannel SendChannel; /* DMA send channel driver */ + + XEmac_SgHandler SgRecvHandler; /* callback for scatter-gather DMA */ + void *SgRecvRef; + XEmac_SgHandler SgSendHandler; /* callback for scatter-gather DMA */ + void *SgSendRef; +} XEmac; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* +* This macro determines if the device is currently configured for +* scatter-gather DMA. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* Boolean TRUE if the device is configured for scatter-gather DMA, or FALSE +* if it is not. +* +* @note +* +* Signature: u32 XEmac_mIsSgDma(XEmac *InstancePtr) +* +******************************************************************************/ +#define XEmac_mIsSgDma(InstancePtr) \ + ((InstancePtr)->IpIfDmaConfig == XEM_CFG_DMA_SG) + +/*****************************************************************************/ +/** +* +* This macro determines if the device is currently configured for simple DMA. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* Boolean TRUE if the device is configured for simple DMA, or FALSE otherwise +* +* @note +* +* Signature: u32 XEmac_mIsSimpleDma(XEmac *InstancePtr) +* +******************************************************************************/ +#define XEmac_mIsSimpleDma(InstancePtr) \ + ((InstancePtr)->IpIfDmaConfig == XEM_CFG_SIMPLE_DMA) + +/*****************************************************************************/ +/** +* +* This macro determines if the device is currently configured with DMA (either +* simple DMA or scatter-gather DMA) +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* Boolean TRUE if the device is configured with DMA, or FALSE otherwise +* +* @note +* +* Signature: u32 XEmac_mIsDma(XEmac *InstancePtr) +* +******************************************************************************/ +#define XEmac_mIsDma(InstancePtr) \ + (XEmac_mIsSimpleDma(InstancePtr) || XEmac_mIsSgDma(InstancePtr)) + +/************************** Function Prototypes ******************************/ + +/* + * Initialization functions in xemac.c + */ +XStatus XEmac_Initialize(XEmac * InstancePtr, u16 DeviceId); +XStatus XEmac_Start(XEmac * InstancePtr); +XStatus XEmac_Stop(XEmac * InstancePtr); +void XEmac_Reset(XEmac * InstancePtr); +XEmac_Config *XEmac_LookupConfig(u16 DeviceId); + +/* + * Diagnostic functions in xemac_selftest.c + */ +XStatus XEmac_SelfTest(XEmac * InstancePtr); + +/* + * Polled functions in xemac_polled.c + */ +XStatus XEmac_PollSend(XEmac * InstancePtr, u8 * BufPtr, u32 ByteCount); +XStatus XEmac_PollRecv(XEmac * InstancePtr, u8 * BufPtr, u32 * ByteCountPtr); + +/* + * Interrupts with scatter-gather DMA functions in xemac_intr_dma.c + */ +XStatus XEmac_SgSend(XEmac * InstancePtr, XBufDescriptor * BdPtr, int Delay); +XStatus XEmac_SgRecv(XEmac * InstancePtr, XBufDescriptor * BdPtr); +XStatus XEmac_SetPktThreshold(XEmac * InstancePtr, u32 Direction, u8 Threshold); +XStatus XEmac_GetPktThreshold(XEmac * InstancePtr, u32 Direction, + u8 * ThreshPtr); +XStatus XEmac_SetPktWaitBound(XEmac * InstancePtr, u32 Direction, + u32 TimerValue); +XStatus XEmac_GetPktWaitBound(XEmac * InstancePtr, u32 Direction, + u32 * WaitPtr); +XStatus XEmac_SetSgRecvSpace(XEmac * InstancePtr, u32 * MemoryPtr, + u32 ByteCount); +XStatus XEmac_SetSgSendSpace(XEmac * InstancePtr, u32 * MemoryPtr, + u32 ByteCount); +void XEmac_SetSgRecvHandler(XEmac * InstancePtr, void *CallBackRef, + XEmac_SgHandler FuncPtr); +void XEmac_SetSgSendHandler(XEmac * InstancePtr, void *CallBackRef, + XEmac_SgHandler FuncPtr); + +void XEmac_IntrHandlerDma(void *InstancePtr); /* interrupt handler */ + +/* + * Interrupts with direct FIFO functions in xemac_intr_fifo.c. Also used + * for simple DMA. + */ +XStatus XEmac_FifoSend(XEmac * InstancePtr, u8 * BufPtr, u32 ByteCount); +XStatus XEmac_FifoRecv(XEmac * InstancePtr, u8 * BufPtr, u32 * ByteCountPtr); +void XEmac_SetFifoRecvHandler(XEmac * InstancePtr, void *CallBackRef, + XEmac_FifoHandler FuncPtr); +void XEmac_SetFifoSendHandler(XEmac * InstancePtr, void *CallBackRef, + XEmac_FifoHandler FuncPtr); + +void XEmac_IntrHandlerFifo(void *InstancePtr); /* interrupt handler */ + +/* + * General interrupt-related functions in xemac_intr.c + */ +void XEmac_SetErrorHandler(XEmac * InstancePtr, void *CallBackRef, + XEmac_ErrorHandler FuncPtr); + +/* + * MAC configuration in xemac_options.c + */ +XStatus XEmac_SetOptions(XEmac * InstancePtr, u32 OptionFlag); +u32 XEmac_GetOptions(XEmac * InstancePtr); +XStatus XEmac_SetMacAddress(XEmac * InstancePtr, u8 * AddressPtr); +void XEmac_GetMacAddress(XEmac * InstancePtr, u8 * BufferPtr); +XStatus XEmac_SetInterframeGap(XEmac * InstancePtr, u8 Part1, u8 Part2); +void XEmac_GetInterframeGap(XEmac * InstancePtr, u8 * Part1Ptr, u8 * Part2Ptr); + +/* + * Multicast functions in xemac_multicast.c (not supported by EMAC yet) + */ +XStatus XEmac_MulticastAdd(XEmac * InstancePtr, u8 * AddressPtr); +XStatus XEmac_MulticastClear(XEmac * InstancePtr); + +/* + * PHY configuration in xemac_phy.c + */ +XStatus XEmac_PhyRead(XEmac * InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 * PhyDataPtr); +XStatus XEmac_PhyWrite(XEmac * InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData); + +/* + * Statistics in xemac_stats.c + */ +void XEmac_GetStats(XEmac * InstancePtr, XEmac_Stats * StatsPtr); +void XEmac_ClearStats(XEmac * InstancePtr); + +#endif /* end of protection macro */ diff --git a/board/xilinx/xilinx_enet/xemac_g.c b/board/xilinx/xilinx_enet/xemac_g.c new file mode 100644 index 0000000000..9340f911f8 --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac_g.c @@ -0,0 +1,60 @@ +/******************************************************************* +* +* CAUTION: This file is automatically generated by libgen. +* Version: Xilinx EDK 6.1.2 EDK_G.14 +* DO NOT EDIT. +* +* 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. +* +* Description: Driver configuration +* +*******************************************************************/ + +#include "xparameters.h" +#include "xemac.h" + +/* +* The configuration table for devices +*/ + +XEmac_Config XEmac_ConfigTable[] = { + { + XPAR_OPB_ETHERNET_0_DEVICE_ID, + XPAR_OPB_ETHERNET_0_BASEADDR, + XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST, + XPAR_OPB_ETHERNET_0_DMA_PRESENT, + XPAR_OPB_ETHERNET_0_MII_EXIST} +}; diff --git a/board/xilinx/xilinx_enet/xemac_i.h b/board/xilinx/xilinx_enet/xemac_i.h new file mode 100644 index 0000000000..9c160f3880 --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac_i.h @@ -0,0 +1,207 @@ +/****************************************************************************** +* +* 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_i.h +* +* This header file contains internal identifiers, which are those shared +* between XEmac components. The identifiers in this file are not intended for +* use external to the driver. +* +*
+* 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.00b rpm  04/29/02 Moved register definitions to xemac_l.h
+* 1.00c rpm  12/05/02 New version includes support for simple DMA
+* 
+* +******************************************************************************/ + +#ifndef XEMAC_I_H /* prevent circular inclusions */ +#define XEMAC_I_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xemac.h" +#include "xemac_l.h" + +/************************** Constant Definitions *****************************/ + +/* + * Default buffer descriptor control word masks. The default send BD control + * is set for incrementing the source address by one for each byte transferred, + * and specify that the destination address (FIFO) is local to the device. The + * default receive BD control is set for incrementing the destination address + * by one for each byte transferred, and specify that the source address is + * local to the device. + */ +#define XEM_DFT_SEND_BD_MASK (XDC_DMACR_SOURCE_INCR_MASK | \ + XDC_DMACR_DEST_LOCAL_MASK) +#define XEM_DFT_RECV_BD_MASK (XDC_DMACR_DEST_INCR_MASK | \ + XDC_DMACR_SOURCE_LOCAL_MASK) + +/* + * Masks for the IPIF Device Interrupt enable and status registers. + */ +#define XEM_IPIF_EMAC_MASK 0x00000004UL /* MAC interrupt */ +#define XEM_IPIF_SEND_DMA_MASK 0x00000008UL /* Send DMA interrupt */ +#define XEM_IPIF_RECV_DMA_MASK 0x00000010UL /* Receive DMA interrupt */ +#define XEM_IPIF_RECV_FIFO_MASK 0x00000020UL /* Receive FIFO interrupt */ +#define XEM_IPIF_SEND_FIFO_MASK 0x00000040UL /* Send FIFO interrupt */ + +/* + * Default IPIF Device Interrupt mask when configured for DMA + */ +#define XEM_IPIF_DMA_DFT_MASK (XEM_IPIF_SEND_DMA_MASK | \ + XEM_IPIF_RECV_DMA_MASK | \ + XEM_IPIF_EMAC_MASK | \ + XEM_IPIF_SEND_FIFO_MASK | \ + XEM_IPIF_RECV_FIFO_MASK) + +/* + * Default IPIF Device Interrupt mask when configured without DMA + */ +#define XEM_IPIF_FIFO_DFT_MASK (XEM_IPIF_EMAC_MASK | \ + XEM_IPIF_SEND_FIFO_MASK | \ + XEM_IPIF_RECV_FIFO_MASK) + +#define XEM_IPIF_DMA_DEV_INTR_COUNT 7 /* Number of interrupt sources */ +#define XEM_IPIF_FIFO_DEV_INTR_COUNT 5 /* Number of interrupt sources */ +#define XEM_IPIF_DEVICE_INTR_COUNT 7 /* Number of interrupt sources */ +#define XEM_IPIF_IP_INTR_COUNT 22 /* Number of MAC interrupts */ + +/* a mask for all transmit interrupts, used in polled mode */ +#define XEM_EIR_XMIT_ALL_MASK (XEM_EIR_XMIT_DONE_MASK | \ + XEM_EIR_XMIT_ERROR_MASK | \ + XEM_EIR_XMIT_SFIFO_EMPTY_MASK | \ + XEM_EIR_XMIT_LFIFO_FULL_MASK) + +/* a mask for all receive interrupts, used in polled mode */ +#define XEM_EIR_RECV_ALL_MASK (XEM_EIR_RECV_DONE_MASK | \ + XEM_EIR_RECV_ERROR_MASK | \ + XEM_EIR_RECV_LFIFO_EMPTY_MASK | \ + XEM_EIR_RECV_LFIFO_OVER_MASK | \ + XEM_EIR_RECV_LFIFO_UNDER_MASK | \ + XEM_EIR_RECV_DFIFO_OVER_MASK | \ + XEM_EIR_RECV_MISSED_FRAME_MASK | \ + XEM_EIR_RECV_COLLISION_MASK | \ + XEM_EIR_RECV_FCS_ERROR_MASK | \ + XEM_EIR_RECV_LEN_ERROR_MASK | \ + XEM_EIR_RECV_SHORT_ERROR_MASK | \ + XEM_EIR_RECV_LONG_ERROR_MASK | \ + XEM_EIR_RECV_ALIGN_ERROR_MASK) + +/* a default interrupt mask for scatter-gather DMA operation */ +#define XEM_EIR_DFT_SG_MASK (XEM_EIR_RECV_ERROR_MASK | \ + XEM_EIR_RECV_LFIFO_OVER_MASK | \ + XEM_EIR_RECV_LFIFO_UNDER_MASK | \ + XEM_EIR_XMIT_SFIFO_OVER_MASK | \ + XEM_EIR_XMIT_SFIFO_UNDER_MASK | \ + XEM_EIR_XMIT_LFIFO_OVER_MASK | \ + XEM_EIR_XMIT_LFIFO_UNDER_MASK | \ + XEM_EIR_RECV_DFIFO_OVER_MASK | \ + XEM_EIR_RECV_MISSED_FRAME_MASK | \ + XEM_EIR_RECV_COLLISION_MASK | \ + XEM_EIR_RECV_FCS_ERROR_MASK | \ + XEM_EIR_RECV_LEN_ERROR_MASK | \ + XEM_EIR_RECV_SHORT_ERROR_MASK | \ + XEM_EIR_RECV_LONG_ERROR_MASK | \ + XEM_EIR_RECV_ALIGN_ERROR_MASK) + +/* a default interrupt mask for non-DMA operation (direct FIFOs) */ +#define XEM_EIR_DFT_FIFO_MASK (XEM_EIR_XMIT_DONE_MASK | \ + XEM_EIR_RECV_DONE_MASK | \ + XEM_EIR_DFT_SG_MASK) + +/* + * Mask for the DMA interrupt enable and status registers when configured + * for scatter-gather DMA. + */ +#define XEM_DMA_SG_INTR_MASK (XDC_IXR_DMA_ERROR_MASK | \ + XDC_IXR_PKT_THRESHOLD_MASK | \ + XDC_IXR_PKT_WAIT_BOUND_MASK | \ + XDC_IXR_SG_END_MASK) + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/* +* +* Clears a structure of given size, in bytes, by setting each byte to 0. +* +* @param StructPtr is a pointer to the structure to be cleared. +* @param NumBytes is the number of bytes in the structure. +* +* @return +* +* None. +* +* @note +* +* Signature: void XEmac_mClearStruct(u8 *StructPtr, unsigned int NumBytes) +* +******************************************************************************/ +#define XEmac_mClearStruct(StructPtr, NumBytes) \ +{ \ + int i; \ + u8 *BytePtr = (u8 *)(StructPtr); \ + for (i=0; i < (unsigned int)(NumBytes); i++) \ + { \ + *BytePtr++ = 0; \ + } \ +} + +/************************** Variable Definitions *****************************/ + +extern XEmac_Config XEmac_ConfigTable[]; + +/************************** Function Prototypes ******************************/ + +void XEmac_CheckEmacError(XEmac * InstancePtr, u32 IntrStatus); +void XEmac_CheckFifoRecvError(XEmac * InstancePtr); +void XEmac_CheckFifoSendError(XEmac * InstancePtr); + +#endif /* end of protection macro */ diff --git a/board/xilinx/xilinx_enet/xemac_intr.c b/board/xilinx/xilinx_enet/xemac_intr.c new file mode 100644 index 0000000000..b9a2621564 --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac_intr.c @@ -0,0 +1,402 @@ +/****************************************************************************** +* +* 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.c +* +* This file contains general interrupt-related functions of the XEmac driver. +* +*
+* 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
+* 1.00c rpm  03/31/03 Added comment to indicate that no Receive Length FIFO
+*                     overrun interrupts occur in v1.00l and later of the EMAC
+*                     device. This avoids the need to reset the device on
+*                     receive overruns.
+* 
+* +******************************************************************************/ + +/***************************** 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 ******************************/ + +/*****************************************************************************/ +/** +* +* Set the callback function for handling asynchronous errors. The upper layer +* software should call this function during initialization. +* +* The error 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. +* +* The Xilinx errors that must be handled by the callback are: +* - XST_DMA_ERROR indicates an unrecoverable DMA error occurred. This is +* typically a bus error or bus timeout. The handler must reset and +* re-configure the device. +* - XST_FIFO_ERROR indicates an unrecoverable FIFO error occurred. This is a +* deadlock condition in the packet FIFO. The handler must reset and +* re-configure the device. +* - XST_RESET_ERROR indicates an unrecoverable MAC error occurred, usually an +* overrun or underrun. The handler must reset and re-configure the device. +* - XST_DMA_SG_NO_LIST indicates an attempt was made to access a scatter-gather +* DMA list that has not yet been created. +* - XST_DMA_SG_LIST_EMPTY indicates the driver tried to get a descriptor from +* the receive descriptor list, but the list was empty. +* +* @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_SetErrorHandler(XEmac * InstancePtr, void *CallBackRef, + XEmac_ErrorHandler FuncPtr) +{ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(FuncPtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + InstancePtr->ErrorHandler = FuncPtr; + InstancePtr->ErrorRef = CallBackRef; +} + +/****************************************************************************/ +/* +* +* Check the interrupt status bits of the Ethernet MAC for errors. Errors +* currently handled are: +* - Receive length FIFO overrun. Indicates data was lost due to the receive +* length FIFO becoming full during the reception of a packet. Only a device +* reset clears this condition. +* - Receive length FIFO underrun. An attempt to read an empty FIFO. Only a +* device reset clears this condition. +* - Transmit status FIFO overrun. Indicates data was lost due to the transmit +* status FIFO becoming full following the transmission of a packet. Only a +* device reset clears this condition. +* - Transmit status FIFO underrun. An attempt to read an empty FIFO. Only a +* device reset clears this condition. +* - Transmit length FIFO overrun. Indicates data was lost due to the transmit +* length FIFO becoming full following the transmission of a packet. Only a +* device reset clears this condition. +* - Transmit length FIFO underrun. An attempt to read an empty FIFO. Only a +* device reset clears this condition. +* - Receive data FIFO overrun. Indicates data was lost due to the receive data +* FIFO becoming full during the reception of a packet. +* - Receive data errors: +* - Receive missed frame error. Valid data was lost by the MAC. +* - Receive collision error. Data was lost by the MAC due to a collision. +* - Receive FCS error. Data was dicarded by the MAC due to FCS error. +* - Receive length field error. Data was dicarded by the MAC due to an invalid +* length field in the packet. +* - Receive short error. Data was dicarded by the MAC because a packet was +* shorter than allowed. +* - Receive long error. Data was dicarded by the MAC because a packet was +* longer than allowed. +* - Receive alignment error. Data was truncated by the MAC because its length +* was not byte-aligned. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param IntrStatus is the contents of the interrupt status register to be checked +* +* @return +* +* None. +* +* @note +* +* This function is intended for internal use only. +* +******************************************************************************/ +void +XEmac_CheckEmacError(XEmac * InstancePtr, u32 IntrStatus) +{ + u32 ResetError = FALSE; + + /* + * First check for receive fifo overrun/underrun errors. Most require a + * reset by the user to clear, but the data FIFO overrun error does not. + */ + if (IntrStatus & XEM_EIR_RECV_DFIFO_OVER_MASK) { + InstancePtr->Stats.RecvOverrunErrors++; + InstancePtr->Stats.FifoErrors++; + } + + if (IntrStatus & XEM_EIR_RECV_LFIFO_OVER_MASK) { + /* + * Receive Length FIFO overrun interrupts no longer occur in v1.00l + * and later of the EMAC device. Frames are just dropped by the EMAC + * if the length FIFO is full. The user would notice the Receive Missed + * Frame count incrementing without any other errors being reported. + * This code is left here for backward compatibility with v1.00k and + * older EMAC devices. + */ + InstancePtr->Stats.RecvOverrunErrors++; + InstancePtr->Stats.FifoErrors++; + ResetError = TRUE; /* requires a reset */ + } + + if (IntrStatus & XEM_EIR_RECV_LFIFO_UNDER_MASK) { + InstancePtr->Stats.RecvUnderrunErrors++; + InstancePtr->Stats.FifoErrors++; + ResetError = TRUE; /* requires a reset */ + } + + /* + * Now check for general receive errors. Get the latest count where + * available, otherwise just bump the statistic so we know the interrupt + * occurred. + */ + if (IntrStatus & XEM_EIR_RECV_ERROR_MASK) { + if (IntrStatus & XEM_EIR_RECV_MISSED_FRAME_MASK) { + /* + * Caused by length FIFO or data FIFO overruns on receive side + */ + 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); + } + + /* + * Bump recv interrupts stats only if not scatter-gather DMA (this + * stat gets bumped elsewhere in that case) + */ + if (!XEmac_mIsSgDma(InstancePtr)) { + InstancePtr->Stats.RecvInterrupts++; /* TODO: double bump? */ + } + + } + + /* + * Check for transmit errors. These apply to both DMA and non-DMA modes + * of operation. The entire device should be reset after overruns or + * underruns. + */ + if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK | + XEM_EIR_XMIT_LFIFO_OVER_MASK)) { + InstancePtr->Stats.XmitOverrunErrors++; + InstancePtr->Stats.FifoErrors++; + ResetError = TRUE; + } + + if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK | + XEM_EIR_XMIT_LFIFO_UNDER_MASK)) { + InstancePtr->Stats.XmitUnderrunErrors++; + InstancePtr->Stats.FifoErrors++; + ResetError = TRUE; + } + + if (ResetError) { + /* + * If a reset error occurred, disable the EMAC interrupts since the + * reset-causing interrupt(s) is latched in the EMAC - meaning it will + * keep occurring until the device is reset. In order to give the higher + * layer software time to reset the device, we have to disable the + * overrun/underrun interrupts until that happens. We trust that the + * higher layer resets the device. We are able to get away with disabling + * all EMAC interrupts since the only interrupts it generates are for + * error conditions, and we don't care about any more errors right now. + */ + XIIF_V123B_WRITE_IIER(InstancePtr->BaseAddress, 0); + + /* + * Invoke the error handler callback, which should result in a reset + * of the device by the upper layer software. + */ + InstancePtr->ErrorHandler(InstancePtr->ErrorRef, + XST_RESET_ERROR); + } +} + +/*****************************************************************************/ +/* +* +* Check the receive packet FIFO for errors. FIFO error interrupts are: +* - Deadlock. See the XPacketFifo component for a description of deadlock on a +* FIFO. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* Although the function returns void, it can return an asynchronous error to the +* application through the error handler. It can return XST_FIFO_ERROR if a FIFO +* error occurred. +* +* @note +* +* This function is intended for internal use only. +* +******************************************************************************/ +void +XEmac_CheckFifoRecvError(XEmac * InstancePtr) +{ + /* + * Although the deadlock is currently the only interrupt from a packet + * FIFO, make sure it is deadlocked before taking action. There is no + * need to clear this interrupt since it requires a reset of the device. + */ + if (XPF_V100B_IS_DEADLOCKED(&InstancePtr->RecvFifo)) { + u32 IntrEnable; + + InstancePtr->Stats.FifoErrors++; + + /* + * Invoke the error callback function, which should result in a reset + * of the device by the upper layer software. We first need to disable + * the FIFO interrupt, since otherwise the upper layer thread that + * handles the reset may never run because this interrupt condition + * doesn't go away until a reset occurs (there is no way to ack it). + */ + IntrEnable = XIIF_V123B_READ_DIER(InstancePtr->BaseAddress); + XIIF_V123B_WRITE_DIER(InstancePtr->BaseAddress, + IntrEnable & ~XEM_IPIF_RECV_FIFO_MASK); + + InstancePtr->ErrorHandler(InstancePtr->ErrorRef, + XST_FIFO_ERROR); + } +} + +/*****************************************************************************/ +/* +* +* Check the send packet FIFO for errors. FIFO error interrupts are: +* - Deadlock. See the XPacketFifo component for a description of deadlock on a +* FIFO. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* Although the function returns void, it can return an asynchronous error to the +* application through the error handler. It can return XST_FIFO_ERROR if a FIFO +* error occurred. +* +* @note +* +* This function is intended for internal use only. +* +******************************************************************************/ +void +XEmac_CheckFifoSendError(XEmac * InstancePtr) +{ + /* + * Although the deadlock is currently the only interrupt from a packet + * FIFO, make sure it is deadlocked before taking action. There is no + * need to clear this interrupt since it requires a reset of the device. + */ + if (XPF_V100B_IS_DEADLOCKED(&InstancePtr->SendFifo)) { + u32 IntrEnable; + + InstancePtr->Stats.FifoErrors++; + + /* + * Invoke the error callback function, which should result in a reset + * of the device by the upper layer software. We first need to disable + * the FIFO interrupt, since otherwise the upper layer thread that + * handles the reset may never run because this interrupt condition + * doesn't go away until a reset occurs (there is no way to ack it). + */ + IntrEnable = XIIF_V123B_READ_DIER(InstancePtr->BaseAddress); + XIIF_V123B_WRITE_DIER(InstancePtr->BaseAddress, + IntrEnable & ~XEM_IPIF_SEND_FIFO_MASK); + + InstancePtr->ErrorHandler(InstancePtr->ErrorRef, + XST_FIFO_ERROR); + } +} diff --git a/board/xilinx/xilinx_enet/xemac_intr_dma.c b/board/xilinx/xilinx_enet/xemac_intr_dma.c new file mode 100644 index 0000000000..567abb42ab --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac_intr_dma.c @@ -0,0 +1,1344 @@ +/****************************************************************************** +* +* Author: Xilinx, Inc. +* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A +* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS +* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, +* XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE +* FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING +* ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. +* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO +* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY +* WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM +* CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE. +* +* +* Xilinx hardware products are not intended for use in life support +* appliances, devices, or systems. Use in such applications is +* expressly prohibited. +* +* +* (c) Copyright 2002-2004 Xilinx Inc. +* All rights reserved. +* +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 675 Mass Ave, Cambridge, MA 02139, USA. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xemac_intr_dma.c +* +* Contains functions used in interrupt mode when configured with scatter-gather +* DMA. +* +* The interrupt handler, XEmac_IntrHandlerDma(), must be connected by the user +* to the interrupt controller. +* +*
+* 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.
+* 
+* +******************************************************************************/ + +/***************************** 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); +} diff --git a/board/xilinx/xilinx_enet/xemac_l.h b/board/xilinx/xilinx_enet/xemac_l.h new file mode 100644 index 0000000000..a463937dbd --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac_l.h @@ -0,0 +1,462 @@ +/****************************************************************************** +* +* 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_l.h +* +* This header file contains identifiers and low-level driver functions (or +* macros) that can be used to access the device. High-level driver functions +* are defined in xemac.h. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver	Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00b rpm  04/26/02 First release
+* 1.00b rmm  09/23/02 Added XEmac_mPhyReset macro
+* 1.00c rpm  12/05/02 New version includes support for simple DMA
+* 
+* +******************************************************************************/ + +#ifndef XEMAC_L_H /* prevent circular inclusions */ +#define XEMAC_L_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xio.h" + +/************************** Constant Definitions *****************************/ + +/* Offset of the MAC registers from the IPIF base address */ +#define XEM_REG_OFFSET 0x1100UL + +/* + * Register offsets for the Ethernet MAC. Each register is 32 bits. + */ +#define XEM_EMIR_OFFSET (XEM_REG_OFFSET + 0x0) /* EMAC Module ID */ +#define XEM_ECR_OFFSET (XEM_REG_OFFSET + 0x4) /* MAC Control */ +#define XEM_IFGP_OFFSET (XEM_REG_OFFSET + 0x8) /* Interframe Gap */ +#define XEM_SAH_OFFSET (XEM_REG_OFFSET + 0xC) /* Station addr, high */ +#define XEM_SAL_OFFSET (XEM_REG_OFFSET + 0x10) /* Station addr, low */ +#define XEM_MGTCR_OFFSET (XEM_REG_OFFSET + 0x14) /* MII mgmt control */ +#define XEM_MGTDR_OFFSET (XEM_REG_OFFSET + 0x18) /* MII mgmt data */ +#define XEM_RPLR_OFFSET (XEM_REG_OFFSET + 0x1C) /* Rx packet length */ +#define XEM_TPLR_OFFSET (XEM_REG_OFFSET + 0x20) /* Tx packet length */ +#define XEM_TSR_OFFSET (XEM_REG_OFFSET + 0x24) /* Tx status */ +#define XEM_RMFC_OFFSET (XEM_REG_OFFSET + 0x28) /* Rx missed frames */ +#define XEM_RCC_OFFSET (XEM_REG_OFFSET + 0x2C) /* Rx collisions */ +#define XEM_RFCSEC_OFFSET (XEM_REG_OFFSET + 0x30) /* Rx FCS errors */ +#define XEM_RAEC_OFFSET (XEM_REG_OFFSET + 0x34) /* Rx alignment errors */ +#define XEM_TEDC_OFFSET (XEM_REG_OFFSET + 0x38) /* Transmit excess + * deferral cnt */ + +/* + * Register offsets for the IPIF components + */ +#define XEM_ISR_OFFSET 0x20UL /* Interrupt status */ + +#define XEM_DMA_OFFSET 0x2300UL +#define XEM_DMA_SEND_OFFSET (XEM_DMA_OFFSET + 0x0) /* DMA send channel */ +#define XEM_DMA_RECV_OFFSET (XEM_DMA_OFFSET + 0x40) /* DMA recv channel */ + +#define XEM_PFIFO_OFFSET 0x2000UL +#define XEM_PFIFO_TXREG_OFFSET (XEM_PFIFO_OFFSET + 0x0) /* Tx registers */ +#define XEM_PFIFO_RXREG_OFFSET (XEM_PFIFO_OFFSET + 0x10) /* Rx registers */ +#define XEM_PFIFO_TXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x100) /* Tx keyhole */ +#define XEM_PFIFO_RXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x200) /* Rx keyhole */ + +/* + * EMAC Module Identification Register (EMIR) + */ +#define XEM_EMIR_VERSION_MASK 0xFFFF0000UL /* Device version */ +#define XEM_EMIR_TYPE_MASK 0x0000FF00UL /* Device type */ + +/* + * EMAC Control Register (ECR) + */ +#define XEM_ECR_FULL_DUPLEX_MASK 0x80000000UL /* Full duplex mode */ +#define XEM_ECR_XMIT_RESET_MASK 0x40000000UL /* Reset transmitter */ +#define XEM_ECR_XMIT_ENABLE_MASK 0x20000000UL /* Enable transmitter */ +#define XEM_ECR_RECV_RESET_MASK 0x10000000UL /* Reset receiver */ +#define XEM_ECR_RECV_ENABLE_MASK 0x08000000UL /* Enable receiver */ +#define XEM_ECR_PHY_ENABLE_MASK 0x04000000UL /* Enable PHY */ +#define XEM_ECR_XMIT_PAD_ENABLE_MASK 0x02000000UL /* Enable xmit pad insert */ +#define XEM_ECR_XMIT_FCS_ENABLE_MASK 0x01000000UL /* Enable xmit FCS insert */ +#define XEM_ECR_XMIT_ADDR_INSERT_MASK 0x00800000UL /* Enable xmit source addr + * insertion */ +#define XEM_ECR_XMIT_ERROR_INSERT_MASK 0x00400000UL /* Insert xmit error */ +#define XEM_ECR_XMIT_ADDR_OVWRT_MASK 0x00200000UL /* Enable xmit source addr + * overwrite */ +#define XEM_ECR_LOOPBACK_MASK 0x00100000UL /* Enable internal + * loopback */ +#define XEM_ECR_RECV_STRIP_ENABLE_MASK 0x00080000UL /* Enable recv pad/fcs strip */ +#define XEM_ECR_UNICAST_ENABLE_MASK 0x00020000UL /* Enable unicast addr */ +#define XEM_ECR_MULTI_ENABLE_MASK 0x00010000UL /* Enable multicast addr */ +#define XEM_ECR_BROAD_ENABLE_MASK 0x00008000UL /* Enable broadcast addr */ +#define XEM_ECR_PROMISC_ENABLE_MASK 0x00004000UL /* Enable promiscuous mode */ +#define XEM_ECR_RECV_ALL_MASK 0x00002000UL /* Receive all frames */ +#define XEM_ECR_RESERVED2_MASK 0x00001000UL /* Reserved */ +#define XEM_ECR_MULTI_HASH_ENABLE_MASK 0x00000800UL /* Enable multicast hash */ +#define XEM_ECR_PAUSE_FRAME_MASK 0x00000400UL /* Interpret pause frames */ +#define XEM_ECR_CLEAR_HASH_MASK 0x00000200UL /* Clear hash table */ +#define XEM_ECR_ADD_HASH_ADDR_MASK 0x00000100UL /* Add hash table address */ + +/* + * Interframe Gap Register (IFGR) + */ +#define XEM_IFGP_PART1_MASK 0xF8000000UL /* Interframe Gap Part1 */ +#define XEM_IFGP_PART1_SHIFT 27 +#define XEM_IFGP_PART2_MASK 0x07C00000UL /* Interframe Gap Part2 */ +#define XEM_IFGP_PART2_SHIFT 22 + +/* + * Station Address High Register (SAH) + */ +#define XEM_SAH_ADDR_MASK 0x0000FFFFUL /* Station address high bytes */ + +/* + * Station Address Low Register (SAL) + */ +#define XEM_SAL_ADDR_MASK 0xFFFFFFFFUL /* Station address low bytes */ + +/* + * MII Management Control Register (MGTCR) + */ +#define XEM_MGTCR_START_MASK 0x80000000UL /* Start/Busy */ +#define XEM_MGTCR_RW_NOT_MASK 0x40000000UL /* Read/Write Not (direction) */ +#define XEM_MGTCR_PHY_ADDR_MASK 0x3E000000UL /* PHY address */ +#define XEM_MGTCR_PHY_ADDR_SHIFT 25 /* PHY address shift */ +#define XEM_MGTCR_REG_ADDR_MASK 0x01F00000UL /* Register address */ +#define XEM_MGTCR_REG_ADDR_SHIFT 20 /* Register addr shift */ +#define XEM_MGTCR_MII_ENABLE_MASK 0x00080000UL /* Enable MII from EMAC */ +#define XEM_MGTCR_RD_ERROR_MASK 0x00040000UL /* MII mgmt read error */ + +/* + * MII Management Data Register (MGTDR) + */ +#define XEM_MGTDR_DATA_MASK 0x0000FFFFUL /* MII data */ + +/* + * Receive Packet Length Register (RPLR) + */ +#define XEM_RPLR_LENGTH_MASK 0x0000FFFFUL /* Receive packet length */ + +/* + * Transmit Packet Length Register (TPLR) + */ +#define XEM_TPLR_LENGTH_MASK 0x0000FFFFUL /* Transmit packet length */ + +/* + * Transmit Status Register (TSR) + */ +#define XEM_TSR_EXCESS_DEFERRAL_MASK 0x80000000UL /* Transmit excess deferral */ +#define XEM_TSR_FIFO_UNDERRUN_MASK 0x40000000UL /* Packet FIFO underrun */ +#define XEM_TSR_ATTEMPTS_MASK 0x3E000000UL /* Transmission attempts */ +#define XEM_TSR_LATE_COLLISION_MASK 0x01000000UL /* Transmit late collision */ + +/* + * Receive Missed Frame Count (RMFC) + */ +#define XEM_RMFC_DATA_MASK 0x0000FFFFUL + +/* + * Receive Collision Count (RCC) + */ +#define XEM_RCC_DATA_MASK 0x0000FFFFUL + +/* + * Receive FCS Error Count (RFCSEC) + */ +#define XEM_RFCSEC_DATA_MASK 0x0000FFFFUL + +/* + * Receive Alignment Error Count (RALN) + */ +#define XEM_RAEC_DATA_MASK 0x0000FFFFUL + +/* + * Transmit Excess Deferral Count (TEDC) + */ +#define XEM_TEDC_DATA_MASK 0x0000FFFFUL + +/* + * EMAC Interrupt Registers (Status and Enable) masks. These registers are + * part of the IPIF IP Interrupt registers + */ +#define XEM_EIR_XMIT_DONE_MASK 0x00000001UL /* Xmit complete */ +#define XEM_EIR_RECV_DONE_MASK 0x00000002UL /* Recv complete */ +#define XEM_EIR_XMIT_ERROR_MASK 0x00000004UL /* Xmit error */ +#define XEM_EIR_RECV_ERROR_MASK 0x00000008UL /* Recv error */ +#define XEM_EIR_XMIT_SFIFO_EMPTY_MASK 0x00000010UL /* Xmit status fifo empty */ +#define XEM_EIR_RECV_LFIFO_EMPTY_MASK 0x00000020UL /* Recv length fifo empty */ +#define XEM_EIR_XMIT_LFIFO_FULL_MASK 0x00000040UL /* Xmit length fifo full */ +#define XEM_EIR_RECV_LFIFO_OVER_MASK 0x00000080UL /* Recv length fifo + * overrun */ +#define XEM_EIR_RECV_LFIFO_UNDER_MASK 0x00000100UL /* Recv length fifo + * underrun */ +#define XEM_EIR_XMIT_SFIFO_OVER_MASK 0x00000200UL /* Xmit status fifo + * overrun */ +#define XEM_EIR_XMIT_SFIFO_UNDER_MASK 0x00000400UL /* Transmit status fifo + * underrun */ +#define XEM_EIR_XMIT_LFIFO_OVER_MASK 0x00000800UL /* Transmit length fifo + * overrun */ +#define XEM_EIR_XMIT_LFIFO_UNDER_MASK 0x00001000UL /* Transmit length fifo + * underrun */ +#define XEM_EIR_XMIT_PAUSE_MASK 0x00002000UL /* Transmit pause pkt + * received */ +#define XEM_EIR_RECV_DFIFO_OVER_MASK 0x00004000UL /* Receive data fifo + * overrun */ +#define XEM_EIR_RECV_MISSED_FRAME_MASK 0x00008000UL /* Receive missed frame + * error */ +#define XEM_EIR_RECV_COLLISION_MASK 0x00010000UL /* Receive collision + * error */ +#define XEM_EIR_RECV_FCS_ERROR_MASK 0x00020000UL /* Receive FCS error */ +#define XEM_EIR_RECV_LEN_ERROR_MASK 0x00040000UL /* Receive length field + * error */ +#define XEM_EIR_RECV_SHORT_ERROR_MASK 0x00080000UL /* Receive short frame + * error */ +#define XEM_EIR_RECV_LONG_ERROR_MASK 0x00100000UL /* Receive long frame + * error */ +#define XEM_EIR_RECV_ALIGN_ERROR_MASK 0x00200000UL /* Receive alignment + * error */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/***************************************************************************** +* +* Low-level driver macros and functions. The list below provides signatures +* to help the user use the macros. +* +* u32 XEmac_mReadReg(u32 BaseAddress, int RegOffset) +* void XEmac_mWriteReg(u32 BaseAddress, int RegOffset, u32 Mask) +* +* void XEmac_mSetControlReg(u32 BaseAddress, u32 Mask) +* void XEmac_mSetMacAddress(u32 BaseAddress, u8 *AddressPtr) +* +* void XEmac_mEnable(u32 BaseAddress) +* void XEmac_mDisable(u32 BaseAddress) +* +* u32 XEmac_mIsTxDone(u32 BaseAddress) +* u32 XEmac_mIsRxEmpty(u32 BaseAddress) +* +* void XEmac_SendFrame(u32 BaseAddress, u8 *FramePtr, int Size) +* int XEmac_RecvFrame(u32 BaseAddress, u8 *FramePtr) +* +*****************************************************************************/ + +/****************************************************************************/ +/** +* +* Read the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be read +* +* @return The 32-bit value of the register +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mReadReg(BaseAddress, RegOffset) \ + XIo_In32((BaseAddress) + (RegOffset)) + +/****************************************************************************/ +/** +* +* Write the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be written +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mWriteReg(BaseAddress, RegOffset, Data) \ + XIo_Out32((BaseAddress) + (RegOffset), (Data)) + +/****************************************************************************/ +/** +* +* Set the contents of the control register. Use the XEM_ECR_* constants +* defined above to create the bit-mask to be written to the register. +* +* @param BaseAddress is the base address of the device +* @param Mask is the 16-bit value to write to the control register +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mSetControlReg(BaseAddress, Mask) \ + XIo_Out32((BaseAddress) + XEM_ECR_OFFSET, (Mask)) + +/****************************************************************************/ +/** +* +* Set the station address of the EMAC device. +* +* @param BaseAddress is the base address of the device +* @param AddressPtr is a pointer to a 6-byte MAC address +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mSetMacAddress(BaseAddress, AddressPtr) \ +{ \ + u32 MacAddr; \ + \ + MacAddr = ((AddressPtr)[0] << 8) | (AddressPtr)[1]; \ + XIo_Out32((BaseAddress) + XEM_SAH_OFFSET, MacAddr); \ + \ + MacAddr = ((AddressPtr)[2] << 24) | ((AddressPtr)[3] << 16) | \ + ((AddressPtr)[4] << 8) | (AddressPtr)[5]; \ + \ + XIo_Out32((BaseAddress) + XEM_SAL_OFFSET, MacAddr); \ +} + +/****************************************************************************/ +/** +* +* Enable the transmitter and receiver. Preserve the contents of the control +* register. +* +* @param BaseAddress is the base address of the device +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mEnable(BaseAddress) \ +{ \ + u32 Control; \ + Control = XIo_In32((BaseAddress) + XEM_ECR_OFFSET); \ + Control &= ~(XEM_ECR_XMIT_RESET_MASK | XEM_ECR_RECV_RESET_MASK); \ + Control |= (XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK); \ + XIo_Out32((BaseAddress) + XEM_ECR_OFFSET, Control); \ +} + +/****************************************************************************/ +/** +* +* Disable the transmitter and receiver. Preserve the contents of the control +* register. +* +* @param BaseAddress is the base address of the device +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mDisable(BaseAddress) \ + XIo_Out32((BaseAddress) + XEM_ECR_OFFSET, \ + XIo_In32((BaseAddress) + XEM_ECR_OFFSET) & \ + ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK)) + +/****************************************************************************/ +/** +* +* Check to see if the transmission is complete. +* +* @param BaseAddress is the base address of the device +* +* @return TRUE if it is done, or FALSE if it is not. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mIsTxDone(BaseAddress) \ + (XIo_In32((BaseAddress) + XEM_ISR_OFFSET) & XEM_EIR_XMIT_DONE_MASK) + +/****************************************************************************/ +/** +* +* Check to see if the receive FIFO is empty. +* +* @param BaseAddress is the base address of the device +* +* @return TRUE if it is empty, or FALSE if it is not. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mIsRxEmpty(BaseAddress) \ + (!(XIo_In32((BaseAddress) + XEM_ISR_OFFSET) & XEM_EIR_RECV_DONE_MASK)) + +/****************************************************************************/ +/** +* +* Reset MII compliant PHY +* +* @param BaseAddress is the base address of the device +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XEmac_mPhyReset(BaseAddress) \ +{ \ + u32 Control; \ + Control = XIo_In32((BaseAddress) + XEM_ECR_OFFSET); \ + Control &= ~XEM_ECR_PHY_ENABLE_MASK; \ + XIo_Out32((BaseAddress) + XEM_ECR_OFFSET, Control); \ + Control |= XEM_ECR_PHY_ENABLE_MASK; \ + XIo_Out32((BaseAddress) + XEM_ECR_OFFSET, Control); \ +} + +/************************** Function Prototypes ******************************/ + +void XEmac_SendFrame(u32 BaseAddress, u8 * FramePtr, int Size); +int XEmac_RecvFrame(u32 BaseAddress, u8 * FramePtr); + +#endif /* end of protection macro */ diff --git a/board/xilinx/xilinx_enet/xemac_options.c b/board/xilinx/xilinx_enet/xemac_options.c new file mode 100644 index 0000000000..1f225f8f52 --- /dev/null +++ b/board/xilinx/xilinx_enet/xemac_options.c @@ -0,0 +1,318 @@ +/****************************************************************************** +* +* 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_options.c +* +* Functions in this file handle configuration of the XEmac driver. +* +*
+* 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
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xbasic_types.h" +#include "xemac_i.h" +#include "xio.h" + +/************************** Constant Definitions *****************************/ + +#define XEM_MAX_IFG 32 /* Maximum Interframe gap value */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/* + * A table of options and masks. This table maps the user-visible options with + * the control register masks. It is used in Set/GetOptions as an alternative + * to a series of if/else pairs. Note that the polled options does not have a + * corresponding entry in the control register, so it does not exist in the + * table. + */ +typedef struct { + u32 Option; + u32 Mask; +} OptionMap; + +static OptionMap OptionsTable[] = { + {XEM_UNICAST_OPTION, XEM_ECR_UNICAST_ENABLE_MASK}, + {XEM_BROADCAST_OPTION, XEM_ECR_BROAD_ENABLE_MASK}, + {XEM_PROMISC_OPTION, XEM_ECR_PROMISC_ENABLE_MASK}, + {XEM_FDUPLEX_OPTION, XEM_ECR_FULL_DUPLEX_MASK}, + {XEM_LOOPBACK_OPTION, XEM_ECR_LOOPBACK_MASK}, + {XEM_MULTICAST_OPTION, XEM_ECR_MULTI_ENABLE_MASK}, + {XEM_FLOW_CONTROL_OPTION, XEM_ECR_PAUSE_FRAME_MASK}, + {XEM_INSERT_PAD_OPTION, XEM_ECR_XMIT_PAD_ENABLE_MASK}, + {XEM_INSERT_FCS_OPTION, XEM_ECR_XMIT_FCS_ENABLE_MASK}, + {XEM_INSERT_ADDR_OPTION, XEM_ECR_XMIT_ADDR_INSERT_MASK}, + {XEM_OVWRT_ADDR_OPTION, XEM_ECR_XMIT_ADDR_OVWRT_MASK}, + {XEM_STRIP_PAD_FCS_OPTION, XEM_ECR_RECV_STRIP_ENABLE_MASK} +}; + +#define XEM_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(OptionMap)) + +/*****************************************************************************/ +/** +* +* Set Ethernet driver/device options. The device must be stopped before +* calling this function. The options are contained within a bit-mask with each +* bit representing an option (i.e., you can OR the options together). A one (1) +* in the bit-mask turns an option on, and a zero (0) turns the option off. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param OptionsFlag is a bit-mask representing the Ethernet options to turn on +* or off. See xemac.h for a description of the available options. +* +* @return +* +* - XST_SUCCESS if the options were set successfully +* - XST_DEVICE_IS_STARTED if the device has not yet been stopped +* +* @note +* +* This function is not thread-safe and makes use of internal resources that are +* shared between the Start, Stop, and SetOptions functions, so if one task +* might be setting device options while another is trying to start the device, +* protection of this shared data (typically using a semaphore) is required. +* +******************************************************************************/ +XStatus +XEmac_SetOptions(XEmac * InstancePtr, u32 OptionsFlag) +{ + u32 ControlReg; + int Index; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + ControlReg = XIo_In32(InstancePtr->BaseAddress + XEM_ECR_OFFSET); + + /* + * Loop through the options table, turning the option on or off + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0; Index < XEM_NUM_OPTIONS; Index++) { + if (OptionsFlag & OptionsTable[Index].Option) { + ControlReg |= OptionsTable[Index].Mask; /* turn it on */ + } else { + ControlReg &= ~OptionsTable[Index].Mask; /* turn it off */ + } + } + + /* + * TODO: need to validate addr-overwrite only if addr-insert? + */ + + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XIo_Out32(InstancePtr->BaseAddress + XEM_ECR_OFFSET, ControlReg); + + /* + * Check the polled option + */ + if (OptionsFlag & XEM_POLLED_OPTION) { + InstancePtr->IsPolled = TRUE; + } else { + InstancePtr->IsPolled = FALSE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Get Ethernet driver/device options. The 32-bit value returned is a bit-mask +* representing the options. A one (1) in the bit-mask means the option is on, +* and a zero (0) means the option is off. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* +* @return +* +* The 32-bit value of the Ethernet options. The value is a bit-mask +* representing all options that are currently enabled. See xemac.h for a +* description of the available options. +* +* @note +* +* None. +* +******************************************************************************/ +u32 +XEmac_GetOptions(XEmac * InstancePtr) +{ + u32 OptionsFlag = 0; + u32 ControlReg; + int Index; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* + * Get the control register to determine which options are currently set. + */ + ControlReg = XIo_In32(InstancePtr->BaseAddress + XEM_ECR_OFFSET); + + /* + * Loop through the options table to determine which options are set + */ + for (Index = 0; Index < XEM_NUM_OPTIONS; Index++) { + if (ControlReg & OptionsTable[Index].Mask) { + OptionsFlag |= OptionsTable[Index].Option; + } + } + + if (InstancePtr->IsPolled) { + OptionsFlag |= XEM_POLLED_OPTION; + } + + return OptionsFlag; +} + +/*****************************************************************************/ +/** +* +* Set the Interframe Gap (IFG), which is the time the MAC delays between +* transmitting frames. There are two parts required. The total interframe gap +* is the total of the two parts. The values provided for the Part1 and Part2 +* parameters are multiplied by 4 to obtain the bit-time interval. The first +* part should be the first 2/3 of the total interframe gap. The MAC will reset +* the interframe gap timer if carrier sense becomes true during the period +* defined by interframe gap Part1. Part1 may be shorter than 2/3 the total and +* can be as small as zero. The second part should be the last 1/3 of the total +* interframe gap, but can be as large as the total interframe gap. The MAC +* will not reset the interframe gap timer if carrier sense becomes true during +* the period defined by interframe gap Part2. +* +* The device must be stopped before setting the interframe gap. +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param Part1 is the interframe gap part 1 (which will be multiplied by 4 to +* get the bit-time interval). +* @param Part2 is the interframe gap part 2 (which will be multiplied by 4 to +* get the bit-time interval). +* +* @return +* +* - XST_SUCCESS if the interframe gap was set successfully +* - XST_DEVICE_IS_STARTED if the device has not been stopped +* +* @note +* +* None. +* +******************************************************************************/ +XStatus +XEmac_SetInterframeGap(XEmac * InstancePtr, u8 Part1, u8 Part2) +{ + u32 Ifg; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(Part1 < XEM_MAX_IFG); + XASSERT_NONVOID(Part2 < XEM_MAX_IFG); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* + * Be sure device has been stopped + */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + Ifg = Part1 << XEM_IFGP_PART1_SHIFT; + Ifg |= (Part2 << XEM_IFGP_PART2_SHIFT); + XIo_Out32(InstancePtr->BaseAddress + XEM_IFGP_OFFSET, Ifg); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Get the interframe gap, parts 1 and 2. See the description of interframe gap +* above in XEmac_SetInterframeGap(). +* +* @param InstancePtr is a pointer to the XEmac instance to be worked on. +* @param Part1Ptr is a pointer to an 8-bit buffer into which the interframe gap +* part 1 value will be copied. +* @param Part2Ptr is a pointer to an 8-bit buffer into which the interframe gap +* part 2 value will be copied. +* +* @return +* +* None. The values of the interframe gap parts are copied into the +* output parameters. +* +******************************************************************************/ +void +XEmac_GetInterframeGap(XEmac * InstancePtr, u8 * Part1Ptr, u8 * Part2Ptr) +{ + u32 Ifg; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(Part1Ptr != NULL); + XASSERT_VOID(Part2Ptr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + Ifg = XIo_In32(InstancePtr->BaseAddress + XEM_IFGP_OFFSET); + *Part1Ptr = (Ifg & XEM_IFGP_PART1_MASK) >> XEM_IFGP_PART1_SHIFT; + *Part2Ptr = (Ifg & XEM_IFGP_PART2_MASK) >> XEM_IFGP_PART2_SHIFT; +} diff --git a/board/xilinx/xilinx_enet/xemac_polled.c b/board/xilinx/xilinx_enet/xemac_polled.c new file mode 100644 index 0000000000..23768bca79 --- /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. +* +*
+* 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
+* 
+* +******************************************************************************/ + +/***************************** 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; +} -- cgit v1.2.1