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 "Zynq/x_emacpsif.h"
\r
27 #include "Zynq/x_topology.h"
\r
28 #include "xstatus.h"
\r
30 #include "xparameters.h"
\r
31 #include "xparameters_ps.h"
\r
32 #include "xil_exception.h"
\r
33 #include "xil_mmu.h"
\r
35 #include "FreeRTOS.h"
\r
40 /* FreeRTOS+TCP includes. */
\r
41 #include "FreeRTOS_IP.h"
\r
42 #include "FreeRTOS_Sockets.h"
\r
43 #include "FreeRTOS_IP_Private.h"
\r
44 #include "NetworkBufferManagement.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 #define RX_BUFFER_ALIGNMENT 14
\r
61 /* Defined in NetworkInterface.c */
\r
62 extern TaskHandle_t xEMACTaskHandle;
\r
65 pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
\r
66 The actual TX buffers are located in uncached RAM.
\r
68 static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
\r
71 pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
\r
72 Once a message has been received by the EMAC, the descriptor can be passed
\r
73 immediately to the IP-task.
\r
75 static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
\r
78 The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
\r
79 ./portable/NetworkInterface/Zynq/NetworkInterface.c
\r
81 extern struct xtopology_t xXTopology;
\r
83 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
86 The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
\r
87 In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
\r
88 "head" is the next index to be written, used.
\r
89 "tail" is the next index to be read, freed.
\r
92 int is_tx_space_available( xemacpsif_s *xemacpsif )
\r
96 if( xTXDescriptorSemaphore != NULL )
\r
98 uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
102 uxCount = ( UBaseType_t ) 0u;
\r
108 void emacps_check_tx( xemacpsif_s *xemacpsif )
\r
110 int tail = xemacpsif->txTail;
\r
111 int head = xemacpsif->txHead;
\r
112 size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
114 /* uxCount is the number of TX descriptors that are in use by the DMA. */
\r
115 /* When done, "TXBUF_USED" will be set. */
\r
117 while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
\r
119 if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
\r
123 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
124 #warning ipconfigZERO_COPY_TX_DRIVER is defined
\r
126 void *pvBuffer = pxDMA_tx_buffers[ tail ];
\r
127 NetworkBufferDescriptor_t *pxBuffer;
\r
129 if( pvBuffer != NULL )
\r
131 pxDMA_tx_buffers[ tail ] = NULL;
\r
132 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
\r
133 if( pxBuffer != NULL )
\r
135 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
139 FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
\r
144 /* Clear all but the "used" and "wrap" bits. */
\r
145 if( tail < ipconfigNIC_N_TX_DESC - 1 )
\r
147 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
\r
151 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
\r
154 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
155 xSemaphoreGive( xTXDescriptorSemaphore );
\r
156 if( ++tail == ipconfigNIC_N_TX_DESC )
\r
160 xemacpsif->txTail = tail;
\r
166 void emacps_send_handler(void *arg)
\r
168 xemacpsif_s *xemacpsif;
\r
169 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
171 xemacpsif = (xemacpsif_s *)(arg);
\r
173 /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
\r
174 "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
\r
176 xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
\r
177 xemacpsif->txBusy = pdFALSE;
\r
179 if( xEMACTaskHandle != NULL )
\r
181 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
184 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
187 static BaseType_t xValidLength( BaseType_t xLength )
\r
189 BaseType_t xReturn;
\r
191 if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )
\r
203 XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )
\r
205 int head = xemacpsif->txHead;
\r
207 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
\r
208 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
\r
210 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
212 /* This driver wants to own all network buffers which are to be transmitted. */
\r
213 configASSERT( iReleaseAfterSend != pdFALSE );
\r
217 /* Open a do {} while ( 0 ) loop to be able to call break. */
\r
220 uint32_t ulFlags = 0;
\r
222 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
\r
227 if( xTXDescriptorSemaphore == NULL )
\r
232 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
234 FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
\r
238 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
239 /* Pass the pointer (and its ownership) directly to DMA. */
\r
240 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
\r
241 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
243 Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
\r
245 /* Buffer has been transferred, do not release it. */
\r
246 iReleaseAfterSend = pdFALSE;
\r
248 if( pxDMA_tx_buffers[ head ] == NULL )
\r
250 FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );
\r
253 /* Copy the message to unbuffered space in RAM. */
\r
254 memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
\r
256 /* Packets will be sent one-by-one, so for each packet
\r
257 the TXBUF_LAST bit will be set. */
\r
258 ulFlags |= XEMACPS_TXBUF_LAST_MASK;
\r
259 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
\r
260 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
\r
262 ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
\r
265 /* Copy the address of the buffer and set the flags. */
\r
266 xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
\r
267 xemacpsif->txSegments[ head ].flags = ulFlags;
\r
270 if( ++head == ipconfigNIC_N_TX_DESC )
\r
274 /* Update the TX-head index. These variable are declared volatile so they will be
\r
275 accessed as little as possible. */
\r
276 xemacpsif->txHead = head;
\r
277 } while( pdFALSE );
\r
279 if( iReleaseAfterSend != pdFALSE )
\r
281 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
285 /* Data Synchronization Barrier */
\r
288 if( iHasSent != pdFALSE )
\r
290 /* Make STARTTX high */
\r
291 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
\r
292 /* Start transmit */
\r
293 xemacpsif->txBusy = pdTRUE;
\r
294 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
\r
301 void emacps_recv_handler(void *arg)
\r
303 xemacpsif_s *xemacpsif;
\r
304 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
306 xemacpsif = (xemacpsif_s *)(arg);
\r
307 xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
\r
309 if( xEMACTaskHandle != NULL )
\r
311 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
314 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
317 static NetworkBufferDescriptor_t *ethMsg = NULL;
\r
318 static NetworkBufferDescriptor_t *ethLast = NULL;
\r
320 static void passEthMessages( void )
\r
322 IPStackEvent_t xRxEvent;
\r
324 xRxEvent.eEventType = eNetworkRxEvent;
\r
325 xRxEvent.pvData = ( void * ) ethMsg;
\r
327 if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
\r
329 /* The buffer could not be sent to the stack so must be released again.
\r
330 This is a deferred handler taskr, not a real interrupt, so it is ok to
\r
331 use the task level function here. */
\r
334 NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;
\r
335 vReleaseNetworkBufferAndDescriptor( ethMsg );
\r
337 } while( ethMsg != NULL );
\r
339 iptraceETHERNET_RX_EVENT_LOST();
\r
340 FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );
\r
343 ethMsg = ethLast = NULL;
\r
346 int emacps_check_rx( xemacpsif_s *xemacpsif )
\r
348 NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
\r
350 volatile int msgCount = 0;
\r
351 int head = xemacpsif->rxHead;
\r
353 /* There seems to be an issue (SI# 692601), see comments below. */
\r
354 resetrx_on_no_rxdata(xemacpsif);
\r
356 /* This FreeRTOS+TCP driver shall be compiled with the option
\r
357 "ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
\r
358 chain of RX messages within one message to the IP-task. */
\r
361 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
\r
362 ( pxDMA_rx_buffers[ head ] == NULL ) )
\r
367 pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );
\r
368 if( pxNewBuffer == NULL )
\r
370 /* A packet has been received, but there is no replacement for this Network Buffer.
\r
371 The packet will be dropped, and it Network Buffer will stay in place. */
\r
372 FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );
\r
373 pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
\r
377 pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
\r
379 /* Just avoiding to use or refer to the same buffer again */
\r
380 pxDMA_rx_buffers[ head ] = pxNewBuffer;
\r
383 * Adjust the buffer size to the actual number of bytes received.
\r
385 rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
\r
387 pxBuffer->xDataLength = rx_bytes;
\r
389 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
391 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );
\r
394 /* store it in the receive queue, where it'll be processed by a
\r
395 different handler. */
\r
396 iptraceNETWORK_INTERFACE_RECEIVE();
\r
397 pxBuffer->pxNextBuffer = NULL;
\r
399 if( ethMsg == NULL )
\r
401 // Becomes the first message
\r
404 else if( ethLast != NULL )
\r
407 ethLast->pxNextBuffer = pxBuffer;
\r
410 ethLast = pxBuffer;
\r
414 if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
\r
416 Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);
\r
419 uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
\r
420 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
\r
422 addr |= XEMACPS_RXBUF_WRAP_MASK;
\r
424 /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
\r
425 xemacpsif->rxSegments[ head ].address = addr;
\r
426 xemacpsif->rxSegments[ head ].flags = 0;
\r
430 if( ++head == ipconfigNIC_N_RX_DESC )
\r
434 xemacpsif->rxHead = head;
\r
437 if( ethMsg != NULL )
\r
439 passEthMessages( );
\r
445 void clean_dma_txdescs(xemacpsif_s *xemacpsif)
\r
448 unsigned char *ucTxBuffer;
\r
450 /* Clear all TX descriptors and assign uncached memory to each descriptor.
\r
451 "tx_space" points to the first available TX buffer. */
\r
452 ucTxBuffer = xemacpsif->tx_space;
\r
454 for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
\r
456 xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
\r
457 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
\r
458 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
459 pxDMA_tx_buffers[ index ] = ( void* )NULL;
\r
461 pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );
\r
463 ucTxBuffer += xemacpsif->uTxUnitSize;
\r
465 xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
\r
466 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
\r
469 XStatus init_dma(xemacpsif_s *xemacpsif)
\r
471 NetworkBufferDescriptor_t *pxBuffer;
\r
474 UBaseType_t xRxSize;
\r
475 UBaseType_t xTxSize;
\r
476 struct xtopology_t *xtopologyp = &xXTopology;
\r
478 xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
\r
480 xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
\r
482 /* Also round-up to 4KB */
\r
483 xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;
\r
485 * We allocate 65536 bytes for RX BDs which can accommodate a
\r
486 * maximum of 8192 BDs which is much more than any application
\r
489 xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) );
\r
490 xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );
\r
491 xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
\r
493 /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
\r
494 xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
\r
495 xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
\r
497 if( xTXDescriptorSemaphore == NULL )
\r
499 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
\r
500 configASSERT( xTXDescriptorSemaphore );
\r
503 * Allocate RX descriptors, 1 RxBD at a time.
\r
505 for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
\r
507 pxBuffer = pxDMA_rx_buffers[ iIndex ];
\r
508 if( pxBuffer == NULL )
\r
510 pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT, ( TickType_t ) 0 );
\r
511 if( pxBuffer == NULL )
\r
513 FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );
\r
518 xemacpsif->rxSegments[ iIndex ].flags = 0;
\r
519 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
\r
521 pxDMA_rx_buffers[ iIndex ] = pxBuffer;
\r
522 /* Make sure this memory is not in cache for now. */
\r
523 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
\r
525 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
\r
526 (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE + RX_BUFFER_ALIGNMENT);
\r
530 xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
\r
532 memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
\r
534 clean_dma_txdescs( xemacpsif );
\r
538 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
\r
540 // 1xxxx: Attempt to use INCR16 AHB bursts
\r
541 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
\r
542 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
\r
543 value |= XEMACPS_DMACR_TCPCKSUM_MASK;
\r
545 #warning Are you sure the EMAC should not calculate outgoing checksums?
\r
546 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
\r
548 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
\r
552 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
\r
554 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
\r
555 Now tell the EMAC that received messages should be stored at "address + 2". */
\r
556 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
\r
558 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
\r
559 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
\r
561 #warning Are you sure the EMAC should not calculate incoming checksums?
\r
562 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
\r
564 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
\r
568 * Connect the device driver handler that will be called when an
\r
569 * interrupt for the device occurs, the handler defined above performs
\r
570 * the specific interrupt processing for the device.
\r
572 XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
\r
573 (Xil_ExceptionHandler)XEmacPs_IntrHandler,
\r
574 (void *)&xemacpsif->emacps);
\r
576 * Enable the interrupt for emacps.
\r
584 * resetrx_on_no_rxdata():
\r
586 * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
\r
587 * called by the user.
\r
588 * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
\r
589 * Under heavy Rx traffic because of the HW bug there are times when the Rx path
\r
590 * becomes unresponsive. The workaround for it is to check for the Rx path for
\r
591 * traffic (by reading the stats registers regularly). If the stats register
\r
592 * does not increment for sometime (proving no Rx traffic), the function resets
\r
593 * the Rx data path.
\r
597 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
\r
599 unsigned long regctrl;
\r
600 unsigned long tempcntr;
\r
602 tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
\r
603 if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
\r
605 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
\r
606 XEMACPS_NWCTRL_OFFSET);
\r
607 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
\r
608 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
\r
609 XEMACPS_NWCTRL_OFFSET, regctrl);
\r
610 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
\r
611 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
\r
612 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
\r
614 xemacpsif->last_rx_frms_cntr = tempcntr;
\r
617 void EmacDisableIntr(void)
\r
619 XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
\r
622 void EmacEnableIntr(void)
\r
624 XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
\r