1 /*
2 * FreeRTOS+TCP V2.3.1
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * http://aws.amazon.com/freertos
23 * http://www.FreeRTOS.org
24 */
25
26 /* Standard includes. */
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 /* FreeRTOS includes. */
32 #include "FreeRTOS.h"
33 #include "task.h"
34 #include "queue.h"
35 #include "semphr.h"
36
37 /* FreeRTOS+TCP includes. */
38 #include "FreeRTOS_IP.h"
39 #include "FreeRTOS_Sockets.h"
40 #include "FreeRTOS_IP_Private.h"
41 #include "FreeRTOS_DNS.h"
42 #include "FreeRTOS_ARP.h"
43 #include "FreeRTOS_Routing.h"
44 #include "NetworkBufferManagement.h"
45 #include "NetworkInterface.h"
46
47 /* Some files from the Atmel Software Framework */
48 /* gmac_SAM.[ch] is a combination of the gmac.[ch] for both SAM4E and SAME70. */
49 #include "gmac_SAM.h"
50 #include <sysclk.h>
51 #include "phyHandling.h"
52
53 /* This file is included to see if 'CONF_BOARD_ENABLE_CACHE' is defined. */
54 #include "conf_board.h"
55
56 /* The SAME70 family has the possibility of caching RAM.
57 * 'NETWORK_BUFFERS_CACHED' can be defined in either "conf_eth.h"
58 * or in "FreeRTOSIPConfig.h".
59 * For now, NETWORK_BUFFERS_CACHED should be defined as zero.
60 * D-cache may be enabled.
61 */
62 #if ( NETWORK_BUFFERS_CACHED != 0 )
63 #error please define this macro as zero
64 #endif
65
66 /* Interrupt events to process. Currently only the Rx event is processed
67 * although code for other events is included to allow for possible future
68 * expansion. */
69 #define EMAC_IF_RX_EVENT 1UL
70 #define EMAC_IF_TX_EVENT 2UL
71 #define EMAC_IF_ERR_EVENT 4UL
72 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
73
74 #ifndef EMAC_MAX_BLOCK_TIME_MS
75
76 /* The task 'prvEMACHandlerTask()' will wake-up every 100 ms, to see
77 * if something has to be done, mostly checking if the PHY has a
78 * change in Link Status. */
79 #define EMAC_MAX_BLOCK_TIME_MS 100ul
80 #endif
81
82 #if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
83 #error This driver works optimal if ipconfigZERO_COPY_RX_DRIVER is defined as 1
84 #endif
85
86 #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
87 #error This driver works optimal if ipconfigZERO_COPY_TX_DRIVER is defined as 1
88 #endif
89
90 /* Default the size of the stack used by the EMAC deferred handler task to 4x
91 * the size of the stack used by the idle task - but allow this to be overridden in
92 * FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
93 #ifndef configEMAC_TASK_STACK_SIZE
94 #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
95 #endif
96
97 #ifndef niEMAC_HANDLER_TASK_PRIORITY
98 #define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
99 #endif
100
101 #if ( NETWORK_BUFFERS_CACHED != 0 ) && ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE )
102 #include "core_cm7.h"
103
104 #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
105 #warning This driver assumes the presence of DCACHE
106 #endif
107
108 #define CACHE_LINE_SIZE 32
109 #define NETWORK_BUFFER_HEADER_SIZE ( ipconfigPACKET_FILLER_SIZE + 8 )
110
cache_clean_invalidate()111 static void cache_clean_invalidate()
112 {
113 /* If you application crashes here, make sure that SCB_EnableDCache() has been called. */
114 SCB_CleanInvalidateDCache();
115 }
116 /*-----------------------------------------------------------*/
117
cache_clean_invalidate_by_addr(uint32_t addr,uint32_t size)118 static void cache_clean_invalidate_by_addr( uint32_t addr,
119 uint32_t size )
120 {
121 /* SAME70 does not have clean/invalidate per area. */
122 SCB_CleanInvalidateDCache_by_Addr( ( uint32_t * ) addr, size );
123 }
124 /*-----------------------------------------------------------*/
125
cache_invalidate_by_addr(uint32_t addr,uint32_t size)126 static void cache_invalidate_by_addr( uint32_t addr,
127 uint32_t size )
128 {
129 /* SAME70 does not have clean/invalidate per area. */
130 SCB_InvalidateDCache_by_Addr( ( uint32_t * ) addr, size );
131 }
132 /*-----------------------------------------------------------*/
133
134 #else /* The DMA buffers are located in non-cached RAM. */
135 #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
136 #warning Sure there is no caching?
137 #endif
138
139 #define cache_clean_invalidate() do {} while( 0 )
140 #define cache_clean_invalidate_by_addr( addr, size ) do {} while( 0 )
141 #define cache_invalidate_by_addr( addr, size ) do {} while( 0 )
142 #endif /* if ( NETWORK_BUFFERS_CACHED != 0 ) && ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) */
143
144 /*-----------------------------------------------------------*/
145
146 /*
147 * Update settings in GMAC for speed and duplex.
148 */
149 static void prvEthernetUpdateConfig( BaseType_t xForce );
150
151 /*
152 * Access functions to the PHY's: read() and write() to be used by
153 * phyHandling.c.
154 */
155 static BaseType_t xPHY_Read( BaseType_t xAddress,
156 BaseType_t xRegister,
157 uint32_t * pulValue );
158 static BaseType_t xPHY_Write( BaseType_t xAddress,
159 BaseType_t xRegister,
160 uint32_t ulValue );
161
162 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
163 void vGMACGenerateChecksum( uint8_t * apBuffer,
164 size_t uxLength );
165 #endif
166
167 /*
168 * Called from the ASF GMAC driver.
169 */
170 void xRxCallback( uint32_t ulStatus );
171 void xTxCallback( uint32_t ulStatus,
172 uint8_t * puc_buffer );
173
174 /*
175 * A deferred interrupt handler task that processes GMAC interrupts.
176 */
177 static void prvEMACHandlerTask( void * pvParameters );
178
179 /*
180 * Initialise the ASF GMAC driver.
181 */
182 static BaseType_t prvGMACInit( NetworkInterface_t * pxInterface );
183
184 /*
185 * Try to obtain an Rx packet from the hardware.
186 */
187 static uint32_t prvEMACRxPoll( void );
188
189 static BaseType_t prvSAM_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface );
190 static BaseType_t prvSAM_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
191 NetworkBufferDescriptor_t * const pxBuffer,
192 BaseType_t bReleaseAfterSend );
193 static BaseType_t prvSAM_GetPhyLinkStatus( NetworkInterface_t * pxInterface );
194
195 NetworkInterface_t * pxSAM_FillInterfaceDescriptor( BaseType_t xEMACIndex,
196 NetworkInterface_t * pxInterface );
197
198 /*
199 * Handle transmission errors.
200 */
201 static void hand_tx_errors( void );
202
203 /* Functions to set the hash table for multicast addresses. */
204 static uint16_t prvGenerateCRC16( const uint8_t * pucAddress );
205 static void prvAddMulticastMACAddress( const uint8_t * ucMacAddress );
206
207 /*-----------------------------------------------------------*/
208
209 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
210 static BaseType_t xGMACSwitchRequired;
211
212 /* LLMNR multicast address. */
213 static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
214
215 /* The GMAC object as defined by the ASF drivers. */
216 static gmac_device_t gs_gmac_dev;
217
218 /* MAC address to use. */
219 extern const uint8_t ucMACAddress[ 6 ];
220
221 /* Holds the handle of the task used as a deferred interrupt processor. The
222 * handle is used so direct notifications can be sent to the task for all EMAC/DMA
223 * related interrupts. */
224 TaskHandle_t xEMACTaskHandle = NULL;
225
226 static NetworkInterface_t * pxMyInterface = NULL;
227
228 /* TX buffers that have been sent must be returned to the driver
229 * using this queue. */
230 static QueueHandle_t xTxBufferQueue;
231
232 /* xTXDescriptorSemaphore is a counting semaphore with
233 * a maximum count of GMAC_TX_BUFFERS, which is the number of
234 * DMA TX descriptors. */
235 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
236
237 /* For local use only: describe the PHY's properties: */
238 const PhyProperties_t xPHYProperties =
239 {
240 #if ( ipconfigETHERNET_AN_ENABLE != 0 )
241 .ucSpeed = PHY_SPEED_AUTO,
242 .ucDuplex = PHY_DUPLEX_AUTO,
243 #else
244 #if ( ipconfigETHERNET_USE_100MB != 0 )
245 .ucSpeed = PHY_SPEED_100,
246 #else
247 .ucSpeed = PHY_SPEED_10,
248 #endif
249
250 #if ( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
251 .ucDuplex = PHY_DUPLEX_FULL,
252 #else
253 .ucDuplex = PHY_DUPLEX_HALF,
254 #endif
255 #endif /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
256
257 #if ( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
258 .ucMDI_X = PHY_MDIX_AUTO,
259 #elif ( ipconfigETHERNET_CROSSED_LINK != 0 )
260 .ucMDI_X = PHY_MDIX_CROSSED,
261 #else
262 .ucMDI_X = PHY_MDIX_DIRECT,
263 #endif
264 };
265
266 /* All PHY handling code has now been separated from the NetworkInterface.c,
267 * see "../Common/phyHandling.c". */
268 static EthernetPhy_t xPhyObject;
269
270 /*-----------------------------------------------------------*/
271
272 /*
273 * GMAC interrupt handler.
274 */
GMAC_Handler(void)275 void GMAC_Handler( void )
276 {
277 xGMACSwitchRequired = pdFALSE;
278
279 /* gmac_handler() may call xRxCallback() which may change
280 * the value of xGMACSwitchRequired. */
281 gmac_handler( &gs_gmac_dev );
282
283 if( xGMACSwitchRequired != pdFALSE )
284 {
285 portEND_SWITCHING_ISR( xGMACSwitchRequired );
286 }
287 }
288 /*-----------------------------------------------------------*/
289
xRxCallback(uint32_t ulStatus)290 void xRxCallback( uint32_t ulStatus )
291 {
292 if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
293 {
294 /* let the prvEMACHandlerTask know that there was an RX event. */
295 xTaskNotifyFromISR( xEMACTaskHandle, EMAC_IF_RX_EVENT, eSetBits, &( xGMACSwitchRequired ) );
296 }
297 }
298 /*-----------------------------------------------------------*/
299
300 /* The following function can be called by gmac_reset_tx_mem().
301 */
returnTxBuffer(uint8_t * puc_buffer)302 void returnTxBuffer( uint8_t * puc_buffer )
303 {
304 /* Called from a non-ISR context. */
305 if( xTxBufferQueue != NULL )
306 {
307 /* return 'puc_buffer' to the pool of transmission buffers. */
308 xQueueSend( xTxBufferQueue, &puc_buffer, 0 );
309 xTaskNotify( xEMACTaskHandle, EMAC_IF_TX_EVENT, eSetBits );
310 }
311 }
312
xTxCallback(uint32_t ulStatus,uint8_t * puc_buffer)313 void xTxCallback( uint32_t ulStatus,
314 uint8_t * puc_buffer )
315 {
316 if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
317 {
318 /* let the prvEMACHandlerTask know that there was an TX event. */
319 /* Wakeup prvEMACHandlerTask. */
320 if( puc_buffer == NULL )
321 {
322 /* (GMAC_TSR) Retry Limit Exceeded */
323 /* Can not send logging, we're in an ISR. */
324 }
325 else
326 {
327 xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
328 xTaskNotifyFromISR( xEMACTaskHandle, EMAC_IF_TX_EVENT, eSetBits, &( xGMACSwitchRequired ) );
329
330 /* TX statistics. Only works when 'GMAC_STATS'
331 * is defined as 1. See gmac_SAM.h for more information. */
332 TX_STAT_INCREMENT( tx_callback );
333 }
334 }
335 }
336 /*-----------------------------------------------------------*/
337
338
339 /*
340 * The two standard defines 'GMAC_MAN_RW_TYPE' and 'GMAC_MAN_READ_ONLY'
341 * are incorrect.
342 * Therefore, use the following:
343 */
344
345 #define GMAC_MAINTENANCE_READ_ACCESS ( 2 )
346 #define GMAC_MAINTENANCE_WRITE_ACCESS ( 1 )
347
xPHY_Read(BaseType_t xAddress,BaseType_t xRegister,uint32_t * pulValue)348 static BaseType_t xPHY_Read( BaseType_t xAddress,
349 BaseType_t xRegister,
350 uint32_t * pulValue )
351 {
352 BaseType_t xReturn;
353 UBaseType_t uxWasEnabled;
354
355 /* Wait until bus idle */
356 while( ( GMAC->GMAC_NSR & GMAC_NSR_IDLE ) == 0 )
357 {
358 }
359
360 /* Write maintain register */
361
362 /*
363 * OP: Operation: 10 is read. 01 is write.
364 */
365 uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u;
366
367 if( uxWasEnabled == 0u )
368 {
369 /* Enable further GMAC maintenance. */
370 GMAC->GMAC_NCR |= GMAC_NCR_MPE;
371 }
372
373 GMAC->GMAC_MAN = GMAC_MAN_WTN( GMAC_MAN_CODE_VALUE )
374 | GMAC_MAN_CLTTO
375 | GMAC_MAN_PHYA( xAddress )
376 | GMAC_MAN_REGA( xRegister )
377 | GMAC_MAN_OP( GMAC_MAINTENANCE_READ_ACCESS )
378 | GMAC_MAN_DATA( ( uint16_t ) 0u );
379
380 if( gmac_wait_phy( GMAC, MAC_PHY_RETRY_MAX ) == GMAC_TIMEOUT )
381 {
382 *pulValue = ( uint32_t ) 0xffffu;
383 xReturn = -1;
384 }
385 else
386 {
387 /* Wait until bus idle */
388 while( ( GMAC->GMAC_NSR & GMAC_NSR_IDLE ) == 0 )
389 {
390 }
391
392 /* Return data */
393 *pulValue = ( uint32_t ) ( GMAC->GMAC_MAN & GMAC_MAN_DATA_Msk );
394
395 xReturn = 0;
396 }
397
398 if( uxWasEnabled == 0u )
399 {
400 /* Disable further GMAC maintenance. */
401 GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
402 }
403
404 return xReturn;
405 }
406 /*-----------------------------------------------------------*/
407
xPHY_Write(BaseType_t xAddress,BaseType_t xRegister,uint32_t ulValue)408 static BaseType_t xPHY_Write( BaseType_t xAddress,
409 BaseType_t xRegister,
410 uint32_t ulValue )
411 {
412 BaseType_t xReturn;
413 UBaseType_t uxWasEnabled;
414
415 /* Wait until bus idle */
416 while( ( GMAC->GMAC_NSR & GMAC_NSR_IDLE ) == 0 )
417 {
418 }
419
420 /* Write maintain register */
421 uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u;
422
423 if( uxWasEnabled == 0u )
424 {
425 /* Enable further GMAC maintenance. */
426 GMAC->GMAC_NCR |= GMAC_NCR_MPE;
427 }
428
429 GMAC->GMAC_MAN = GMAC_MAN_WTN( GMAC_MAN_CODE_VALUE )
430 | GMAC_MAN_CLTTO
431 | GMAC_MAN_PHYA( xAddress )
432 | GMAC_MAN_REGA( xRegister )
433 | GMAC_MAN_OP( GMAC_MAINTENANCE_WRITE_ACCESS )
434 | GMAC_MAN_DATA( ( uint16_t ) ulValue );
435
436 if( gmac_wait_phy( GMAC, MAC_PHY_RETRY_MAX ) == GMAC_TIMEOUT )
437 {
438 xReturn = -1;
439 }
440 else
441 {
442 xReturn = 0;
443 }
444
445 if( uxWasEnabled == 0u )
446 {
447 /* Disable further GMAC maintenance. */
448 GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
449 }
450
451 return xReturn;
452 }
453 /*-----------------------------------------------------------*/
454
prvSAM_NetworkInterfaceInitialise(NetworkInterface_t * pxInterface)455 static BaseType_t prvSAM_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
456 {
457 const TickType_t x5_Seconds = 5000UL;
458
459 if( xEMACTaskHandle == NULL )
460 {
461 prvGMACInit( pxInterface );
462
463 cache_clean_invalidate();
464
465 /* The handler task is created at the highest possible priority to
466 * ensure the interrupt handler can return directly to it. */
467 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle );
468 configASSERT( xEMACTaskHandle );
469 pxMyInterface = pxInterface;
470 }
471
472 if( xTxBufferQueue == NULL )
473 {
474 xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
475 configASSERT( xTxBufferQueue );
476 }
477
478 if( xTXDescriptorSemaphore == NULL )
479 {
480 /* When there are N TX descriptors, we want to use
481 * at most "N-1" simultaneously. */
482 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS - 1U, ( UBaseType_t ) GMAC_TX_BUFFERS - 1U );
483 configASSERT( xTXDescriptorSemaphore );
484 }
485
486 /* When returning non-zero, the stack will become active and
487 * start DHCP (in configured) */
488 return prvSAM_GetPhyLinkStatus( NULL );
489 }
490 /*-----------------------------------------------------------*/
491
492 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
493
494 /* Do not call the following function directly. It is there for downward compatibility.
495 * The function FreeRTOS_IPInit() will call it to initialice the interface and end-point
496 * objects. See the description in FreeRTOS_Routing.h. */
pxFillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)497 NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex,
498 NetworkInterface_t * pxInterface )
499 {
500 pxSAM_FillInterfaceDescriptor( xEMACIndex, pxInterface );
501 }
502
503 #endif
504 /*-----------------------------------------------------------*/
505
pxSAM_FillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)506 NetworkInterface_t * pxSAM_FillInterfaceDescriptor( BaseType_t xEMACIndex,
507 NetworkInterface_t * pxInterface )
508 {
509 static char pcName[ 8 ];
510
511 /* This function pxSAM_FillInterfaceDescriptor() adds a network-interface.
512 * Make sure that the object pointed to by 'pxInterface'
513 * is declared static or global, and that it will remain to exist. */
514
515 snprintf( pcName, sizeof( pcName ), "GMAC%ld", xEMACIndex );
516
517 memset( pxInterface, '\0', sizeof( *pxInterface ) );
518 pxInterface->pcName = pcName; /* Just for logging, debugging. */
519 pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
520 pxInterface->pfInitialise = prvSAM_NetworkInterfaceInitialise;
521 pxInterface->pfOutput = prvSAM_NetworkInterfaceOutput;
522 pxInterface->pfGetPhyLinkStatus = prvSAM_GetPhyLinkStatus;
523
524 FreeRTOS_AddNetworkInterface( pxInterface );
525
526 return pxInterface;
527 }
528 /*-----------------------------------------------------------*/
529
prvSAM_GetPhyLinkStatus(NetworkInterface_t * pxInterface)530 static BaseType_t prvSAM_GetPhyLinkStatus( NetworkInterface_t * pxInterface )
531 {
532 BaseType_t xReturn;
533
534 /*_RB_ Will this parameter be used by any port? */
535
536 /*_HT_ I think it will if there are two instances of an EMAC that share
537 * the same driver and obviously get a different 'NetworkInterface_t'. */
538 /* Avoid warning about unused parameter. */
539 ( void ) pxInterface;
540
541 /* This function returns true if the Link Status in the PHY is high. */
542 if( xPhyObject.ulLinkStatusMask != 0 )
543 {
544 xReturn = pdPASS;
545 }
546 else
547 {
548 xReturn = pdFAIL;
549 }
550
551 return xReturn;
552 }
553 /*-----------------------------------------------------------*/
554
555 /** The GMAC TX errors to handle */
556 #define GMAC_TX_ERRORS ( GMAC_TSR_TFC | GMAC_TSR_HRESP )
557
hand_tx_errors(void)558 static void hand_tx_errors( void )
559 {
560 /* Handle GMAC underrun or AHB errors. */
561 if( gmac_get_tx_status( GMAC ) & GMAC_TX_ERRORS )
562 {
563 gmac_enable_transmit( GMAC, false );
564
565 /* Reinit TX descriptors. */
566 gmac_reset_tx_mem( &gs_gmac_dev );
567 /* Clear error status. */
568 gmac_clear_tx_status( GMAC, GMAC_TX_ERRORS );
569
570 gmac_enable_transmit( GMAC, true );
571 }
572 }
573
574 volatile IPPacket_t * pxSendPacket;
575
prvSAM_NetworkInterfaceOutput(NetworkInterface_t * pxInterface,NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t bReleaseAfterSend)576 static BaseType_t prvSAM_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
577 NetworkBufferDescriptor_t * const pxDescriptor,
578 BaseType_t bReleaseAfterSend )
579 {
580 /* Do not wait too long for a free TX DMA buffer. */
581 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50U );
582 uint32_t ulTransmitSize;
583
584 /* Avoid warning about unused parameter. */
585 ( void ) pxInterface;
586 ulTransmitSize = pxDescriptor->xDataLength;
587
588 pxSendPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer;
589
590 /* 'GMAC_TX_UNITSIZE' is the netto size of a transmission buffer. */
591 if( ulTransmitSize > GMAC_TX_UNITSIZE )
592 {
593 ulTransmitSize = GMAC_TX_UNITSIZE;
594 }
595
596 /* A do{}while(0) loop is introduced to allow the use of multiple break
597 * statement. */
598 do
599 {
600 if( xCheckLoopback( pxDescriptor, bReleaseAfterSend ) != 0 )
601 {
602 /* The packet has been sent back to the IP-task.
603 * The IP-task will further handle it.
604 * Do not release the descriptor. */
605 bReleaseAfterSend = pdFALSE;
606 break;
607 }
608
609 uint32_t ulResult;
610
611 if( xPhyObject.ulLinkStatusMask == 0ul )
612 {
613 /* Do not attempt to send packets as long as the Link Status is low. */
614 break;
615 }
616
617 if( xTXDescriptorSemaphore == NULL )
618 {
619 /* Semaphore has not been created yet? */
620 break;
621 }
622
623 hand_tx_errors();
624
625 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
626 {
627 /* Time-out waiting for a free TX descriptor. */
628 TX_STAT_INCREMENT( tx_enqueue_fail );
629 break;
630 }
631
632 TX_STAT_INCREMENT( tx_enqueue_ok );
633 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
634 {
635 /* Confirm that the pxDescriptor may be kept by the driver. */
636 configASSERT( bReleaseAfterSend != pdFALSE );
637 }
638 #endif /* ipconfigZERO_COPY_TX_DRIVER */
639
640 #if ( NETWORK_BUFFERS_CACHED != 0 )
641 {
642 uint32_t xlength = CACHE_LINE_SIZE * ( ( ulTransmitSize + NETWORK_BUFFER_HEADER_SIZE + CACHE_LINE_SIZE - 1 ) / CACHE_LINE_SIZE );
643 uint32_t xAddress = ( uint32_t ) ( pxDescriptor->pucEthernetBuffer - NETWORK_BUFFER_HEADER_SIZE );
644 cache_clean_invalidate_by_addr( xAddress, xlength );
645 }
646 #endif
647
648 ulResult = gmac_dev_write( &gs_gmac_dev, ( void * ) pxDescriptor->pucEthernetBuffer, ulTransmitSize );
649
650 if( ulResult != GMAC_OK )
651 {
652 TX_STAT_INCREMENT( tx_write_fail );
653 }
654
655 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
656 {
657 /* Confirm that the pxDescriptor may be kept by the driver. */
658 bReleaseAfterSend = pdFALSE;
659 }
660 #endif /* ipconfigZERO_COPY_TX_DRIVER */
661 /* Not interested in a call-back after TX. */
662 iptraceNETWORK_INTERFACE_TRANSMIT();
663 } while( ipFALSE_BOOL );
664
665 if( bReleaseAfterSend != pdFALSE )
666 {
667 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
668 }
669
670 return pdTRUE;
671 }
672 /*-----------------------------------------------------------*/
673
prvGMACInit(NetworkInterface_t * pxInterface)674 static BaseType_t prvGMACInit( NetworkInterface_t * pxInterface )
675 {
676 uint32_t ncfgr;
677 NetworkEndPoint_t * pxEndPoint;
678 BaseType_t xEntry = 1;
679
680 gmac_options_t gmac_option;
681
682 pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
683 configASSERT( pxEndPoint != NULL );
684
685 gmac_enable_management( GMAC, true );
686 /* Enable further GMAC maintenance. */
687 GMAC->GMAC_NCR |= GMAC_NCR_MPE;
688
689 memset( &gmac_option, '\0', sizeof( gmac_option ) );
690 gmac_option.uc_copy_all_frame = 0;
691 gmac_option.uc_no_boardcast = 0;
692 memcpy( gmac_option.uc_mac_addr, pxEndPoint->xMACAddress.ucBytes, sizeof( gmac_option.uc_mac_addr ) );
693
694 gs_gmac_dev.p_hw = GMAC;
695 gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
696
697 NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
698 NVIC_EnableIRQ( GMAC_IRQn );
699
700 /* Clear the hash table for multicast MAC addresses. */
701 GMAC->GMAC_HRB = 0U; /* Hash Register Bottom. */
702 GMAC->GMAC_HRT = 0U; /* Hash Register Top. */
703
704 /* gmac_enable_multicast_hash() sets the wrong bit, don't use it. */
705 /* gmac_enable_multicast_hash( GMAC, pdTRUE ); */
706 /* set Multicast Hash Enable. */
707 GMAC->GMAC_NCFGR |= GMAC_NCFGR_MTIHEN;
708
709 #if ( ipconfigUSE_LLMNR == 1 )
710 {
711 prvAddMulticastMACAddress( xLLMNR_MacAdress.ucBytes );
712 }
713 #endif /* ipconfigUSE_LLMNR */
714
715 #if ( ipconfigUSE_IPv6 != 0 )
716 {
717 NetworkEndPoint_t * pxEndPoint;
718 #if ( ipconfigUSE_LLMNR == 1 )
719 {
720 prvAddMulticastMACAddress( xLLMNR_MacAdressIPv6.ucBytes );
721 }
722 #endif /* ipconfigUSE_LLMNR */
723
724 for( pxEndPoint = FreeRTOS_FirstEndPoint( pxMyInterface );
725 pxEndPoint != NULL;
726 pxEndPoint = FreeRTOS_NextEndPoint( pxMyInterface, pxEndPoint ) )
727 {
728 if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
729 {
730 uint8_t ucMACAddress[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 };
731
732 ucMACAddress[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ];
733 ucMACAddress[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ];
734 ucMACAddress[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ];
735 prvAddMulticastMACAddress( ucMACAddress );
736 }
737 }
738 }
739 #endif /* ipconfigUSE_IPv6 */
740
741 {
742 /* Set MDC clock divider. */
743 gmac_set_mdc_clock( GMAC, sysclk_get_peripheral_hz() );
744
745 vPhyInitialise( &xPhyObject, xPHY_Read, xPHY_Write );
746 xPhyDiscover( &xPhyObject );
747 xPhyConfigure( &xPhyObject, &xPHYProperties );
748
749 /* For a reset / reconfigure of the EMAC. */
750 prvEthernetUpdateConfig( pdTRUE );
751
752 /* Select Media Independent Interface type */
753 #if ( SAME70 != 0 )
754 {
755 /* Selecting RMII mode. */
756 GMAC->GMAC_UR &= ~GMAC_UR_RMII;
757 }
758 #else
759 {
760 gmac_select_mii_mode( GMAC, ETH_PHY_MODE );
761 }
762 #endif
763
764 gmac_enable_transmit( GMAC, true );
765 gmac_enable_receive( GMAC, true );
766 }
767
768 gmac_enable_management( GMAC, false );
769 /* Disable further GMAC maintenance. */
770 GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
771
772 return 1;
773 }
774 /*-----------------------------------------------------------*/
775
prvGenerateCRC16(const uint8_t * pucAddress)776 static uint16_t prvGenerateCRC16( const uint8_t * pucAddress )
777 {
778 uint16_t usSum;
779 uint16_t usValues[ ipMAC_ADDRESS_LENGTH_BYTES ];
780 size_t x;
781
782 /* Get 6 shorts. */
783 for( x = 0; x < ipMAC_ADDRESS_LENGTH_BYTES; x++ )
784 {
785 usValues[ x ] = ( uint16_t ) pucAddress[ x ];
786 }
787
788 /* Apply the hash function. */
789 usSum = ( usValues[ 0 ] >> 6 ) ^ usValues[ 0 ];
790 usSum ^= ( usValues[ 1 ] >> 4 ) ^ ( usValues[ 1 ] << 2 );
791 usSum ^= ( usValues[ 2 ] >> 2 ) ^ ( usValues[ 2 ] << 4 );
792 usSum ^= ( usValues[ 3 ] >> 6 ) ^ usValues[ 3 ];
793 usSum ^= ( usValues[ 4 ] >> 4 ) ^ ( usValues[ 4 ] << 2 );
794 usSum ^= ( usValues[ 5 ] >> 2 ) ^ ( usValues[ 5 ] << 4 );
795
796 usSum &= 0x3FU;
797 return usSum;
798 }
799 /*-----------------------------------------------------------*/
800
prvAddMulticastMACAddress(const uint8_t * ucMacAddress)801 static void prvAddMulticastMACAddress( const uint8_t * ucMacAddress )
802 {
803 uint32_t ulMask;
804 uint16_t usIndex;
805
806 usIndex = prvGenerateCRC16( ucMacAddress );
807
808 ulMask = 1U << ( usIndex % 32 );
809
810 if( usIndex < 32U )
811 {
812 /* 0 .. 31 */
813 GMAC->GMAC_HRB |= ulMask;
814 }
815 else
816 {
817 /* 32 .. 63 */
818 GMAC->GMAC_HRT |= ulMask;
819 }
820 }
821 /*-----------------------------------------------------------*/
822
prvEthernetUpdateConfig(BaseType_t xForce)823 static void prvEthernetUpdateConfig( BaseType_t xForce )
824 {
825 FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
826 xPhyObject.ulLinkStatusMask,
827 ( int ) xForce ) );
828
829 if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
830 {
831 #if ( ipconfigETHERNET_AN_ENABLE != 0 )
832 {
833 UBaseType_t uxWasEnabled;
834
835 /* Restart the auto-negotiation. */
836 uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u;
837
838 if( uxWasEnabled == 0u )
839 {
840 /* Enable further GMAC maintenance. */
841 GMAC->GMAC_NCR |= GMAC_NCR_MPE;
842 }
843
844 xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
845
846 /* Configure the MAC with the Duplex Mode fixed by the
847 * auto-negotiation process. */
848 if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
849 {
850 gmac_enable_full_duplex( GMAC, pdTRUE );
851 }
852 else
853 {
854 gmac_enable_full_duplex( GMAC, pdFALSE );
855 }
856
857 /* Configure the MAC with the speed fixed by the
858 * auto-negotiation process. */
859 if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
860 {
861 gmac_set_speed( GMAC, pdFALSE );
862 }
863 else
864 {
865 gmac_set_speed( GMAC, pdTRUE );
866 }
867
868 if( uxWasEnabled == 0u )
869 {
870 /* Enable further GMAC maintenance. */
871 GMAC->GMAC_NCR &= ~GMAC_NCR_MPE;
872 }
873 }
874 #else /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
875 {
876 if( xPHYProperties.ucDuplex == PHY_DUPLEX_FULL )
877 {
878 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;
879 gmac_enable_full_duplex( GMAC, pdTRUE );
880 }
881 else
882 {
883 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;
884 gmac_enable_full_duplex( GMAC, pdFALSE );
885 }
886
887 if( xPHYProperties.ucSpeed == PHY_SPEED_100 )
888 {
889 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;
890 gmac_set_speed( GMAC, pdTRUE );
891 }
892 else
893 {
894 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;
895 gmac_set_speed( GMAC, pdFALSE );
896 }
897
898 xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;
899
900 /* Use predefined (fixed) configuration. */
901 xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
902 }
903 #endif /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
904 }
905 }
906 /*-----------------------------------------------------------*/
907
vGMACGenerateChecksum(uint8_t * pucBuffer,size_t uxLength)908 void vGMACGenerateChecksum( uint8_t * pucBuffer,
909 size_t uxLength )
910 {
911 ProtocolPacket_t * xProtPacket = ( ProtocolPacket_t * ) pucBuffer;
912
913 /* The SAM4E has problems offloading checksums for transmission.
914 * The SAME70 does not set the CRC for ICMP packets (ping). */
915
916 if( xProtPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
917 {
918 #if ( SAME70 != 0 )
919 if( ( xProtPacket->xICMPPacket.xIPHeader.ucProtocol != ipPROTOCOL_UDP ) &&
920 ( xProtPacket->xICMPPacket.xIPHeader.ucProtocol != ipPROTOCOL_TCP ) )
921 #endif
922 {
923 IPHeader_t * pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
924
925 /* Calculate the IP header checksum. */
926 pxIPHeader->usHeaderChecksum = 0x00;
927 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
928 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
929
930 /* Calculate the TCP checksum for an outgoing packet. */
931 usGenerateProtocolChecksum( pucBuffer, uxLength, pdTRUE );
932 }
933 }
934 else if( xProtPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
935 {
936 ICMPPacket_IPv6_t * xProtPacket16 = ( ICMPPacket_IPv6_t * ) pucBuffer;
937 IPHeader_IPv6_t * pxIPHeader = &( xProtPacket16->xIPHeader );
938
939 #if ( SAME70 != 0 )
940 if( ( pxIPHeader->ucNextHeader != ipPROTOCOL_UDP ) &&
941 ( pxIPHeader->ucNextHeader != ipPROTOCOL_TCP ) )
942 #endif
943 {
944 /* Calculate the TCP checksum for an outgoing packet. */
945 usGenerateProtocolChecksum( pucBuffer, uxLength, pdTRUE );
946 }
947 }
948 else
949 {
950 /* Possibly ARP. */
951 }
952 }
953 /*-----------------------------------------------------------*/
954
prvEMACRxPoll(void)955 static uint32_t prvEMACRxPoll( void )
956 {
957 unsigned char * pucUseBuffer;
958 uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
959 static NetworkBufferDescriptor_t * pxNextNetworkBufferDescriptor = NULL;
960 const UBaseType_t xMinDescriptorsToLeave = 2UL;
961 const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
962 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
963 uint8_t * pucDMABuffer = NULL;
964
965 for( ; ; )
966 {
967 BaseType_t xRelease = pdFALSE;
968
969 /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
970 * descriptor then allocate one now. */
971 if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
972 {
973 pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( GMAC_RX_UNITSIZE, xBlockTime );
974 }
975
976 if( pxNextNetworkBufferDescriptor != NULL )
977 {
978 /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
979 pucUseBuffer = ( unsigned char * ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
980 }
981 else
982 {
983 /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
984 * messages will be flushed and ignored. */
985 pucUseBuffer = NULL;
986 }
987
988 /* Read the next packet from the hardware into pucUseBuffer. */
989 ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, GMAC_RX_UNITSIZE, &ulReceiveCount, &pucDMABuffer );
990
991 if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
992 {
993 /* No data from the hardware. */
994 break;
995 }
996
997 if( pxNextNetworkBufferDescriptor == NULL )
998 {
999 /* Data was read from the hardware, but no descriptor was available
1000 * for it, so it will be dropped. */
1001 iptraceETHERNET_RX_EVENT_LOST();
1002 continue;
1003 }
1004
1005 iptraceNETWORK_INTERFACE_RECEIVE();
1006 #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
1007 {
1008 pxNextNetworkBufferDescriptor = pxPacketBuffer_to_NetworkBuffer( pucDMABuffer );
1009
1010 if( pxNextNetworkBufferDescriptor == NULL )
1011 {
1012 /* Strange: can not translate from a DMA buffer to a Network Buffer. */
1013 break;
1014 }
1015 }
1016 #endif /* ipconfigZERO_COPY_RX_DRIVER */
1017
1018 pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
1019 pxNextNetworkBufferDescriptor->pxInterface = pxMyInterface;
1020 pxNextNetworkBufferDescriptor->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pxNextNetworkBufferDescriptor->pucEthernetBuffer );
1021
1022 if( pxNextNetworkBufferDescriptor->pxEndPoint == NULL )
1023 {
1024 FreeRTOS_printf( ( "NetworkInterface: can not find a proper endpoint\n" ) );
1025 xRelease = pdTRUE;
1026 }
1027 else
1028 {
1029 xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
1030
1031 if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
1032 {
1033 /* xSendEventStructToIPTask() timed out. Release the descriptor. */
1034 xRelease = pdTRUE;
1035 }
1036 }
1037
1038 /* Release the descriptor in case it can not be delivered. */
1039 if( xRelease == pdTRUE )
1040 {
1041 /* The buffer could not be sent to the stack so must be released
1042 * again. */
1043 vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
1044 iptraceETHERNET_RX_EVENT_LOST();
1045 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
1046 }
1047
1048 /* Now the buffer has either been passed to the IP-task,
1049 * or it has been released in the code above. */
1050 pxNextNetworkBufferDescriptor = NULL;
1051 ulReturnValue++;
1052 }
1053
1054 return ulReturnValue;
1055 }
1056 /*-----------------------------------------------------------*/
1057
1058 volatile UBaseType_t uxLastMinBufferCount = 0;
1059 #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1060 volatile UBaseType_t uxLastMinQueueSpace;
1061 #endif
1062 volatile UBaseType_t uxCurrentSemCount;
1063 volatile UBaseType_t uxLowestSemCount;
1064
vCheckBuffersAndQueue(void)1065 void vCheckBuffersAndQueue( void )
1066 {
1067 static UBaseType_t uxCurrentCount;
1068
1069 #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1070 {
1071 uxCurrentCount = uxGetMinimumIPQueueSpace();
1072
1073 if( uxLastMinQueueSpace != uxCurrentCount )
1074 {
1075 /* The logging produced below may be helpful
1076 * while tuning +TCP: see how many buffers are in use. */
1077 uxLastMinQueueSpace = uxCurrentCount;
1078 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
1079 }
1080 }
1081 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
1082 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
1083
1084 if( uxLastMinBufferCount != uxCurrentCount )
1085 {
1086 /* The logging produced below may be helpful
1087 * while tuning +TCP: see how many buffers are in use. */
1088 uxLastMinBufferCount = uxCurrentCount;
1089 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
1090 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
1091 }
1092
1093 if( xTXDescriptorSemaphore != NULL )
1094 {
1095 uxCurrentSemCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
1096
1097 if( uxLowestSemCount > uxCurrentSemCount )
1098 {
1099 uxLowestSemCount = uxCurrentSemCount;
1100 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
1101 }
1102 }
1103 }
1104 /*-----------------------------------------------------------*/
1105
1106 extern uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE ];
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])1107 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
1108 {
1109 uint8_t * ucRAMBuffer = ucNetworkPackets;
1110 uint32_t ulIndex;
1111
1112 for( ulIndex = 0; ulIndex < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ulIndex++ )
1113 {
1114 pxNetworkBuffers[ ulIndex ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
1115 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ulIndex ] ) );
1116 ucRAMBuffer += NETWORK_BUFFER_SIZE;
1117 }
1118
1119 cache_clean_invalidate();
1120 }
1121 /*-----------------------------------------------------------*/
1122
prvEMACHandlerTask(void * pvParameters)1123 static void prvEMACHandlerTask( void * pvParameters )
1124 {
1125 UBaseType_t uxCount;
1126 UBaseType_t uxLowestSemCount = GMAC_TX_BUFFERS + 1;
1127
1128 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
1129 NetworkBufferDescriptor_t * pxBuffer;
1130 #endif
1131 uint8_t * pucBuffer;
1132 BaseType_t xResult = 0;
1133 uint32_t xStatus;
1134 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
1135 uint32_t ulISREvents = 0U;
1136
1137 /* Remove compiler warnings about unused parameters. */
1138 ( void ) pvParameters;
1139
1140 configASSERT( xEMACTaskHandle );
1141
1142 for( ; ; )
1143 {
1144 xResult = 0;
1145 vCheckBuffersAndQueue();
1146
1147 /* Wait for a new event or a time-out. */
1148 xTaskNotifyWait( 0U, /* ulBitsToClearOnEntry */
1149 EMAC_IF_ALL_EVENT, /* ulBitsToClearOnExit */
1150 &( ulISREvents ), /* pulNotificationValue */
1151 ulMaxBlockTime );
1152
1153 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
1154 {
1155 /* Wait for the EMAC interrupt to indicate that another packet has been
1156 * received. */
1157 xResult = prvEMACRxPoll();
1158 }
1159
1160 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
1161 {
1162 while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
1163 {
1164 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
1165 {
1166 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
1167
1168 if( pxBuffer != NULL )
1169 {
1170 vReleaseNetworkBufferAndDescriptor( pxBuffer );
1171 TX_STAT_INCREMENT( tx_release_ok );
1172 }
1173 else
1174 {
1175 TX_STAT_INCREMENT( tx_release_bad );
1176 }
1177 }
1178 #else /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
1179 {
1180 TX_STAT_INCREMENT( tx_release_ok );
1181 }
1182 #endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
1183 uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
1184
1185 if( uxCount < ( GMAC_TX_BUFFERS - 1 ) )
1186 {
1187 /* Tell the counting semaphore that one more TX descriptor is available. */
1188 xSemaphoreGive( xTXDescriptorSemaphore );
1189 }
1190 }
1191 }
1192
1193 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
1194 {
1195 /* Future extension: logging about errors that occurred. */
1196 }
1197
1198 gmac_enable_management( GMAC, true );
1199
1200 if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
1201 {
1202 /* Something has changed to a Link Status, need re-check. */
1203 prvEthernetUpdateConfig( pdFALSE );
1204 }
1205
1206 gmac_enable_management( GMAC, false );
1207 }
1208 }
1209 /*-----------------------------------------------------------*/
1210