]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2822 1d2547de-c912-0410...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / Zynq / x_emacpsif_dma.c
index 13a62852d4de046ef505ce189a59e6f49d0879cd..fc09d218335022fd0750a72d6ceb635138ca90e7 100644 (file)
-/*
-FreeRTOS+TCP V2.0.11
-Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  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.
-
-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 AUTHORS OR
-COPYRIGHT HOLDERS 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.
-
- http://aws.amazon.com/freertos
- http://www.FreeRTOS.org
-*/
-
-#include "Zynq/x_emacpsif.h"
-#include "Zynq/x_topology.h"
-#include "xstatus.h"
-
-#include "xparameters.h"
-#include "xparameters_ps.h"
-#include "xil_exception.h"
-#include "xil_mmu.h"
-
-#include "FreeRTOS.h"
-#include "task.h"
-#include "timers.h"
-#include "semphr.h"
-
-/* FreeRTOS+TCP includes. */
-#include "FreeRTOS_IP.h"
-#include "FreeRTOS_Sockets.h"
-#include "FreeRTOS_IP_Private.h"
-#include "NetworkBufferManagement.h"
-
-#include "uncached_memory.h"
-
-/* Two defines used to set or clear the EMAC interrupt */
-#define INTC_BASE_ADDR         XPAR_SCUGIC_CPU_BASEADDR
-#define INTC_DIST_BASE_ADDR    XPAR_SCUGIC_DIST_BASEADDR
-
-
-
-#if( ipconfigPACKET_FILLER_SIZE != 2 )
-       #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
-#endif
-#define TX_OFFSET                              ipconfigPACKET_FILLER_SIZE
-
-#define RX_BUFFER_ALIGNMENT    14
-
-/* Defined in NetworkInterface.c */
-extern TaskHandle_t xEMACTaskHandle;
-
-/*
-       pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
-       The actual TX buffers are located in uncached RAM.
-*/
-static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
-
-/*
-       pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
-       Once a message has been received by the EMAC, the descriptor can be passed
-       immediately to the IP-task.
-*/
-static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
-
-/*
-       The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
-       ./portable/NetworkInterface/Zynq/NetworkInterface.c
-*/
-extern struct xtopology_t xXTopology;
-
-static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
-
-/*
-       The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
-       In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
-       "head" is the next index to be written, used.
-       "tail" is the next index to be read, freed.
-*/
-
-int is_tx_space_available( xemacpsif_s *xemacpsif )
-{
-size_t uxCount;
-
-       if( xTXDescriptorSemaphore != NULL )
-       {
-               uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
-       }
-       else
-       {
-               uxCount = ( UBaseType_t ) 0u;
-       }
-
-       return uxCount;
-}
-
-void emacps_check_tx( xemacpsif_s *xemacpsif )
-{
-int tail = xemacpsif->txTail;
-int head = xemacpsif->txHead;
-size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
-
-       /* uxCount is the number of TX descriptors that are in use by the DMA. */
-       /* When done, "TXBUF_USED" will be set. */
-
-       while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
-       {
-               if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
-               {
-                       break;
-               }
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-#warning ipconfigZERO_COPY_TX_DRIVER is defined
-               {
-               void *pvBuffer = pxDMA_tx_buffers[ tail ];
-               NetworkBufferDescriptor_t *pxBuffer;
-
-                       if( pvBuffer != NULL )
-                       {
-                               pxDMA_tx_buffers[ tail ] = NULL;
-                               pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
-                               if( pxBuffer != NULL )
-                               {
-                                       vReleaseNetworkBufferAndDescriptor( pxBuffer );
-                               }
-                               else
-                               {
-                                       FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
-                               }
-                       }
-               }
-#endif
-               /* Clear all but the "used" and "wrap" bits. */
-               if( tail < ipconfigNIC_N_TX_DESC - 1 )
-               {
-                       xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
-               }
-               else
-               {
-                       xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
-               }
-               uxCount--;
-               /* Tell the counting semaphore that one more TX descriptor is available. */
-               xSemaphoreGive( xTXDescriptorSemaphore );
-               if( ++tail == ipconfigNIC_N_TX_DESC )
-               {
-                       tail = 0;
-               }
-               xemacpsif->txTail = tail;
-       }
-
-       return;
-}
-
-void emacps_send_handler(void *arg)
-{
-xemacpsif_s   *xemacpsif;
-BaseType_t xHigherPriorityTaskWoken = pdFALSE;
-
-       xemacpsif = (xemacpsif_s *)(arg);
-
-       /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
-       "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
-       */
-       xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
-       xemacpsif->txBusy = pdFALSE;
-
-       if( xEMACTaskHandle != NULL )
-       {
-               vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
-       }
-
-       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
-}
-
-static BaseType_t xValidLength( BaseType_t xLength )
-{
-BaseType_t xReturn;
-
-       if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )
-       {
-               xReturn = pdTRUE;
-       }
-       else
-       {
-               xReturn =  pdFALSE;
-       }
-
-       return xReturn;
-}
-
-XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )
-{
-int head = xemacpsif->txHead;
-int iHasSent = 0;
-uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
-TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
-
-       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-       {
-               /* This driver wants to own all network buffers which are to be transmitted. */
-               configASSERT( iReleaseAfterSend != pdFALSE );
-       }
-       #endif
-
-       /* Open a do {} while ( 0 ) loop to be able to call break. */
-       do
-       {
-       uint32_t ulFlags = 0;
-
-               if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
-               {
-                       break;
-               }
-
-               if( xTXDescriptorSemaphore == NULL )
-               {
-                       break;
-               }
-
-               if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
-               {
-                       FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
-                       break;
-               }
-
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-               /* Pass the pointer (and its ownership) directly to DMA. */
-               pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
-               if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
-               {
-                       Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
-               }
-               /* Buffer has been transferred, do not release it. */
-               iReleaseAfterSend = pdFALSE;
-#else
-               if( pxDMA_tx_buffers[ head ] == NULL )
-               {
-                       FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );
-                       break;
-               }
-               /* Copy the message to unbuffered space in RAM. */
-               memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
-#endif
-               /* Packets will be sent one-by-one, so for each packet
-               the TXBUF_LAST bit will be set. */
-               ulFlags |= XEMACPS_TXBUF_LAST_MASK;
-               ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
-               if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
-               {
-                       ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
-               }
-
-               /* Copy the address of the buffer and set the flags. */
-               xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
-               xemacpsif->txSegments[ head ].flags = ulFlags;
-
-               iHasSent = pdTRUE;
-               if( ++head == ipconfigNIC_N_TX_DESC )
-               {
-                       head = 0;
-               }
-               /* Update the TX-head index. These variable are declared volatile so they will be
-               accessed as little as possible. */
-               xemacpsif->txHead = head;
-       } while( pdFALSE );
-
-       if( iReleaseAfterSend != pdFALSE )
-       {
-               vReleaseNetworkBufferAndDescriptor( pxBuffer );
-               pxBuffer = NULL;
-       }
-
-       /* Data Synchronization Barrier */
-       dsb();
-
-       if( iHasSent != pdFALSE )
-       {
-               /* Make STARTTX high */
-               uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
-               /* Start transmit */
-               xemacpsif->txBusy = pdTRUE;
-               XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
-       }
-       dsb();
-
-       return 0;
-}
-
-void emacps_recv_handler(void *arg)
-{
-       xemacpsif_s *xemacpsif;
-       BaseType_t xHigherPriorityTaskWoken = pdFALSE;
-
-       xemacpsif = (xemacpsif_s *)(arg);
-       xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
-
-       if( xEMACTaskHandle != NULL )
-       {
-               vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
-       }
-
-       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
-}
-
-static NetworkBufferDescriptor_t *ethMsg = NULL;
-static NetworkBufferDescriptor_t *ethLast = NULL;
-
-static void passEthMessages( void )
-{
-IPStackEvent_t xRxEvent;
-
-       xRxEvent.eEventType = eNetworkRxEvent;
-       xRxEvent.pvData = ( void * ) ethMsg;
-
-       if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
-       {
-               /* The buffer could not be sent to the stack so must be released again.
-               This is a deferred handler taskr, not a real interrupt, so it is ok to
-               use the task level function here. */
-               do
-               {
-                       NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;
-                       vReleaseNetworkBufferAndDescriptor( ethMsg );
-                       ethMsg = xNext;
-               } while( ethMsg != NULL );
-
-               iptraceETHERNET_RX_EVENT_LOST();
-               FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );
-       }
-
-       ethMsg = ethLast = NULL;
-}
-
-int emacps_check_rx( xemacpsif_s *xemacpsif )
-{
-NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
-int rx_bytes;
-volatile int msgCount = 0;
-int head = xemacpsif->rxHead;
-
-       /* There seems to be an issue (SI# 692601), see comments below. */
-       resetrx_on_no_rxdata(xemacpsif);
-
-       /* This FreeRTOS+TCP driver shall be compiled with the option
-       "ipconfigUSE_LINKED_RX_MESSAGES" enabled.  It allows the driver to send a
-       chain of RX messages within one message to the IP-task. */
-       for( ;; )
-       {
-               if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
-                       ( pxDMA_rx_buffers[ head ] == NULL ) )
-               {
-                       break;
-               }
-
-               pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );
-               if( pxNewBuffer == NULL )
-               {
-                       /* A packet has been received, but there is no replacement for this Network Buffer.
-                       The packet will be dropped, and it Network Buffer will stay in place. */
-                       FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );
-                       pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
-               }
-               else
-               {
-                       pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
-
-                       /* Just avoiding to use or refer to the same buffer again */
-                       pxDMA_rx_buffers[ head ] = pxNewBuffer;
-
-                       /*
-                        * Adjust the buffer size to the actual number of bytes received.
-                        */
-                       rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
-
-                       pxBuffer->xDataLength = rx_bytes;
-
-                       if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
-                       {
-                               Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );
-                       }
-
-                       /* store it in the receive queue, where it'll be processed by a
-                       different handler. */
-                       iptraceNETWORK_INTERFACE_RECEIVE();
-                       pxBuffer->pxNextBuffer = NULL;
-
-                       if( ethMsg == NULL )
-                       {
-                               // Becomes the first message
-                               ethMsg = pxBuffer;
-                       }
-                       else if( ethLast != NULL )
-                       {
-                               // Add to the tail
-                               ethLast->pxNextBuffer = pxBuffer;
-                       }
-
-                       ethLast = pxBuffer;
-                       msgCount++;
-               }
-               {
-                       if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
-                       {
-                               Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);
-                       }
-                       {
-                               uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
-                               if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
-                               {
-                                       addr |= XEMACPS_RXBUF_WRAP_MASK;
-                               }
-                               /* Clearing 'XEMACPS_RXBUF_NEW_MASK'       0x00000001 *< Used bit.. */
-                               xemacpsif->rxSegments[ head ].address = addr;
-                               xemacpsif->rxSegments[ head ].flags = 0;
-                       }
-               }
-
-               if( ++head == ipconfigNIC_N_RX_DESC )
-               {
-                       head = 0;
-               }
-               xemacpsif->rxHead = head;
-       }
-
-       if( ethMsg != NULL )
-       {
-               passEthMessages( );
-       }
-
-       return msgCount;
-}
-
-void clean_dma_txdescs(xemacpsif_s *xemacpsif)
-{
-int index;
-unsigned char *ucTxBuffer;
-
-       /* Clear all TX descriptors and assign uncached memory to each descriptor.
-       "tx_space" points to the first available TX buffer. */
-       ucTxBuffer = xemacpsif->tx_space;
-
-       for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
-       {
-               xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
-               xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-               pxDMA_tx_buffers[ index ] = ( void* )NULL;
-#else
-               pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );
-#endif
-               ucTxBuffer += xemacpsif->uTxUnitSize;
-       }
-       xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
-               XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
-}
-
-XStatus init_dma(xemacpsif_s *xemacpsif)
-{
-       NetworkBufferDescriptor_t *pxBuffer;
-
-       int iIndex;
-       UBaseType_t xRxSize;
-       UBaseType_t xTxSize;
-       struct xtopology_t *xtopologyp = &xXTopology;
-
-       xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
-
-       xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
-
-       /* Also round-up to 4KB */
-       xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;
-       /*
-        * We allocate 65536 bytes for RX BDs which can accommodate a
-        * maximum of 8192 BDs which is much more than any application
-        * will ever need.
-        */
-       xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize )  );
-       xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );
-       xemacpsif->tx_space   = ( unsigned char *   )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
-
-       /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
-       xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
-       xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
-
-       if( xTXDescriptorSemaphore == NULL )
-       {
-               xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
-               configASSERT( xTXDescriptorSemaphore );
-       }
-       /*
-        * Allocate RX descriptors, 1 RxBD at a time.
-        */
-       for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
-       {
-               pxBuffer = pxDMA_rx_buffers[ iIndex ];
-               if( pxBuffer == NULL )
-               {
-                       pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );
-                       if( pxBuffer == NULL )
-                       {
-                               FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );
-                               return -1;
-                       }
-               }
-
-               xemacpsif->rxSegments[ iIndex ].flags = 0;
-               xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
-
-               pxDMA_rx_buffers[ iIndex ] = pxBuffer;
-               /* Make sure this memory is not in cache for now. */
-               if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
-               {
-                       Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
-                               (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);
-               }
-       }
-
-       xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
-
-       memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
-
-       clean_dma_txdescs( xemacpsif );
-
-       {
-               uint32_t value;
-               value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
-
-               // 1xxxx: Attempt to use INCR16 AHB bursts
-               value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
-#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
-               value |= XEMACPS_DMACR_TCPCKSUM_MASK;
-#else
-#warning Are you sure the EMAC should not calculate outgoing checksums?
-               value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
-#endif
-               XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
-       }
-       {
-               uint32_t value;
-               value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
-
-               /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
-               Now tell the EMAC that received messages should be stored at "address + 2". */
-               value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
-
-#if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
-               value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
-#else
-#warning Are you sure the EMAC should not calculate incoming checksums?
-               value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
-#endif
-               XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
-       }
-
-       /*
-        * 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.
-        */
-       XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
-               (Xil_ExceptionHandler)XEmacPs_IntrHandler,
-               (void *)&xemacpsif->emacps);
-       /*
-        * Enable the interrupt for emacps.
-        */
-       EmacEnableIntr( );
-
-       return 0;
-}
-
-/*
- * resetrx_on_no_rxdata():
- *
- * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
- * called by the user.
- * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
- * Under heavy Rx traffic because of the HW bug there are times when the Rx path
- * becomes unresponsive. The workaround for it is to check for the Rx path for
- * traffic (by reading the stats registers regularly). If the stats register
- * does not increment for sometime (proving no Rx traffic), the function resets
- * the Rx data path.
- *
- */
-
-void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
-{
-       unsigned long regctrl;
-       unsigned long tempcntr;
-
-       tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
-       if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
-       {
-               regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
-                               XEMACPS_NWCTRL_OFFSET);
-               regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
-               XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
-                               XEMACPS_NWCTRL_OFFSET, regctrl);
-               regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
-               regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
-               XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
-       }
-       xemacpsif->last_rx_frms_cntr = tempcntr;
-}
-
-void EmacDisableIntr(void)
-{
-       XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
-}
-
-void EmacEnableIntr(void)
-{
-       XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
-}
-
+/*\r
+FreeRTOS+TCP V2.0.11\r
+Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+this software and associated documentation files (the "Software"), to deal in\r
+the Software without restriction, including without limitation the rights to\r
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+the Software, and to permit persons to whom the Software is furnished to do so,\r
+subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in all\r
+copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+\r
+ http://aws.amazon.com/freertos\r
+ http://www.FreeRTOS.org\r
+*/\r
+\r
+#include "Zynq/x_emacpsif.h"\r
+#include "Zynq/x_topology.h"\r
+#include "xstatus.h"\r
+\r
+#include "xparameters.h"\r
+#include "xparameters_ps.h"\r
+#include "xil_exception.h"\r
+#include "xil_mmu.h"\r
+\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "timers.h"\r
+#include "semphr.h"\r
+\r
+/* FreeRTOS+TCP includes. */\r
+#include "FreeRTOS_IP.h"\r
+#include "FreeRTOS_Sockets.h"\r
+#include "FreeRTOS_IP_Private.h"\r
+#include "NetworkBufferManagement.h"\r
+\r
+#include "uncached_memory.h"\r
+\r
+/* Two defines used to set or clear the EMAC interrupt */\r
+#define INTC_BASE_ADDR         XPAR_SCUGIC_CPU_BASEADDR\r
+#define INTC_DIST_BASE_ADDR    XPAR_SCUGIC_DIST_BASEADDR\r
+\r
+\r
+\r
+#if( ipconfigPACKET_FILLER_SIZE != 2 )\r
+       #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'\r
+#endif\r
+#define TX_OFFSET                              ipconfigPACKET_FILLER_SIZE\r
+\r
+#define RX_BUFFER_ALIGNMENT    14\r
+\r
+/* Defined in NetworkInterface.c */\r
+extern TaskHandle_t xEMACTaskHandle;\r
+\r
+/*\r
+       pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.\r
+       The actual TX buffers are located in uncached RAM.\r
+*/\r
+static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };\r
+\r
+/*\r
+       pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.\r
+       Once a message has been received by the EMAC, the descriptor can be passed\r
+       immediately to the IP-task.\r
+*/\r
+static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };\r
+\r
+/*\r
+       The FreeRTOS+TCP port is using a fixed 'topology', which is declared in\r
+       ./portable/NetworkInterface/Zynq/NetworkInterface.c\r
+*/\r
+extern struct xtopology_t xXTopology;\r
+\r
+static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
+\r
+/*\r
+       The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".\r
+       In stead 'struct xemacpsif_s' has a "head" and a "tail" index.\r
+       "head" is the next index to be written, used.\r
+       "tail" is the next index to be read, freed.\r
+*/\r
+\r
+int is_tx_space_available( xemacpsif_s *xemacpsif )\r
+{\r
+size_t uxCount;\r
+\r
+       if( xTXDescriptorSemaphore != NULL )\r
+       {\r
+               uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
+       }\r
+       else\r
+       {\r
+               uxCount = ( UBaseType_t ) 0u;\r
+       }\r
+\r
+       return uxCount;\r
+}\r
+\r
+void emacps_check_tx( xemacpsif_s *xemacpsif )\r
+{\r
+int tail = xemacpsif->txTail;\r
+int head = xemacpsif->txHead;\r
+size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
+\r
+       /* uxCount is the number of TX descriptors that are in use by the DMA. */\r
+       /* When done, "TXBUF_USED" will be set. */\r
+\r
+       while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )\r
+       {\r
+               if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )\r
+               {\r
+                       break;\r
+               }\r
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+#warning ipconfigZERO_COPY_TX_DRIVER is defined\r
+               {\r
+               void *pvBuffer = pxDMA_tx_buffers[ tail ];\r
+               NetworkBufferDescriptor_t *pxBuffer;\r
+\r
+                       if( pvBuffer != NULL )\r
+                       {\r
+                               pxDMA_tx_buffers[ tail ] = NULL;\r
+                               pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );\r
+                               if( pxBuffer != NULL )\r
+                               {\r
+                                       vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
+                               }\r
+                               else\r
+                               {\r
+                                       FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );\r
+                               }\r
+                       }\r
+               }\r
+#endif\r
+               /* Clear all but the "used" and "wrap" bits. */\r
+               if( tail < ipconfigNIC_N_TX_DESC - 1 )\r
+               {\r
+                       xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;\r
+               }\r
+               else\r
+               {\r
+                       xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
+               }\r
+               uxCount--;\r
+               /* Tell the counting semaphore that one more TX descriptor is available. */\r
+               xSemaphoreGive( xTXDescriptorSemaphore );\r
+               if( ++tail == ipconfigNIC_N_TX_DESC )\r
+               {\r
+                       tail = 0;\r
+               }\r
+               xemacpsif->txTail = tail;\r
+       }\r
+\r
+       return;\r
+}\r
+\r
+void emacps_send_handler(void *arg)\r
+{\r
+xemacpsif_s   *xemacpsif;\r
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+       xemacpsif = (xemacpsif_s *)(arg);\r
+\r
+       /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in\r
+       "isr_events". The task in NetworkInterface will wake-up and do the necessary work.\r
+       */\r
+       xemacpsif->isr_events |= EMAC_IF_TX_EVENT;\r
+       xemacpsif->txBusy = pdFALSE;\r
+\r
+       if( xEMACTaskHandle != NULL )\r
+       {\r
+               vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
+       }\r
+\r
+       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+}\r
+\r
+static BaseType_t xValidLength( BaseType_t xLength )\r
+{\r
+BaseType_t xReturn;\r
+\r
+       if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )\r
+       {\r
+               xReturn = pdTRUE;\r
+       }\r
+       else\r
+       {\r
+               xReturn =  pdFALSE;\r
+       }\r
+\r
+       return xReturn;\r
+}\r
+\r
+XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )\r
+{\r
+int head = xemacpsif->txHead;\r
+int iHasSent = 0;\r
+uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;\r
+TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );\r
+\r
+       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+       {\r
+               /* This driver wants to own all network buffers which are to be transmitted. */\r
+               configASSERT( iReleaseAfterSend != pdFALSE );\r
+       }\r
+       #endif\r
+\r
+       /* Open a do {} while ( 0 ) loop to be able to call break. */\r
+       do\r
+       {\r
+       uint32_t ulFlags = 0;\r
+\r
+               if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )\r
+               {\r
+                       break;\r
+               }\r
+\r
+               if( xTXDescriptorSemaphore == NULL )\r
+               {\r
+                       break;\r
+               }\r
+\r
+               if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
+               {\r
+                       FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );\r
+                       break;\r
+               }\r
+\r
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+               /* Pass the pointer (and its ownership) directly to DMA. */\r
+               pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;\r
+               if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
+               {\r
+                       Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
+               }\r
+               /* Buffer has been transferred, do not release it. */\r
+               iReleaseAfterSend = pdFALSE;\r
+#else\r
+               if( pxDMA_tx_buffers[ head ] == NULL )\r
+               {\r
+                       FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );\r
+                       break;\r
+               }\r
+               /* Copy the message to unbuffered space in RAM. */\r
+               memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
+#endif\r
+               /* Packets will be sent one-by-one, so for each packet\r
+               the TXBUF_LAST bit will be set. */\r
+               ulFlags |= XEMACPS_TXBUF_LAST_MASK;\r
+               ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );\r
+               if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )\r
+               {\r
+                       ulFlags |= XEMACPS_TXBUF_WRAP_MASK;\r
+               }\r
+\r
+               /* Copy the address of the buffer and set the flags. */\r
+               xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];\r
+               xemacpsif->txSegments[ head ].flags = ulFlags;\r
+\r
+               iHasSent = pdTRUE;\r
+               if( ++head == ipconfigNIC_N_TX_DESC )\r
+               {\r
+                       head = 0;\r
+               }\r
+               /* Update the TX-head index. These variable are declared volatile so they will be\r
+               accessed as little as possible. */\r
+               xemacpsif->txHead = head;\r
+       } while( pdFALSE );\r
+\r
+       if( iReleaseAfterSend != pdFALSE )\r
+       {\r
+               vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
+               pxBuffer = NULL;\r
+       }\r
+\r
+       /* Data Synchronization Barrier */\r
+       dsb();\r
+\r
+       if( iHasSent != pdFALSE )\r
+       {\r
+               /* Make STARTTX high */\r
+               uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);\r
+               /* Start transmit */\r
+               xemacpsif->txBusy = pdTRUE;\r
+               XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );\r
+       }\r
+       dsb();\r
+\r
+       return 0;\r
+}\r
+\r
+void emacps_recv_handler(void *arg)\r
+{\r
+       xemacpsif_s *xemacpsif;\r
+       BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+       xemacpsif = (xemacpsif_s *)(arg);\r
+       xemacpsif->isr_events |= EMAC_IF_RX_EVENT;\r
+\r
+       if( xEMACTaskHandle != NULL )\r
+       {\r
+               vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
+       }\r
+\r
+       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+}\r
+\r
+static NetworkBufferDescriptor_t *ethMsg = NULL;\r
+static NetworkBufferDescriptor_t *ethLast = NULL;\r
+\r
+static void passEthMessages( void )\r
+{\r
+IPStackEvent_t xRxEvent;\r
+\r
+       xRxEvent.eEventType = eNetworkRxEvent;\r
+       xRxEvent.pvData = ( void * ) ethMsg;\r
+\r
+       if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )\r
+       {\r
+               /* The buffer could not be sent to the stack so must be released again.\r
+               This is a deferred handler taskr, not a real interrupt, so it is ok to\r
+               use the task level function here. */\r
+               do\r
+               {\r
+                       NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;\r
+                       vReleaseNetworkBufferAndDescriptor( ethMsg );\r
+                       ethMsg = xNext;\r
+               } while( ethMsg != NULL );\r
+\r
+               iptraceETHERNET_RX_EVENT_LOST();\r
+               FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );\r
+       }\r
+\r
+       ethMsg = ethLast = NULL;\r
+}\r
+\r
+int emacps_check_rx( xemacpsif_s *xemacpsif )\r
+{\r
+NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;\r
+int rx_bytes;\r
+volatile int msgCount = 0;\r
+int head = xemacpsif->rxHead;\r
+\r
+       /* There seems to be an issue (SI# 692601), see comments below. */\r
+       resetrx_on_no_rxdata(xemacpsif);\r
+\r
+       /* This FreeRTOS+TCP driver shall be compiled with the option\r
+       "ipconfigUSE_LINKED_RX_MESSAGES" enabled.  It allows the driver to send a\r
+       chain of RX messages within one message to the IP-task. */\r
+       for( ;; )\r
+       {\r
+               if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||\r
+                       ( pxDMA_rx_buffers[ head ] == NULL ) )\r
+               {\r
+                       break;\r
+               }\r
+\r
+               pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );\r
+               if( pxNewBuffer == NULL )\r
+               {\r
+                       /* A packet has been received, but there is no replacement for this Network Buffer.\r
+                       The packet will be dropped, and it Network Buffer will stay in place. */\r
+                       FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );\r
+                       pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
+               }\r
+               else\r
+               {\r
+                       pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
+\r
+                       /* Just avoiding to use or refer to the same buffer again */\r
+                       pxDMA_rx_buffers[ head ] = pxNewBuffer;\r
+\r
+                       /*\r
+                        * Adjust the buffer size to the actual number of bytes received.\r
+                        */\r
+                       rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;\r
+\r
+                       pxBuffer->xDataLength = rx_bytes;\r
+\r
+                       if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
+                       {\r
+                               Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );\r
+                       }\r
+\r
+                       /* store it in the receive queue, where it'll be processed by a\r
+                       different handler. */\r
+                       iptraceNETWORK_INTERFACE_RECEIVE();\r
+                       pxBuffer->pxNextBuffer = NULL;\r
+\r
+                       if( ethMsg == NULL )\r
+                       {\r
+                               // Becomes the first message\r
+                               ethMsg = pxBuffer;\r
+                       }\r
+                       else if( ethLast != NULL )\r
+                       {\r
+                               // Add to the tail\r
+                               ethLast->pxNextBuffer = pxBuffer;\r
+                       }\r
+\r
+                       ethLast = pxBuffer;\r
+                       msgCount++;\r
+               }\r
+               {\r
+                       if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )\r
+                       {\r
+                               Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);\r
+                       }\r
+                       {\r
+                               uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
+                               if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )\r
+                               {\r
+                                       addr |= XEMACPS_RXBUF_WRAP_MASK;\r
+                               }\r
+                               /* Clearing 'XEMACPS_RXBUF_NEW_MASK'       0x00000001 *< Used bit.. */\r
+                               xemacpsif->rxSegments[ head ].address = addr;\r
+                               xemacpsif->rxSegments[ head ].flags = 0;\r
+                       }\r
+               }\r
+\r
+               if( ++head == ipconfigNIC_N_RX_DESC )\r
+               {\r
+                       head = 0;\r
+               }\r
+               xemacpsif->rxHead = head;\r
+       }\r
+\r
+       if( ethMsg != NULL )\r
+       {\r
+               passEthMessages( );\r
+       }\r
+\r
+       return msgCount;\r
+}\r
+\r
+void clean_dma_txdescs(xemacpsif_s *xemacpsif)\r
+{\r
+int index;\r
+unsigned char *ucTxBuffer;\r
+\r
+       /* Clear all TX descriptors and assign uncached memory to each descriptor.\r
+       "tx_space" points to the first available TX buffer. */\r
+       ucTxBuffer = xemacpsif->tx_space;\r
+\r
+       for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )\r
+       {\r
+               xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;\r
+               xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;\r
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
+               pxDMA_tx_buffers[ index ] = ( void* )NULL;\r
+#else\r
+               pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );\r
+#endif\r
+               ucTxBuffer += xemacpsif->uTxUnitSize;\r
+       }\r
+       xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =\r
+               XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
+}\r
+\r
+XStatus init_dma(xemacpsif_s *xemacpsif)\r
+{\r
+       NetworkBufferDescriptor_t *pxBuffer;\r
+\r
+       int iIndex;\r
+       UBaseType_t xRxSize;\r
+       UBaseType_t xTxSize;\r
+       struct xtopology_t *xtopologyp = &xXTopology;\r
+\r
+       xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );\r
+\r
+       xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );\r
+\r
+       /* Also round-up to 4KB */\r
+       xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;\r
+       /*\r
+        * We allocate 65536 bytes for RX BDs which can accommodate a\r
+        * maximum of 8192 BDs which is much more than any application\r
+        * will ever need.\r
+        */\r
+       xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize )  );\r
+       xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );\r
+       xemacpsif->tx_space   = ( unsigned char *   )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );\r
+\r
+       /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */\r
+       xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;\r
+       xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;\r
+\r
+       if( xTXDescriptorSemaphore == NULL )\r
+       {\r
+               xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );\r
+               configASSERT( xTXDescriptorSemaphore );\r
+       }\r
+       /*\r
+        * Allocate RX descriptors, 1 RxBD at a time.\r
+        */\r
+       for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )\r
+       {\r
+               pxBuffer = pxDMA_rx_buffers[ iIndex ];\r
+               if( pxBuffer == NULL )\r
+               {\r
+                       pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );\r
+                       if( pxBuffer == NULL )\r
+                       {\r
+                               FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );\r
+                               return -1;\r
+                       }\r
+               }\r
+\r
+               xemacpsif->rxSegments[ iIndex ].flags = 0;\r
+               xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
+\r
+               pxDMA_rx_buffers[ iIndex ] = pxBuffer;\r
+               /* Make sure this memory is not in cache for now. */\r
+               if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
+               {\r
+                       Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,\r
+                               (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);\r
+               }\r
+       }\r
+\r
+       xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;\r
+\r
+       memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );\r
+\r
+       clean_dma_txdescs( xemacpsif );\r
+\r
+       {\r
+               uint32_t value;\r
+               value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );\r
+\r
+               // 1xxxx: Attempt to use INCR16 AHB bursts\r
+               value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;\r
+#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )\r
+               value |= XEMACPS_DMACR_TCPCKSUM_MASK;\r
+#else\r
+#warning Are you sure the EMAC should not calculate outgoing checksums?\r
+               value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;\r
+#endif\r
+               XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );\r
+       }\r
+       {\r
+               uint32_t value;\r
+               value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );\r
+\r
+               /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).\r
+               Now tell the EMAC that received messages should be stored at "address + 2". */\r
+               value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;\r
+\r
+#if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )\r
+               value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
+#else\r
+#warning Are you sure the EMAC should not calculate incoming checksums?\r
+               value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
+#endif\r
+               XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );\r
+       }\r
+\r
+       /*\r
+        * Connect the device driver handler that will be called when an\r
+        * interrupt for the device occurs, the handler defined above performs\r
+        * the specific interrupt processing for the device.\r
+        */\r
+       XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,\r
+               (Xil_ExceptionHandler)XEmacPs_IntrHandler,\r
+               (void *)&xemacpsif->emacps);\r
+       /*\r
+        * Enable the interrupt for emacps.\r
+        */\r
+       EmacEnableIntr( );\r
+\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * resetrx_on_no_rxdata():\r
+ *\r
+ * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata\r
+ * called by the user.\r
+ * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.\r
+ * Under heavy Rx traffic because of the HW bug there are times when the Rx path\r
+ * becomes unresponsive. The workaround for it is to check for the Rx path for\r
+ * traffic (by reading the stats registers regularly). If the stats register\r
+ * does not increment for sometime (proving no Rx traffic), the function resets\r
+ * the Rx data path.\r
+ *\r
+ */\r
+\r
+void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)\r
+{\r
+       unsigned long regctrl;\r
+       unsigned long tempcntr;\r
+\r
+       tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );\r
+       if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )\r
+       {\r
+               regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,\r
+                               XEMACPS_NWCTRL_OFFSET);\r
+               regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);\r
+               XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,\r
+                               XEMACPS_NWCTRL_OFFSET, regctrl);\r
+               regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);\r
+               regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);\r
+               XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);\r
+       }\r
+       xemacpsif->last_rx_frms_cntr = tempcntr;\r
+}\r
+\r
+void EmacDisableIntr(void)\r
+{\r
+       XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
+}\r
+\r
+void EmacEnableIntr(void)\r
+{\r
+       XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
+}\r
+\r