summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c')
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c1252
1 files changed, 626 insertions, 626 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
index fc09d2183..13a62852d 100644
--- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
@@ -1,626 +1,626 @@
-/*
-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);
-}
-
+/*
+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);
+}
+