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