summaryrefslogtreecommitdiff
path: root/board/xilinx/xilinx_enet
diff options
context:
space:
mode:
authorwdenk <wdenk>2004-02-23 23:54:43 +0000
committerwdenk <wdenk>2004-02-23 23:54:43 +0000
commit028ab6b598b628326116acd88e0f35aa9f526d12 (patch)
tree0d54315bd92d713a405004b6e36fca8d2b7c53e3 /board/xilinx/xilinx_enet
parent63e73c9a8ed5b32d9c4067ffaad953e9a8fe8f0a (diff)
downloadu-boot-imx-028ab6b598b628326116acd88e0f35aa9f526d12.zip
u-boot-imx-028ab6b598b628326116acd88e0f35aa9f526d12.tar.gz
u-boot-imx-028ab6b598b628326116acd88e0f35aa9f526d12.tar.bz2
* 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
Diffstat (limited to 'board/xilinx/xilinx_enet')
-rw-r--r--board/xilinx/xilinx_enet/emac_adapter.c153
-rw-r--r--board/xilinx/xilinx_enet/xemac.c844
-rw-r--r--board/xilinx/xilinx_enet/xemac.h673
-rw-r--r--board/xilinx/xilinx_enet/xemac_g.c60
-rw-r--r--board/xilinx/xilinx_enet/xemac_i.h207
-rw-r--r--board/xilinx/xilinx_enet/xemac_intr.c402
-rw-r--r--board/xilinx/xilinx_enet/xemac_intr_dma.c1344
-rw-r--r--board/xilinx/xilinx_enet/xemac_l.h462
-rw-r--r--board/xilinx/xilinx_enet/xemac_options.c318
-rw-r--r--board/xilinx/xilinx_enet/xemac_polled.c482
10 files changed, 4945 insertions, 0 deletions
diff --git a/board/xilinx/xilinx_enet/emac_adapter.c b/board/xilinx/xilinx_enet/emac_adapter.c
new file mode 100644
index 0000000..a3c37ba
--- /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 <common.h>
+#include <net.h>
+#include <configs/ml300.h>
+#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 0000000..48b4ede
--- /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.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a rpm 07/31/01 First release
+* 1.00b rpm 02/20/02 Repartitioned files and functions
+* 1.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.
+* </pre>
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+
+#include "xbasic_types.h"
+#include "xemac_i.h"
+#include "xio.h"
+#include "xipif_v1_23_b.h" /* Uses v1.23b of the IPIF */
+
+/************************** Constant Definitions *****************************/
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** 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 0000000..ed704bf
--- /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.
+*
+* <b>Driver Description</b>
+*
+* 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
+*
+* <b>PHY Communication</b>
+*
+* 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.
+*
+* <b>Asynchronous Callbacks</b>
+*
+* 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.
+*
+* <b>Interrupts</b>
+*
+* 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.
+*
+* <b>Interrupt Frequency</b>
+*
+* 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.
+*
+* <b>Device Reset</b>
+*
+* 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.
+*
+* <b>Device Configuration</b>
+*
+* 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):
+* <pre>
+* XEmac_Config *ConfigPtr;
+*
+* ConfigPtr = XEmac_LookupConfig(DeviceId);
+* ConfigPtr->IpIfDmaConfig = XEM_CFG_SIMPLE_DMA;
+* </pre>
+*
+* <b>Simple DMA</b>
+*
+* 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:
+* <pre>
+* XEmac_Config *ConfigPtr;
+*
+* ConfigPtr = XEmac_LookupConfig(DeviceId);
+* ConfigPtr->IpIfDmaConfig = XEM_CFG_NO_DMA;
+* </pre>
+*
+* <b>Asserts</b>
+*
+* 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.
+*
+* <b>Building the driver</b>
+*
+* 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.
+* <br><br>
+* 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.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a rpm 07/31/01 First release
+* 1.00b rpm 02/20/02 Repartitioned files and functions
+* 1.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.
+* </pre>
+*
+******************************************************************************/
+
+#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)
+ * @{
+ */
+/**
+ * <pre>
+ * 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)
+ * </pre>
+ */
+#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 0000000..9340f91
--- /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 0000000..9c160f3
--- /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.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a rpm 07/31/01 First release
+* 1.00b rpm 02/20/02 Repartitioned files and functions
+* 1.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
+* </pre>
+*
+******************************************************************************/
+
+#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 0000000..b9a2621
--- /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.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a rpm 07/31/01 First release
+* 1.00b rpm 02/20/02 Repartitioned files and functions
+* 1.00c rpm 12/05/02 New version includes support for simple DMA
+* 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.
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+
+#include "xbasic_types.h"
+#include "xemac_i.h"
+#include "xio.h"
+#include "xipif_v1_23_b.h" /* Uses v1.23b of the IPIF */
+
+/************************** Constant Definitions *****************************/
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Variable Definitions *****************************/
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+/**
+*
+* 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 0000000..567abb4
--- /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.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- ---------------------------------------------------------
+* 1.00a rpm 07/31/01 First release
+* 1.00b rpm 02/20/02 Repartitioned files and functions
+* 1.00c rpm 12/05/02 New version includes support for simple DMA and the delay
+* argument to SgSend
+* 1.00c rpm 02/03/03 The XST_DMA_SG_COUNT_EXCEEDED return code was removed
+* from SetPktThreshold in the internal DMA driver. Also
+* avoided compiler warnings by initializing Result in the
+* interrupt service routines.
+* 1.00c rpm 03/26/03 Fixed a problem in the interrupt service routines where
+* the interrupt status was toggled clear after a call to
+* ErrorHandler, but if ErrorHandler reset the device the
+* toggle actually asserted the interrupt because the
+* reset had cleared it.
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+
+#include "xbasic_types.h"
+#include "xemac_i.h"
+#include "xio.h"
+#include "xbuf_descriptor.h"
+#include "xdma_channel.h"
+#include "xipif_v1_23_b.h" /* Uses v1.23b of the IPIF */
+
+/************************** Constant Definitions *****************************/
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Variable Definitions *****************************/
+
+/************************** Function Prototypes ******************************/
+
+static void HandleDmaRecvIntr(XEmac * InstancePtr);
+static void HandleDmaSendIntr(XEmac * InstancePtr);
+static void HandleEmacDmaIntr(XEmac * InstancePtr);
+
+/*****************************************************************************/
+/**
+*
+* Send an Ethernet frame using scatter-gather DMA. The caller attaches the
+* frame to one or more buffer descriptors, then calls this function once for
+* each descriptor. The caller is responsible for allocating and setting up the
+* descriptor. An entire Ethernet frame may or may not be contained within one
+* descriptor. This function simply inserts the descriptor into the scatter-
+* gather engine's transmit list. The caller is responsible for providing mutual
+* exclusion to guarantee that a frame is contiguous in the transmit list. The
+* buffer attached to the descriptor must be word-aligned.
+*
+* The driver updates the descriptor with the device control register before
+* being inserted into the transmit list. If this is the last descriptor in
+* the frame, the inserts are committed, which means the descriptors for this
+* frame are now available for transmission.
+*
+* It is assumed that the upper layer software supplies a correctly formatted
+* Ethernet frame, including the destination and source addresses, the
+* type/length field, and the data field. It is also assumed that upper layer
+* software does not append FCS at the end of the frame.
+*
+* The buffer attached to the descriptor must be word-aligned on the front end.
+*
+* This call is non-blocking. Notification of error or successful transmission
+* is done asynchronously through the send or error callback function.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param BdPtr is the address of a descriptor to be inserted into the transmit
+* ring.
+* @param Delay indicates whether to start the scatter-gather DMA channel
+* immediately, or whether to wait. This allows the user to build up a
+* list of more than one descriptor before starting the transmission of
+* the packets, which allows the application to keep up with DMA and have
+* a constant stream of frames being transmitted. Use XEM_SGDMA_NODELAY or
+* XEM_SGDMA_DELAY, defined in xemac.h, as the value of this argument. If
+* the user chooses to delay and build a list, the user must call this
+* function with the XEM_SGDMA_NODELAY option or call XEmac_Start() to
+* kick off the tranmissions.
+*
+* @return
+*
+* - XST_SUCCESS if the buffer was successfull sent
+* - XST_DEVICE_IS_STOPPED if the Ethernet MAC has not been started yet
+* - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
+* - XST_DMA_SG_LIST_FULL if the descriptor list for the DMA channel is full
+* - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
+* the list because a locked descriptor exists at the insert point
+* - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
+* list, the DMA channel believes there are no new descriptors to commit. If
+* this is ever encountered, there is likely a thread mutual exclusion problem
+* on transmit.
+*
+* @note
+*
+* This function is not thread-safe. The user must provide mutually exclusive
+* access to this function if there are to be multiple threads that can call it.
+*
+* @internal
+*
+* A status that should never be returned from this function, although
+* the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
+* requires a list to be created, and this function requires the device to be
+* started.
+*
+******************************************************************************/
+XStatus
+XEmac_SgSend(XEmac * InstancePtr, XBufDescriptor * BdPtr, int Delay)
+{
+ XStatus Result;
+ u32 BdControl;
+
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(BdPtr != NULL);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ /*
+ * Be sure the device is configured for scatter-gather DMA, then be sure
+ * it is started.
+ */
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ /*
+ * Set some descriptor control word defaults (source address increment
+ * and local destination address) and the destination address
+ * (the FIFO). These are the same for every transmit descriptor.
+ */
+ BdControl = XBufDescriptor_GetControl(BdPtr);
+ XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_SEND_BD_MASK);
+
+ XBufDescriptor_SetDestAddress(BdPtr,
+ InstancePtr->BaseAddress +
+ XEM_PFIFO_TXDATA_OFFSET);
+
+ /*
+ * Put the descriptor in the send list. The DMA component accesses data
+ * here that can also be modified in interrupt context, so a critical
+ * section is required.
+ */
+ XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);
+
+ Result = XDmaChannel_PutDescriptor(&InstancePtr->SendChannel, BdPtr);
+ if (Result != XST_SUCCESS) {
+ XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
+ return Result;
+ }
+
+ /*
+ * If this is the last buffer in the frame, commit the inserts and start
+ * the DMA engine if necessary
+ */
+ if (XBufDescriptor_IsLastControl(BdPtr)) {
+ Result = XDmaChannel_CommitPuts(&InstancePtr->SendChannel);
+ if (Result != XST_SUCCESS) {
+ XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
+ return Result;
+ }
+
+ if (Delay == XEM_SGDMA_NODELAY) {
+ /*
+ * Start the DMA channel. Ignore the return status since we know the
+ * list exists and has at least one entry and we don't care if the
+ * channel is already started. The DMA component accesses data here
+ * that can be modified at interrupt or task levels, so a critical
+ * section is required.
+ */
+ (void) XDmaChannel_SgStart(&InstancePtr->SendChannel);
+ }
+ }
+
+ XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
+
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* Add a descriptor, with an attached empty buffer, into the receive descriptor
+* list. The buffer attached to the descriptor must be word-aligned. This is
+* used by the upper layer software during initialization when first setting up
+* the receive descriptors, and also during reception of frames to replace
+* filled buffers with empty buffers. This function can be called when the
+* device is started or stopped. Note that it does start the scatter-gather DMA
+* engine. Although this is not necessary during initialization, it is not a
+* problem during initialization because the MAC receiver is not yet started.
+*
+* The buffer attached to the descriptor must be word-aligned on both the front
+* end and the back end.
+*
+* Notification of received frames are done asynchronously through the receive
+* callback function.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param BdPtr is a pointer to the buffer descriptor that will be added to the
+* descriptor list.
+*
+* @return
+*
+* - XST_SUCCESS if a descriptor was successfully returned to the driver
+* - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
+* - XST_DMA_SG_LIST_FULL if the receive descriptor list is full
+* - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
+* the list because a locked descriptor exists at the insert point.
+* - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
+* list, the DMA channel believes there are no new descriptors to commit.
+*
+* @internal
+*
+* A status that should never be returned from this function, although
+* the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
+* requires a list to be created, and this function requires the device to be
+* started.
+*
+******************************************************************************/
+XStatus
+XEmac_SgRecv(XEmac * InstancePtr, XBufDescriptor * BdPtr)
+{
+ XStatus Result;
+ u32 BdControl;
+
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(BdPtr != NULL);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ /*
+ * Be sure the device is configured for scatter-gather DMA
+ */
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ /*
+ * Set some descriptor control word defaults (destination address increment
+ * and local source address) and the source address (the FIFO). These are
+ * the same for every receive descriptor.
+ */
+ BdControl = XBufDescriptor_GetControl(BdPtr);
+ XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_RECV_BD_MASK);
+ XBufDescriptor_SetSrcAddress(BdPtr,
+ InstancePtr->BaseAddress +
+ XEM_PFIFO_RXDATA_OFFSET);
+
+ /*
+ * Put the descriptor into the channel's descriptor list and commit.
+ * Although this function is likely called within interrupt context, there
+ * is the possibility that the upper layer software queues it to a task.
+ * In this case, a critical section is needed here to protect shared data
+ * in the DMA component.
+ */
+ XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);
+
+ Result = XDmaChannel_PutDescriptor(&InstancePtr->RecvChannel, BdPtr);
+ if (Result != XST_SUCCESS) {
+ XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
+ return Result;
+ }
+
+ Result = XDmaChannel_CommitPuts(&InstancePtr->RecvChannel);
+ if (Result != XST_SUCCESS) {
+ XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
+ return Result;
+ }
+
+ /*
+ * Start the DMA channel. Ignore the return status since we know the list
+ * exists and has at least one entry and we don't care if the channel is
+ * already started. The DMA component accesses data here that can be
+ * modified at interrupt or task levels, so a critical section is required.
+ */
+ (void) XDmaChannel_SgStart(&InstancePtr->RecvChannel);
+
+ XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
+
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* The interrupt handler for the Ethernet driver when configured with scatter-
+* gather DMA.
+*
+* Get the interrupt status from the IpIf to determine the source of the
+* interrupt. The source can be: MAC, Recv Packet FIFO, Send Packet FIFO, Recv
+* DMA channel, or Send DMA channel. The packet FIFOs only interrupt during
+* "deadlock" conditions.
+*
+* @param InstancePtr is a pointer to the XEmac instance that just interrupted.
+*
+* @return
+*
+* None.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+void
+XEmac_IntrHandlerDma(void *InstancePtr)
+{
+ u32 IntrStatus;
+ XEmac *EmacPtr = (XEmac *) InstancePtr;
+
+ EmacPtr->Stats.TotalIntrs++;
+
+ /*
+ * Get the interrupt status from the IPIF. There is no clearing of
+ * interrupts in the IPIF. Interrupts must be cleared at the source.
+ */
+ IntrStatus = XIIF_V123B_READ_DIPR(EmacPtr->BaseAddress);
+
+ /*
+ * See which type of interrupt is being requested, and service it
+ */
+ if (IntrStatus & XEM_IPIF_RECV_DMA_MASK) { /* Receive DMA interrupt */
+ EmacPtr->Stats.RecvInterrupts++;
+ HandleDmaRecvIntr(EmacPtr);
+ }
+
+ if (IntrStatus & XEM_IPIF_SEND_DMA_MASK) { /* Send DMA interrupt */
+ EmacPtr->Stats.XmitInterrupts++;
+ HandleDmaSendIntr(EmacPtr);
+ }
+
+ if (IntrStatus & XEM_IPIF_EMAC_MASK) { /* MAC interrupt */
+ EmacPtr->Stats.EmacInterrupts++;
+ HandleEmacDmaIntr(EmacPtr);
+ }
+
+ if (IntrStatus & XEM_IPIF_RECV_FIFO_MASK) { /* Receive FIFO interrupt */
+ EmacPtr->Stats.RecvInterrupts++;
+ XEmac_CheckFifoRecvError(EmacPtr);
+ }
+
+ if (IntrStatus & XEM_IPIF_SEND_FIFO_MASK) { /* Send FIFO interrupt */
+ EmacPtr->Stats.XmitInterrupts++;
+ XEmac_CheckFifoSendError(EmacPtr);
+ }
+
+ if (IntrStatus & XIIF_V123B_ERROR_MASK) {
+ /*
+ * An error occurred internal to the IPIF. This is more of a debug and
+ * integration issue rather than a production error. Don't do anything
+ * other than clear it, which provides a spot for software to trap
+ * on the interrupt and begin debugging.
+ */
+ XIIF_V123B_WRITE_DISR(EmacPtr->BaseAddress,
+ XIIF_V123B_ERROR_MASK);
+ }
+}
+
+/*****************************************************************************/
+/**
+*
+* Set the packet count threshold for this device. The device must be stopped
+* before setting the threshold. The packet count threshold is used for interrupt
+* coalescing, which reduces the frequency of interrupts from the device to the
+* processor. In this case, the scatter-gather DMA engine only interrupts when
+* the packet count threshold is reached, instead of interrupting for each packet.
+* A packet is a generic term used by the scatter-gather DMA engine, and is
+* equivalent to an Ethernet frame in our case.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param Direction indicates the channel, send or receive, from which the
+* threshold register is read.
+* @param Threshold is the value of the packet threshold count used during
+* interrupt coalescing. A value of 0 disables the use of packet threshold
+* by the hardware.
+*
+* @return
+*
+* - XST_SUCCESS if the threshold was successfully set
+* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
+* - XST_DEVICE_IS_STARTED if the device has not been stopped
+* - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
+* asserts would also catch this error.
+*
+* @note
+*
+* The packet threshold could be set to larger than the number of descriptors
+* allocated to the DMA channel. In this case, the wait bound will take over
+* and always indicate data arrival. There was a check in this function that
+* returned an error if the treshold was larger than the number of descriptors,
+* but that was removed because users would then have to set the threshold
+* only after they set descriptor space, which is an order dependency that
+* caused confustion.
+*
+******************************************************************************/
+XStatus
+XEmac_SetPktThreshold(XEmac * InstancePtr, u32 Direction, u8 Threshold)
+{
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ /*
+ * Be sure device is configured for scatter-gather DMA and has been stopped
+ */
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) {
+ return XST_DEVICE_IS_STARTED;
+ }
+
+ /*
+ * Based on the direction, set the packet threshold in the
+ * corresponding DMA channel component. Default to the receive
+ * channel threshold register (if an invalid Direction is passed).
+ */
+ switch (Direction) {
+ case XEM_SEND:
+ return XDmaChannel_SetPktThreshold(&InstancePtr->SendChannel,
+ Threshold);
+
+ case XEM_RECV:
+ return XDmaChannel_SetPktThreshold(&InstancePtr->RecvChannel,
+ Threshold);
+
+ default:
+ return XST_INVALID_PARAM;
+ }
+}
+
+/*****************************************************************************/
+/**
+*
+* Get the value of the packet count threshold for this driver/device. The packet
+* count threshold is used for interrupt coalescing, which reduces the frequency
+* of interrupts from the device to the processor. In this case, the
+* scatter-gather DMA engine only interrupts when the packet count threshold is
+* reached, instead of interrupting for each packet. A packet is a generic term
+* used by the scatter-gather DMA engine, and is equivalent to an Ethernet frame
+* in our case.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param Direction indicates the channel, send or receive, from which the
+* threshold register is read.
+* @param ThreshPtr is a pointer to the byte into which the current value of the
+* packet threshold register will be copied. An output parameter. A value
+* of 0 indicates the use of packet threshold by the hardware is disabled.
+*
+* @return
+*
+* - XST_SUCCESS if the packet threshold was retrieved successfully
+* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
+* - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
+* asserts would also catch this error.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+XStatus
+XEmac_GetPktThreshold(XEmac * InstancePtr, u32 Direction, u8 * ThreshPtr)
+{
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
+ XASSERT_NONVOID(ThreshPtr != NULL);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ /*
+ * Based on the direction, return the packet threshold set in the
+ * corresponding DMA channel component. Default to the value in
+ * the receive channel threshold register (if an invalid Direction
+ * is passed).
+ */
+ switch (Direction) {
+ case XEM_SEND:
+ *ThreshPtr =
+ XDmaChannel_GetPktThreshold(&InstancePtr->SendChannel);
+ break;
+
+ case XEM_RECV:
+ *ThreshPtr =
+ XDmaChannel_GetPktThreshold(&InstancePtr->RecvChannel);
+ break;
+
+ default:
+ return XST_INVALID_PARAM;
+ }
+
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* Set the packet wait bound timer for this driver/device. The device must be
+* stopped before setting the timer value. The packet wait bound is used during
+* interrupt coalescing to trigger an interrupt when not enough packets have been
+* received to reach the packet count threshold. A packet is a generic term used
+* by the scatter-gather DMA engine, and is equivalent to an Ethernet frame in
+* our case. The timer is in milliseconds.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param Direction indicates the channel, send or receive, from which the
+* threshold register is read.
+* @param TimerValue is the value of the packet wait bound used during interrupt
+* coalescing. It is in milliseconds in the range 0 - 1023. A value of 0
+* disables the packet wait bound timer.
+*
+* @return
+*
+* - XST_SUCCESS if the packet wait bound was set successfully
+* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
+* - XST_DEVICE_IS_STARTED if the device has not been stopped
+* - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
+* asserts would also catch this error.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+XStatus
+XEmac_SetPktWaitBound(XEmac * InstancePtr, u32 Direction, u32 TimerValue)
+{
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
+ XASSERT_NONVOID(TimerValue <= XEM_SGDMA_MAX_WAITBOUND);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ /*
+ * Be sure device is configured for scatter-gather DMA and has been stopped
+ */
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) {
+ return XST_DEVICE_IS_STARTED;
+ }
+
+ /*
+ * Based on the direction, set the packet wait bound in the
+ * corresponding DMA channel component. Default to the receive
+ * channel wait bound register (if an invalid Direction is passed).
+ */
+ switch (Direction) {
+ case XEM_SEND:
+ XDmaChannel_SetPktWaitBound(&InstancePtr->SendChannel,
+ TimerValue);
+ break;
+
+ case XEM_RECV:
+ XDmaChannel_SetPktWaitBound(&InstancePtr->RecvChannel,
+ TimerValue);
+ break;
+
+ default:
+ return XST_INVALID_PARAM;
+ }
+
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* Get the packet wait bound timer for this driver/device. The packet wait bound
+* is used during interrupt coalescing to trigger an interrupt when not enough
+* packets have been received to reach the packet count threshold. A packet is a
+* generic term used by the scatter-gather DMA engine, and is equivalent to an
+* Ethernet frame in our case. The timer is in milliseconds.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param Direction indicates the channel, send or receive, from which the
+* threshold register is read.
+* @param WaitPtr is a pointer to the byte into which the current value of the
+* packet wait bound register will be copied. An output parameter. Units
+* are in milliseconds in the range 0 - 1023. A value of 0 indicates the
+* packet wait bound timer is disabled.
+*
+* @return
+*
+* - XST_SUCCESS if the packet wait bound was retrieved successfully
+* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
+* - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
+* asserts would also catch this error.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+XStatus
+XEmac_GetPktWaitBound(XEmac * InstancePtr, u32 Direction, u32 * WaitPtr)
+{
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
+ XASSERT_NONVOID(WaitPtr != NULL);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ /*
+ * Based on the direction, return the packet wait bound set in the
+ * corresponding DMA channel component. Default to the value in
+ * the receive channel wait bound register (if an invalid Direction
+ * is passed).
+ */
+ switch (Direction) {
+ case XEM_SEND:
+ *WaitPtr =
+ XDmaChannel_GetPktWaitBound(&InstancePtr->SendChannel);
+ break;
+
+ case XEM_RECV:
+ *WaitPtr =
+ XDmaChannel_GetPktWaitBound(&InstancePtr->RecvChannel);
+ break;
+
+ default:
+ return XST_INVALID_PARAM;
+ }
+
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* Give the driver the memory space to be used for the scatter-gather DMA
+* receive descriptor list. This function should only be called once, during
+* initialization of the Ethernet driver. The memory space must be big enough
+* to hold some number of descriptors, depending on the needs of the system.
+* The xemac.h file defines minimum and default numbers of descriptors
+* which can be used to allocate this memory space.
+*
+* The memory space must be word-aligned. An assert will occur if asserts are
+* turned on and the memory is not word-aligned.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param MemoryPtr is a pointer to the word-aligned memory.
+* @param ByteCount is the length, in bytes, of the memory space.
+*
+* @return
+*
+* - XST_SUCCESS if the space was initialized successfully
+* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
+* - XST_DMA_SG_LIST_EXISTS if this list space has already been created
+*
+* @note
+*
+* If the device is configured for scatter-gather DMA, this function must be
+* called AFTER the XEmac_Initialize() function because the DMA channel
+* components must be initialized before the memory space is set.
+*
+******************************************************************************/
+XStatus
+XEmac_SetSgRecvSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
+{
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(MemoryPtr != NULL);
+ XASSERT_NONVOID(ByteCount != 0);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ return XDmaChannel_CreateSgList(&InstancePtr->RecvChannel, MemoryPtr,
+ ByteCount);
+}
+
+/*****************************************************************************/
+/**
+*
+* Give the driver the memory space to be used for the scatter-gather DMA
+* transmit descriptor list. This function should only be called once, during
+* initialization of the Ethernet driver. The memory space must be big enough
+* to hold some number of descriptors, depending on the needs of the system.
+* The xemac.h file defines minimum and default numbers of descriptors
+* which can be used to allocate this memory space.
+*
+* The memory space must be word-aligned. An assert will occur if asserts are
+* turned on and the memory is not word-aligned.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param MemoryPtr is a pointer to the word-aligned memory.
+* @param ByteCount is the length, in bytes, of the memory space.
+*
+* @return
+*
+* - XST_SUCCESS if the space was initialized successfully
+* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
+* - XST_DMA_SG_LIST_EXISTS if this list space has already been created
+*
+* @note
+*
+* If the device is configured for scatter-gather DMA, this function must be
+* called AFTER the XEmac_Initialize() function because the DMA channel
+* components must be initialized before the memory space is set.
+*
+******************************************************************************/
+XStatus
+XEmac_SetSgSendSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
+{
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(MemoryPtr != NULL);
+ XASSERT_NONVOID(ByteCount != 0);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ if (!XEmac_mIsSgDma(InstancePtr)) {
+ return XST_NOT_SGDMA;
+ }
+
+ return XDmaChannel_CreateSgList(&InstancePtr->SendChannel, MemoryPtr,
+ ByteCount);
+}
+
+/*****************************************************************************/
+/**
+*
+* Set the callback function for handling received frames in scatter-gather DMA
+* mode. The upper layer software should call this function during
+* initialization. The callback is called once per frame received. The head of
+* a descriptor list is passed in along with the number of descriptors in the
+* list. Before leaving the callback, the upper layer software should attach a
+* new buffer to each descriptor in the list.
+*
+* The callback is invoked by the driver within interrupt context, so it needs
+* to do its job quickly. Sending the received frame up the protocol stack
+* should be done at task-level. If there are other potentially slow operations
+* within the callback, these too should be done at task-level.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param CallBackRef is a reference pointer to be passed back to the adapter in
+* the callback. This helps the adapter correlate the callback to a
+* particular driver.
+* @param FuncPtr is the pointer to the callback function.
+*
+* @return
+*
+* None.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+void
+XEmac_SetSgRecvHandler(XEmac * InstancePtr, void *CallBackRef,
+ XEmac_SgHandler FuncPtr)
+{
+ /*
+ * Asserted IsDmaSg here instead of run-time check because there is really
+ * no ill-effects of setting these when not configured for scatter-gather.
+ */
+ XASSERT_VOID(InstancePtr != NULL);
+ XASSERT_VOID(FuncPtr != NULL);
+ XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
+ XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ InstancePtr->SgRecvHandler = FuncPtr;
+ InstancePtr->SgRecvRef = CallBackRef;
+}
+
+/*****************************************************************************/
+/**
+*
+* Set the callback function for handling confirmation of transmitted frames in
+* scatter-gather DMA mode. The upper layer software should call this function
+* during initialization. The callback is called once per frame sent. The head
+* of a descriptor list is passed in along with the number of descriptors in
+* the list. The callback is responsible for freeing buffers attached to these
+* descriptors.
+*
+* The callback is invoked by the driver within interrupt context, so it needs
+* to do its job quickly. If there are potentially slow operations within the
+* callback, these should be done at task-level.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param CallBackRef is a reference pointer to be passed back to the adapter in
+* the callback. This helps the adapter correlate the callback to a
+* particular driver.
+* @param FuncPtr is the pointer to the callback function.
+*
+* @return
+*
+* None.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+void
+XEmac_SetSgSendHandler(XEmac * InstancePtr, void *CallBackRef,
+ XEmac_SgHandler FuncPtr)
+{
+ /*
+ * Asserted IsDmaSg here instead of run-time check because there is really
+ * no ill-effects of setting these when not configured for scatter-gather.
+ */
+ XASSERT_VOID(InstancePtr != NULL);
+ XASSERT_VOID(FuncPtr != NULL);
+ XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
+ XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ InstancePtr->SgSendHandler = FuncPtr;
+ InstancePtr->SgSendRef = CallBackRef;
+}
+
+/*****************************************************************************/
+/*
+*
+* Handle an interrupt from the DMA receive channel. DMA interrupts are:
+*
+* - DMA error. DMA encountered a bus error or timeout. This is a fatal error
+* that requires reset of the channel. The driver calls the error handler
+* of the upper layer software with an error code indicating the device should
+* be reset.
+* - Packet count threshold reached. For scatter-gather operations, indicates
+* the threshold for the number of packets not serviced by software has been
+* reached. The driver behaves as follows:
+* - Get the value of the packet counter, which tells us how many packets
+* are ready to be serviced
+* - For each packet
+* - For each descriptor, remove it from the scatter-gather list
+* - Check for the last descriptor in the frame, and if set
+* - Bump frame statistics
+* - Call the scatter-gather receive callback function
+* - Decrement the packet counter by one
+* Note that there are no receive errors reported in the status word of
+* the buffer descriptor. If receive errors occur, the MAC drops the
+* packet, and we only find out about the errors through various error
+* count registers.
+* - Packet wait bound reached. For scatter-gather, indicates the time to wait
+* for the next packet has expired. The driver follows the same logic as when
+* the packet count threshold interrupt is received.
+* - Scatter-gather end acknowledge. Hardware has reached the end of the
+* descriptor list. The driver follows the same logic as when the packet count
+* threshold interrupt is received. In addition, the driver restarts the DMA
+* scatter-gather channel in case there are newly inserted descriptors.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+*
+* @return
+*
+* Although the function returns void, there are asynchronous errors that can
+* be generated (by calling the ErrorHandler) from this function. These are:
+* - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from the
+* DMA channel, but there was not one ready for software.
+* - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a fatal
+* error that requires reset.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+static void
+HandleDmaRecvIntr(XEmac * InstancePtr)
+{
+ u32 IntrStatus;
+
+ /*
+ * Read the interrupt status
+ */
+ IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->RecvChannel);
+
+ /*
+ * For packet threshold or wait bound interrupts, process desciptors. Also
+ * process descriptors on a SG end acknowledgement, which means the end of
+ * the descriptor list has been reached by the hardware. For receive, this
+ * is potentially trouble since it means the descriptor list is full,
+ * unless software can process enough packets quickly enough so the
+ * hardware has room to put new packets.
+ */
+ if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
+ XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
+ XStatus Result = XST_SUCCESS;
+ u32 NumFrames;
+ u32 NumProcessed;
+ u32 NumBuffers;
+ u32 NumBytes;
+ u32 IsLast;
+ XBufDescriptor *FirstBdPtr;
+ XBufDescriptor *BdPtr;
+
+ /*
+ * Get the number of unserviced packets
+ */
+ NumFrames = XDmaChannel_GetPktCount(&InstancePtr->RecvChannel);
+
+ for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
+ IsLast = FALSE;
+ FirstBdPtr = NULL;
+ NumBuffers = 0;
+ NumBytes = 0;
+
+ /*
+ * For each packet, get the descriptor from the list. On the
+ * last one in the frame, make the callback to the upper layer.
+ */
+ while (!IsLast) {
+ Result =
+ XDmaChannel_GetDescriptor(&InstancePtr->
+ RecvChannel,
+ &BdPtr);
+ if (Result != XST_SUCCESS) {
+ /*
+ * An error getting a buffer descriptor from the list.
+ * This should not happen, but if it does, report it to
+ * the error callback and break out of the loops to service
+ * other interrupts.
+ */
+ InstancePtr->ErrorHandler(InstancePtr->
+ ErrorRef,
+ Result);
+ break;
+ }
+
+ /*
+ * Keep a pointer to the first descriptor in the list, as it
+ * will be passed to the upper layers in a bit. By the fact
+ * that we received this packet means no errors occurred, so
+ * no need to check the device status word for errors.
+ */
+ if (FirstBdPtr == NULL) {
+ FirstBdPtr = BdPtr;
+ }
+
+ NumBytes += XBufDescriptor_GetLength(BdPtr);
+
+ /*
+ * Check to see if this is the last descriptor in the frame,
+ * and if so, set the IsLast flag to get out of the loop.
+ */
+ if (XBufDescriptor_IsLastStatus(BdPtr)) {
+ IsLast = TRUE;
+ }
+
+ /*
+ * Bump the number of buffers in this packet
+ */
+ NumBuffers++;
+
+ } /* end while loop */
+
+ /*
+ * Check for error that occurred inside the while loop, and break
+ * out of the for loop if there was one so other interrupts can
+ * be serviced.
+ */
+ if (Result != XST_SUCCESS) {
+ break;
+ }
+
+ InstancePtr->Stats.RecvFrames++;
+ InstancePtr->Stats.RecvBytes += NumBytes;
+
+ /*
+ * Make the callback to the upper layers, passing it the first
+ * descriptor in the packet and the number of descriptors in the
+ * packet.
+ */
+ InstancePtr->SgRecvHandler(InstancePtr->SgRecvRef,
+ FirstBdPtr, NumBuffers);
+
+ /*
+ * Decrement the packet count register to reflect the fact we
+ * just processed a packet
+ */
+ XDmaChannel_DecrementPktCount(&InstancePtr->
+ RecvChannel);
+
+ } /* end for loop */
+
+ /*
+ * If the interrupt was an end-ack, check the descriptor list again to
+ * see if it is empty. If not, go ahead and restart the scatter-gather
+ * channel. This is to fix a possible race condition where, on receive,
+ * the driver attempted to start a scatter-gather channel that was
+ * already started, which resulted in no action from the XDmaChannel
+ * component. But, just after the XDmaChannel component saw that the
+ * hardware was already started, the hardware stopped because it
+ * reached the end of the list. In that case, this interrupt is
+ * generated and we can restart the hardware here.
+ */
+ if (IntrStatus & XDC_IXR_SG_END_MASK) {
+ /*
+ * Ignore the return status since we know the list exists and we
+ * don't care if the list is empty or the channel is already started.
+ */
+ (void) XDmaChannel_SgStart(&InstancePtr->RecvChannel);
+ }
+ }
+
+ /*
+ * All interrupts are handled (except the error below) so acknowledge
+ * (clear) the interrupts by writing the value read above back to the status
+ * register. The packet count interrupt must be acknowledged after the
+ * decrement, otherwise it will come right back. We clear the interrupts
+ * before we handle the error interrupt because the ErrorHandler should
+ * result in a reset, which clears the interrupt status register. So we
+ * don't want to toggle the interrupt back on by writing the interrupt
+ * status register with an old value after a reset.
+ */
+ XDmaChannel_SetIntrStatus(&InstancePtr->RecvChannel, IntrStatus);
+
+ /*
+ * Check for DMA errors and call the error callback function if an error
+ * occurred (DMA bus or timeout error), which should result in a reset of
+ * the device by the upper layer software.
+ */
+ if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
+ InstancePtr->Stats.DmaErrors++;
+ InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
+ }
+}
+
+/*****************************************************************************/
+/*
+*
+* Handle an interrupt from the DMA send channel. DMA interrupts are:
+*
+* - DMA error. DMA encountered a bus error or timeout. This is a fatal error
+* that requires reset of the channel. The driver calls the error handler
+* of the upper layer software with an error code indicating the device should
+* be reset.
+* - Packet count threshold reached. For scatter-gather operations, indicates
+* the threshold for the number of packets not serviced by software has been
+* reached. The driver behaves as follows:
+* - Get the value of the packet counter, which tells us how many packets
+* are ready to be serviced
+* - For each packet
+* - For each descriptor, remove it from the scatter-gather list
+* - Check for the last descriptor in the frame, and if set
+* - Bump frame statistics
+* - Call the scatter-gather receive callback function
+* - Decrement the packet counter by one
+* Note that there are no receive errors reported in the status word of
+* the buffer descriptor. If receive errors occur, the MAC drops the
+* packet, and we only find out about the errors through various error
+* count registers.
+* - Packet wait bound reached. For scatter-gather, indicates the time to wait
+* for the next packet has expired. The driver follows the same logic as when
+* the packet count threshold interrupt is received.
+* - Scatter-gather end acknowledge. Hardware has reached the end of the
+* descriptor list. The driver follows the same logic as when the packet count
+* threshold interrupt is received. In addition, the driver restarts the DMA
+* scatter-gather channel in case there are newly inserted descriptors.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+*
+* @return
+*
+* Although the function returns void, there are asynchronous errors
+* that can be generated from this function. These are:
+* - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from
+* the DMA channel, but there was not one ready for software.
+* - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a
+* fatal error that requires reset.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+static void
+HandleDmaSendIntr(XEmac * InstancePtr)
+{
+ u32 IntrStatus;
+
+ /*
+ * Read the interrupt status
+ */
+ IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->SendChannel);
+
+ /*
+ * For packet threshold or wait bound interrupt, process descriptors. Also
+ * process descriptors on a SG end acknowledgement, which means the end of
+ * the descriptor list has been reached by the hardware. For transmit,
+ * this is a normal condition during times of light traffic. In fact, the
+ * wait bound interrupt may be masked for transmit since the end-ack would
+ * always occur before the wait bound expires.
+ */
+ if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
+ XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
+ XStatus Result = XST_SUCCESS;
+ u32 NumFrames;
+ u32 NumProcessed;
+ u32 NumBuffers;
+ u32 NumBytes;
+ u32 IsLast;
+ XBufDescriptor *FirstBdPtr;
+ XBufDescriptor *BdPtr;
+
+ /*
+ * Get the number of unserviced packets
+ */
+ NumFrames = XDmaChannel_GetPktCount(&InstancePtr->SendChannel);
+
+ for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
+ IsLast = FALSE;
+ FirstBdPtr = NULL;
+ NumBuffers = 0;
+ NumBytes = 0;
+
+ /*
+ * For each frame, traverse the descriptor list and look for
+ * errors. On the last one in the frame, make the callback.
+ */
+ while (!IsLast) {
+ Result =
+ XDmaChannel_GetDescriptor(&InstancePtr->
+ SendChannel,
+ &BdPtr);
+ if (Result != XST_SUCCESS) {
+ /*
+ * An error getting a buffer descriptor from the list.
+ * This should not happen, but if it does, report it to
+ * the error callback and break out of the loops to service
+ * other interrupts
+ */
+ InstancePtr->ErrorHandler(InstancePtr->
+ ErrorRef,
+ Result);
+ break;
+ }
+
+ /*
+ * Keep a pointer to the first descriptor in the list and
+ * check the device status for errors. The device status is
+ * only available in the first descriptor of a packet.
+ */
+ if (FirstBdPtr == NULL) {
+ u32 XmitStatus;
+
+ FirstBdPtr = BdPtr;
+
+ XmitStatus =
+ XBufDescriptor_GetDeviceStatus
+ (BdPtr);
+ if (XmitStatus &
+ XEM_TSR_EXCESS_DEFERRAL_MASK) {
+ InstancePtr->Stats.
+ XmitExcessDeferral++;
+ }
+
+ if (XmitStatus &
+ XEM_TSR_LATE_COLLISION_MASK) {
+ InstancePtr->Stats.
+ XmitLateCollisionErrors++;
+ }
+ }
+
+ NumBytes += XBufDescriptor_GetLength(BdPtr);
+
+ /*
+ * Check to see if this is the last descriptor in the frame,
+ * and if so, set the IsLast flag to get out of the loop. The
+ * transmit channel must check the last bit in the control
+ * word, not the status word (the DMA engine does not update
+ * the last bit in the status word for the transmit direction).
+ */
+ if (XBufDescriptor_IsLastControl(BdPtr)) {
+ IsLast = TRUE;
+ }
+
+ /*
+ * Bump the number of buffers in this packet
+ */
+ NumBuffers++;
+
+ } /* end while loop */
+
+ /*
+ * Check for error that occurred inside the while loop, and break
+ * out of the for loop if there was one so other interrupts can
+ * be serviced.
+ */
+ if (Result != XST_SUCCESS) {
+ break;
+ }
+
+ InstancePtr->Stats.XmitFrames++;
+ InstancePtr->Stats.XmitBytes += NumBytes;
+
+ /*
+ * Make the callback to the upper layers, passing it the first
+ * descriptor in the packet and the number of descriptors in the
+ * packet.
+ */
+ InstancePtr->SgSendHandler(InstancePtr->SgSendRef,
+ FirstBdPtr, NumBuffers);
+
+ /*
+ * Decrement the packet count register to reflect the fact we
+ * just processed a packet
+ */
+ XDmaChannel_DecrementPktCount(&InstancePtr->
+ SendChannel);
+
+ } /* end for loop */
+
+ /*
+ * If the interrupt was an end-ack, check the descriptor list again to
+ * see if it is empty. If not, go ahead and restart the scatter-gather
+ * channel. This is to fix a possible race condition where, on transmit,
+ * the driver attempted to start a scatter-gather channel that was
+ * already started, which resulted in no action from the XDmaChannel
+ * component. But, just after the XDmaChannel component saw that the
+ * hardware was already started, the hardware stopped because it
+ * reached the end of the list. In that case, this interrupt is
+ * generated and we can restart the hardware here.
+ */
+ if (IntrStatus & XDC_IXR_SG_END_MASK) {
+ /*
+ * Ignore the return status since we know the list exists and we
+ * don't care if the list is empty or the channel is already started.
+ */
+ (void) XDmaChannel_SgStart(&InstancePtr->SendChannel);
+ }
+ }
+
+ /*
+ * All interrupts are handled (except the error below) so acknowledge
+ * (clear) the interrupts by writing the value read above back to the status
+ * register. The packet count interrupt must be acknowledged after the
+ * decrement, otherwise it will come right back. We clear the interrupts
+ * before we handle the error interrupt because the ErrorHandler should
+ * result in a reset, which clears the interrupt status register. So we
+ * don't want to toggle the interrupt back on by writing the interrupt
+ * status register with an old value after a reset.
+ */
+ XDmaChannel_SetIntrStatus(&InstancePtr->SendChannel, IntrStatus);
+
+ /*
+ * Check for DMA errors and call the error callback function if an error
+ * occurred (DMA bus or timeout error), which should result in a reset of
+ * the device by the upper layer software.
+ */
+ if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
+ InstancePtr->Stats.DmaErrors++;
+ InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
+ }
+}
+
+/*****************************************************************************/
+/*
+*
+* Handle an interrupt from the Ethernet MAC when configured with scatter-gather
+* DMA. The only interrupts handled in this case are errors.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+*
+* @return
+*
+* None.
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+static void
+HandleEmacDmaIntr(XEmac * InstancePtr)
+{
+ u32 IntrStatus;
+
+ /*
+ * When configured with DMA, the EMAC generates interrupts only when errors
+ * occur. We clear the interrupts immediately so that any latched status
+ * interrupt bits will reflect the true status of the device, and so any
+ * pulsed interrupts (non-status) generated during the Isr will not be lost.
+ */
+ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
+ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, IntrStatus);
+
+ /*
+ * Check the MAC for errors
+ */
+ XEmac_CheckEmacError(InstancePtr, IntrStatus);
+}
diff --git a/board/xilinx/xilinx_enet/xemac_l.h b/board/xilinx/xilinx_enet/xemac_l.h
new file mode 100644
index 0000000..a463937
--- /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.
+*
+* <pre>
+* 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
+* </pre>
+*
+******************************************************************************/
+
+#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 0000000..1f225f8
--- /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.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a rpm 07/31/01 First release
+* 1.00b rpm 02/20/02 Repartitioned files and functions
+* 1.00c rpm 12/05/02 New version includes support for simple DMA
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+
+#include "xbasic_types.h"
+#include "xemac_i.h"
+#include "xio.h"
+
+/************************** 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 0000000..23768bc
--- /dev/null
+++ b/board/xilinx/xilinx_enet/xemac_polled.c
@@ -0,0 +1,482 @@
+/******************************************************************************
+*
+* Author: Xilinx, Inc.
+*
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+*
+* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD,
+* XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
+* FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING
+* ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY
+* WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM
+* CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND
+* FITNESS FOR A PARTICULAR PURPOSE.
+*
+*
+* Xilinx hardware products are not intended for use in life support
+* appliances, devices, or systems. Use in such applications is
+* expressly prohibited.
+*
+*
+* (c) Copyright 2002-2004 Xilinx Inc.
+* All rights reserved.
+*
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+******************************************************************************/
+/*****************************************************************************/
+/**
+*
+* @file xemac_polled.c
+*
+* Contains functions used when the driver is in polled mode. Use the
+* XEmac_SetOptions() function to put the driver into polled mode.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a rpm 07/31/01 First release
+* 1.00b rpm 02/20/02 Repartitioned files and functions
+* 1.00c rpm 12/05/02 New version includes support for simple DMA
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+
+#include "xbasic_types.h"
+#include "xemac_i.h"
+#include "xio.h"
+#include "xipif_v1_23_b.h" /* Uses v1.23b of the IPIF */
+
+/************************** Constant Definitions *****************************/
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Variable Definitions *****************************/
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+/**
+*
+* Send an Ethernet frame in polled mode. The device/driver must be in polled
+* mode before calling this function. The driver writes the frame directly to
+* the MAC's packet FIFO, then enters a loop checking the device status for
+* completion or error. Statistics are updated if an error occurs. The buffer
+* to be sent must be word-aligned.
+*
+* It is assumed that the upper layer software supplies a correctly formatted
+* Ethernet frame, including the destination and source addresses, the
+* type/length field, and the data field. It is also assumed that upper layer
+* software does not append FCS at the end of the frame.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param BufPtr is a pointer to a word-aligned buffer containing the Ethernet
+* frame to be sent.
+* @param ByteCount is the size of the Ethernet frame.
+*
+* @return
+*
+* - XST_SUCCESS if the frame was sent successfully
+* - XST_DEVICE_IS_STOPPED if the device has not yet been started
+* - XST_NOT_POLLED if the device is not in polled mode
+* - XST_FIFO_NO_ROOM if there is no room in the EMAC's length FIFO for this frame
+* - XST_FIFO_ERROR if the FIFO was overrun or underrun. This error is critical
+* and requires the caller to reset the device.
+* - XST_EMAC_COLLISION if the send failed due to excess deferral or late
+* collision
+*
+* @note
+*
+* There is the possibility that this function will not return if the hardware
+* is broken (i.e., it never sets the status bit indicating that transmission is
+* done). If this is of concern to the user, the user should provide protection
+* from this problem - perhaps by using a different timer thread to monitor the
+* PollSend thread. On a 10Mbps MAC, it takes about 1.21 msecs to transmit a
+* maximum size Ethernet frame (1518 bytes). On a 100Mbps MAC, it takes about
+* 121 usecs to transmit a maximum size Ethernet frame.
+*
+* @internal
+*
+* The EMAC uses FIFOs behind its length and status registers. For this reason,
+* it is important to keep the length, status, and data FIFOs in sync when
+* reading or writing to them.
+*
+******************************************************************************/
+XStatus
+XEmac_PollSend(XEmac * InstancePtr, u8 * BufPtr, u32 ByteCount)
+{
+ u32 IntrStatus;
+ u32 XmitStatus;
+ XStatus Result;
+
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(BufPtr != NULL);
+ XASSERT_NONVOID(ByteCount > XEM_HDR_SIZE); /* send at least 1 byte */
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ /*
+ * Be sure the device is configured for polled mode and it is started
+ */
+ if (!InstancePtr->IsPolled) {
+ return XST_NOT_POLLED;
+ }
+
+ if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) {
+ return XST_DEVICE_IS_STOPPED;
+ }
+
+ /*
+ * Check for overruns and underruns for the transmit status and length
+ * FIFOs and make sure the send packet FIFO is not deadlocked. Any of these
+ * conditions is bad enough that we do not want to continue. The upper layer
+ * software should reset the device to resolve the error.
+ */
+ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
+
+ /*
+ * Overrun errors
+ */
+ if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
+ XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
+ InstancePtr->Stats.XmitOverrunErrors++;
+ InstancePtr->Stats.FifoErrors++;
+ return XST_FIFO_ERROR;
+ }
+
+ /*
+ * Underrun errors
+ */
+ if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
+ XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
+ InstancePtr->Stats.XmitUnderrunErrors++;
+ InstancePtr->Stats.FifoErrors++;
+ return XST_FIFO_ERROR;
+ }
+
+ if (XPF_V100B_IS_DEADLOCKED(&InstancePtr->SendFifo)) {
+ InstancePtr->Stats.FifoErrors++;
+ return XST_FIFO_ERROR;
+ }
+
+ /*
+ * Before writing to the data FIFO, make sure the length FIFO is not
+ * full. The data FIFO might not be full yet even though the length FIFO
+ * is. This avoids an overrun condition on the length FIFO and keeps the
+ * FIFOs in sync.
+ */
+ if (IntrStatus & XEM_EIR_XMIT_LFIFO_FULL_MASK) {
+ /*
+ * Clear the latched LFIFO_FULL bit so next time around the most
+ * current status is represented
+ */
+ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress,
+ XEM_EIR_XMIT_LFIFO_FULL_MASK);
+ return XST_FIFO_NO_ROOM;
+ }
+
+ /*
+ * This is a non-blocking write. The packet FIFO returns an error if there
+ * is not enough room in the FIFO for this frame.
+ */
+ Result =
+ XPacketFifoV100b_Write(&InstancePtr->SendFifo, BufPtr, ByteCount);
+ if (Result != XST_SUCCESS) {
+ return Result;
+ }
+
+ /*
+ * Loop on the MAC's status to wait for any pause to complete.
+ */
+ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
+
+ while ((IntrStatus & XEM_EIR_XMIT_PAUSE_MASK) != 0) {
+ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
+ /*
+ * Clear the pause status from the transmit status register
+ */
+ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress,
+ IntrStatus & XEM_EIR_XMIT_PAUSE_MASK);
+ }
+
+ /*
+ * Set the MAC's transmit packet length register to tell it to transmit
+ */
+ XIo_Out32(InstancePtr->BaseAddress + XEM_TPLR_OFFSET, ByteCount);
+
+ /*
+ * Loop on the MAC's status to wait for the transmit to complete. The
+ * transmit status is in the FIFO when the XMIT_DONE bit is set.
+ */
+ do {
+ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
+ }
+ while ((IntrStatus & XEM_EIR_XMIT_DONE_MASK) == 0);
+
+ XmitStatus = XIo_In32(InstancePtr->BaseAddress + XEM_TSR_OFFSET);
+
+ InstancePtr->Stats.XmitFrames++;
+ InstancePtr->Stats.XmitBytes += ByteCount;
+
+ /*
+ * Check for various errors, bump statistics, and return an error status.
+ */
+
+ /*
+ * Overrun errors
+ */
+ if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
+ XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
+ InstancePtr->Stats.XmitOverrunErrors++;
+ InstancePtr->Stats.FifoErrors++;
+ return XST_FIFO_ERROR;
+ }
+
+ /*
+ * Underrun errors
+ */
+ if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
+ XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
+ InstancePtr->Stats.XmitUnderrunErrors++;
+ InstancePtr->Stats.FifoErrors++;
+ return XST_FIFO_ERROR;
+ }
+
+ /*
+ * Clear the interrupt status register of transmit statuses
+ */
+ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress,
+ IntrStatus & XEM_EIR_XMIT_ALL_MASK);
+
+ /*
+ * Collision errors are stored in the transmit status register
+ * instead of the interrupt status register
+ */
+ if (XmitStatus & XEM_TSR_EXCESS_DEFERRAL_MASK) {
+ InstancePtr->Stats.XmitExcessDeferral++;
+ return XST_EMAC_COLLISION_ERROR;
+ }
+
+ if (XmitStatus & XEM_TSR_LATE_COLLISION_MASK) {
+ InstancePtr->Stats.XmitLateCollisionErrors++;
+ return XST_EMAC_COLLISION_ERROR;
+ }
+
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* Receive an Ethernet frame in polled mode. The device/driver must be in polled
+* mode before calling this function. The driver receives the frame directly
+* from the MAC's packet FIFO. This is a non-blocking receive, in that if there
+* is no frame ready to be received at the device, the function returns with an
+* error. The MAC's error status is not checked, so statistics are not updated
+* for polled receive. The buffer into which the frame will be received must be
+* word-aligned.
+*
+* @param InstancePtr is a pointer to the XEmac instance to be worked on.
+* @param BufPtr is a pointer to a word-aligned buffer into which the received
+* Ethernet frame will be copied.
+* @param ByteCountPtr is both an input and an output parameter. It is a pointer
+* to a 32-bit word that contains the size of the buffer on entry into the
+* function and the size the received frame on return from the function.
+*
+* @return
+*
+* - XST_SUCCESS if the frame was sent successfully
+* - XST_DEVICE_IS_STOPPED if the device has not yet been started
+* - XST_NOT_POLLED if the device is not in polled mode
+* - XST_NO_DATA if there is no frame to be received from the FIFO
+* - XST_BUFFER_TOO_SMALL if the buffer to receive the frame is too small for
+* the frame waiting in the FIFO.
+*
+* @note
+*
+* Input buffer must be big enough to hold the largest Ethernet frame. Buffer
+* must also be 32-bit aligned.
+*
+* @internal
+*
+* The EMAC uses FIFOs behind its length and status registers. For this reason,
+* it is important to keep the length, status, and data FIFOs in sync when
+* reading or writing to them.
+*
+******************************************************************************/
+XStatus
+XEmac_PollRecv(XEmac * InstancePtr, u8 * BufPtr, u32 * ByteCountPtr)
+{
+ XStatus Result;
+ u32 PktLength;
+ u32 IntrStatus;
+
+ XASSERT_NONVOID(InstancePtr != NULL);
+ XASSERT_NONVOID(BufPtr != NULL);
+ XASSERT_NONVOID(ByteCountPtr != NULL);
+ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
+
+ /*
+ * Be sure the device is configured for polled mode and it is started
+ */
+ if (!InstancePtr->IsPolled) {
+ return XST_NOT_POLLED;
+ }
+
+ if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) {
+ return XST_DEVICE_IS_STOPPED;
+ }
+
+ /*
+ * Make sure the buffer is big enough to hold the maximum frame size.
+ * We need to do this because as soon as we read the MAC's packet length
+ * register, which is actually a FIFO, we remove that length from the
+ * FIFO. We do not want to read the length FIFO without also reading the
+ * data FIFO since this would get the FIFOs out of sync. So we have to
+ * make this restriction.
+ */
+ if (*ByteCountPtr < XEM_MAX_FRAME_SIZE) {
+ return XST_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * First check for packet FIFO deadlock and return an error if it has
+ * occurred. A reset by the caller is necessary to correct this problem.
+ */
+ if (XPF_V100B_IS_DEADLOCKED(&InstancePtr->RecvFifo)) {
+ InstancePtr->Stats.FifoErrors++;
+ return XST_FIFO_ERROR;
+ }
+
+ /*
+ * Get the interrupt status to know what happened (whether an error occurred
+ * and/or whether frames have been received successfully). When clearing the
+ * intr status register, clear only statuses that pertain to receive.
+ */
+ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
+ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress,
+ IntrStatus & XEM_EIR_RECV_ALL_MASK);
+
+ /*
+ * Check receive errors and bump statistics so the caller will have a clue
+ * as to why data may not have been received. We continue on if an error
+ * occurred since there still may be frames that were received successfully.
+ */
+ if (IntrStatus & (XEM_EIR_RECV_LFIFO_OVER_MASK |
+ XEM_EIR_RECV_DFIFO_OVER_MASK)) {
+ InstancePtr->Stats.RecvOverrunErrors++;
+ InstancePtr->Stats.FifoErrors++;
+ }
+
+ if (IntrStatus & XEM_EIR_RECV_LFIFO_UNDER_MASK) {
+ InstancePtr->Stats.RecvUnderrunErrors++;
+ InstancePtr->Stats.FifoErrors++;
+ }
+
+ /*
+ * General receive errors
+ */
+ if (IntrStatus & XEM_EIR_RECV_ERROR_MASK) {
+ if (IntrStatus & XEM_EIR_RECV_MISSED_FRAME_MASK) {
+ InstancePtr->Stats.RecvMissedFrameErrors =
+ XIo_In32(InstancePtr->BaseAddress +
+ XEM_RMFC_OFFSET);
+ }
+
+ if (IntrStatus & XEM_EIR_RECV_COLLISION_MASK) {
+ InstancePtr->Stats.RecvCollisionErrors =
+ XIo_In32(InstancePtr->BaseAddress + XEM_RCC_OFFSET);
+ }
+
+ if (IntrStatus & XEM_EIR_RECV_FCS_ERROR_MASK) {
+ InstancePtr->Stats.RecvFcsErrors =
+ XIo_In32(InstancePtr->BaseAddress +
+ XEM_RFCSEC_OFFSET);
+ }
+
+ if (IntrStatus & XEM_EIR_RECV_LEN_ERROR_MASK) {
+ InstancePtr->Stats.RecvLengthFieldErrors++;
+ }
+
+ if (IntrStatus & XEM_EIR_RECV_SHORT_ERROR_MASK) {
+ InstancePtr->Stats.RecvShortErrors++;
+ }
+
+ if (IntrStatus & XEM_EIR_RECV_LONG_ERROR_MASK) {
+ InstancePtr->Stats.RecvLongErrors++;
+ }
+
+ if (IntrStatus & XEM_EIR_RECV_ALIGN_ERROR_MASK) {
+ InstancePtr->Stats.RecvAlignmentErrors =
+ XIo_In32(InstancePtr->BaseAddress +
+ XEM_RAEC_OFFSET);
+ }
+ }
+
+ /*
+ * Before reading from the length FIFO, make sure the length FIFO is not
+ * empty. We could cause an underrun error if we try to read from an
+ * empty FIFO.
+ */
+ if ((IntrStatus & XEM_EIR_RECV_DONE_MASK) == 0) {
+ return XST_NO_DATA;
+ }
+
+ /*
+ * Determine, from the MAC, the length of the next packet available
+ * in the data FIFO (there should be a non-zero length here)
+ */
+ PktLength = XIo_In32(InstancePtr->BaseAddress + XEM_RPLR_OFFSET);
+ if (PktLength == 0) {
+ return XST_NO_DATA;
+ }
+
+ /*
+ * Write the RECV_DONE bit in the status register to clear it. This bit
+ * indicates the RPLR is non-empty, and we know it's set at this point.
+ * We clear it so that subsequent entry into this routine will reflect the
+ * current status. This is done because the non-empty bit is latched in the
+ * IPIF, which means it may indicate a non-empty condition even though
+ * there is something in the FIFO.
+ */
+ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_RECV_DONE_MASK);
+
+ /*
+ * We assume that the MAC never has a length bigger than the largest
+ * Ethernet frame, so no need to make another check here.
+ */
+
+ /*
+ * This is a non-blocking read. The FIFO returns an error if there is
+ * not at least the requested amount of data in the FIFO.
+ */
+ Result =
+ XPacketFifoV100b_Read(&InstancePtr->RecvFifo, BufPtr, PktLength);
+ if (Result != XST_SUCCESS) {
+ return Result;
+ }
+
+ InstancePtr->Stats.RecvFrames++;
+ InstancePtr->Stats.RecvBytes += PktLength;
+
+ *ByteCountPtr = PktLength;
+
+ return XST_SUCCESS;
+}