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 "x_emacpsif.h"
40 #include "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 #ifndef ipconfigULTRASCALE
51 #error please define ipconfigULTRASCALE
52 #endif
53
54 /* Two defines used to set or clear the EMAC interrupt */
55 #if ( ipconfigULTRASCALE == 1 )
56
57 /*
58 * XPAR_SCUGIC_0_CPU_BASEADDR 0xF9020000U
59 * XPAR_SCUGIC_0_DIST_BASEADDR 0xF9010000U
60 */
61 #define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR
62 #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR
63 #else
64
65 /*
66 * XPAR_SCUGIC_CPU_BASEADDR (XPS_SCU_PERIPH_BASE + 0x00000100U)
67 * XPAR_SCUGIC_DIST_BASEADDR (XPS_SCU_PERIPH_BASE + 0x00001000U)
68 */
69
70 #define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
71 #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
72 #endif
73
74 #if ( ipconfigPACKET_FILLER_SIZE != 2 )
75 #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
76 #endif
77 #define TX_OFFSET ipconfigPACKET_FILLER_SIZE
78
79 #if ( ipconfigNETWORK_MTU > 1526 )
80 #warning the use of Jumbo Frames has not been tested sufficiently yet.
81 #define USE_JUMBO_FRAMES 1
82 #endif
83
84 #if ( USE_JUMBO_FRAMES == 1 )
85 #define dmaRX_TX_BUFFER_SIZE 10240
86 #else
87 #define dmaRX_TX_BUFFER_SIZE 1536
88 #endif
89
90 #if ( ipconfigULTRASCALE == 1 )
91 extern XScuGic xInterruptController;
92 #endif
93
94 /* Defined in NetworkInterface.c */
95 extern TaskHandle_t xEMACTaskHandle;
96
97 /*
98 * pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
99 * The actual TX buffers are located in uncached RAM.
100 */
101 static unsigned char * pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
102
103 /*
104 * pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
105 * Once a message has been received by the EMAC, the descriptor can be passed
106 * immediately to the IP-task.
107 */
108 static NetworkBufferDescriptor_t * pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
109
110 /*
111 * The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
112 * ./portable/NetworkInterface/Zynq/NetworkInterface.c
113 */
114 extern struct xtopology_t xXTopology;
115
116 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
117
118 /*
119 * The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
120 * In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
121 * "head" is the next index to be written, used.
122 * "tail" is the next index to be read, freed.
123 */
124
is_tx_space_available(xemacpsif_s * xemacpsif)125 int is_tx_space_available( xemacpsif_s * xemacpsif )
126 {
127 size_t uxCount;
128
129 if( xTXDescriptorSemaphore != NULL )
130 {
131 uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
132 }
133 else
134 {
135 uxCount = ( UBaseType_t ) 0u;
136 }
137
138 return uxCount;
139 }
140
emacps_check_tx(xemacpsif_s * xemacpsif)141 void emacps_check_tx( xemacpsif_s * xemacpsif )
142 {
143 int tail = xemacpsif->txTail;
144 int head = xemacpsif->txHead;
145 size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
146
147 /* uxCount is the number of TX descriptors that are in use by the DMA. */
148 /* When done, "TXBUF_USED" will be set. */
149
150 while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
151 {
152 if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
153 {
154 break;
155 }
156
157 {
158 void * pvBuffer = pxDMA_tx_buffers[ tail ];
159 NetworkBufferDescriptor_t * pxBuffer;
160
161 if( pvBuffer != NULL )
162 {
163 pxDMA_tx_buffers[ tail ] = NULL;
164 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
165
166 if( pxBuffer != NULL )
167 {
168 vReleaseNetworkBufferAndDescriptor( pxBuffer );
169 }
170 else
171 {
172 FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
173 }
174 }
175 }
176
177 /* Clear all but the "used" and "wrap" bits. */
178 if( tail < ipconfigNIC_N_TX_DESC - 1 )
179 {
180 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
181 }
182 else
183 {
184 xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
185 }
186
187 uxCount--;
188 /* Tell the counting semaphore that one more TX descriptor is available. */
189 xSemaphoreGive( xTXDescriptorSemaphore );
190
191 if( ++tail == ipconfigNIC_N_TX_DESC )
192 {
193 tail = 0;
194 }
195
196 xemacpsif->txTail = tail;
197 }
198 }
199
emacps_send_handler(void * arg)200 void emacps_send_handler( void * arg )
201 {
202 xemacpsif_s * xemacpsif;
203 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
204
205 xemacpsif = ( xemacpsif_s * ) arg;
206
207 /* This function is called from an ISR. The Xilinx ISR-handler has already
208 * cleared the TXCOMPL and TXSR_USEDREAD status bits in the XEMACPS_TXSR register.
209 * But it forgets to do a read-back. Do so now to avoid ever-returning ISR's. */
210 ( void ) XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET );
211
212 /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
213 * "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
214 */
215 xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
216 xemacpsif->txBusy = pdFALSE;
217
218 if( xEMACTaskHandle != NULL )
219 {
220 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
221 }
222
223 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
224 }
225
xValidLength(BaseType_t xLength)226 static BaseType_t xValidLength( BaseType_t xLength )
227 {
228 BaseType_t xReturn;
229
230 if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= dmaRX_TX_BUFFER_SIZE ) )
231 {
232 xReturn = pdTRUE;
233 }
234 else
235 {
236 xReturn = pdFALSE;
237 }
238
239 return xReturn;
240 }
241
emacps_send_message(xemacpsif_s * xemacpsif,NetworkBufferDescriptor_t * pxBuffer,int iReleaseAfterSend)242 XStatus emacps_send_message( xemacpsif_s * xemacpsif,
243 NetworkBufferDescriptor_t * pxBuffer,
244 int iReleaseAfterSend )
245 {
246 int head = xemacpsif->txHead;
247 int iHasSent = 0;
248 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
249 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000U );
250
251 /* This driver wants to own all network buffers which are to be transmitted. */
252 configASSERT( iReleaseAfterSend != pdFALSE );
253
254 /* Open a do {} while ( 0 ) loop to be able to call break. */
255 do
256 {
257 uint32_t ulFlags = 0;
258
259 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
260 {
261 break;
262 }
263
264 if( xTXDescriptorSemaphore == NULL )
265 {
266 break;
267 }
268
269 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
270 {
271 FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
272 break;
273 }
274
275 /* Pass the pointer (and its ownership) directly to DMA. */
276 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
277
278 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
279 {
280 Xil_DCacheFlushRange( ( INTPTR ) pxBuffer->pucEthernetBuffer, ( INTPTR ) pxBuffer->xDataLength );
281 }
282
283 /* Buffer has been transferred, do not release it. */
284 iReleaseAfterSend = pdFALSE;
285
286 /* Packets will be sent one-by-one, so for each packet
287 * the TXBUF_LAST bit will be set. */
288 ulFlags |= XEMACPS_TXBUF_LAST_MASK;
289 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
290
291 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
292 {
293 ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
294 }
295
296 /* Copy the address of the buffer and set the flags. */
297 xemacpsif->txSegments[ head ].address = ( uintptr_t ) pxDMA_tx_buffers[ head ];
298 xemacpsif->txSegments[ head ].flags = ulFlags;
299
300 iHasSent = pdTRUE;
301
302 if( ++head == ipconfigNIC_N_TX_DESC )
303 {
304 head = 0;
305 }
306
307 /* Update the TX-head index. These variable are declared volatile so they will be
308 * accessed as little as possible. */
309 xemacpsif->txHead = head;
310 } while( pdFALSE );
311
312 if( iReleaseAfterSend != pdFALSE )
313 {
314 vReleaseNetworkBufferAndDescriptor( pxBuffer );
315 pxBuffer = NULL;
316 }
317
318 /* Data Synchronization Barrier */
319 dsb();
320
321 if( iHasSent != pdFALSE )
322 {
323 /* Make STARTTX high */
324 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );
325 /* Start transmit */
326 xemacpsif->txBusy = pdTRUE;
327 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
328 /* Read back the register to make sure the data is flushed. */
329 ( void ) XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );
330 }
331
332 dsb();
333
334 return 0;
335 }
336
emacps_recv_handler(void * arg)337 void emacps_recv_handler( void * arg )
338 {
339 xemacpsif_s * xemacpsif;
340 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
341
342 xemacpsif = ( xemacpsif_s * ) arg;
343 xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
344
345 /* The driver has already cleared the FRAMERX, BUFFNA and error bits
346 * in the XEMACPS_RXSR register,
347 * But it forgets to do a read-back. Do so now. */
348 ( void ) XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET );
349
350 if( xEMACTaskHandle != NULL )
351 {
352 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
353 }
354
355 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
356 }
357
prvPassEthMessages(NetworkBufferDescriptor_t * pxDescriptor)358 static void prvPassEthMessages( NetworkBufferDescriptor_t * pxDescriptor )
359 {
360 IPStackEvent_t xRxEvent;
361
362 xRxEvent.eEventType = eNetworkRxEvent;
363 xRxEvent.pvData = ( void * ) pxDescriptor;
364
365 if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000U ) != pdPASS )
366 {
367 /* The buffer could not be sent to the stack so must be released again.
368 * This is a deferred handler taskr, not a real interrupt, so it is ok to
369 * use the task level function here. */
370 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
371 {
372 do
373 {
374 NetworkBufferDescriptor_t * pxNext = pxDescriptor->pxNextBuffer;
375 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
376 pxDescriptor = pxNext;
377 } while( pxDescriptor != NULL );
378 }
379 #else
380 {
381 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
382 }
383 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
384 iptraceETHERNET_RX_EVENT_LOST();
385 FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) );
386 }
387 }
388
emacps_check_rx(xemacpsif_s * xemacpsif)389 int emacps_check_rx( xemacpsif_s * xemacpsif )
390 {
391 NetworkBufferDescriptor_t * pxBuffer, * pxNewBuffer;
392 int rx_bytes;
393 volatile int msgCount = 0;
394 int head = xemacpsif->rxHead;
395
396 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
397 NetworkBufferDescriptor_t * pxFirstDescriptor = NULL;
398 NetworkBufferDescriptor_t * pxLastDescriptor = NULL;
399 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
400
401 /* There seems to be an issue (SI# 692601), see comments below. */
402 resetrx_on_no_rxdata( xemacpsif );
403
404 /* This FreeRTOS+TCP driver shall be compiled with the option
405 * "ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
406 * chain of RX messages within one message to the IP-task. */
407 for( ; ; )
408 {
409 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
410 ( pxDMA_rx_buffers[ head ] == NULL ) )
411 {
412 break;
413 }
414
415 pxNewBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );
416
417 if( pxNewBuffer == NULL )
418 {
419 /* A packet has been received, but there is no replacement for this Network Buffer.
420 * The packet will be dropped, and it Network Buffer will stay in place. */
421 FreeRTOS_printf( ( "emacps_check_rx: unable to allocate a Network Buffer\n" ) );
422 pxNewBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ head ];
423 }
424 else
425 {
426 pxBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ head ];
427
428 /* Just avoiding to use or refer to the same buffer again */
429 pxDMA_rx_buffers[ head ] = pxNewBuffer;
430
431 /*
432 * Adjust the buffer size to the actual number of bytes received.
433 */
434 rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
435
436 pxBuffer->xDataLength = rx_bytes;
437
438 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
439 {
440 Xil_DCacheInvalidateRange( ( ( uintptr_t ) pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, ( unsigned ) rx_bytes );
441 }
442
443 /* store it in the receive queue, where it'll be processed by a
444 * different handler. */
445 iptraceNETWORK_INTERFACE_RECEIVE();
446 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
447 {
448 pxBuffer->pxNextBuffer = NULL;
449
450 if( pxFirstDescriptor == NULL )
451 {
452 /* Becomes the first message */
453 pxFirstDescriptor = pxBuffer;
454 }
455 else if( pxLastDescriptor != NULL )
456 {
457 /* Add to the tail */
458 pxLastDescriptor->pxNextBuffer = pxBuffer;
459 }
460
461 pxLastDescriptor = pxBuffer;
462 }
463 #else /* if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) */
464 {
465 prvPassEthMessages( pxBuffer );
466 }
467 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
468
469 msgCount++;
470 }
471
472 {
473 if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
474 {
475 Xil_DCacheInvalidateRange( ( ( uintptr_t ) pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, ( uint32_t ) dmaRX_TX_BUFFER_SIZE );
476 }
477
478 {
479 uintptr_t addr = ( ( uintptr_t ) pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
480
481 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
482 {
483 addr |= XEMACPS_RXBUF_WRAP_MASK;
484 }
485
486 /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
487 xemacpsif->rxSegments[ head ].flags = 0;
488 xemacpsif->rxSegments[ head ].address = addr;
489 /* Make sure that the value has reached the peripheral by reading it back. */
490 ( void ) xemacpsif->rxSegments[ head ].address;
491 }
492 }
493
494 if( ++head == ipconfigNIC_N_RX_DESC )
495 {
496 head = 0;
497 }
498
499 xemacpsif->rxHead = head;
500 }
501
502 #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
503 {
504 if( pxFirstDescriptor != NULL )
505 {
506 prvPassEthMessages( pxFirstDescriptor );
507 }
508 }
509 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
510
511 return msgCount;
512 }
513
clean_dma_txdescs(xemacpsif_s * xemacpsif)514 void clean_dma_txdescs( xemacpsif_s * xemacpsif )
515 {
516 int index;
517
518 for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
519 {
520 xemacpsif->txSegments[ index ].address = ( uintptr_t ) NULL;
521 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
522 pxDMA_tx_buffers[ index ] = ( unsigned char * ) NULL;
523 }
524
525 xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
526 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
527 }
528
init_dma(xemacpsif_s * xemacpsif)529 XStatus init_dma( xemacpsif_s * xemacpsif )
530 {
531 NetworkBufferDescriptor_t * pxBuffer;
532
533 int iIndex;
534 UBaseType_t xRxSize;
535 UBaseType_t xTxSize;
536 struct xtopology_t * xtopologyp = &xXTopology;
537 XEmacPs_BdRing * rxRing;
538 XEmacPs * emac = &( xemacpsif->emacps );
539 XEmacPs_Bd bdTemplate;
540 XEmacPs_Bd * dmaBdPtr = NULL;
541 uint32_t status;
542
543 xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
544
545 xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
546
547 xemacpsif->uTxUnitSize = ( dmaRX_TX_BUFFER_SIZE + 0x1000UL ) & ~0xfffUL;
548
549 /*
550 * We allocate 65536 bytes for RX BDs which can accommodate a
551 * maximum of 8192 BDs which is much more than any application
552 * will ever need.
553 */
554 xemacpsif->rxSegments = ( struct xBD_TYPE * ) ( pucGetUncachedMemory( xRxSize ) );
555 xemacpsif->txSegments = ( struct xBD_TYPE * ) ( pucGetUncachedMemory( xTxSize ) );
556
557 configASSERT( xemacpsif->rxSegments );
558 configASSERT( xemacpsif->txSegments );
559 configASSERT( ( ( ( uintptr_t ) xemacpsif->rxSegments ) % XEMACPS_DMABD_MINIMUM_ALIGNMENT ) == 0 );
560 configASSERT( ( ( ( uintptr_t ) xemacpsif->txSegments ) % XEMACPS_DMABD_MINIMUM_ALIGNMENT ) == 0 );
561
562
563 rxRing = &( XEmacPs_GetRxRing( emac ) );
564 XEmacPs_BdClear( bdTemplate );
565
566 status = XEmacPs_BdRingCreate( rxRing, ( UINTPTR ) xemacpsif->rxSegments,
567 ( UINTPTR ) xemacpsif->rxSegments, XEMACPS_DMABD_MINIMUM_ALIGNMENT,
568 ipconfigNIC_N_RX_DESC );
569
570 if( status != 0 )
571 {
572 return status;
573 }
574
575 status = XEmacPs_BdRingClone( rxRing, &bdTemplate, XEMACPS_RECV );
576
577 if( status != 0 )
578 {
579 return status;
580 }
581
582 if( xTXDescriptorSemaphore == NULL )
583 {
584 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
585 configASSERT( xTXDescriptorSemaphore != NULL );
586 }
587
588 /*
589 * Allocate RX descriptors, 1 RxBD at a time.
590 */
591 for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
592 {
593 pxBuffer = pxDMA_rx_buffers[ iIndex ];
594
595 if( pxBuffer == NULL )
596 {
597 pxBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );
598
599 if( pxBuffer == NULL )
600 {
601 FreeRTOS_printf( ( "Unable to allocate a network buffer in recv_handler\n" ) );
602 return -1;
603 }
604 }
605
606 status = XEmacPs_BdRingAlloc( rxRing, 1, &dmaBdPtr );
607
608 if( status != 0 )
609 {
610 return status;
611 }
612
613 XEmacPs_BdSetAddressRx( dmaBdPtr,
614 ( ( uintptr_t ) pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK );
615
616 status = XEmacPs_BdRingToHw( rxRing, 1, dmaBdPtr );
617
618 if( status != 0 )
619 {
620 return status;
621 }
622
623 /* Writing for debug - can look at it in RX processing */
624 #ifdef __aarch64__
625 xemacpsif->rxSegments[ iIndex ].reserved = iIndex;
626 #endif
627
628 pxDMA_rx_buffers[ iIndex ] = pxBuffer;
629
630 /* Make sure this memory is not in cache for now. */
631 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
632 {
633 Xil_DCacheInvalidateRange( ( ( uintptr_t ) pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
634 ( unsigned ) dmaRX_TX_BUFFER_SIZE );
635 }
636 }
637
638 xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
639
640 clean_dma_txdescs( xemacpsif );
641
642 {
643 uint32_t value;
644 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
645
646 /* 1xxxx: Attempt to use INCR16 AHB bursts */
647 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
648 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
649 value |= XEMACPS_DMACR_TCPCKSUM_MASK;
650 #else
651 #warning Are you sure the EMAC should not calculate outgoing checksums?
652 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
653 #endif
654 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
655 }
656 {
657 uint32_t value;
658 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
659
660 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
661 * Now tell the EMAC that received messages should be stored at "address + 2". */
662 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
663
664 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
665 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
666 #else
667 #warning Are you sure the EMAC should not calculate incoming checksums?
668 value &= ~( ( uint32_t ) XEMACPS_NWCFG_RXCHKSUMEN_MASK );
669 #endif
670 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
671 }
672
673 /* Set terminating BDs for US+ GEM */
674 if( xemacpsif->emacps.Version > 2 )
675 {
676 xemacpsif->rxBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->rxBdTerminator ) );
677 xemacpsif->txBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->txBdTerminator ) );
678
679 XEmacPs_BdClear( xemacpsif->rxBdTerminator );
680 XEmacPs_BdSetAddressRx( xemacpsif->rxBdTerminator, ( XEMACPS_RXBUF_NEW_MASK |
681 XEMACPS_RXBUF_WRAP_MASK ) );
682 XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_RXQ1BASE_OFFSET ),
683 ( UINTPTR ) xemacpsif->rxBdTerminator );
684
685 XEmacPs_BdClear( xemacpsif->txBdTerminator );
686 XEmacPs_BdSetStatus( xemacpsif->txBdTerminator,
687 ( XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK ) );
688 XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_TXQBASE_OFFSET ),
689 ( UINTPTR ) xemacpsif->txBdTerminator );
690 }
691
692 /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
693 XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->rxSegments, 0, XEMACPS_RECV );
694
695 if( xemacpsif->emacps.Version > 2 )
696 {
697 XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->txSegments, 1, XEMACPS_SEND );
698 }
699 else
700 {
701 XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->txSegments, 0, XEMACPS_SEND );
702 }
703
704 XScuGic_Connect( &xInterruptController,
705 xtopologyp->scugic_emac_intr,
706 XEmacPs_IntrHandler,
707 emac );
708
709 /*
710 * Enable the interrupt for emacps.
711 */
712 EmacEnableIntr();
713
714 return 0;
715 }
716
717 /*
718 * resetrx_on_no_rxdata():
719 *
720 * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
721 * called by the user.
722 * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
723 * Under heavy Rx traffic because of the HW bug there are times when the Rx path
724 * becomes unresponsive. The workaround for it is to check for the Rx path for
725 * traffic (by reading the stats registers regularly). If the stats register
726 * does not increment for sometime (proving no Rx traffic), the function resets
727 * the Rx data path.
728 *
729 */
730
resetrx_on_no_rxdata(xemacpsif_s * xemacpsif)731 void resetrx_on_no_rxdata( xemacpsif_s * xemacpsif )
732 {
733 uint32_t regctrl;
734 uint32_t tempcntr;
735
736 tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
737
738 if( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
739 {
740 regctrl = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress,
741 XEMACPS_NWCTRL_OFFSET );
742 regctrl &= ( ~XEMACPS_NWCTRL_RXEN_MASK );
743 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress,
744 XEMACPS_NWCTRL_OFFSET, regctrl );
745 regctrl = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET );
746 regctrl |= ( XEMACPS_NWCTRL_RXEN_MASK );
747 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl );
748 }
749
750 xemacpsif->last_rx_frms_cntr = tempcntr;
751 }
752
EmacDisableIntr(void)753 void EmacDisableIntr( void )
754 {
755 XScuGic_DisableIntr( INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr );
756 }
757
EmacEnableIntr(void)758 void EmacEnableIntr( void )
759 {
760 XScuGic_Enable( &xInterruptController, xXTopology.scugic_emac_intr );
761 }
762