1 /*
2 * FreeRTOS+TCP V3.1.0
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 #include "FreeRTOS.h"
29 #include "task.h"
30 #include "timers.h"
31 #include "semphr.h"
32
33 /* FreeRTOS+TCP includes. */
34 #include "FreeRTOS_IP.h"
35 #include "FreeRTOS_Sockets.h"
36 #include "FreeRTOS_IP_Private.h"
37 #include "NetworkBufferManagement.h"
38
39 #include "Zynq/x_emacpsif.h"
40 #include "Zynq/x_topology.h"
41 #include "xstatus.h"
42
43 #include "xparameters.h"
44 #include "xparameters_ps.h"
45 #include "xil_exception.h"
46 #include "xil_mmu.h"
47
48 #include "uncached_memory.h"
49
50 /* Two defines used to set or clear the EMAC interrupt */
51 #define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
52 #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
53
54
55
56 #if ( ipconfigPACKET_FILLER_SIZE != 2 )
57 #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
58 #endif
59 #define TX_OFFSET ipconfigPACKET_FILLER_SIZE
60
61 #define dmaRX_TX_BUFFER_SIZE 1536
62
63 /* Defined in NetworkInterface.c */
64 extern TaskHandle_t xEMACTaskHandle;
65
66 /*
67 * pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
68 * The actual TX buffers are located in uncached RAM.
69 */
70 static unsigned char * pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
71
72 /*
73 * pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
74 * Once a message has been received by the EMAC, the descriptor can be passed
75 * immediately to the IP-task.
76 */
77 static NetworkBufferDescriptor_t * pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
78
79 /*
80 * The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
81 * ./portable/NetworkInterface/Zynq/NetworkInterface.c
82 */
83 extern struct xtopology_t xXTopology;
84
85 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
86
87 /*
88 * The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
89 * In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
90 * "head" is the next index to be written, used.
91 * "tail" is the next index to be read, freed.
92 */
93
is_tx_space_available(xemacpsif_s * xemacpsif)94 int is_tx_space_available( xemacpsif_s * xemacpsif )
95 {
96 size_t uxCount;
97
98 if( xTXDescriptorSemaphore != NULL )
99 {
100 uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
101 }
102 else
103 {
104 uxCount = ( UBaseType_t ) 0u;
105 }
106
107 return uxCount;
108 }
109
emacps_check_tx(xemacpsif_s * xemacpsif)110 void emacps_check_tx( xemacpsif_s * xemacpsif )
111 {
112 int tail = xemacpsif->txTail;
113 int head = xemacpsif->txHead;
114 size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
115
116 /* uxCount is the number of TX descriptors that are in use by the DMA. */
117 /* When done, "TXBUF_USED" will be set. */
118
119 while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
120 {
121 if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
122 {
123 break;
124 }
125
126 {
127 void * pvBuffer = pxDMA_tx_buffers[ tail ];
128 NetworkBufferDescriptor_t * pxBuffer;
129
130 if( pvBuffer != NULL )
131 {
132 pxDMA_tx_buffers[ tail ] = NULL;
133 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
134
135 if( pxBuffer != NULL )
136 {
137 vReleaseNetworkBufferAndDescriptor( pxBuffer );
138 }
139 else
140 {
141 FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
142 }
143 }
144 }
145
146 /* Clear all but the "used" and "wrap" bits. */
147 if( tail < ipconfigNIC_N_TX_DESC - 1 )
148 {
149 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
150 }
151 else
152 {
153 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
154 }
155
156 uxCount--;
157 /* Tell the counting semaphore that one more TX descriptor is available. */
158 xSemaphoreGive( xTXDescriptorSemaphore );
159
160 if( ++tail == ipconfigNIC_N_TX_DESC )
161 {
162 tail = 0;
163 }
164
165 xemacpsif->txTail = tail;
166 }
167 }
168
emacps_send_handler(void * arg)169 void emacps_send_handler( void * arg )
170 {
171 xemacpsif_s * xemacpsif;
172 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
173
174 xemacpsif = ( xemacpsif_s * ) ( arg );
175
176 /* This function is called from an ISR. The Xilinx ISR-handler has already
177 * cleared the TXCOMPL and TXSR_USEDREAD status bits in the XEMACPS_TXSR register.
178 * But it forgets to do a read-back. Do so now to avoid ever-returning ISR's. */
179 ( void ) XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET );
180
181 /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
182 * "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
183 */
184 xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
185 xemacpsif->txBusy = pdFALSE;
186
187 if( xEMACTaskHandle != NULL )
188 {
189 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
190 }
191
192 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
193 }
194
xValidLength(BaseType_t xLength)195 static BaseType_t xValidLength( BaseType_t xLength )
196 {
197 BaseType_t xReturn;
198
199 if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= dmaRX_TX_BUFFER_SIZE ) )
200 {
201 xReturn = pdTRUE;
202 }
203 else
204 {
205 xReturn = pdFALSE;
206 }
207
208 return xReturn;
209 }
210
emacps_send_message(xemacpsif_s * xemacpsif,NetworkBufferDescriptor_t * pxBuffer,int iReleaseAfterSend)211 XStatus emacps_send_message( xemacpsif_s * xemacpsif,
212 NetworkBufferDescriptor_t * pxBuffer,
213 int iReleaseAfterSend )
214 {
215 int head = xemacpsif->txHead;
216 int iHasSent = 0;
217 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
218 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
219
220 /* This driver wants to own all network buffers which are to be transmitted. */
221 configASSERT( iReleaseAfterSend != pdFALSE );
222
223 /* Open a do {} while ( 0 ) loop to be able to call break. */
224 do
225 {
226 uint32_t ulFlags = 0;
227
228 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
229 {
230 break;
231 }
232
233 if( xTXDescriptorSemaphore == NULL )
234 {
235 break;
236 }
237
238 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
239 {
240 FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
241 break;
242 }
243
244 /* Pass the pointer (and its ownership) directly to DMA. */
245 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
246
247 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
248 {
249 Xil_DCacheFlushRange( ( unsigned ) pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
250 }
251
252 /* Buffer has been transferred, do not release it. */
253 iReleaseAfterSend = pdFALSE;
254
255 /* Packets will be sent one-by-one, so for each packet
256 * the TXBUF_LAST bit will be set. */
257 ulFlags |= XEMACPS_TXBUF_LAST_MASK;
258 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
259
260 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
261 {
262 ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
263 }
264
265 /* Copy the address of the buffer and set the flags. */
266 xemacpsif->txSegments[ head ].address = ( uint32_t ) pxDMA_tx_buffers[ head ];
267 xemacpsif->txSegments[ head ].flags = ulFlags;
268
269 iHasSent = pdTRUE;
270
271 if( ++head == ipconfigNIC_N_TX_DESC )
272 {
273 head = 0;
274 }
275
276 /* Update the TX-head index. These variable are declared volatile so they will be
277 * accessed as little as possible. */
278 xemacpsif->txHead = head;
279 } while( pdFALSE );
280
281 if( iReleaseAfterSend != pdFALSE )
282 {
283 vReleaseNetworkBufferAndDescriptor( pxBuffer );
284 pxBuffer = NULL;
285 }
286
287 /* Data Synchronization Barrier */
288 dsb();
289
290 if( iHasSent != pdFALSE )
291 {
292 /* Make STARTTX high */
293 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );
294 /* Start transmit */
295 xemacpsif->txBusy = pdTRUE;
296 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
297 /* Read back the register to make sure the data is flushed. */
298 ( void ) XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );
299 }
300
301 dsb();
302
303 return 0;
304 }
305
emacps_recv_handler(void * arg)306 void emacps_recv_handler( void * arg )
307 {
308 xemacpsif_s * xemacpsif;
309 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
310
311 xemacpsif = ( xemacpsif_s * ) ( arg );
312 xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
313
314 /* The driver has already cleared the FRAMERX, BUFFNA and error bits
315 * in the XEMACPS_RXSR register,
316 * But it forgets to do a read-back. Do so now. */
317 ( void ) XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET );
318
319 if( xEMACTaskHandle != NULL )
320 {
321 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
322 }
323
324 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
325 }
326
prvPassEthMessages(NetworkBufferDescriptor_t * pxDescriptor)327 static void prvPassEthMessages( NetworkBufferDescriptor_t * pxDescriptor )
328 {
329 IPStackEvent_t xRxEvent;
330
331 xRxEvent.eEventType = eNetworkRxEvent;
332 xRxEvent.pvData = ( void * ) pxDescriptor;
333
334 if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
335 {
336 /* The buffer could not be sent to the stack so must be released again.
337 * This is a deferred handler task, not a real interrupt, so it is ok to
338 * use the task level function here. */
339 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
340 {
341 do
342 {
343 NetworkBufferDescriptor_t * pxNext = pxDescriptor->pxNextBuffer;
344 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
345 pxDescriptor = pxNext;
346 } while( pxDescriptor != NULL );
347 }
348 #else
349 {
350 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
351 }
352 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
353 iptraceETHERNET_RX_EVENT_LOST();
354 FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) );
355 }
356 }
357
emacps_check_rx(xemacpsif_s * xemacpsif)358 int emacps_check_rx( xemacpsif_s * xemacpsif )
359 {
360 NetworkBufferDescriptor_t * pxBuffer, * pxNewBuffer;
361 int rx_bytes;
362 volatile int msgCount = 0;
363 int head = xemacpsif->rxHead;
364
365 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
366 NetworkBufferDescriptor_t * pxFirstDescriptor = NULL;
367 NetworkBufferDescriptor_t * pxLastDescriptor = NULL;
368 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
369
370 /* There seems to be an issue (SI# 692601), see comments below. */
371 resetrx_on_no_rxdata( xemacpsif );
372
373 /* This FreeRTOS+TCP driver shall be compiled with the option
374 * "ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
375 * chain of RX messages within one message to the IP-task. */
376 for( ; ; )
377 {
378 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
379 ( pxDMA_rx_buffers[ head ] == NULL ) )
380 {
381 break;
382 }
383
384 pxNewBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );
385
386 if( pxNewBuffer == NULL )
387 {
388 /* A packet has been received, but there is no replacement for this Network Buffer.
389 * The packet will be dropped, and it Network Buffer will stay in place. */
390 FreeRTOS_printf( ( "emacps_check_rx: unable to allocate a Network Buffer\n" ) );
391 pxNewBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ head ];
392 }
393 else
394 {
395 pxBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ head ];
396
397 /* Just avoiding to use or refer to the same buffer again */
398 pxDMA_rx_buffers[ head ] = pxNewBuffer;
399
400 /*
401 * Adjust the buffer size to the actual number of bytes received.
402 */
403 rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
404
405 pxBuffer->xDataLength = rx_bytes;
406
407 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
408 {
409 Xil_DCacheInvalidateRange( ( ( uint32_t ) pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, ( unsigned ) rx_bytes );
410 }
411
412 /* store it in the receive queue, where it'll be processed by a
413 * different handler. */
414 iptraceNETWORK_INTERFACE_RECEIVE();
415 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
416 {
417 pxBuffer->pxNextBuffer = NULL;
418
419 if( pxFirstDescriptor == NULL )
420 {
421 /* Becomes the first message */
422 pxFirstDescriptor = pxBuffer;
423 }
424 else if( pxLastDescriptor != NULL )
425 {
426 /* Add to the tail */
427 pxLastDescriptor->pxNextBuffer = pxBuffer;
428 }
429
430 pxLastDescriptor = pxBuffer;
431 }
432 #else /* if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) */
433 {
434 prvPassEthMessages( pxBuffer );
435 }
436 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
437
438 msgCount++;
439 }
440
441 {
442 if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
443 {
444 Xil_DCacheInvalidateRange( ( ( uint32_t ) pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, ( uint32_t ) dmaRX_TX_BUFFER_SIZE );
445 }
446
447 {
448 uint32_t addr = ( ( uint32_t ) pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
449
450 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
451 {
452 addr |= XEMACPS_RXBUF_WRAP_MASK;
453 }
454
455 /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
456 xemacpsif->rxSegments[ head ].flags = 0;
457 xemacpsif->rxSegments[ head ].address = addr;
458 /* Make sure that the value has reached the peripheral by reading it back. */
459 ( void ) xemacpsif->rxSegments[ head ].address;
460 }
461 }
462
463 if( ++head == ipconfigNIC_N_RX_DESC )
464 {
465 head = 0;
466 }
467
468 xemacpsif->rxHead = head;
469 }
470
471 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
472 {
473 if( pxFirstDescriptor != NULL )
474 {
475 prvPassEthMessages( pxFirstDescriptor );
476 }
477 }
478 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
479
480 return msgCount;
481 }
482
clean_dma_txdescs(xemacpsif_s * xemacpsif)483 void clean_dma_txdescs( xemacpsif_s * xemacpsif )
484 {
485 int index;
486 unsigned char * ucTxBuffer;
487
488 /* Clear all TX descriptors and assign uncached memory to each descriptor.
489 * "tx_space" points to the first available TX buffer. */
490 ucTxBuffer = xemacpsif->tx_space;
491
492 for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
493 {
494 xemacpsif->txSegments[ index ].address = ( uint32_t ) ucTxBuffer;
495 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
496 pxDMA_tx_buffers[ index ] = ( unsigned char * ) NULL;
497 ucTxBuffer += xemacpsif->uTxUnitSize;
498 }
499
500 xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
501 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
502 }
503
init_dma(xemacpsif_s * xemacpsif)504 XStatus init_dma( xemacpsif_s * xemacpsif )
505 {
506 NetworkBufferDescriptor_t * pxBuffer;
507
508 int iIndex;
509 UBaseType_t xRxSize;
510 UBaseType_t xTxSize;
511 struct xtopology_t * xtopologyp = &xXTopology;
512
513 xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
514
515 xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
516
517 xemacpsif->uTxUnitSize = dmaRX_TX_BUFFER_SIZE;
518
519 /*
520 * We allocate 65536 bytes for RX BDs which can accommodate a
521 * maximum of 8192 BDs which is much more than any application
522 * will ever need.
523 */
524 xemacpsif->rxSegments = ( struct xBD_TYPE * ) ( pucGetUncachedMemory( xRxSize ) );
525 xemacpsif->txSegments = ( struct xBD_TYPE * ) ( pucGetUncachedMemory( xTxSize ) );
526 xemacpsif->tx_space = ( unsigned char * ) ( pucGetUncachedMemory( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
527
528 /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
529 xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
530 xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
531
532 if( xTXDescriptorSemaphore == NULL )
533 {
534 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
535 configASSERT( xTXDescriptorSemaphore );
536 }
537
538 /*
539 * Allocate RX descriptors, 1 RxBD at a time.
540 */
541 for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
542 {
543 pxBuffer = pxDMA_rx_buffers[ iIndex ];
544
545 if( pxBuffer == NULL )
546 {
547 pxBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );
548
549 if( pxBuffer == NULL )
550 {
551 FreeRTOS_printf( ( "Unable to allocate a network buffer in recv_handler\n" ) );
552 return -1;
553 }
554 }
555
556 xemacpsif->rxSegments[ iIndex ].flags = 0;
557 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t ) pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
558
559 pxDMA_rx_buffers[ iIndex ] = pxBuffer;
560
561 /* Make sure this memory is not in cache for now. */
562 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
563 {
564 Xil_DCacheInvalidateRange( ( ( uint32_t ) pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
565 ( unsigned ) dmaRX_TX_BUFFER_SIZE );
566 }
567 }
568
569 xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
570
571 memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
572
573 clean_dma_txdescs( xemacpsif );
574
575 {
576 uint32_t value;
577 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
578
579 /* 1xxxx: Attempt to use INCR16 AHB bursts */
580 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
581 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
582 value |= XEMACPS_DMACR_TCPCKSUM_MASK;
583 #else
584 #warning Are you sure the EMAC should not calculate outgoing checksums?
585 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
586 #endif
587 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
588 }
589 {
590 uint32_t value;
591 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
592
593 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
594 * Now tell the EMAC that received messages should be stored at "address + 2". */
595 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
596
597 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
598 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
599 #else
600 #warning Are you sure the EMAC should not calculate incoming checksums?
601 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
602 #endif
603 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
604 }
605
606 /*
607 * Connect the device driver handler that will be called when an
608 * interrupt for the device occurs, the handler defined above performs
609 * the specific interrupt processing for the device.
610 */
611 XScuGic_RegisterHandler( INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
612 ( Xil_ExceptionHandler ) XEmacPs_IntrHandler,
613 ( void * ) &xemacpsif->emacps );
614
615 /*
616 * Enable the interrupt for emacps.
617 */
618 EmacEnableIntr();
619
620 return 0;
621 }
622
623 /*
624 * resetrx_on_no_rxdata():
625 *
626 * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
627 * called by the user.
628 * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
629 * Under heavy Rx traffic because of the HW bug there are times when the Rx path
630 * becomes unresponsive. The workaround for it is to check for the Rx path for
631 * traffic (by reading the stats registers regularly). If the stats register
632 * does not increment for sometime (proving no Rx traffic), the function resets
633 * the Rx data path.
634 *
635 */
636
resetrx_on_no_rxdata(xemacpsif_s * xemacpsif)637 void resetrx_on_no_rxdata( xemacpsif_s * xemacpsif )
638 {
639 unsigned long regctrl;
640 unsigned long tempcntr;
641
642 tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
643
644 if( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
645 {
646 regctrl = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress,
647 XEMACPS_NWCTRL_OFFSET );
648 regctrl &= ( ~XEMACPS_NWCTRL_RXEN_MASK );
649 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress,
650 XEMACPS_NWCTRL_OFFSET, regctrl );
651 regctrl = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET );
652 regctrl |= ( XEMACPS_NWCTRL_RXEN_MASK );
653 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl );
654 }
655
656 xemacpsif->last_rx_frms_cntr = tempcntr;
657 }
658
EmacDisableIntr(void)659 void EmacDisableIntr( void )
660 {
661 XScuGic_DisableIntr( INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr );
662 }
663
EmacEnableIntr(void)664 void EmacEnableIntr( void )
665 {
666 XScuGic_EnableIntr( INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr );
667 }
668