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