3 Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 this software and associated documentation files (the "Software"), to deal in
\r
7 the Software without restriction, including without limitation the rights to
\r
8 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 subject to the following conditions:
\r
12 The above copyright notice and this permission notice shall be included in all
\r
13 copies or substantial portions of the Software.
\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 http://aws.amazon.com/freertos
\r
23 http://www.FreeRTOS.org
\r
26 #include "FreeRTOS.h"
\r
31 /* FreeRTOS+TCP includes. */
\r
32 #include "FreeRTOS_IP.h"
\r
33 #include "FreeRTOS_Sockets.h"
\r
34 #include "FreeRTOS_IP_Private.h"
\r
35 #include "NetworkBufferManagement.h"
\r
37 #include "Zynq/x_emacpsif.h"
\r
38 #include "Zynq/x_topology.h"
\r
39 #include "xstatus.h"
\r
41 #include "xparameters.h"
\r
42 #include "xparameters_ps.h"
\r
43 #include "xil_exception.h"
\r
44 #include "xil_mmu.h"
\r
46 #include "uncached_memory.h"
\r
48 /* Two defines used to set or clear the EMAC interrupt */
\r
49 #define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
\r
50 #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
\r
54 #if( ipconfigPACKET_FILLER_SIZE != 2 )
\r
55 #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
\r
57 #define TX_OFFSET ipconfigPACKET_FILLER_SIZE
\r
59 /* Defined in NetworkInterface.c */
\r
60 extern TaskHandle_t xEMACTaskHandle;
\r
63 pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
\r
64 The actual TX buffers are located in uncached RAM.
\r
66 static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
\r
69 pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
\r
70 Once a message has been received by the EMAC, the descriptor can be passed
\r
71 immediately to the IP-task.
\r
73 static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
\r
76 The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
\r
77 ./portable/NetworkInterface/Zynq/NetworkInterface.c
\r
79 extern struct xtopology_t xXTopology;
\r
81 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
84 The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
\r
85 In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
\r
86 "head" is the next index to be written, used.
\r
87 "tail" is the next index to be read, freed.
\r
90 int is_tx_space_available( xemacpsif_s *xemacpsif )
\r
94 if( xTXDescriptorSemaphore != NULL )
\r
96 uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
100 uxCount = ( UBaseType_t ) 0u;
\r
106 void emacps_check_tx( xemacpsif_s *xemacpsif )
\r
108 int tail = xemacpsif->txTail;
\r
109 int head = xemacpsif->txHead;
\r
110 size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
112 /* uxCount is the number of TX descriptors that are in use by the DMA. */
\r
113 /* When done, "TXBUF_USED" will be set. */
\r
115 while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
\r
117 if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
\r
121 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
122 #warning ipconfigZERO_COPY_TX_DRIVER is defined
\r
124 void *pvBuffer = pxDMA_tx_buffers[ tail ];
\r
125 NetworkBufferDescriptor_t *pxBuffer;
\r
127 if( pvBuffer != NULL )
\r
129 pxDMA_tx_buffers[ tail ] = NULL;
\r
130 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
\r
131 if( pxBuffer != NULL )
\r
133 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
137 FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
\r
142 /* Clear all but the "used" and "wrap" bits. */
\r
143 if( tail < ipconfigNIC_N_TX_DESC - 1 )
\r
145 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
\r
149 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
\r
152 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
153 xSemaphoreGive( xTXDescriptorSemaphore );
\r
154 if( ++tail == ipconfigNIC_N_TX_DESC )
\r
158 xemacpsif->txTail = tail;
\r
164 void emacps_send_handler(void *arg)
\r
166 xemacpsif_s *xemacpsif;
\r
167 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
169 xemacpsif = (xemacpsif_s *)(arg);
\r
171 /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
\r
172 "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
\r
174 xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
\r
175 xemacpsif->txBusy = pdFALSE;
\r
177 if( xEMACTaskHandle != NULL )
\r
179 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
182 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
185 static BaseType_t xValidLength( BaseType_t xLength )
\r
187 BaseType_t xReturn;
\r
189 if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )
\r
201 XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )
\r
203 int head = xemacpsif->txHead;
\r
204 //int tail = xemacpsif->txTail;
\r
206 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
\r
207 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
\r
209 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
211 /* This driver wants to own all network buffers which are to be transmitted. */
\r
212 configASSERT( iReleaseAfterSend != pdFALSE );
\r
216 /* Open a do {} while ( 0 ) loop to be able to call break. */
\r
219 uint32_t ulFlags = 0;
\r
221 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
\r
226 if( xTXDescriptorSemaphore == NULL )
\r
231 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
233 FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
\r
237 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
238 /* Pass the pointer (and its ownership) directly to DMA. */
\r
239 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
\r
240 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
242 Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
\r
244 /* Buffer has been transferred, do not release it. */
\r
245 iReleaseAfterSend = pdFALSE;
\r
247 if( pxDMA_tx_buffers[ head ] == NULL )
\r
249 FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );
\r
252 /* Copy the message to unbuffered space in RAM. */
\r
253 memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
\r
255 /* Packets will be sent one-by-one, so for each packet
\r
256 the TXBUF_LAST bit will be set. */
\r
257 ulFlags |= XEMACPS_TXBUF_LAST_MASK;
\r
258 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
\r
259 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
\r
261 ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
\r
264 /* Copy the address of the buffer and set the flags. */
\r
265 xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
\r
266 xemacpsif->txSegments[ head ].flags = ulFlags;
\r
269 if( ++head == ipconfigNIC_N_TX_DESC )
\r
273 /* Update the TX-head index. These variable are declared volatile so they will be
\r
274 accessed as little as possible. */
\r
275 xemacpsif->txHead = head;
\r
276 } while( pdFALSE );
\r
278 if( iReleaseAfterSend != pdFALSE )
\r
280 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
284 /* Data Synchronization Barrier */
\r
287 if( iHasSent != pdFALSE )
\r
289 /* Make STARTTX high */
\r
290 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
\r
291 /* Start transmit */
\r
292 xemacpsif->txBusy = pdTRUE;
\r
293 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
\r
300 void emacps_recv_handler(void *arg)
\r
302 xemacpsif_s *xemacpsif;
\r
303 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
305 xemacpsif = (xemacpsif_s *)(arg);
\r
306 xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
\r
308 if( xEMACTaskHandle != NULL )
\r
310 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
313 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
316 static void passEthMessages( NetworkBufferDescriptor_t *ethMsg )
\r
318 IPStackEvent_t xRxEvent;
\r
320 xRxEvent.eEventType = eNetworkRxEvent;
\r
321 xRxEvent.pvData = ( void * ) ethMsg;
\r
323 if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
\r
325 /* The buffer could not be sent to the stack so must be released again.
\r
326 This is a deferred handler taskr, not a real interrupt, so it is ok to
\r
327 use the task level function here. */
\r
330 NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;
\r
331 vReleaseNetworkBufferAndDescriptor( ethMsg );
\r
333 } while( ethMsg != NULL );
\r
335 iptraceETHERNET_RX_EVENT_LOST();
\r
336 FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );
\r
340 TickType_t ack_reception_delay = 10;
\r
342 int emacps_check_rx( xemacpsif_s *xemacpsif )
\r
344 NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
\r
346 volatile int msgCount = 0;
\r
347 int head = xemacpsif->rxHead;
\r
348 BaseType_t bHasDataPacket = pdFALSE;
\r
349 NetworkBufferDescriptor_t *ethMsg = NULL;
\r
350 NetworkBufferDescriptor_t *ethLast = NULL;
\r
352 /* There seems to be an issue (SI# 692601), see comments below. */
\r
353 resetrx_on_no_rxdata(xemacpsif);
\r
356 static int maxcount = 0;
\r
360 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
\r
361 ( pxDMA_rx_buffers[ head ] == NULL ) )
\r
366 if( ++head == ipconfigNIC_N_RX_DESC )
\r
370 if( head == xemacpsif->rxHead )
\r
375 if (maxcount < count) {
\r
377 FreeRTOS_printf( ( "emacps_check_rx: %d packets\n", maxcount ) );
\r
379 head = xemacpsif->rxHead;
\r
382 /* This FreeRTOS+TCP driver shall be compiled with the option
\r
383 "ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
\r
384 chain of RX messages within one message to the IP-task. */
\r
387 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
\r
388 ( pxDMA_rx_buffers[ head ] == NULL ) )
\r
393 pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
\r
394 if( pxNewBuffer == NULL )
\r
396 /* A packet has been received, but there is no replacement for this Network Buffer.
\r
397 The packet will be dropped, and it Network Buffer will stay in place. */
\r
398 FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );
\r
399 pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
\r
403 pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
\r
405 /* Just avoiding to use or refer to the same buffer again */
\r
406 pxDMA_rx_buffers[ head ] = pxNewBuffer;
\r
409 * Adjust the buffer size to the actual number of bytes received.
\r
411 rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
\r
413 pxBuffer->xDataLength = rx_bytes;
\r
414 if( rx_bytes > 60 )
\r
416 bHasDataPacket = 1;
\r
418 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
420 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );
\r
423 /* store it in the receive queue, where it'll be processed by a
\r
424 different handler. */
\r
425 iptraceNETWORK_INTERFACE_RECEIVE();
\r
426 pxBuffer->pxNextBuffer = NULL;
\r
428 if( ethMsg == NULL )
\r
430 // Becomes the first message
\r
433 else if( ethLast != NULL )
\r
436 ethLast->pxNextBuffer = pxBuffer;
\r
439 ethLast = pxBuffer;
\r
443 if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
\r
445 Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
\r
448 uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
\r
449 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
\r
451 addr |= XEMACPS_RXBUF_WRAP_MASK;
\r
453 /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
\r
454 xemacpsif->rxSegments[ head ].flags = 0;
\r
455 xemacpsif->rxSegments[ head ].address = addr;
\r
456 if (xemacpsif->rxSegments[ head ].address) {
\r
462 if( ++head == ipconfigNIC_N_RX_DESC )
\r
466 xemacpsif->rxHead = head;
\r
469 if( ethMsg != NULL )
\r
471 if( bHasDataPacket == pdFALSE )
\r
473 // vTaskDelay( ack_reception_delay );
\r
475 passEthMessages( ethMsg );
\r
481 void clean_dma_txdescs(xemacpsif_s *xemacpsif)
\r
484 unsigned char *ucTxBuffer;
\r
486 /* Clear all TX descriptors and assign uncached memory to each descriptor.
\r
487 "tx_space" points to the first available TX buffer. */
\r
488 ucTxBuffer = xemacpsif->tx_space;
\r
490 for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
\r
492 xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
\r
493 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
\r
494 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
495 pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;
\r
497 pxDMA_tx_buffers[ index ] = ( unsigned char * )( ucTxBuffer + TX_OFFSET );
\r
499 ucTxBuffer += xemacpsif->uTxUnitSize;
\r
501 xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
\r
502 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
\r
505 XStatus init_dma(xemacpsif_s *xemacpsif)
\r
507 NetworkBufferDescriptor_t *pxBuffer;
\r
510 UBaseType_t xRxSize;
\r
511 UBaseType_t xTxSize;
\r
512 struct xtopology_t *xtopologyp = &xXTopology;
\r
514 xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
\r
516 xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
\r
518 /* Also round-up to 4KB */
\r
519 xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;
\r
521 * We allocate 65536 bytes for RX BDs which can accommodate a
\r
522 * maximum of 8192 BDs which is much more than any application
\r
525 xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) );
\r
526 xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );
\r
527 xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
\r
529 /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
\r
530 xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
\r
531 xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
\r
533 if( xTXDescriptorSemaphore == NULL )
\r
535 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
\r
536 configASSERT( xTXDescriptorSemaphore );
\r
539 * Allocate RX descriptors, 1 RxBD at a time.
\r
541 for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
\r
543 pxBuffer = pxDMA_rx_buffers[ iIndex ];
\r
544 if( pxBuffer == NULL )
\r
546 pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
\r
547 if( pxBuffer == NULL )
\r
549 FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );
\r
554 xemacpsif->rxSegments[ iIndex ].flags = 0;
\r
555 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
\r
557 pxDMA_rx_buffers[ iIndex ] = pxBuffer;
\r
558 /* Make sure this memory is not in cache for now. */
\r
559 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
561 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
\r
562 (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
\r
566 xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
\r
568 memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
\r
570 clean_dma_txdescs( xemacpsif );
\r
574 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
\r
576 // 1xxxx: Attempt to use INCR16 AHB bursts
\r
577 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
\r
578 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
\r
579 value |= XEMACPS_DMACR_TCPCKSUM_MASK;
\r
581 #warning Are you sure the EMAC should not calculate outgoing checksums?
\r
582 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
\r
584 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
\r
588 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
\r
590 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
\r
591 Now tell the EMAC that received messages should be stored at "address + 2". */
\r
592 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
\r
594 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
\r
595 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
\r
597 #warning Are you sure the EMAC should not calculate incoming checksums?
\r
598 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
\r
600 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
\r
604 * Connect the device driver handler that will be called when an
\r
605 * interrupt for the device occurs, the handler defined above performs
\r
606 * the specific interrupt processing for the device.
\r
608 XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
\r
609 (Xil_ExceptionHandler)XEmacPs_IntrHandler,
\r
610 (void *)&xemacpsif->emacps);
\r
612 * Enable the interrupt for emacps.
\r
620 * resetrx_on_no_rxdata():
\r
622 * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
\r
623 * called by the user.
\r
624 * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
\r
625 * Under heavy Rx traffic because of the HW bug there are times when the Rx path
\r
626 * becomes unresponsive. The workaround for it is to check for the Rx path for
\r
627 * traffic (by reading the stats registers regularly). If the stats register
\r
628 * does not increment for sometime (proving no Rx traffic), the function resets
\r
629 * the Rx data path.
\r
633 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
\r
635 unsigned long regctrl;
\r
636 unsigned long tempcntr;
\r
638 tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
\r
639 if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
\r
641 FreeRTOS_printf( ( "resetrx_on_no_rxdata: RESET~\n" ) );
\r
642 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
\r
643 XEMACPS_NWCTRL_OFFSET);
\r
644 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
\r
645 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
\r
646 XEMACPS_NWCTRL_OFFSET, regctrl);
\r
647 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
\r
648 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
\r
649 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
\r
651 xemacpsif->last_rx_frms_cntr = tempcntr;
\r
654 void EmacDisableIntr(void)
\r
656 XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
\r
659 void EmacEnableIntr(void)
\r
661 XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
\r