/******************************************************************************
*
* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/**
*
* @file xaxiethernet_example_intr_fifo.c
*
* Implements examples that utilize the Axi Ethernet's interrupt driven FIFO
* direct packet transfer mode to send and receive frames.
*
* These examples demonstrate:
*
* - How to perform simple send and receive.
* - Advanced frame processing
* - Error handling
* - Device reset
*
* Functional guide to example:
*
* - AxiEthernetSingleFrameIntrExample() demonstrates the simplest way to send
* and receive frames in interrupt driven FIFO direct mode.
*
* - AxiEthernetSingleFrameNonContIntrExample demonstrates how to handle frames
* that are stored in more than one memory location.
*
* - AxiEthernetMultipleFramesIntrExample demonstrates how to defer frame
* reception so that CPU intensive receive functions are not performed in
* interrupt context.
*
* - AxiEthernetErrorHandler() demonstrates how to manage asynchronous errors.
*
* - AxiEthernetResetDevice() demonstrates how to reset the driver/HW while
maintaining driver/HW state.
*
*
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a asa 4/30/10 First release based on the ll temac driver
* 3.00a bss 10/22/12 Added support for Fast Interrupt Handlers.
* 3.01a srt 02/14/13 Added support for Zynq (CR 681136)
* 3.02a srt 08/06/13 Fixed CR 727634 -
* Modified FifoHandler() logic to reflect the bit
* changes in the Interrupt Status Register as per
* the latest AXI FIFO stream IP.
*
*
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xaxiethernet_example.h"
#include "xllfifo.h"
#include "xil_cache.h"
#include "xil_exception.h"
#ifdef XPAR_INTC_0_DEVICE_ID
#include "xintc.h"
#else
#include "xscugic.h"
#endif
#ifdef XPAR_XUARTNS550_NUM_INSTANCES
#include "xuartns550_l.h"
#endif
/*************************** Constant Definitions ****************************/
/*
* The following constants map to the XPAR parameters created in the
* xparameters.h file. They are defined here such that a user can easily
* change all the needed parameters in one place.
*/
#ifndef TESTAPP_GEN
#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID
#define FIFO_DEVICE_ID XPAR_AXI_FIFO_0_DEVICE_ID
#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID
#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID
#define FIFO_IRPT_INTR XPAR_INTC_0_LLFIFO_0_VEC_ID
#else
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID
#define FIFO_IRPT_INTR XPAR_FABRIC_LLFIFO_0_VEC_ID
#endif
#endif
#define PAYLOAD_SIZE 100 /* Payload size used in examples */
/*************************** Variable Definitions ****************************/
static EthernetFrame TxFrame; /* Frame used to send with */
static EthernetFrame RxFrame; /* Frame used to receive data */
volatile static int DeferRx = 0;
/*
* Counters setup to be incremented by callbacks
*/
static volatile int FramesRx; /* Number of received frames */
static volatile int FramesRxInts; /* Number of ints for received
* frames
*/
static volatile int FramesTxInts; /* Number of ints for sent frames */
static volatile int DeviceErrors; /* Num of errors detected in
* the device
*/
static volatile int FrameDataErrors; /* Num of times frame data check
* failed
*/
XAxiEthernet AxiEthernetInstance;
XLlFifo FifoInstance;
#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC XIntc
#define INTC_HANDLER XIntc_InterruptHandler
#else
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
#endif
#ifndef TESTAPP_GEN
static INTC IntcInstance;
#endif
#if XPAR_INTC_0_HAS_FAST == 1
/* Variables for Fast Interrupt Handlers */
XAxiEthernet *AxiEthernetInstancePtr_Fast;
XLlFifo *Fifo_Fast;
/****** Fast Interrupt Handlers prototypes ******/
static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt));
static void FifoFastHandler(void) __attribute__ ((fast_interrupt));
#else
static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet);
static void FifoHandler(XLlFifo *Fifo);
#endif
/*************************** Function Prototypes *****************************/
/*
* The different examples given in this file
*/
int AxiEthernetFifoIntrExample(INTC *IntcInstancePtr,
XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr,
u16 AxiEthernetDeviceId,
u16 FifoDeviceId, u16 AxiEthernetIntrId,
u16 FifoIntrId);
int AxiEthernetSingleFrameIntrExample(XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr);
int AxiEthernetSingleFrameNonContIntrExample(XAxiEthernet
*AxiEthernetInstancePtr, XLlFifo *FifoInstancePtr);
int AxiEthernetMultipleFramesIntrExample(XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr);
/*
* The Interrupt setup and callbacks
*/
static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr,
XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr,
u16 AxiEthernetIntrId, u16 FifoIntrId);
static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr,
u16 AxiEthernetIntrId, u16 FifoIntrId);
static void FifoRecvHandler(XLlFifo *Fifo);
/*
* Utility routines
*/
static int AxiEthernetResetDevice(XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr);
/*****************************************************************************/
/**
*
* This is the main function for the Axi Ethernet example. This function is not
* included if the example is generated from the TestAppGen test tool.
*
* @param None.
*
* - XST_SUCCESS to indicate success.
* - XST_FAILURE.to indicate failure.
* @note None.
*
****************************************************************************/
#ifndef TESTAPP_GEN
int main(void)
{
int Status;
#ifdef XPAR_XUARTNS550_NUM_INSTANCES
XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600);
XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS);
#endif
#if XPAR_MICROBLAZE_USE_ICACHE
Xil_ICacheInvalidate();
Xil_ICacheEnable();
#endif
#if XPAR_MICROBLAZE_USE_DCACHE
Xil_DCacheInvalidate();
Xil_DCacheEnable();
#endif
AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---");
AxiEthernetUtilErrorTrap("This test may take several minutes to finish");
/*
* Call the Axi Ethernet interrupt example , specify the parameters
* generated in xparameters.h
*/
Status = AxiEthernetFifoIntrExample(&IntcInstance,
&AxiEthernetInstance,
&FifoInstance,
AXIETHERNET_DEVICE_ID,
FIFO_DEVICE_ID,
AXIETHERNET_IRPT_INTR, FIFO_IRPT_INTR);
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap("Failed test intr fifo");
} else {
AxiEthernetUtilErrorTrap("Test passed");
}
AxiEthernetUtilErrorTrap("--- Exiting main() ---");
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
#endif
/*****************************************************************************/
/**
*
* This function demonstrates the usage usage of the Axi Ethernet by sending
* and receiving frames in interrupt driven fifo mode.
*
*
* @param IntcInstancePtr is a pointer to the instance of the Intc
* component.
* @param AxiEthernetInstancePtr is a pointer to the instance of the
* Axi Ethernet component.
* @param FifoInstancePtr is a pointer to the instance of the AXIFIFO
* component.
* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device ,
* typically XPAR__DEVICE_ID value from
* xparameters.h.
* @param FifoDeviceId is the Interrupt ID and is typically
* XPAR___VEC_ID
* value from xparameters.h.
* @param AxiEthernetIntrId is the Interrupt ID and is typically
* XPAR___VEC_ID
* value from xparameters.h.
* @param FifoIntrId is the interrupt id for fifo.
*
* - XST_SUCCESS to indicate success.
* - XST_FAILURE.to indicate failure.
*
* @note AxiFifo hardware must be initialized before initializing
* AxiEthernet. Since AxiFifo reset line is connected to the
* AxiEthernet reset line, a reset of AxiFifo hardware during its
* initialization would reset AxiEthernet.
*
******************************************************************************/
int AxiEthernetFifoIntrExample(INTC *IntcInstancePtr,
XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr,
u16 AxiEthernetDeviceId,
u16 FifoDeviceId, u16 AxiEthernetIntrId,
u16 FifoIntrId)
{
int Status;
XAxiEthernet_Config *MacCfgPtr;
int LoopbackSpeed;
/*************************************/
/* Setup device for first-time usage */
/*************************************/
/*
* Get the configuration of AxiEthernet hardware.
*/
MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId);
/*
* Check whether AXIFIFO is present or not
*/
if(MacCfgPtr->AxiDevType != XPAR_AXI_FIFO) {
AxiEthernetUtilErrorTrap
("Device HW not configured for FIFO mode\r\n");
return XST_FAILURE;
}
/*
* Initialize AXIFIFO hardware. AXIFIFO must be initialized before
* AxiEthernet. During AXIFIFO initialization, AXIFIFO hardware is
* reset, and since AXIFIFO reset line is connected to AxiEthernet,
* this would ensure a reset of AxiEthernet.
*/
XLlFifo_Initialize(FifoInstancePtr, MacCfgPtr->AxiDevBaseAddress);
/*
* Initialize AxiEthernet hardware.
*/
Status = XAxiEthernet_CfgInitialize(AxiEthernetInstancePtr, MacCfgPtr,
MacCfgPtr->BaseAddress);
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap("Error in initialize");
return XST_FAILURE;
}
/*
* Set the MAC address
*/
Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr,
(u8 *) AxiEthernetMAC);
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap("Error setting MAC address");
return XST_FAILURE;
}
/*
* Set PHY to loopback, speed depends on phy type.
* MII is 100 and all others are 1000.
*/
if (XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr) ==
XAE_PHY_TYPE_MII) {
LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED;
} else {
LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED_1G;
}
Status = AxiEthernetUtilEnterLoopback(AxiEthernetInstancePtr,
LoopbackSpeed);
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap("Error setting the PHY loopback");
return XST_FAILURE;
}
/*
* Set PHY<-->MAC data clock
*/
Status = XAxiEthernet_SetOperatingSpeed(AxiEthernetInstancePtr,
(u16)LoopbackSpeed);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Setting the operating speed of the MAC needs a delay. There
* doesn't seem to be register to poll, so please consider this
* during your application design.
*/
AxiEthernetUtilPhyDelay(2);
/* Clear any pending FIFO interrupts from any previous
* examples (e.g., polled)
*/
XLlFifo_IntClear(FifoInstancePtr, XLLF_INT_ALL_MASK);
/*
* Connect to the interrupt controller and enable interrupts
*/
Status = AxiEthernetSetupIntrSystem(IntcInstancePtr,
AxiEthernetInstancePtr,
FifoInstancePtr, AxiEthernetIntrId,
FifoIntrId);
/****************************/
/* Run through the examples */
/****************************/
/*
* Run the AxiEthernet Single Frame Interrupt example
*/
Status = AxiEthernetSingleFrameIntrExample(AxiEthernetInstancePtr,
FifoInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Run the AxiEthernet Single Frame Non Continuous Interrupt example
*/
Status = AxiEthernetSingleFrameNonContIntrExample
(AxiEthernetInstancePtr, FifoInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
DeferRx = 1;
Status = AxiEthernetMultipleFramesIntrExample(AxiEthernetInstancePtr,
FifoInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = AxiEthernetResetDevice(AxiEthernetInstancePtr,
FifoInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Disable the interrupts for the AxiEthernet device
*/
AxiEthernetDisableIntrSystem(IntcInstancePtr, AxiEthernetIntrId,
FifoIntrId);
/*
* Stop the device
*/
XAxiEthernet_Stop(AxiEthernetInstancePtr);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function demonstrates the usage of the Axi Ethernet by sending and
* receiving a single frame in interrupt mode.
*
* @param AxiEthernetInstancePtr is a pointer to the instance of the
* AxiEthernet component.
* @param FifoInstancePtr is a pointer to the instance of the Fifo
* component.
*
* - XST_SUCCESS to indicate success.
* - XST_FAILURE.to indicate failure.
*
* @note None.
*
******************************************************************************/
int AxiEthernetSingleFrameIntrExample(XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr)
{
u32 FifoFreeBytes;
u32 TxFrameLength;
int PayloadSize = PAYLOAD_SIZE;
/*
* Clear variables shared with callbacks
*/
FramesRx = 0;
FramesRxInts = 0;
FramesTxInts = 0;
DeviceErrors = 0;
FrameDataErrors = 0;
/*
* Setup packet to be transmitted
*/
AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC);
AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize);
AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize);
/*
* Clear out receive packet memory area
*/
AxiEthernetUtilFrameMemClear(&RxFrame);
/*
* Calculate frame length (not including FCS)
*/
TxFrameLength = XAE_HDR_SIZE + PayloadSize;
/****************/
/* Setup device */
/****************/
/*
* Start the device
*/
XAxiEthernet_Start(AxiEthernetInstancePtr);
/*
* Enable the interrupts
*/
XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_ALL_MASK);
XAxiEthernet_IntEnable(AxiEthernetInstancePtr,
XAE_INT_RXRJECT_MASK | XAE_INT_RXFIFOOVR_MASK);
/*******************/
/* Send the packet */
/*******************/
/*
* Find out how much room is in the FIFO
* Vacancy is a value in 32 bit words. Multiply by 4 to get bytes.
*/
FifoFreeBytes = XLlFifo_TxVacancy(FifoInstancePtr) * 4;
if (FifoFreeBytes < TxFrameLength) {
AxiEthernetUtilErrorTrap("Not enough room in FIFO for frame");
return XST_FAILURE;
}
/*
* Write frame data to FIFO
*/
XLlFifo_Write(FifoInstancePtr, TxFrame, TxFrameLength);
/*
* Initiate the transmit
*/
XLlFifo_TxSetLen(FifoInstancePtr, TxFrameLength);
/*
* Wait for receive indication or error
*/
while ((FramesRx == 0) && (DeviceErrors == 0));
/*
* Stop the device
*/
XAxiEthernet_Stop(AxiEthernetInstancePtr);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This example sends a packet from non-contiguous memory locations. The header
* is stored in one area. The payload data is calculated and written to the
* packet FIFO one byte at a time.
*
* @param AxiEthernetInstancePtr is a pointer to the instance of the
* AxiEthernet component.
* @param FifoInstancePtr is a pointer to the instance of the Fifo
* component.
*
* - XST_SUCCESS to indicate success.
* - XST_FAILURE.to indicate failure.
*
* @note None.
*
******************************************************************************/
int AxiEthernetSingleFrameNonContIntrExample(XAxiEthernet
*AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr)
{
u32 FifoFreeBytes;
int PayloadSize = 20;
u8 PayloadData;
u32 TxFrameLength;
/*
* Clear variables shared with callbacks
*/
FramesRx = 0;
FramesRxInts = 0;
FramesTxInts = 0;
DeviceErrors = 0;
FrameDataErrors = 0;
/*
* Setup the transmit packet header
*/
AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC);
AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize);
/*
* Clear out receive packet memory area
*/
AxiEthernetUtilFrameMemClear(&RxFrame);
/*
* Calculate frame length (not including FCS)
*/
TxFrameLength = XAE_HDR_SIZE + PayloadSize;
/****************/
/* Setup device */
/****************/
/*
* Start the device
*/
XAxiEthernet_Start(AxiEthernetInstancePtr);
/*
* Enable interrupts
*/
XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_ALL_MASK);
/*******************/
/* Send the packet */
/*******************/
/*
* Make sure there is enough room for a full sized frame
* Vacancy is a value in 32 bit words. Multiply by 4 to get bytes.
*/
FifoFreeBytes = XLlFifo_TxVacancy(FifoInstancePtr) * 4;
if (FifoFreeBytes < (XAE_MTU + XAE_HDR_SIZE)) {
AxiEthernetUtilErrorTrap("Not enough room in FIFO for frame");
return XST_FAILURE;
}
/*
* Write the header data
*/
XLlFifo_Write(FifoInstancePtr, TxFrame, XAE_HDR_SIZE);
/*
* Write payload one byte at a time. Set the payload like the
* AxiEthernetUtilFrameSetPayloadData() function would. This is done
* so that the received packet will pass validation in
* AxiEthernetRecvHandler().
*
* Keep PayloadSize less than 255 since
* AxiEthernetUtilFrameSetPayloadData() switches to a 16 bit
* counter at 256.
*
* This is not the fastest way to send a frame of data but it does
* illustrate the flexibility of the API.
*/
PayloadData = 0;
while ((PayloadData < PayloadSize) && (DeviceErrors == 0)) {
XLlFifo_Write(FifoInstancePtr, &PayloadData, 1);
PayloadData++;
}
/*
* Did it all get written without error
*/
if (DeviceErrors != 0) {
AxiEthernetUtilErrorTrap
("Error writing payload to FIFO, reset recommended");
return XST_FAILURE;
}
/*
* Now begin transmission
*/
XLlFifo_TxSetLen(FifoInstancePtr, TxFrameLength);
/*
* Wait for receive indication or error
*/
while ((FramesRx == 0) && (DeviceErrors == 0));
/*
* Stop the device
*/
XAxiEthernet_Stop(AxiEthernetInstancePtr);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This example sends and receives a batch of frames. Frame reception is handled
* in this function and not in the callback function.
*
* Use this method of reception when interrupt latency is important.
*
* @param AxiEthernetInstancePtr is a pointer to the instance of the
* AxiEthernet component.
* @param FifoInstancePtr is a pointer to the instance of the Fifo
* component.
*
* - XST_SUCCESS to indicate success.
* - XST_FAILURE.to indicate failure.
*
* @note None.
*
******************************************************************************/
int AxiEthernetMultipleFramesIntrExample(XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr)
{
int FramesToLoopback;
int PayloadSize;
u32 TxFrameLength;
u32 RxFrameLength;
int Index;
/*
* Clear variables shared with callbacks
*/
FramesRx = 0;
FramesRxInts = 0;
FramesTxInts = 0;
DeviceErrors = 0;
FrameDataErrors = 0;
/*
* Setup the number of frames to loopback and the size of the frame to
* loopback. The default settings should work for every case. Modifying
* the settings can cause problems, see discussion below:
*
* If PayloadSize is set small and FramesToLoopback high, then it is
* possible to cause the transmit status FIFO to overflow.
*
* If PayloadSize is set large and FramesToLoopback high, then it is
* possible to cause the transmit packet FIFO to overflow.
*
* Either of these scenarios may be worth trying out to observe how the
* driver reacts. The exact values to cause these types of errors
* will vary due to the sizes of the FIFOs selected at hardware build
* time. But the following settings should create problems for all
* FIFO sizes:
*
* Transmit status FIFO overflow
* PayloadSize = 1
* FramesToLoopback = 1000
*
* Transmit packet FIFO overflow
* PayloadSize = 1500
* FramesToLoopback = 16
*
* These values should always work without error
* PayloadSize = 100
* FramesToLoopback = 5
*/
PayloadSize = 100;
FramesToLoopback = 5;
/*
* Setup the transmit packet
*/
AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC);
AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize);
AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize);
/*
* Calculate frame length (not including FCS)
*/
TxFrameLength = XAE_HDR_SIZE + PayloadSize;
/****************/
/* Setup device */
/****************/
/*
* Start the device
*/
XAxiEthernet_Start(AxiEthernetInstancePtr);
/*
* Enable the interrupts
*/
XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_ALL_MASK);
/****************/
/* Send packets */
/****************/
/*
* Since we may be interested to see what happens when FIFOs overflow,
* don't check for room in the transmit packet FIFO prior to writing
* to it.
*/
/*
* With the xps_ll_fifo core we can't stuff the fifo with data from
* multiple packets and then send them. Instead, the code needs to
* write the data, and then immediately send the packet before
* writting the data for the next packet.
*/
for (Index = 0; Index < FramesToLoopback; Index++) {
/*
* Write frame data to FIFO
*/
XLlFifo_Write(FifoInstancePtr, TxFrame, TxFrameLength);
/*
* Initiate the transmission
*/
XLlFifo_TxSetLen(FifoInstancePtr, TxFrameLength);
}
/*******************/
/* Receive packets */
/*******************/
/*
* Now wait for frames to be received. When the callback is executed,
* it will disable interrupts and set a shared variable which will
* trigger this routine to process received frames
*/
for (Index = 0; Index < FramesToLoopback; Index++) {
/*
* Wait
*/
while (FramesRxInts == 0);
/*
* Frame has arrived, so get the length
*/
RxFrameLength = XLlFifo_RxGetLen(FifoInstancePtr);
/*
* Decision time: We can re-enable receive interrupts here or
* after we read the frame out of the FIFO. This is a matter
* of preference and goals of an application using the driver.
*/
XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_RC_MASK);
/*
* Frame size as expected?
*/
if ((RxFrameLength) != TxFrameLength) {
AxiEthernetUtilErrorTrap("Receive length incorrect");
}
/*
* Clear out receive packet memory area
*/
AxiEthernetUtilFrameMemClear(&RxFrame);
/*
* Read frame from packet FIFO
*/
XLlFifo_Read(FifoInstancePtr, &RxFrame, RxFrameLength);
/*
* Verify the received data
*/
if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) {
AxiEthernetUtilErrorTrap("Data mismatch");
return XST_FAILURE;
}
}
/*
* Stop the device
*/
XAxiEthernet_Stop(AxiEthernetInstancePtr);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This is the Receive handler callback function for examples 1 and 2.
* It will increment a shared counter, receive and validate the frame.
*
* @param Fifo is a reference to the Fifo device instance.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void FifoRecvHandler(XLlFifo *Fifo)
{
u32 FrameLength;
/*
* We get the interrupt only once for multiple frames received.
* So get all the frames we can.
*/
/* While there is data in the fifo ... */
while (XLlFifo_RxOccupancy(Fifo)) {
/*
* Get the packet length
*/
FrameLength = XLlFifo_RxGetLen(Fifo);
XLlFifo_Read(Fifo, RxFrame, FrameLength);
/*
* Validate the packet data against the header of the TxFrame.
* The payload data should as placed by
* AxiEthernetUtilFrameSetPayloadData()
*/
if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) {
FrameDataErrors++;
AxiEthernetUtilErrorTrap("Data mismatch");
return;
}
/*
* Bump counter
*/
FramesRx++;
}
}
/*****************************************************************************/
/**
*
* This is the Error handler callback function and this function increments the
* the error counter so that the main thread knows the number of errors.
*
* @param Fifo is a reference to the AxiEthernet device instance.
*
* @param Pending is a bitmask of the pending interrupts.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void FifoErrorHandler(XLlFifo *Fifo, u32 Pending)
{
int timeout_counter;
if (Pending & XLLF_INT_RPURE_MASK) {
AxiEthernetUtilErrorTrap("Fifo: Rx under-read error");
}
if (Pending & XLLF_INT_RPORE_MASK) {
AxiEthernetUtilErrorTrap("Fifo: Rx over-read error");
}
if (Pending & XLLF_INT_RPUE_MASK) {
AxiEthernetUtilErrorTrap("Fifo: Rx fifo empty");
}
if (Pending & XLLF_INT_TPOE_MASK) {
AxiEthernetUtilErrorTrap("Fifo: Tx fifo overrun");
}
if (Pending & XLLF_INT_TSE_MASK) {
AxiEthernetUtilErrorTrap("Fifo: Tx length mismatch");
}
/*
* Reset the tx or rx side of the fifo as needed
*/
if (Pending & XLLF_INT_RXERROR_MASK) {
XLlFifo_IntClear(Fifo, XLLF_INT_RRC_MASK);
XLlFifo_RxReset(Fifo);
timeout_counter = 10000;
while ((XLlFifo_Status(Fifo) & XLLF_INT_RRC_MASK) == 0) {
timeout_counter--;
if (timeout_counter == 0) {
XLlFifo_Reset(Fifo);
/* we've reset the whole core so just exit out */
goto feh_exit;
}
}
}
if (Pending & XLLF_INT_TXERROR_MASK) {
XLlFifo_IntClear(Fifo, XLLF_INT_TRC_MASK);
XLlFifo_TxReset(Fifo);
timeout_counter = 10000;
while ((XLlFifo_Status(Fifo) & XLLF_INT_TRC_MASK) == 0) {
timeout_counter--;
if (timeout_counter == 0) {
XLlFifo_Reset(Fifo);
/* we've reset the whole core so just exit out */
goto feh_exit;
}
}
}
feh_exit:
/*
* Bump counter
*/
DeviceErrors++;
}
/*****************************************************************************/
/**
*
* This is the Fifo handler function and will increment a shared
* counter that can be tested by the main thread of operation.
*
* @param Fifo is a reference to the Fifo instance.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void FifoHandler(XLlFifo *Fifo)
{
u32 Pending = XLlFifo_IntPending(Fifo);
while (Pending) {
if (Pending & XLLF_INT_RC_MASK) {
/*
* Receive the frame, unless we are deferring the
* receive.
*/
if (DeferRx) {
FramesRxInts++; /* We can count the interrupts,
* but in the handler we don't
* exactly know how many frames
* as we could get one int for
* multiple frames.
*/
/*
* use for example 3: Disable receive
* interrupts to defer frame reception
* to the example function.
*/
XLlFifo_IntDisable(Fifo, XLLF_INT_RC_MASK);
}
else {
FifoRecvHandler(Fifo);
}
XLlFifo_IntClear(Fifo, XLLF_INT_RC_MASK);
}
else if (Pending & XLLF_INT_TC_MASK) {
FramesTxInts++; /* We can count the interrupts, but in
* the handler we don't exactly know
* how many frames as we could get one
* int for multiple frames.
*/
XLlFifo_IntClear(Fifo, XLLF_INT_TC_MASK);
}
else if (Pending & XLLF_INT_ERROR_MASK){
FifoErrorHandler(Fifo, Pending);
XLlFifo_IntClear(Fifo, XLLF_INT_ERROR_MASK);
} else {
XLlFifo_IntClear(Fifo, Pending);
}
Pending = XLlFifo_IntPending(Fifo);
}
}
/*****************************************************************************/
/**
*
* This is the Error handler callback function and this function increments the
* the error counter so that the main thread knows the number of errors.
*
* @param AxiEthernet is a reference to the AxiEthernet device instance.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet)
{
u32 Pending = XAxiEthernet_IntPending(AxiEthernet);
if (Pending & XAE_INT_RXRJECT_MASK) {
AxiEthernetUtilErrorTrap("AxiEthernet: Rx packet rejected");
}
if (Pending & XAE_INT_RXFIFOOVR_MASK) {
AxiEthernetUtilErrorTrap("AxiEthernet: Rx fifo over run");
}
XAxiEthernet_IntClear(AxiEthernet, Pending);
/*
* Bump counter
*/
DeviceErrors++;
}
/******************************************************************************/
/**
* This function resets the device but preserves the options set by the user.
*
* @param AxiEthernetInstancePtr is a pointer to the instance of the
* AxiEthernet component.
* @param FifoInstancePtr is a pointer to the instance of the Fifo
* component.
*
* @return - XST_SUCCESS to indicate success.
* - XST_FAILURE.to indicate failure.
*
* @note None.
*
******************************************************************************/
static int AxiEthernetResetDevice(XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr)
{
int Status;
u8 MacSave[6];
u32 Options;
/*
* Stop the Axi Ethernet device
*/
XAxiEthernet_Stop(AxiEthernetInstancePtr);
/*
* Save the device state
*/
XAxiEthernet_GetMacAddress(AxiEthernetInstancePtr, MacSave);
Options = XAxiEthernet_GetOptions(AxiEthernetInstancePtr);
/*
* Stop and reset the Axi Ethernet device
*/
XAxiEthernet_Reset(AxiEthernetInstancePtr);
/*
* reset the fifo
*/
XLlFifo_Reset(FifoInstancePtr);
/*
* Restore the state
*/
Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, MacSave);
Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr, Options);
Status |= XAxiEthernet_ClearOptions(AxiEthernetInstancePtr, ~Options);
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap("Error restoring state after reset");
return XST_FAILURE;
}
/*
* Restart the device
*/
XAxiEthernet_Start(AxiEthernetInstancePtr);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function setups the interrupt system so interrupts can occur for the
* Axi Ethernet. This function is application-specific since the actual system
* may or may not have an interrupt controller. The Axi Ethernet could be
* directly connected to a processor without an interrupt controller. The user
* should modify this function to fit the application.
*
* @param IntcInstancePtr is a pointer to the instance of the Intc component.
* @param AxiEthernetInstancePtr is a pointer to the instance of the
* AxiEthernet component.
* @param FifoInstancePtr is a pointer to the instance of the AXIFIFO
* component.
* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device ,
* typically XPAR__DEVICE_ID value from
* xparameters.h.
* @param AxiEthernetIntrId is the Interrupt ID and is typically
* XPAR___VEC_ID
* value from xparameters.h.
* @param FifoIntrId is the interrupt id fifo.
*
* @return - XST_SUCCESS to indicate success.
* - XST_FAILURE.to indicate failure.
*
* @note None.
*
******************************************************************************/
static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr,
XAxiEthernet *AxiEthernetInstancePtr,
XLlFifo *FifoInstancePtr,
u16 AxiEthernetIntrId, u16 FifoIntrId)
{
int Status;
#ifdef XPAR_INTC_0_DEVICE_ID
#ifndef TESTAPP_GEN
/*
* Initialize the interrupt controller and connect the ISR
*/
Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap
("Unable to intialize the interrupt controller");
return XST_FAILURE;
}
#endif
#if XPAR_INTC_0_HAS_FAST == 1
AxiEthernetInstancePtr_Fast = AxiEthernetInstancePtr;
Fifo_Fast = FifoInstancePtr;
Status = XIntc_ConnectFastHandler(IntcInstancePtr, AxiEthernetIntrId,
(XFastInterruptHandler) AxiEthernetErrorFastHandler);
Status |= XIntc_ConnectFastHandler(IntcInstancePtr, FifoIntrId,
(XFastInterruptHandler) FifoFastHandler);
#else
Status = XIntc_Connect(IntcInstancePtr, AxiEthernetIntrId,
(XInterruptHandler) AxiEthernetErrorHandler,
AxiEthernetInstancePtr);
Status |= XIntc_Connect(IntcInstancePtr, FifoIntrId,
(XInterruptHandler) FifoHandler,
FifoInstancePtr);
#endif
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap
("Unable to connect ISR to interrupt controller");
return XST_FAILURE;
}
#ifndef TESTAPP_GEN
/*
* Start the interrupt controller
*/
Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
if (Status != XST_SUCCESS) {
AxiEthernetUtilErrorTrap("Error starting intc");
return XST_FAILURE;
}
#endif
/*
* Enable interrupts from the hardware
*/
XIntc_Enable(IntcInstancePtr, AxiEthernetIntrId);
XIntc_Enable(IntcInstancePtr, FifoIntrId);
#else
XScuGic_Config *IntcConfig;
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(IntcInstancePtr, FifoIntrId, 0xA0, 0x3);
XScuGic_SetPriorityTriggerType(IntcInstancePtr, AxiEthernetIntrId, 0xA0, 0x3);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(IntcInstancePtr, FifoIntrId,
(Xil_InterruptHandler)FifoHandler,
FifoInstancePtr);
if (Status != XST_SUCCESS) {
return Status;
}
Status = XScuGic_Connect(IntcInstancePtr, AxiEthernetIntrId,
(Xil_InterruptHandler)AxiEthernetErrorHandler,
AxiEthernetInstancePtr);
if (Status != XST_SUCCESS) {
return Status;
}
XScuGic_Enable(IntcInstancePtr, AxiEthernetIntrId);
XScuGic_Enable(IntcInstancePtr, FifoIntrId);
#endif
#ifndef TESTAPP_GEN
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)INTC_HANDLER,
(void *)(IntcInstancePtr));
Xil_ExceptionEnable();
#endif
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function disables the interrupts that occur for AxiEthernet.
*
* @param IntcInstancePtr is a pointer to the instance of the Intc
* component.
* @param AxiEthernetIntrId is the Interrupt ID and is typically
* XPAR___VEC_ID
* value from xparameters.h.
* @param FifoIntrId is the interrupt id for fifo.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr,
u16 AxiEthernetIntrId, u16 FifoIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_ID
/*
* Disconnect and disable the interrupt for the AxiEthernet device
*/
XIntc_Disconnect(IntcInstancePtr, AxiEthernetIntrId);
/*
* Disconnect and disable the interrupt for the Fifo device
*/
XIntc_Disconnect(IntcInstancePtr, FifoIntrId);
#else
/*
* Disconnect and disable the interrupt for the AxiEthernet device
*/
XScuGic_Disconnect(IntcInstancePtr, AxiEthernetIntrId);
/*
* Disconnect and disable the interrupt for the Fifo device
*/
XScuGic_Disconnect(IntcInstancePtr, FifoIntrId);
#endif
}
#if XPAR_INTC_0_HAS_FAST == 1
/*****************************************************************************/
/**
*
* Fast Error Handler which calls AxiEthernetErrorHandler.
*
* @param None
*
* @return None.
*
* @note None.
*
******************************************************************************/
void AxiEthernetErrorFastHandler(void)
{
AxiEthernetErrorHandler((XAxiEthernet *)AxiEthernetInstancePtr_Fast);
}
/*****************************************************************************/
/**
*
* Fast FIFO Handler which calls FifoHandler.
*
* @param None
*
* @return None.
*
* @note None.
*
******************************************************************************/
void FifoFastHandler(void)
{
FifoHandler((XLlFifo *)Fifo_Fast);
}
#endif