/****************************************************************************** * * 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_sgdma.c * * Implements examples that utilize the Axi Ethernet's interrupt driven SGDMA * packet transfer mode to send and receive frames. * * These examples demonstrate: * * - How to perform simple send and receive * - Interrupt coalescing * - Checksum offload * - Error handling * - Device reset * * Functional guide to example: * * - AxiEthernetSgDmaIntrSingleFrameExample demonstrates the simplest way to * send and receive frames in in interrupt driven SGDMA mode. * * - AxiEthernetSgDmaIntrCoalescingExample demonstrates how to use interrupt * coalescing to increase throughput. * * - AxiEthernetSgDmaPartialChecksumOffloadExample demonstrates the partial * checksum offloading. The HW must be setup for partial checksum * offloading for this example to execute. * * - AxiEthernetSgDmaFullChecksumOffloadExample demonstrates the full * checksum offloading. The HW must be setup for full checksum offloading * for this example to execute. * * - AxiEthernetAxiEthernetErrorHandler() demonstrates how to manage * asynchronous errors. * * - AxiEthernetResetDevice() demonstrates how to reset the driver/HW without * loosing all configuration settings. * *
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a asa  4/30/10  First release based on the ll temac driver
* 1.01a asa  12/10/10 Added full checksum offload example.
* 		      		  Changes made to enable the AXIDMA Tx/Rx ring interrupts
*		      		  before allocation of Tx/Rx BDs for all examples.
* 3.00a asa  6/25/12  Modifed XAxiDma_BdSetLength API call to support new
*		      		  AXI DMA driver version 7.00a. Removed the calls to
*		      		  XAxiDma_BdRingStart for the coalesce and checksum
*		      		  offload examples. They are not required with the new
*		      		  AxiDMA version.
* 3.00a bss  10/22/12 Added support for Fast Interrupt Handlers.
* 3.01a srt  02/14/13 Added support for Zynq (CR 681136).
*
* 
* ******************************************************************************/ /***************************** Include Files *********************************/ #include "xaxiethernet_example.h" #include "xaxidma.h" #include "xil_cache.h" #include "xil_exception.h" #include "stdio.h" /* stdio */ #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 AXIDMA_DEVICE_ID XPAR_AXIDMA_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 DMA_RX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR #define DMA_TX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR #else #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID #define DMA_RX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID #define DMA_TX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID #endif #endif #ifdef XPAR_INTC_0_DEVICE_ID #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID #else #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #endif #define RXBD_CNT 128 /* Number of RxBDs to use */ #define TXBD_CNT 128 /* Number of TxBDs to use */ #define BD_ALIGNMENT XAXIDMA_BD_MINIMUM_ALIGNMENT /* Byte alignment of BDs */ #define PAYLOAD_SIZE 1000 /* Payload size used in examples */ #define BD_USR0_OFFSET 0 /* AXI4-Stream Control Word offset from * the start of app user words in BD. Offset * 0 means, Control Word 0, used for enabling * checksum offloading. */ #define BD_USR1_OFFSET 1 /* AXI4-Stream Control Word offset from * the start of app user words in BD. Offset * 1 means, Control Word 1, used for * mentioning checksum begin and checksum * insert points */ #define BD_USR2_OFFSET 2 /* AXI4-Stream Control Word offset from * the start of app user words in BD. Offset * 2 means, Control Word 2, used for * mentioning checksum seed. */ #define PARTIAL_CSUM_ENABLE 0x00000001 /* Option for partial csum enable */ #define FULL_CSUM_ENABLE 0x00000002 /* Option for full csum enable */ #define TX_CS_INIT_OFFSET 16 /* Offset in the control word where * byte offset in the ethernet frame * to start CSUM calculation need to * be inserted */ #define RCV_FRM_NOT_CORRUPTED 0xFFFF /* If the received frame is not * corrupted, for partial csum * offloading case, the control * word 3 would return 0xFFFF */ #define IP_VERSION_4 0x800 /* For IPV4, the Ethernet frame * type/length field will have a * value of 0x800 */ #define IP_HEADER_VERSION 0x04 /* For IPv4, the version entry in * IP header is always 4 */ #define IP_HEADER_LEN_IN_WORDS 0x05 /* For our case, the header length * is always 20 bytes (5 words */ #define IP_HEADER_LENGTH 20 /* IP header length in bytes. Used * as offset to kigure out the start * of TCP header. */ #define IP_HEADER_PROTOCOL_TCP 0x6 /* IP header protocol entry. For TCP * packets, it is 6. */ #define IP_HEADER_PROTOCOL_UDP 0x17 /* IP header protocol entry. For UDP * packets, it is 17. */ #define TCP_HEADER_LEN_IN_WORDS 0x5 /* For our case, the header length * is always 20 bytes (5 words) */ #define TCP_HEADER_LENGTH 20 /* IP header length in bytes. Used * as offset to kigure out the start * of TCP header. */ #define FULL_CSUM_STATUS_MASK 0x00000038 /* Mask to extract full checksum * status field from AXI4 Stream * Status Word 2. */ #define FULL_CSUM_VALIDATED 0x00000002 /* If bits 3-5 in AXI4 Status word * have a value of 0x010, it means * both IP and TCP checksums have * been found to be correct. */ #define IP_TCP_CSUMS_NOT_CHECKED 0x00000000 #define IP_CSUM_OK_TCP_NOT_CHECKED 0x00000001 #define TCP_CSUM_NOT_CHECKED_IP_NOT_OK 0x00000005 #define IP_CSUM_OK_TCP_NOT_OK 0x00000006 #define DUMMY_TCP_PORT_1 0x1111 #define DUMMY_TCP_PORT_2 0x1112 /* * Number of bytes to reserve for BD space for the number of BDs desired */ #define RXBD_SPACE_BYTES (XAxiDma_BdRingMemCalc(BD_ALIGNMENT, RXBD_CNT)) #define TXBD_SPACE_BYTES (XAxiDma_BdRingMemCalc(BD_ALIGNMENT, TXBD_CNT)) /*************************** Variable Definitions ****************************/ static EthernetFrame TxFrame; /* Transmit buffer */ static EthernetFrame RxFrame; /* Receive buffer */ XAxiEthernet AxiEthernetInstance; XAxiDma DmaInstance; #if XPAR_INTC_0_HAS_FAST == 1 /* Variables for Fast Interrupt Handlers */ XAxiEthernet *AxiEthernetInstancePtr_Fast; XAxiDma_BdRing *TxRingPtr_Fast; XAxiDma_BdRing *RxRingPtr_Fast; /****** Fast Interrupt Handlers prototypes ******/ static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); static void RxIntrFastHandler(void) __attribute__ ((fast_interrupt)); static void TxIntrFastHandler(void) __attribute__ ((fast_interrupt)); #else static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr); static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr); #endif /* * Aligned memory segments to be used for buffer descriptors */ char RxBdSpace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); char TxBdSpace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); /* * Counters to be incremented by callbacks */ static volatile int FramesRx; /* Num of frames that have been received */ static volatile int FramesTx; /* Num of frames that have been sent */ static volatile int DeviceErrors;/* Num of errors detected in the device */ #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 /*************************** Function Prototypes *****************************/ /* * Examples */ int AxiEthernetSgDmaIntrExample(INTC *IntcInstancePtr, XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr, u16 AxiEthernetDeviceId, u16 AxiDmaDeviceId, u16 AxiEthernetIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId); int AxiEthernetSgDmaIntrSingleFrameExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); int AxiEthernetSgDmaIntrCoalescingExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); int AxiEthernetSgDmaPartialChecksumOffloadExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); int AxiEthernetSgDmaFullChecksumOffloadExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); /* * Interrupt setup and Callbacks for examples */ static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr, u16 AxiEthernetIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId); static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, u16 AxiEthernetIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId); void AxiEthernetPHYRegistersDump(XAxiEthernet * AxiEthernetInstancePtr); /*****************************************************************************/ /** * * 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. * * @return - 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 SGDMA interrupt example , specify the * parameters generated in xparameters.h. */ Status = AxiEthernetSgDmaIntrExample(&IntcInstance, &AxiEthernetInstance, &DmaInstance, AXIETHERNET_DEVICE_ID, AXIDMA_DEVICE_ID, AXIETHERNET_IRPT_INTR, DMA_RX_IRPT_INTR, DMA_TX_IRPT_INTR); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Failed test intr sgdma"); AxiEthernetUtilErrorTrap("--- Exiting main() ---"); return XST_FAILURE; } AxiEthernetUtilErrorTrap("Test passed"); AxiEthernetUtilErrorTrap("--- Exiting main() ---"); return XST_SUCCESS; } #endif /*****************************************************************************/ /** * * This function demonstrates the usage usage of the Axi Ethernet by sending * and receiving frames in interrupt driven SGDMA mode. * * * @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 DmaInstancePtr is a pointer to the instance of the AXIDMA * component. * @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , * typically XPAR__DEVICE_ID value from * xparameters.h. * @param AxiDmaDeviceId is Device ID of the Axi DMAA 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 DmaRxIntrId is the interrupt id for DMA Rx and is typically * taken from XPAR__CONNECTED_DMARX_INTR * @param DmaTxIntrId is the interrupt id for DMA Tx and is typically * taken from XPAR__CONNECTED_DMATX_INTR * * @return -XST_SUCCESS to indicate success * -XST_FAILURE to indicate failure * * @note AxiDma hardware must be initialized before initializing * AxiEthernet. Since AxiDma reset line is connected to the * AxiEthernet reset line, a reset of AxiDma hardware during its * initialization would reset AxiEthernet. * ******************************************************************************/ int AxiEthernetSgDmaIntrExample(INTC *IntcInstancePtr, XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr, u16 AxiEthernetDeviceId, u16 AxiDmaDeviceId, u16 AxiEthernetIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId) { int Status; int LoopbackSpeed; XAxiEthernet_Config *MacCfgPtr; XAxiDma_Config* DmaConfig; XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_Bd BdTemplate; /*************************************/ /* Setup device for first-time usage */ /*************************************/ /* * Get the configuration of AxiEthernet hardware. */ MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId); /* * Check whether DMA is present or not */ if(MacCfgPtr->AxiDevType != XPAR_AXI_DMA) { AxiEthernetUtilErrorTrap ("Device HW not configured for SGDMA mode\r\n"); return XST_FAILURE; } DmaConfig = XAxiDma_LookupConfig(AxiDmaDeviceId); /* * Initialize AXIDMA engine. AXIDMA engine must be initialized before * AxiEthernet. During AXIDMA engine initialization, AXIDMA hardware is * reset, and since AXIDMA reset line is connected to AxiEthernet, this * would ensure a reset of AxiEthernet. */ Status = XAxiDma_CfgInitialize(DmaInstancePtr, DmaConfig); if(Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error initializing DMA\r\n"); return XST_FAILURE; } /* * 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, AxiEthernetMAC); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting MAC address"); return XST_FAILURE; } /* * Setup RxBD space. * * We have already defined a properly aligned area of memory to store * RxBDs at the beginning of this source code file so just pass its * address into the function. No MMU is being used so the physical and * virtual addresses are the same. * * Setup a BD template for the Rx channel. This template will be * copied to every RxBD. We will not have to explicitly set these * again. */ /* * Disable all RX interrupts before RxBD space setup */ XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Create the RxBD ring */ Status = XAxiDma_BdRingCreate(RxRingPtr, (u32) &RxBdSpace, (u32) &RxBdSpace, BD_ALIGNMENT, RXBD_CNT); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting up RxBD space"); return XST_FAILURE; } XAxiDma_BdClear(&BdTemplate); Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error initializing RxBD space"); return XST_FAILURE; } /* * Setup TxBD space. * * Like RxBD space, we have already defined a properly aligned area of * memory to use. */ /* * Create the TxBD ring */ Status = XAxiDma_BdRingCreate(TxRingPtr, (u32) &TxBdSpace, (u32) &TxBdSpace, BD_ALIGNMENT, TXBD_CNT); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting up TxBD space"); return XST_FAILURE; } /* * We reuse the bd template, as the same one will work for both rx * and tx. */ Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error initializing TxBD space"); 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; } AxiEthernetUtilEnterLoopback(AxiEthernetInstancePtr, LoopbackSpeed); /* * 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); /* * Connect to the interrupt controller and enable interrupts */ Status = AxiEthernetSetupIntrSystem(IntcInstancePtr, AxiEthernetInstancePtr, DmaInstancePtr, AxiEthernetIntrId, DmaRxIntrId, DmaTxIntrId); /****************************/ /* Run through the examples */ /****************************/ /* * Run the AxiEthernet DMA Single Frame Interrupt example */ Status = AxiEthernetSgDmaIntrSingleFrameExample(AxiEthernetInstancePtr, DmaInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Run the Axi Ethernet DMA Interrupt Coalescing example */ Status = AxiEthernetSgDmaIntrCoalescingExample(AxiEthernetInstancePtr, DmaInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Tx/Rx Partial checksum offload will be disabled when any of * Tx/Rx VLAN features are built in hardware. */ if (XAxiEthernet_IsRxPartialCsum(AxiEthernetInstancePtr) && XAxiEthernet_IsTxPartialCsum(AxiEthernetInstancePtr) && !XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && !XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && !XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && !XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && !XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && !XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr)) { Status = AxiEthernetSgDmaPartialChecksumOffloadExample (AxiEthernetInstancePtr,DmaInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } } /* * Tx/Rx Full checksum offload will be disabled when any of * Tx/Rx VLAN features are built in hardware. */ if (XAxiEthernet_IsRxFullCsum(AxiEthernetInstancePtr) && XAxiEthernet_IsTxFullCsum(AxiEthernetInstancePtr) && !XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && !XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && !XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && !XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && !XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && !XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr)) { Status = AxiEthernetSgDmaFullChecksumOffloadExample (AxiEthernetInstancePtr,DmaInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } } /* * Disable the interrupts for the Axi Ethernet device */ AxiEthernetDisableIntrSystem(IntcInstancePtr, AxiEthernetIntrId, DmaRxIntrId, DmaTxIntrId); /* * 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 SGDMA interrupt mode. * The source packet will be described by two descriptors. It will be received * into a buffer described by a single descriptor. * * @param AxiEthernetInstancePtr is a pointer to the instance of the * Axi Ethernet component. * @param DmaInstancePtr is a pointer to the instance of the Dma * component. * * @return -XST_SUCCESS to indicate success * -XST_FAILURE to indicate failure * * @note None. * ******************************************************************************/ int AxiEthernetSgDmaIntrSingleFrameExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) { int Status; u32 TxFrameLength; u32 RxFrameLength; int PayloadSize = PAYLOAD_SIZE; XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_Bd *Bd1Ptr; XAxiDma_Bd *Bd2Ptr; XAxiDma_Bd *BdCurPtr; u32 BdSts; /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; memset(RxFrame,0,sizeof(RxFrame)); memset(TxFrame,0,sizeof(TxFrame)); /* * Calculate the frame length (not including FCS) */ TxFrameLength = XAE_HDR_SIZE + PayloadSize; /* * Setup packet to be transmitted */ AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); /* * Flush the TX frame before giving it to DMA TX channel to transmit. */ Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); /* * Clear out receive packet memory area */ AxiEthernetUtilFrameMemClear(&RxFrame); /* * Invalidate the RX frame before giving it to DMA RX channel to * receive data. */ Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); /* * Make sure Tx and Rx are enabled */ Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_RECEIVER_ENABLE_OPTION | XAE_TRANSMITTER_ENABLE_OPTION); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting options"); return XST_FAILURE; } /* * Start the Axi Ethernet device and enable the ERROR interrupt */ XAxiEthernet_Start(AxiEthernetInstancePtr); XAxiEthernet_IntEnable(AxiEthernetInstancePtr, XAE_INT_RECV_ERROR_MASK); /* * Enable DMA RX interrupt. * * Interrupt coalescing parameters are left at their default settings * which is to interrupt the processor after every frame has been * processed by the DMA engine. */ XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate 1 RxBD. */ Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &Bd1Ptr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating RxBD"); return XST_FAILURE; } /* * Setup the BD. */ XAxiDma_BdSetBufAddr(Bd1Ptr, (u32)&RxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(Bd1Ptr, sizeof(RxFrame)); #else XAxiDma_BdSetLength(Bd1Ptr, sizeof(RxFrame), RxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(Bd1Ptr, 0); /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(RxRingPtr, 1, Bd1Ptr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); return XST_FAILURE; } /* * Start DMA RX channel. Now it's ready to receive data. */ Status = XAxiDma_BdRingStart(RxRingPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Enable DMA transmit interrupts */ XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate, setup, and enqueue 2 TxBDs. The first BD will describe * the first 32 bytes of TxFrame and the second BD will describe the * rest of the frame. * * The function below will allocate two adjacent BDs with Bd1Ptr being * set as the lead BD. */ Status = XAxiDma_BdRingAlloc(TxRingPtr, 2, &Bd1Ptr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating TxBD"); return XST_FAILURE; } /* * Setup TxBD #1 */ XAxiDma_BdSetBufAddr(Bd1Ptr, (u32)&TxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(Bd1Ptr, 32); #else XAxiDma_BdSetLength(Bd1Ptr, 32, TxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(Bd1Ptr, XAXIDMA_BD_CTRL_TXSOF_MASK); /* * Setup TxBD #2 */ Bd2Ptr = XAxiDma_BdRingNext(TxRingPtr, Bd1Ptr); XAxiDma_BdSetBufAddr(Bd2Ptr, (u32) (&TxFrame) + 32); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(Bd2Ptr, TxFrameLength - 32); #else XAxiDma_BdSetLength(Bd2Ptr, TxFrameLength - 32, TxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(Bd2Ptr, XAXIDMA_BD_CTRL_TXEOF_MASK); /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(TxRingPtr, 2, Bd1Ptr); if (Status != XST_SUCCESS) { /* * Undo BD allocation and exit */ XAxiDma_BdRingUnAlloc(TxRingPtr, 2, Bd1Ptr); AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); return XST_FAILURE; } /* * Start DMA TX channel. Transmission starts at once. */ Status = XAxiDma_BdRingStart(TxRingPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Wait for transmission to complete */ while (!FramesTx); /* * Now that the frame has been sent, post process our TxBDs. * Since we have only submitted 2 to HW, then there should be only 2 ready * for post processing. */ if (XAxiDma_BdRingFromHw(TxRingPtr, 2, &Bd1Ptr) == 0) { AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); return XST_FAILURE; } /* * Examine the TxBDs. * * There isn't much to do. The only thing to check would be DMA exception * bits. But this would also be caught in the error handler. So we just * return these BDs to the free list */ Status = XAxiDma_BdRingFree(TxRingPtr, 2, Bd1Ptr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Wait for Rx indication */ while (!FramesRx); /* * Now that the frame has been received, post process our RxBD. * Since we have only submitted 1 to HW, then there should be only 1 * ready for post processing. */ if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &Bd1Ptr) == 0) { AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); return XST_FAILURE; } BdCurPtr = Bd1Ptr; BdSts = XAxiDma_BdGetSts(BdCurPtr); if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { AxiEthernetUtilErrorTrap("Rx Error"); return XST_FAILURE; } else { RxFrameLength = (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; } if (RxFrameLength != TxFrameLength) { AxiEthernetUtilErrorTrap("Length mismatch"); return XST_FAILURE; } if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) { AxiEthernetUtilErrorTrap("Data mismatch"); return XST_FAILURE; } /* * Return the RxBD back to the channel for later allocation. Free the * exact number we just post processed. */ Status = XAxiDma_BdRingFree(RxRingPtr, 1, Bd1Ptr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Finished this example. If everything worked correctly, all TxBDs and * RxBDs should be free for allocation. Stop the device. */ XAxiEthernet_Stop(AxiEthernetInstancePtr); return XST_SUCCESS; } /*****************************************************************************/ /** * * This example sends frames with the interrupt coalescing settings altered * from their defaults. * * The default settings will interrupt the processor after every frame has been * sent. This example will increase the threshold resulting in lower CPU * utilization since it spends less time servicing interrupts. * * @param AxiEthernetInstancePtr is a pointer to the instance of the * Axi Ethernet component. * @param DmaInstancePtr is a pointer to the instance of the Dma * component. * * @return -XST_SUCCESS to indicate success * -XST_FAILURE to indicate failure * * @note None. * ******************************************************************************/ int AxiEthernetSgDmaIntrCoalescingExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) { int Status; u32 TxFrameLength; int PayloadSize = 100; u32 Index; u32 NumBd; u16 Threshold = 10; XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_Bd *BdPtr; XAxiDma_Bd *BdCurPtr; /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; /* * Calculate the frame length (not including FCS) */ TxFrameLength = XAE_HDR_SIZE + PayloadSize; /* * Setup packet to be transmitted. The same packet will be * transmitted over and over */ AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); /* * Flush the TX frame before giving it to DMA TX channel to transmit. */ Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); /* * Make sure Tx and Rx are enabled */ Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_TRANSMITTER_ENABLE_OPTION); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting options"); return XST_FAILURE; } /* * We don't care about the receive channel for this example, * so turn it off, in case it was turned on earlier. */ Status = XAxiEthernet_ClearOptions(AxiEthernetInstancePtr, XAE_RECEIVER_ENABLE_OPTION); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error clearing option"); return XST_FAILURE; } /* * Set the interrupt coalescing parameters for the test. The waitbound * timer is set to 1 (ms) to catch the last few frames. * * If you set variable Threshold to some value larger than TXBD_CNT, * then there can never be enough frames sent to meet the threshold. * In this case the waitbound timer will always cause the interrupt to * occur. */ Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, Threshold, 255); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting coalescing settings"); return XST_FAILURE; } /* * Enable the send interrupts. Nothing should be transmitted yet as the * device has not been started */ XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Prime the engine, allocate all BDs and assign them to the same buffer */ Status = XAxiDma_BdRingAlloc(TxRingPtr, Threshold, &BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating TxBDs prior to starting"); return XST_FAILURE; } /* * Setup the TxBDs */ BdCurPtr = BdPtr; for (Index = 0; Index < Threshold; Index++) { XAxiDma_BdSetBufAddr(BdCurPtr, (u32)&TxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(BdCurPtr, TxFrameLength); #else XAxiDma_BdSetLength(BdCurPtr, TxFrameLength, TxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(BdCurPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK); BdCurPtr = XAxiDma_BdRingNext(TxRingPtr, BdCurPtr); } /* * Enqueue all TxBDs to HW */ Status = XAxiDma_BdRingToHw(TxRingPtr, Threshold, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing TxBDs prior to starting"); return XST_FAILURE; } /* * Start the device. Transmission commences now! */ XAxiEthernet_Start(AxiEthernetInstancePtr); /* * Wait for the interrupt */ while (!FramesTx); NumBd = XAxiDma_BdRingFromHw(TxRingPtr, Threshold, &BdPtr); if (NumBd != Threshold) { AxiEthernetUtilErrorTrap("Error in interrupt coalescing"); } else { /* * Don't bother to check the BDs status, just free them */ Status = XAxiDma_BdRingFree(TxRingPtr, Threshold, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing TxBDs"); } } /* * Done sending frames. Stop the device */ XAxiEthernet_Stop(AxiEthernetInstancePtr); return XST_SUCCESS; } /*****************************************************************************/ /** * * This example sends and receives a single packet in loopback mode with * checksum offloading support. * * The transmit frame will be checksummed over the entire Ethernet payload * and inserted into the last 2 bytes of the frame. * * On receive, HW should calculate the Ethernet payload checksum and return a * value of 0xFFFF which means the payload data was likely not corrupted. * * @param AxiEthernetInstancePtr is a pointer to the instance of the * AxiEthernet component. * @param DmaInstancePtr is a pointer to the instance of the Dma * component. * * @return -XST_SUCCESS to indicate success * -XST_FAILURE to indicate failure * * @note None. * ******************************************************************************/ int AxiEthernetSgDmaPartialChecksumOffloadExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) { int Status; u32 TxFrameLength; u32 RxFrameLength; int PayloadSize = PAYLOAD_SIZE; XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_Bd *BdPtr; XAxiDma_Bd *BdCurPtr; u32 BdSts; /* * Cannot run this example if partial checksum offloading support is not * available */ if (!(XAxiEthernet_IsRxPartialCsum(AxiEthernetInstancePtr) && XAxiEthernet_IsTxPartialCsum(AxiEthernetInstancePtr))) { AxiEthernetUtilErrorTrap("Partial Checksum offloading not available"); return XST_FAILURE; } /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; memset(RxFrame,0,sizeof(RxFrame)); memset(TxFrame,0,sizeof(TxFrame)); /* * Calculate frame length (not including FCS) */ TxFrameLength = XAE_HDR_SIZE + PayloadSize; /* * Setup the packet to be transmitted, * Last 2 bytes are reserved for checksum */ AxiEthernetUtilFrameMemClear(&TxFrame); AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize - 2); /* * Flush the TX frame before giving it to DMA TX channel to transmit. */ Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); /* * Clear out receive packet memory area */ AxiEthernetUtilFrameMemClear(&RxFrame); /* * Invalidate the RX frame before giving it to DMA RX channel to * receive data. */ Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); /* * Interrupt coalescing parameters are set to their default settings * which is to interrupt the processor after every frame has been * processed by the DMA engine. */ Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting coalescing for transmit"); return XST_FAILURE; } Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, 1, 1); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting coalescing for recv"); return XST_FAILURE; } /* * Make sure Tx and Rx are enabled */ Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_RECEIVER_ENABLE_OPTION | XAE_TRANSMITTER_ENABLE_OPTION); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting options"); return XST_FAILURE; } /* * Start the Axi Ethernet and enable its ERROR interrupts */ XAxiEthernet_Start(AxiEthernetInstancePtr); XAxiEthernet_IntEnable(AxiEthernetInstancePtr, XAE_INT_RECV_ERROR_MASK); /* * Enable DMA receive related interrupts */ XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate 1 RxBD. */ Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating RxBD"); return XST_FAILURE; } /* * Setup the BD. */ XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame)); #else XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame), RxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(BdPtr, 0); /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(RxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); return XST_FAILURE; } /* * Enable DMA transmit related interrupts */ XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate 1 TxBD */ Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating TxBD"); return XST_FAILURE; } /* * Setup the TxBD */ XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(BdPtr, TxFrameLength); #else XAxiDma_BdSetLength(BdPtr, TxFrameLength, TxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK); /* * Setup TxBd checksum offload attributes. * Note that the checksum offload values can be set globally for all * TxBds when XAxiDma_BdRingClone() is called to setup Tx BD space. * This would eliminate the need to set them here. */ /* Enable hardware checksum computation for the buffer descriptor */ Status = XAxiDma_BdSetAppWord(BdPtr,BD_USR0_OFFSET,PARTIAL_CSUM_ENABLE); if(Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error in enabling partial csum offloading"); return XST_FAILURE; } /* Write Start Offset and Insert Offset into BD */ Status = XAxiDma_BdSetAppWord(BdPtr,BD_USR1_OFFSET, ((XAE_HDR_SIZE << TX_CS_INIT_OFFSET) | (TxFrameLength - 2))); if(Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error in setting csum insert point"); return XST_FAILURE; } /* Write 0, as the seed value, to the BD */ Status = XAxiDma_BdSetAppWord(BdPtr,BD_USR2_OFFSET,0); if(Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error in enabling partial csum offloading"); return XST_FAILURE; } /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); return XST_FAILURE; } /* * Wait for transmission to complete */ while (!FramesTx); /* * Now that the frame has been sent, post process our TxBDs. * Since we have only submitted 2 to HW, then there should be only 2 ready * for post processing. */ if (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); return XST_FAILURE; } /* * Examine the TxBDs. * * There isn't much to do. The only thing to check would be DMA exception * bits. But this would also be caught in the error handler. So we just * return these BDs to the free list */ Status = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Wait for Rx indication */ while (!FramesRx); /* * Now that the frame has been received, post process our RxBD. * Since we have only submitted 1 to HW, then there should be only 1 ready * for post processing. */ if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); return XST_FAILURE; } /* * There is no device status to check. If there was a DMA error, it * should have been reported to the error handler. Check the receive * length against the transmitted length, then verify the data. * * Note in Axi Ethernet case, USR4_OFFSET word in the RX BD is used to store * the real length of the received packet */ BdCurPtr = BdPtr; BdSts = XAxiDma_BdGetSts(BdCurPtr); if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { AxiEthernetUtilErrorTrap("Rx Error"); return XST_FAILURE; } else { RxFrameLength = (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; } if (RxFrameLength != TxFrameLength) { AxiEthernetUtilErrorTrap("Length mismatch"); return XST_FAILURE; } /* * Verify the checksum as computed by HW. It should add up to 0xFFFF * if frame was uncorrupted */ if ((u16) (XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR3_OFFSET)) != RCV_FRM_NOT_CORRUPTED) { AxiEthernetUtilErrorTrap("Rx checksum incorrect"); return XST_FAILURE; } /* * Return the RxBD back to the channel for later allocation. Free the * exact number we just post processed. */ Status = XAxiDma_BdRingFree(RxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Finished this example. If everything worked correctly, all TxBDs * and RxBDs should be free for allocation. Stop the device. */ XAxiEthernet_Stop(AxiEthernetInstancePtr); return XST_SUCCESS; } /*****************************************************************************/ /** * * This example sends and receives a single packet in loopback mode with * full checksum offloading support. * * An Ethernet frame is formed with IP header, TCP header and payload. The * hardware calculates the IP Header checksum and populates it at the * appropriate location in the IP header. Similarly, the hardware calculates * the TCP Pseudo header from IP header and calculates TCP checksum for TCP * Pseudo header, TCP header and TCP payload. It then populates the checksum * in the TCP header. * The Ethernet frame is then looped back and received. The hardware validates * the IP header checksum and the TCP checksum. * The example retrieves the checksum validation information from the AXI4- * Stream Appword2. * * @param AxiEthernetInstancePtr is a pointer to the instance of the * AxiEthernet component. * @param DmaInstancePtr is a pointer to the instance of the Dma * component. * * @return -XST_SUCCESS to indicate success * -XST_FAILURE to indicate failure * * @note None. * ******************************************************************************/ int AxiEthernetSgDmaFullChecksumOffloadExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) { int Status; u32 TxFrameLength; u32 RxFrameLength; int PayloadSize = 64; XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_Bd *BdPtr; XAxiDma_Bd *BdCurPtr; u32 BdSts; u8 DummyIPAddr[4]; u32 FullCsumStatus; u8 *IPHdrPntr; u8 *TCPHdrPntr; u16 TempShortToCopy; u8 *PtrToCopyShort; /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; memset(RxFrame,0,sizeof(RxFrame)); memset(TxFrame,0,sizeof(TxFrame)); /* * Calculate frame length (not including FCS) */ TxFrameLength = XAE_HDR_SIZE + IP_HEADER_LENGTH + TCP_HEADER_LENGTH + PayloadSize ; /* * Setup the Ethernet frame header. */ AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); AxiEthernetUtilFrameHdrFormatType(&TxFrame, IP_VERSION_4); /* * Setup the IP header. */ IPHdrPntr = (u8 *)((u8 *)(TxFrame) + XAE_HDR_SIZE); /* * Form the version and IP header length. Version is 4 for IP * and length is 5 words */ *IPHdrPntr++ = (IP_HEADER_VERSION << 4) | IP_HEADER_LEN_IN_WORDS; /* Type of service is not important for this example */ *IPHdrPntr++ = 0x00; /* * Total length in bytes. This will be our payload size in this example */ TempShortToCopy = Xil_Htons(PayloadSize + IP_HEADER_LENGTH + TCP_HEADER_LENGTH); PtrToCopyShort = (u8 *)(&TempShortToCopy); *IPHdrPntr++ = PtrToCopyShort[0]; *IPHdrPntr++ = PtrToCopyShort[1]; /* * Fill the IP Identification (16 bit wide) field. Here it is made * as zero. */ *IPHdrPntr++ = 0; *IPHdrPntr++ = 0; /* * Fragmentation is not allowed for full checksum offloading. * Hence both the fragment offset (LS 14 bits) and fragment flags * (MS 2 bits) are set to 0. */ TempShortToCopy = Xil_Htons(0x4000); PtrToCopyShort = (u8 *)(&TempShortToCopy); *IPHdrPntr++ = PtrToCopyShort[0]; *IPHdrPntr++ = PtrToCopyShort[1]; /* * IP time to live. Let us make it 0x3F. Not important in any case for * this example. IP protocol field is 6 for TCP. */ *IPHdrPntr++ = 0x3F; *IPHdrPntr++ = IP_HEADER_PROTOCOL_TCP; /* * IP header checksum (16 bit wide) is made 0. It will be calculated * by the hardware and filled in at this place. */ *IPHdrPntr++ = 0; *IPHdrPntr++ = 0; /* * Let us use some source address (172.23.16.1) and the same destination * address. In any case the packet is looped back in the PHY and these * addresses are meaningful only for IP header checksum calculation * and Pseudo-header for TCP checksum calculation. */ DummyIPAddr[0] = 172; DummyIPAddr[1] = 23; DummyIPAddr[2] = 16; DummyIPAddr[3] = 1; memcpy(IPHdrPntr, DummyIPAddr, 4); IPHdrPntr = IPHdrPntr + 4; memcpy(IPHdrPntr, DummyIPAddr, 4); IPHdrPntr = IPHdrPntr + 4; /* * Populate the TCP header fields. */ TCPHdrPntr = (u8 *)((u8 *)(TxFrame) + XAE_HDR_SIZE + IP_HEADER_LENGTH); /* * Use some port number for source and destination for the purpose of * filling up the TCP header. */ TempShortToCopy = Xil_Htons(DUMMY_TCP_PORT_1); PtrToCopyShort = (u8 *)(&TempShortToCopy); *TCPHdrPntr++ = PtrToCopyShort[0]; *TCPHdrPntr++ = PtrToCopyShort[1]; TempShortToCopy = Xil_Htons(DUMMY_TCP_PORT_2); PtrToCopyShort = (u8 *)(&TempShortToCopy); *TCPHdrPntr++ = PtrToCopyShort[0]; *TCPHdrPntr++ = PtrToCopyShort[1]; /* * Sequence number and Ack number are of no significance in this * example. */ /* Copy TCP Seq number */ *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; /* Copy TCP Ack number */ *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; /* Size of TCP header which is 20 bytes (5 words) in normal case. */ *TCPHdrPntr++ = TCP_HEADER_LEN_IN_WORDS; *TCPHdrPntr++ = 0xF0; /* Some entry for flags */ /* * TCP Window and TCP Urgent pointer are irrelevant for this * example. Hence they are made zero. TCP Checksum will be * calculated and populated in TCP Checksum field. Hence it is * left as zero. */ /* Copy TCP Window */ *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; /* Copy TCP Checksum */ *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; /* Copy TCP Urgent pointer */ *TCPHdrPntr++ = 0; *TCPHdrPntr++ = 0; /* Now populate the payload data for the TCP packet */ AxiEthernetUtilFrameSetPayloadData((EthernetFrame *)((u8 *)(TxFrame) + IP_HEADER_LENGTH + TCP_HEADER_LENGTH), PayloadSize); /* * Flush the TX frame before giving it to DMA TX channel to transmit. */ Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); /* * Invalidate the RX frame before giving it to DMA RX channel to * receive data. */ Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); /* * Interrupt coalescing parameters are set to their default settings * which is to interrupt the processor after every frame has been * processed by the DMA engine. */ Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting coalescing for transmit"); return XST_FAILURE; } Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, 1, 1); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting coalescing for recv"); return XST_FAILURE; } /* * Make sure Tx and Rx are enabled */ Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_RECEIVER_ENABLE_OPTION | XAE_TRANSMITTER_ENABLE_OPTION); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting options"); return XST_FAILURE; } /* * Start the Axi Ethernet and enable its ERROR interrupts */ XAxiEthernet_Start(AxiEthernetInstancePtr); XAxiEthernet_IntEnable(AxiEthernetInstancePtr, XAE_INT_RECV_ERROR_MASK); /* * Enable DMA receive related interrupts */ XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate 1 RxBD. */ Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating RxBD"); return XST_FAILURE; } /* * Setup the BD. */ XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame)); #else XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame), RxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(BdPtr, 0); /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(RxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); return XST_FAILURE; } /* * Enable DMA transmit related interrupts */ XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate 1 TxBD */ Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating TxBD"); return XST_FAILURE; } /* * Setup the TxBD */ XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(BdPtr, TxFrameLength); #else XAxiDma_BdSetLength(BdPtr, TxFrameLength, TxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK); /* * Setup TxBd checksum offload attributes. */ /* Enable hardware checksum computation for the buffer descriptor */ Status = XAxiDma_BdSetAppWord(BdPtr, BD_USR0_OFFSET, FULL_CSUM_ENABLE); if(Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error in enabling full csum offloading"); return XST_FAILURE; } /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); return XST_FAILURE; } /* * Wait for transmission to complete */ while (!FramesTx); /* * Now that the frame has been sent, post process our TxBDs. * Since we have only submitted 1 to HW, then there should be only 1 ready * for post processing. */ if (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); return XST_FAILURE; } /* * Examine the TxBDs. * * There isn't much to do. The only thing to check would be DMA exception * bits. But this would also be caught in the error handler. So we just * return these BDs to the free list */ Status = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Wait for Rx indication */ while (!FramesRx); /* * Now that the frame has been received, post process our RxBD. * Since we have only submitted 1 to HW, then there should be only 1 ready * for post processing. */ if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); return XST_FAILURE; } /* * There is no device status to check. If there was a DMA error, it * should have been reported to the error handler. Check the receive * length against the transmitted length, then verify the data. * * Note in Axi Ethernet case, USR4_OFFSET word in the RX BD is used to store * the real length of the received packet */ BdCurPtr = BdPtr; BdSts = XAxiDma_BdGetSts(BdCurPtr); if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { AxiEthernetUtilErrorTrap("Rx Error"); return XST_FAILURE; } else { RxFrameLength = (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; } if (RxFrameLength != TxFrameLength) { AxiEthernetUtilErrorTrap("Length mismatch"); return XST_FAILURE; } /* * Read the full checksum validation status from AXI4 Status Word. */ FullCsumStatus = (((XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR2_OFFSET)) & FULL_CSUM_STATUS_MASK) >> 3); if (FullCsumStatus != FULL_CSUM_VALIDATED) { if(FullCsumStatus == IP_TCP_CSUMS_NOT_CHECKED) { AxiEthernetUtilErrorTrap("IP and TCP checksums not checked"); return XST_FAILURE; } else if(FullCsumStatus == IP_CSUM_OK_TCP_NOT_CHECKED) { AxiEthernetUtilErrorTrap("IP checksum is OK, TCP checksum not checked for"); return XST_FAILURE; } else if(FullCsumStatus == TCP_CSUM_NOT_CHECKED_IP_NOT_OK) { AxiEthernetUtilErrorTrap("IP checksum is not correct, TCP checksum not checked for"); return XST_FAILURE; } else if(FullCsumStatus == IP_CSUM_OK_TCP_NOT_OK) { AxiEthernetUtilErrorTrap("IP checksum is correct, TCP checksum is incorrect"); return XST_FAILURE; } else { AxiEthernetUtilErrorTrap("IP and TCP checksums not validated because of other reasons"); return XST_FAILURE; } } /* * Return the RxBD back to the channel for later allocation. Free the * exact number we just post processed. */ Status = XAxiDma_BdRingFree(RxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Finished this example. If everything worked correctly, all TxBDs * and RxBDs should be free for allocation. Stop the device. */ XAxiEthernet_Stop(AxiEthernetInstancePtr); return XST_SUCCESS; } /*****************************************************************************/ /** * * This is the DMA TX callback function to be called by TX interrupt handler. * This function handles BDs finished by hardware. * * @param TxRingPtr is a pointer to TX channel of the DMA engine. * * @return None. * * @note None. * ******************************************************************************/ static void TxCallBack(XAxiDma_BdRing *TxRingPtr) { /* * Disable the transmit related interrupts */ XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Increment the counter so that main thread knows something happened */ FramesTx++; } /*****************************************************************************/ /** * * This is the DMA TX Interrupt handler function. * * @param TxRingPtr is a pointer to TX channel of the DMA engine. * * @return None. * * @note This Interrupt handler MUST clear pending interrupts before * handling them by calling the call back. Otherwise the following * corner case could raise some issue: * * A packet got transmitted and a TX interrupt got asserted. If * the interrupt handler calls the callback before clearing the * interrupt, a new packet may get transmitted in the callback. * This new packet then can assert one more TX interrupt before * the control comes out of the callback function. Now when * eventually control comes out of the callback function, it will * never know about the second new interrupt and hence while * clearing the interrupts, would clear the new interrupt as well * and will never process it. * To avoid such cases, interrupts must be cleared before calling * the callback. * ******************************************************************************/ static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr) { u32 IrqStatus; /* Read pending interrupts */ IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr); /* Acknowledge pending interrupts */ XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus); /* * If no interrupt is asserted, raise error flag, reset the * hardware to recover from the error, and return with no further * processing. */ if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { DeviceErrors++; AxiEthernetUtilErrorTrap ("AXIDma: No interrupts asserted in TX status register"); XAxiDma_Reset(&DmaInstance); if(!XAxiDma_ResetIsDone(&DmaInstance)) { AxiEthernetUtilErrorTrap ("AxiDMA: Error: Could not reset\n"); } return; } /* * If error interrupt is asserted, raise error flag, reset the * hardware to recover from the error, and return with no further * processing. */ if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { AxiEthernetUtilErrorTrap("AXIDMA: TX Error interrupts\n"); /* Reset should never fail for transmit channel */ XAxiDma_Reset(&DmaInstance); if(!XAxiDma_ResetIsDone(&DmaInstance)) { AxiEthernetUtilErrorTrap ("AXIDMA: Error: Could not reset\n"); } return; } /* * If Transmit done interrupt is asserted, call TX call back function * to handle the processed BDs and raise the according flag */ if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { TxCallBack(TxRingPtr); } } /*****************************************************************************/ /** * * This is the DMA RX callback function to be called by RX interrupt handler. * This function handles finished BDs by hardware, attaches new buffers to those * BDs, and give them back to hardware to receive more incoming packets * * @param RxRingPtr is a pointer to RX channel of the DMA engine. * * @return None. * * @note None. * ******************************************************************************/ static void RxCallBack(XAxiDma_BdRing *RxRingPtr) { /* * Disable the receive related interrupts */ XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Increment the counter so that main thread knows something * happened */ FramesRx++; } /*****************************************************************************/ /** * * This is the Receive handler function for examples 1 and 2. * It will increment a shared counter, receive and validate the frame. * * @param RxRingPtr is a pointer to the DMA ring instance. * * @return None. * * @note None. * ******************************************************************************/ static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr) { u32 IrqStatus; /* Read pending interrupts */ IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr); /* Acknowledge pending interrupts */ XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus); /* * If no interrupt is asserted, raise error flag, reset the * hardware to recover from the error, and return with no further * processing. */ if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { DeviceErrors++; AxiEthernetUtilErrorTrap ("AXIDma: No interrupts asserted in RX status register"); XAxiDma_Reset(&DmaInstance); if(!XAxiDma_ResetIsDone(&DmaInstance)) { AxiEthernetUtilErrorTrap ("Could not reset\n"); } return; } /* * If error interrupt is asserted, raise error flag, reset the * hardware to recover from the error, and return with no further * processing. */ if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { AxiEthernetUtilErrorTrap("AXIDMA: RX Error interrupts\n"); /* * Reset could fail and hang * NEED a way to handle this or do not call it?? */ XAxiDma_Reset(&DmaInstance); if(!XAxiDma_ResetIsDone(&DmaInstance)) { AxiEthernetUtilErrorTrap ("AXIDMA: Could not reset\n"); } return; } /* * If Reception done interrupt is asserted, call RX call back function * to handle the processed BDs and then raise the according flag. */ if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { RxCallBack(RxRingPtr); } } /*****************************************************************************/ /** * * 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 Axi Ethernet 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 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 DmaInstancePtr is a pointer to the instance of the AXIDMA * component. * @param AxiEthernetIntrId is the Interrupt ID and is typically * XPAR___VEC_ID * value from xparameters.h. * @param DmaRxIntrId is the interrupt id for DMA Rx and is typically * taken from XPAR__CONNECTED_DMARX_INTR * @param DmaTxIntrId is the interrupt id for DMA Tx and is typically * taken from XPAR__CONNECTED_DMATX_INTR * * @return -XST_SUCCESS to indicate success * -XST_FAILURE to indicate failure * * @note None. * ******************************************************************************/ static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr, u16 AxiEthernetIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId) { XAxiDma_BdRing * TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_BdRing * RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); 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 TxRingPtr_Fast = TxRingPtr; RxRingPtr_Fast = RxRingPtr; AxiEthernetInstancePtr_Fast = AxiEthernetInstancePtr; Status = XIntc_ConnectFastHandler(IntcInstancePtr, AxiEthernetIntrId, (XFastInterruptHandler) AxiEthernetErrorFastHandler); Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaTxIntrId, (XFastInterruptHandler) TxIntrFastHandler); Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaRxIntrId, (XFastInterruptHandler) RxIntrFastHandler); #else Status = XIntc_Connect(IntcInstancePtr, AxiEthernetIntrId, (XInterruptHandler)AxiEthernetErrorHandler, AxiEthernetInstancePtr); Status |= XIntc_Connect(IntcInstancePtr, DmaTxIntrId, (XInterruptHandler) TxIntrHandler, TxRingPtr); Status |= XIntc_Connect(IntcInstancePtr, DmaRxIntrId, (XInterruptHandler) RxIntrHandler, RxRingPtr); #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, DmaTxIntrId); XIntc_Enable(IntcInstancePtr, DmaRxIntrId); #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, DmaTxIntrId, 0xA0, 0x3); XScuGic_SetPriorityTriggerType(IntcInstancePtr, DmaRxIntrId, 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, DmaTxIntrId, (Xil_InterruptHandler)TxIntrHandler, TxRingPtr); if (Status != XST_SUCCESS) { return Status; } Status = XScuGic_Connect(IntcInstancePtr, DmaRxIntrId, (Xil_InterruptHandler)RxIntrHandler, RxRingPtr); 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, DmaTxIntrId); XScuGic_Enable(IntcInstancePtr, DmaRxIntrId); #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 DmaRxIntrId is the interrupt id for DMA Rx and is typically * taken from XPAR__CONNECTED_DMARX_INTR * @param DmaTxIntrId is the interrupt id for DMA Tx and is typically * taken from XPAR__CONNECTED_DMATX_INTR * * @return None. * * @note None. * ******************************************************************************/ static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, u16 AxiEthernetIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId) { #ifdef XPAR_INTC_0_DEVICE_ID /* * Disconnect the interrupts for the DMA TX and RX channels */ XIntc_Disconnect(IntcInstancePtr, DmaTxIntrId); XIntc_Disconnect(IntcInstancePtr, DmaRxIntrId); /* * Disconnect and disable the interrupt for the AxiEthernet device */ XIntc_Disconnect(IntcInstancePtr, AxiEthernetIntrId); #else /* * Disconnect the interrupts for the DMA TX and RX channels */ XScuGic_Disconnect(IntcInstancePtr, DmaTxIntrId); XScuGic_Disconnect(IntcInstancePtr, DmaRxIntrId); /* * Disconnect and disable the interrupt for the AxiEthernet device */ XScuGic_Disconnect(IntcInstancePtr, AxiEthernetIntrId); #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 Tramsmit Handler which calls TxIntrHandler. * * @param None * * @return None. * * @note None. * ******************************************************************************/ void TxIntrFastHandler(void) { TxIntrHandler((XAxiDma_BdRing *)TxRingPtr_Fast); } /*****************************************************************************/ /** * * Fast Receive Handler which calls RxIntrHandler. * * @param None * * @return None. * * @note None. * ******************************************************************************/ void RxIntrFastHandler(void) { RxIntrHandler((XAxiDma_BdRing *)RxRingPtr_Fast); } #endif