2 * FreeRTOS+TCP Labs Build 200417 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
58 #include "Zynq/x_emacpsif.h"
\r
59 #include "Zynq/x_topology.h"
\r
60 #include "xstatus.h"
\r
62 #include "xparameters.h"
\r
63 #include "xparameters_ps.h"
\r
64 #include "xil_exception.h"
\r
65 #include "xil_mmu.h"
\r
67 #include "FreeRTOS.h"
\r
72 /* FreeRTOS+TCP includes. */
\r
73 #include "FreeRTOS_IP.h"
\r
74 #include "FreeRTOS_Sockets.h"
\r
75 #include "FreeRTOS_IP_Private.h"
\r
76 #include "NetworkBufferManagement.h"
\r
78 #include "uncached_memory.h"
\r
80 /* Two defines used to set or clear the EMAC interrupt */
\r
81 #define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
\r
82 #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
\r
86 #if( ipconfigPACKET_FILLER_SIZE != 2 )
\r
87 #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
\r
89 #define TX_OFFSET ipconfigPACKET_FILLER_SIZE
\r
91 /* Defined in NetworkInterface.c */
\r
92 extern TaskHandle_t xEMACTaskHandle;
\r
95 pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
\r
96 The actual TX buffers are located in uncached RAM.
\r
98 static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
\r
101 pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
\r
102 Once a message has been received by the EMAC, the descriptor can be passed
\r
103 immediately to the IP-task.
\r
105 static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
\r
108 The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
\r
109 ./portable/NetworkInterface/Zynq/NetworkInterface.c
\r
111 extern struct xtopology_t xXTopology;
\r
113 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
116 The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
\r
117 In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
\r
118 "head" is the next index to be written, used.
\r
119 "tail" is the next index to be read, freed.
\r
122 int is_tx_space_available( xemacpsif_s *xemacpsif )
\r
126 if( xTXDescriptorSemaphore != NULL )
\r
128 uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
132 uxCount = ( UBaseType_t ) 0u;
\r
138 void emacps_check_tx( xemacpsif_s *xemacpsif )
\r
140 int tail = xemacpsif->txTail;
\r
141 int head = xemacpsif->txHead;
\r
142 size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
144 /* uxCount is the number of TX descriptors that are in use by the DMA. */
\r
145 /* When done, "TXBUF_USED" will be set. */
\r
147 while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
\r
149 if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
\r
153 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
154 #warning ipconfigZERO_COPY_TX_DRIVER is defined
\r
156 void *pvBuffer = pxDMA_tx_buffers[ tail ];
\r
157 NetworkBufferDescriptor_t *pxBuffer;
\r
159 if( pvBuffer != NULL )
\r
161 pxDMA_tx_buffers[ tail ] = NULL;
\r
162 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
\r
163 if( pxBuffer != NULL )
\r
165 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
169 FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
\r
174 /* Clear all but the "used" and "wrap" bits. */
\r
175 if( tail < ipconfigNIC_N_TX_DESC - 1 )
\r
177 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
\r
181 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
\r
184 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
185 xSemaphoreGive( xTXDescriptorSemaphore );
\r
186 if( ++tail == ipconfigNIC_N_TX_DESC )
\r
190 xemacpsif->txTail = tail;
\r
196 void emacps_send_handler(void *arg)
\r
198 xemacpsif_s *xemacpsif;
\r
199 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
201 xemacpsif = (xemacpsif_s *)(arg);
\r
203 /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
\r
204 "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
\r
206 xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
\r
207 xemacpsif->txBusy = pdFALSE;
\r
209 if( xEMACTaskHandle != NULL )
\r
211 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
214 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
217 static BaseType_t xValidLength( BaseType_t xLength )
\r
219 BaseType_t xReturn;
\r
221 if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )
\r
233 XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )
\r
235 int head = xemacpsif->txHead;
\r
236 int tail = xemacpsif->txTail;
\r
238 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
\r
239 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
\r
241 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
243 /* This driver wants to own all network buffers which are to be transmitted. */
\r
244 configASSERT( iReleaseAfterSend != pdFALSE );
\r
248 /* Open a do {} while ( 0 ) loop to be able to call break. */
\r
251 uint32_t ulFlags = 0;
\r
253 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
\r
258 if( xTXDescriptorSemaphore == NULL )
\r
263 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
265 FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
\r
269 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
270 /* Pass the pointer (and its ownership) directly to DMA. */
\r
271 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
\r
272 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
274 Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
\r
276 /* Buffer has been transferred, do not release it. */
\r
277 iReleaseAfterSend = pdFALSE;
\r
279 if( pxDMA_tx_buffers[ head ] == NULL )
\r
281 FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );
\r
284 /* Copy the message to unbuffered space in RAM. */
\r
285 memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
\r
287 /* Packets will be sent one-by-one, so for each packet
\r
288 the TXBUF_LAST bit will be set. */
\r
289 ulFlags |= XEMACPS_TXBUF_LAST_MASK;
\r
290 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
\r
291 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
\r
293 ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
\r
296 /* Copy the address of the buffer and set the flags. */
\r
297 xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
\r
298 xemacpsif->txSegments[ head ].flags = ulFlags;
\r
301 if( ++head == ipconfigNIC_N_TX_DESC )
\r
305 /* Update the TX-head index. These variable are declared volatile so they will be
\r
306 accessed as little as possible. */
\r
307 xemacpsif->txHead = head;
\r
308 } while( pdFALSE );
\r
310 if( iReleaseAfterSend != pdFALSE )
\r
312 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
316 /* Data Synchronization Barrier */
\r
319 if( iHasSent != pdFALSE )
\r
321 /* Make STARTTX high */
\r
322 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
\r
323 /* Start transmit */
\r
324 xemacpsif->txBusy = pdTRUE;
\r
325 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
\r
332 void emacps_recv_handler(void *arg)
\r
334 xemacpsif_s *xemacpsif;
\r
335 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
337 xemacpsif = (xemacpsif_s *)(arg);
\r
338 xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
\r
340 if( xEMACTaskHandle != NULL )
\r
342 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
345 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
348 static NetworkBufferDescriptor_t *ethMsg = NULL;
\r
349 static NetworkBufferDescriptor_t *ethLast = NULL;
\r
351 static void passEthMessages( void )
\r
353 IPStackEvent_t xRxEvent;
\r
355 xRxEvent.eEventType = eNetworkRxEvent;
\r
356 xRxEvent.pvData = ( void * ) ethMsg;
\r
358 if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
\r
360 /* The buffer could not be sent to the stack so must be released again.
\r
361 This is a deferred handler taskr, not a real interrupt, so it is ok to
\r
362 use the task level function here. */
\r
365 NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;
\r
366 vReleaseNetworkBufferAndDescriptor( ethMsg );
\r
368 } while( ethMsg != NULL );
\r
370 iptraceETHERNET_RX_EVENT_LOST();
\r
371 FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );
\r
374 ethMsg = ethLast = NULL;
\r
377 int emacps_check_rx( xemacpsif_s *xemacpsif )
\r
379 NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
\r
381 volatile int msgCount = 0;
\r
382 int head = xemacpsif->rxHead;
\r
384 /* There seems to be an issue (SI# 692601), see comments below. */
\r
385 resetrx_on_no_rxdata(xemacpsif);
\r
387 /* This FreeRTOS+TCP driver shall be compiled with the option
\r
388 "ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
\r
389 chain of RX messages within one message to the IP-task. */
\r
392 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
\r
393 ( pxDMA_rx_buffers[ head ] == NULL ) )
\r
398 pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
\r
399 if( pxNewBuffer == NULL )
\r
401 /* A packet has been received, but there is no replacement for this Network Buffer.
\r
402 The packet will be dropped, and it Network Buffer will stay in place. */
\r
403 FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );
\r
404 pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
\r
408 pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
\r
410 /* Just avoiding to use or refer to the same buffer again */
\r
411 pxDMA_rx_buffers[ head ] = pxNewBuffer;
\r
414 * Adjust the buffer size to the actual number of bytes received.
\r
416 rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
\r
418 pxBuffer->xDataLength = rx_bytes;
\r
420 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
422 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );
\r
425 /* store it in the receive queue, where it'll be processed by a
\r
426 different handler. */
\r
427 iptraceNETWORK_INTERFACE_RECEIVE();
\r
428 pxBuffer->pxNextBuffer = NULL;
\r
430 if( ethMsg == NULL )
\r
432 // Becomes the first message
\r
435 else if( ethLast != NULL )
\r
438 ethLast->pxNextBuffer = pxBuffer;
\r
441 ethLast = pxBuffer;
\r
445 if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
\r
447 Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
\r
450 uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
\r
451 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
\r
453 addr |= XEMACPS_RXBUF_WRAP_MASK;
\r
455 /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
\r
456 xemacpsif->rxSegments[ head ].address = addr;
\r
457 xemacpsif->rxSegments[ head ].flags = 0;
\r
461 if( ++head == ipconfigNIC_N_RX_DESC )
\r
465 xemacpsif->rxHead = head;
\r
468 if( ethMsg != NULL )
\r
470 passEthMessages( );
\r
476 void clean_dma_txdescs(xemacpsif_s *xemacpsif)
\r
479 unsigned char *ucTxBuffer;
\r
481 /* Clear all TX descriptors and assign uncached memory to each descriptor.
\r
482 "tx_space" points to the first available TX buffer. */
\r
483 ucTxBuffer = xemacpsif->tx_space;
\r
485 for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
\r
487 xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
\r
488 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
\r
489 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
490 pxDMA_tx_buffers[ index ] = ( void* )NULL;
\r
492 pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );
\r
494 ucTxBuffer += xemacpsif->uTxUnitSize;
\r
496 xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
\r
497 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
\r
500 XStatus init_dma(xemacpsif_s *xemacpsif)
\r
502 NetworkBufferDescriptor_t *pxBuffer;
\r
505 UBaseType_t xRxSize;
\r
506 UBaseType_t xTxSize;
\r
507 struct xtopology_t *xtopologyp = &xXTopology;
\r
509 xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
\r
511 xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
\r
513 /* Also round-up to 4KB */
\r
514 xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;
\r
516 * We allocate 65536 bytes for RX BDs which can accommodate a
\r
517 * maximum of 8192 BDs which is much more than any application
\r
520 xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) );
\r
521 xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );
\r
522 xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
\r
524 /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
\r
525 xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
\r
526 xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
\r
528 if( xTXDescriptorSemaphore == NULL )
\r
530 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
\r
531 configASSERT( xTXDescriptorSemaphore );
\r
534 * Allocate RX descriptors, 1 RxBD at a time.
\r
536 for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
\r
538 pxBuffer = pxDMA_rx_buffers[ iIndex ];
\r
539 if( pxBuffer == NULL )
\r
541 pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
\r
542 if( pxBuffer == NULL )
\r
544 FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );
\r
549 xemacpsif->rxSegments[ iIndex ].flags = 0;
\r
550 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
\r
552 pxDMA_rx_buffers[ iIndex ] = pxBuffer;
\r
553 /* Make sure this memory is not in cache for now. */
\r
554 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
556 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
\r
557 (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
\r
561 xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
\r
563 memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
\r
565 clean_dma_txdescs( xemacpsif );
\r
569 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
\r
571 // 1xxxx: Attempt to use INCR16 AHB bursts
\r
572 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
\r
573 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
\r
574 value |= XEMACPS_DMACR_TCPCKSUM_MASK;
\r
576 #warning Are you sure the EMAC should not calculate outgoing checksums?
\r
577 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
\r
579 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
\r
583 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
\r
585 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
\r
586 Now tell the EMAC that received messages should be stored at "address + 2". */
\r
587 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
\r
589 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
\r
590 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
\r
592 #warning Are you sure the EMAC should not calculate incoming checksums?
\r
593 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
\r
595 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
\r
599 * Connect the device driver handler that will be called when an
\r
600 * interrupt for the device occurs, the handler defined above performs
\r
601 * the specific interrupt processing for the device.
\r
603 XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
\r
604 (Xil_ExceptionHandler)XEmacPs_IntrHandler,
\r
605 (void *)&xemacpsif->emacps);
\r
607 * Enable the interrupt for emacps.
\r
615 * resetrx_on_no_rxdata():
\r
617 * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
\r
618 * called by the user.
\r
619 * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
\r
620 * Under heavy Rx traffic because of the HW bug there are times when the Rx path
\r
621 * becomes unresponsive. The workaround for it is to check for the Rx path for
\r
622 * traffic (by reading the stats registers regularly). If the stats register
\r
623 * does not increment for sometime (proving no Rx traffic), the function resets
\r
624 * the Rx data path.
\r
628 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
\r
630 unsigned long regctrl;
\r
631 unsigned long tempcntr;
\r
633 tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
\r
634 if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
\r
636 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
\r
637 XEMACPS_NWCTRL_OFFSET);
\r
638 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
\r
639 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
\r
640 XEMACPS_NWCTRL_OFFSET, regctrl);
\r
641 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
\r
642 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
\r
643 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
\r
645 xemacpsif->last_rx_frms_cntr = tempcntr;
\r
648 void EmacDisableIntr(void)
\r
650 XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
\r
653 void EmacEnableIntr(void)
\r
655 XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
\r