1 /*
2  * Some constants, hardware definitions and comments taken from ST's HAL driver
3  * library, COPYRIGHT(c) 2015 STMicroelectronics.
4  */
5 
6 /*
7  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
8  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
9  *
10  * SPDX-License-Identifier: MIT
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of
13  * this software and associated documentation files (the "Software"), to deal in
14  * the Software without restriction, including without limitation the rights to
15  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
16  * the Software, and to permit persons to whom the Software is furnished to do so,
17  * subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
25  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
26  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28  *
29  * http://aws.amazon.com/freertos
30  * http://www.FreeRTOS.org
31  */
32 
33 /* Standard includes. */
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 
38 /* FreeRTOS includes. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 #include "queue.h"
42 #include "semphr.h"
43 
44 /* FreeRTOS+TCP includes. */
45 #include "FreeRTOS_IP.h"
46 #include "FreeRTOS_Sockets.h"
47 #include "FreeRTOS_IP_Private.h"
48 #include "FreeRTOS_DNS.h"
49 #include "FreeRTOS_ARP.h"
50 #include "NetworkBufferManagement.h"
51 #include "NetworkInterface.h"
52 #include "phyHandling.h"
53 #include "FreeRTOS_Routing.h"
54 
55 #include "stm32fxx_hal_eth.h"
56 
57 /* ST includes. */
58 #if defined( STM32F7xx )
59     #include "stm32f7xx_hal.h"
60     #define CACHE_LINE_SIZE    32u
61 #elif defined( STM32F4xx )
62     #include "stm32f4xx_hal.h"
63 #elif defined( STM32F2xx )
64     #include "stm32f2xx_hal.h"
65 #elif defined( STM32F1xx )
66     #include "stm32f1xx_hal.h"
67 #elif !defined( _lint ) /* Lint does not like an #error */
68     #error What part?
69 #endif /* if defined( STM32F7xx ) */
70 
71 
72 /* Interrupt events to process.  Currently only the Rx event is processed
73  * although code for other events is included to allow for possible future
74  * expansion. */
75 #define EMAC_IF_RX_EVENT        1UL
76 #define EMAC_IF_TX_EVENT        2UL
77 #define EMAC_IF_ERR_EVENT       4UL
78 #define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
79 
80 /* Calculate the maximum packet size that the DMA can receive. */
81 #define EMAC_DMA_BUFFER_SIZE    ( ( uint32_t ) ( ETH_MAX_PACKET_SIZE - ipBUFFER_PADDING ) )
82 
83 #define ETH_DMA_ALL_INTS                                                  \
84     ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | \
85       ETH_DMA_IT_AIS | ETH_DMA_IT_ER | ETH_DMA_IT_FBE | ETH_DMA_IT_RWT |  \
86       ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | ETH_DMA_IT_TU |    \
87       ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )
88 
89 #ifndef NETWORK_BUFFER_HEADER_SIZE
90     #define NETWORK_BUFFER_HEADER_SIZE    ( ipBUFFER_PADDING )
91 #endif
92 
93 #ifndef niEMAC_HANDLER_TASK_PRIORITY
94     #define niEMAC_HANDLER_TASK_PRIORITY    configMAX_PRIORITIES - 1
95 #endif
96 
97 #if ( ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )
98     #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
99         #warning Consider enabling checksum offloading
100     #endif
101 #endif
102 
103 #ifndef niDESCRIPTOR_WAIT_TIME_MS
104     #define niDESCRIPTOR_WAIT_TIME_MS    250uL
105 #endif
106 
107 /*
108  * Most users will want a PHY that negotiates about
109  * the connection properties: speed, dmix and duplex.
110  * On some rare cases, you want to select what is being
111  * advertised, properties like MDIX and duplex.
112  */
113 
114 #if !defined( ipconfigETHERNET_AN_ENABLE )
115     /* Enable auto-negotiation */
116     #define ipconfigETHERNET_AN_ENABLE    1
117 #endif
118 
119 #if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )
120     #define ipconfigETHERNET_AUTO_CROSS_ENABLE    1
121 #endif
122 
123 #if ( ipconfigETHERNET_AN_ENABLE == 0 )
124 
125 /*
126  * The following three defines are only used in case there
127  * is no auto-negotiation.
128  */
129     #if !defined( ipconfigETHERNET_CROSSED_LINK )
130         #define ipconfigETHERNET_CROSSED_LINK    1
131     #endif
132 
133     #if !defined( ipconfigETHERNET_USE_100MB )
134         #define ipconfigETHERNET_USE_100MB    1
135     #endif
136 
137     #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
138         #define ipconfigETHERNET_USE_FULL_DUPLEX    1
139     #endif
140 #endif /* ipconfigETHERNET_AN_ENABLE == 0 */
141 
142 /* Default the size of the stack used by the EMAC deferred handler task to twice
143  * the size of the stack used by the idle task - but allow this to be overridden in
144  * FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
145 #ifndef configEMAC_TASK_STACK_SIZE
146     #define configEMAC_TASK_STACK_SIZE    ( 2 * configMINIMAL_STACK_SIZE )
147 #endif
148 
149 /* Two choices must be made: RMII versus MII,
150  * and the index of the PHY in use ( between 0 and 31 ). */
151 #ifndef ipconfigUSE_RMII
152     #ifdef STM32F7xx
153         #define ipconfigUSE_RMII    1
154         #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
155             #warning Using RMII, make sure if this is correct
156         #endif
157     #else
158         #define ipconfigUSE_RMII    0
159         #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
160             #warning Using MII, make sure if this is correct
161         #endif
162     #endif /* STM32F7xx */
163 #endif /* ipconfigUSE_RMII */
164 
165 typedef enum
166 {
167     eMACInit,   /* Must initialise MAC. */
168     eMACPass,   /* Initialisation was successful. */
169     eMACFailed, /* Initialisation failed. */
170 } eMAC_INIT_STATUS_TYPE;
171 
172 static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
173 
174 /*-----------------------------------------------------------*/
175 
176 /*
177  * A deferred interrupt handler task that processes
178  */
179 static void prvEMACHandlerTask( void * pvParameters );
180 
181 /*
182  * Force a negotiation with the Switch or Router and wait for LS.
183  */
184 static void prvEthernetUpdateConfig( BaseType_t xForce );
185 
186 /*
187  * See if there is a new packet and forward it to the IP-task.
188  */
189 static BaseType_t prvNetworkInterfaceInput( void );
190 
191 
192 /*
193  * For LLMNR, an extra MAC-address must be configured to
194  * be able to receive the multicast messages.
195  */
196 static void prvMACAddressConfig( ETH_HandleTypeDef * heth,
197                                  uint32_t ulIndex,
198                                  uint8_t * Addr );
199 
200 /* FreeRTOS+TCP/multi :
201  * Each network device has 3 access functions:
202  * - Initialise the device
203  * - Output a network packet
204  * - Return the PHY Link-Status (LS)
205  * They can be defined as static because the function addresses
206  * will be stored in struct NetworkInterface_t.  The latter will be done in
207  * the function pxSTM32Fxx_FillInterfaceDescriptor(). */
208 
209 static BaseType_t xSTM32F_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface );
210 
211 static BaseType_t xSTM32F_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
212                                                   NetworkBufferDescriptor_t * const pxBuffer,
213                                                   BaseType_t bReleaseAfterSend );
214 
215 static BaseType_t xSTM32F_GetPhyLinkStatus( NetworkInterface_t * pxInterface );
216 
217 NetworkInterface_t * pxSTM32Fxx_FillInterfaceDescriptor( BaseType_t xEMACIndex,
218                                                          NetworkInterface_t * pxInterface );
219 
220 /*
221  * Check if a given packet should be accepted.
222  */
223 static BaseType_t xMayAcceptPacket( uint8_t * pucEthernetBuffer );
224 
225 /*
226  * Initialise the TX descriptors.
227  */
228 static void prvDMATxDescListInit( void );
229 
230 /*
231  * Initialise the RX descriptors.
232  */
233 static void prvDMARxDescListInit( void );
234 
235 /* After packets have been sent, the network
236  * buffers will be released. */
237 static void vClearTXBuffers( void );
238 
239 /*-----------------------------------------------------------*/
240 
241 #if ( ipconfigUSE_LLMNR == 1 )
242     static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
243 #endif
244 
245 #if ( ipconfigUSE_MDNS == 1 )
246     static const uint8_t xMDNS_MACAddressIPv4[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb };
247 #endif
248 
249 static EthernetPhy_t xPhyObject;
250 
251 /* Ethernet handle. */
252 static ETH_HandleTypeDef xETH;
253 
254 /* xTXDescriptorSemaphore is a counting semaphore with
255  * a maximum count of ETH_TXBUFNB, which is the number of
256  * DMA TX descriptors. */
257 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
258 
259 /*
260  * Note: it is advised to define both
261  *
262  *     #define  ipconfigZERO_COPY_RX_DRIVER   1
263  *     #define  ipconfigZERO_COPY_TX_DRIVER   1
264  *
265  * The method using memcpy is slower and probably uses more RAM memory.
266  * The possibility is left in the code just for comparison.
267  *
268  * It is advised to define ETH_TXBUFNB at least 4. Note that no
269  * TX buffers are allocated in a zero-copy driver.
270  */
271 /* MAC buffers: ---------------------------------------------------------*/
272 
273 /* Put the DMA descriptors in '.first_data'.
274  * This is important for STM32F7, which has an L1 data cache.
275  * The first 64KB of the SRAM is not cached.
276  * See README.TXT in this folder. */
277 
278 /* Ethernet Rx MA Descriptor */
279 __attribute__( ( aligned( 32 ) ) )
280 #if defined( STM32F7xx )
281     __attribute__( ( section( ".first_data" ) ) )
282 #endif
283 ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ];
284 
285 #if ( ipconfigZERO_COPY_RX_DRIVER == 0 )
286     /* Ethernet Receive Buffer */
287     __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END;
288 #endif
289 
290 /* Ethernet Tx DMA Descriptor */
291 __attribute__( ( aligned( 32 ) ) )
292 #if defined( STM32F7xx )
293     __attribute__( ( section( ".first_data" ) ) )
294 #endif
295 ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ];
296 
297 #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
298     /* Ethernet Transmit Buffer */
299     __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END;
300 #endif
301 
302 /* DMATxDescToClear points to the next TX DMA descriptor
303  * that must be cleared by vClearTXBuffers(). */
304 static __IO ETH_DMADescTypeDef * DMATxDescToClear;
305 
306 static NetworkInterface_t * pxMyInterface = NULL;
307 
308 /* Holds the handle of the task used as a deferred interrupt processor.  The
309  * handle is used so direct notifications can be sent to the task for all EMAC/DMA
310  * related interrupts. */
311 static TaskHandle_t xEMACTaskHandle = NULL;
312 
313 /* For local use only: describe the PHY's properties: */
314 const PhyProperties_t xPHYProperties =
315 {
316     #if ( ipconfigETHERNET_AN_ENABLE != 0 )
317         .ucSpeed      = PHY_SPEED_AUTO,
318         .ucDuplex     = PHY_DUPLEX_AUTO,
319     #else
320         #if ( ipconfigETHERNET_USE_100MB != 0 )
321             .ucSpeed  = PHY_SPEED_100,
322         #else
323             .ucSpeed  = PHY_SPEED_10,
324         #endif
325 
326         #if ( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
327             .ucDuplex = PHY_DUPLEX_FULL,
328         #else
329             .ucDuplex = PHY_DUPLEX_HALF,
330         #endif
331     #endif /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
332 
333     #if ( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
334         .ucMDI_X      = PHY_MDIX_AUTO,
335     #elif ( ipconfigETHERNET_CROSSED_LINK != 0 )
336         .ucMDI_X      = PHY_MDIX_CROSSED,
337     #else
338         .ucMDI_X      = PHY_MDIX_DIRECT,
339     #endif
340 };
341 
342 /*-----------------------------------------------------------*/
343 
xNetworkInterfaceInitialise(NetworkInterface_t * pxInterface)344 BaseType_t xNetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
345 {
346     return xSTM32F_NetworkInterfaceInitialise( pxInterface );
347 }
348 
xNetworkInterfaceOutput(NetworkInterface_t * pxInterface,NetworkBufferDescriptor_t * const pxBuffer,BaseType_t bReleaseAfterSend)349 BaseType_t xNetworkInterfaceOutput( NetworkInterface_t * pxInterface,
350                                     NetworkBufferDescriptor_t * const pxBuffer,
351                                     BaseType_t bReleaseAfterSend )
352 {
353     return xSTM32F_NetworkInterfaceOutput( pxInterface, pxBuffer, bReleaseAfterSend );
354 }
355 
356 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
357 
358 /* Do not call the following function directly. It is there for downward compatibility.
359  * The function FreeRTOS_IPInit() will call it to initialice the interface and end-point
360  * objects.  See the description in FreeRTOS_Routing.h. */
361 
pxFillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)362     NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex,
363                                                     NetworkInterface_t * pxInterface )
364     {
365         return pxSTM32Fxx_FillInterfaceDescriptor( xEMACIndex, pxInterface );
366     }
367 
368 #endif
369 
xGetPhyLinkStatus(NetworkInterface_t * pxInterface)370 BaseType_t xGetPhyLinkStatus( NetworkInterface_t * pxInterface )
371 {
372     return xSTM32F_GetPhyLinkStatus( pxInterface );
373 }
374 
HAL_ETH_RxCpltCallback(ETH_HandleTypeDef * heth)375 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef * heth )
376 {
377     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
378 
379     ( void ) heth;
380 
381     /* Pass an RX-event and wakeup the prvEMACHandlerTask. */
382     if( xEMACTaskHandle != NULL )
383     {
384         xTaskNotifyFromISR( xEMACTaskHandle, EMAC_IF_RX_EVENT, eSetBits, &( xHigherPriorityTaskWoken ) );
385         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
386     }
387 }
388 /*-----------------------------------------------------------*/
389 
HAL_ETH_TxCpltCallback(ETH_HandleTypeDef * heth)390 void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef * heth )
391 {
392     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
393 
394     ( void ) heth;
395 
396     /* Pass a TX-event and wakeup the prvEMACHandlerTask. */
397     if( xEMACTaskHandle != NULL )
398     {
399         xTaskNotifyFromISR( xEMACTaskHandle, EMAC_IF_TX_EVENT, eSetBits, &( xHigherPriorityTaskWoken ) );
400         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
401     }
402 }
403 /*-----------------------------------------------------------*/
404 
vClearTXBuffers()405 static void vClearTXBuffers()
406 {
407     __IO ETH_DMADescTypeDef * txLastDescriptor = xETH.TxDesc;
408     size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
409 
410     #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
411         NetworkBufferDescriptor_t * pxNetworkBuffer;
412         uint8_t * ucPayLoad;
413     #endif
414 
415     /* This function is called after a TX-completion interrupt.
416      * It will release each Network Buffer used in xNetworkInterfaceOutput().
417      * 'uxCount' represents the number of descriptors given to DMA for transmission.
418      * After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */
419     while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )
420     {
421         if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )
422         {
423             break;
424         }
425 
426         #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
427             {
428                 ucPayLoad = ( uint8_t * ) DMATxDescToClear->Buffer1Addr;
429 
430                 if( ucPayLoad != NULL )
431                 {
432                     pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
433 
434                     if( pxNetworkBuffer != NULL )
435                     {
436                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
437                     }
438 
439                     DMATxDescToClear->Buffer1Addr = ( uint32_t ) 0u;
440                 }
441             }
442         #endif /* ipconfigZERO_COPY_TX_DRIVER */
443 
444         DMATxDescToClear = ( ETH_DMADescTypeDef * ) ( DMATxDescToClear->Buffer2NextDescAddr );
445 
446         uxCount--;
447         /* Tell the counting semaphore that one more TX descriptor is available. */
448         xSemaphoreGive( xTXDescriptorSemaphore );
449     }
450 }
451 /*-----------------------------------------------------------*/
452 
xSTM32F_NetworkInterfaceInitialise(NetworkInterface_t * pxInterface)453 BaseType_t xSTM32F_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
454 {
455     HAL_StatusTypeDef hal_eth_init_status;
456     BaseType_t xResult;
457     NetworkEndPoint_t * pxEndPoint;
458 
459     BaseType_t xMACEntry = ETH_MAC_ADDRESS1; /* ETH_MAC_ADDRESS0 reserved for the primary MAC-address. */
460 
461     if( xMacInitStatus == eMACInit )
462     {
463         xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
464 
465         if( xTXDescriptorSemaphore == NULL )
466         {
467             xMacInitStatus = eMACFailed;
468         }
469         else
470         {
471             /* Initialise ETH */
472             pxMyInterface = pxInterface;
473             pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
474             configASSERT( pxEndPoint != NULL );
475 
476             xETH.Instance = ETH;
477             xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
478             xETH.Init.Speed = ETH_SPEED_100M;
479             xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
480             /* Value of PhyAddress doesn't matter, will be probed for. */
481             xETH.Init.PhyAddress = 0;
482 
483             xETH.Init.MACAddr = ( uint8_t * ) pxEndPoint->xMACAddress.ucBytes;
484             xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;
485 
486             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
487                 {
488                     /* using the ETH_CHECKSUM_BY_HARDWARE option:
489                      * both the IP and the protocol checksums will be calculated
490                      * by the peripheral. */
491                     xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
492                 }
493             #else
494                 {
495                     xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
496                 }
497             #endif
498 
499             #if ( ipconfigUSE_RMII != 0 )
500                 {
501                     xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
502                 }
503             #else
504                 {
505                     xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
506                 }
507             #endif /* ipconfigUSE_RMII */
508 
509             hal_eth_init_status = HAL_ETH_Init( &xETH );
510 
511             /* Only for inspection by debugger. */
512             ( void ) hal_eth_init_status;
513 
514             /* Set the TxDesc and RxDesc pointers. */
515             xETH.TxDesc = DMATxDscrTab;
516             xETH.RxDesc = DMARxDscrTab;
517 
518             /* Make sure that all unused fields are cleared. */
519             memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
520             memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );
521 
522             /* Initialize Tx Descriptors list: Chain Mode */
523             DMATxDescToClear = DMATxDscrTab;
524 
525             /* Initialise TX-descriptors. */
526             prvDMATxDescListInit();
527 
528             /* Initialise RX-descriptors. */
529             prvDMARxDescListInit();
530 
531             #if ( ipconfigUSE_MDNS == 1 )
532                 {
533                     /* Program the MDNS address. */
534                     prvMACAddressConfig( &xETH, xMACEntry, ( uint8_t * ) xMDNS_MACAddressIPv4 );
535                     xMACEntry += 8;
536                 }
537             #endif
538             #if ( ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
539                 {
540                     prvMACAddressConfig( &xETH, xMACEntry, ( uint8_t * ) xMDNS_MACAdressIPv6.ucBytes );
541                     xMACEntry += 8;
542                 }
543             #endif
544             #if ( ipconfigUSE_LLMNR == 1 )
545                 {
546                     /* Program the LLMNR address. */
547                     prvMACAddressConfig( &xETH, xMACEntry, ( uint8_t * ) xLLMNR_MACAddress );
548                     xMACEntry += 8;
549                 }
550             #endif
551             #if ( ( ipconfigUSE_LLMNR == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
552                 {
553                     prvMACAddressConfig( &xETH, xMACEntry, ( uint8_t * ) xLLMNR_MacAdressIPv6.ucBytes );
554                     xMACEntry += 8;
555                 }
556             #endif
557 
558             {
559                 /* The EMAC address of the first end-point has been registered in HAL_ETH_Init(). */
560                 for( ;
561                      pxEndPoint != NULL;
562                      pxEndPoint = FreeRTOS_NextEndPoint( pxMyInterface, pxEndPoint ) )
563                 {
564                     #if ( ipconfigUSE_IPv6 != 0 )
565                         if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
566                         {
567                             uint8_t ucMACAddress[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 };
568 
569                             ucMACAddress[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ];
570                             ucMACAddress[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ];
571                             ucMACAddress[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ];
572                             prvMACAddressConfig( &xETH, xMACEntry, ucMACAddress );
573                             xMACEntry += 8;
574                         }
575                         else
576                     #else /* if ( ipconfigUSE_IPv6 != 0 ) */
577                         {
578                             if( xETH.Init.MACAddr != ( uint8_t * ) pxEndPoint->xMACAddress.ucBytes )
579                             {
580                                 prvMACAddressConfig( &xETH, xMACEntry, pxEndPoint->xMACAddress.ucBytes );
581                                 xMACEntry += 8;
582                             }
583                         }
584                     #endif /* if ( ipconfigUSE_IPv6 != 0 ) */
585                     if( xMACEntry > ( BaseType_t ) ETH_MAC_ADDRESS3 )
586                     {
587                         /* No more locations available. */
588                         break;
589                     }
590                 }
591             }
592             #if ( ipconfigUSE_IPv6 != 0 )
593                 {
594                     if( xMACEntry <= ( BaseType_t ) ETH_MAC_ADDRESS3 )
595                     {
596                         /* 33:33:00:00:00:01 */
597                         uint8_t ucMACAddress[ 6 ] = { 0x33, 0x33, 0, 0, 0, 0x01 };
598 
599                         prvMACAddressConfig( &xETH, xMACEntry, ucMACAddress );
600                         xMACEntry += 8;
601                     }
602                 }
603             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
604 
605             /* Force a negotiation with the Switch or Router and wait for LS. */
606             prvEthernetUpdateConfig( pdTRUE );
607 
608             /* The deferred interrupt handler task is created at the highest
609              * possible priority to ensure the interrupt handler can return directly
610              * to it.  The task's handle is stored in xEMACTaskHandle so interrupts can
611              * notify the task when there is something to process. */
612             if( xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ) == pdPASS )
613             {
614                 /* The xTXDescriptorSemaphore and the task are created successfully. */
615                 xMacInitStatus = eMACPass;
616             }
617             else
618             {
619                 xMacInitStatus = eMACFailed;
620             }
621         }
622     } /* if( xMacInitStatus == eMACInit ) */
623 
624     if( xMacInitStatus != eMACPass )
625     {
626         /* EMAC initialisation failed, return pdFAIL. */
627         xResult = pdFAIL;
628     }
629     else
630     {
631         if( xPhyObject.ulLinkStatusMask != 0U )
632         {
633             xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
634             xResult = pdPASS;
635             FreeRTOS_printf( ( "Link Status is high\n" ) );
636         }
637         else
638         {
639             /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
640              * and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
641             xResult = pdFAIL;
642         }
643     }
644 
645     /* When returning non-zero, the stack will become active and
646      * start DHCP (in configured) */
647     return xResult;
648 }
649 /*-----------------------------------------------------------*/
650 
prvDMATxDescListInit()651 static void prvDMATxDescListInit()
652 {
653     ETH_DMADescTypeDef * pxDMADescriptor;
654     BaseType_t xIndex;
655 
656     /* Get the pointer on the first member of the descriptor list */
657     pxDMADescriptor = DMATxDscrTab;
658 
659     /* Fill each DMA descriptor with the right values */
660     for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )
661     {
662         /* Set Second Address Chained bit */
663         pxDMADescriptor->Status = ETH_DMATXDESC_TCH;
664 
665         #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
666             {
667                 /* Set Buffer1 address pointer */
668                 pxDMADescriptor->Buffer1Addr = ( uint32_t ) ( Tx_Buff[ xIndex ] );
669             }
670         #endif
671 
672         if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )
673         {
674             /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */
675             pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
676         }
677         else
678         {
679             pxDMADescriptor->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL );
680         }
681 
682         /* Initialize the next descriptor with the Next Descriptor Polling Enable */
683         if( xIndex < ETH_TXBUFNB - 1 )
684         {
685             /* Set next descriptor address register with next descriptor base address */
686             pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );
687         }
688         else
689         {
690             /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
691             pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;
692         }
693     }
694 
695     /* Set Transmit Descriptor List Address Register */
696     xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;
697 }
698 /*-----------------------------------------------------------*/
699 
prvDMARxDescListInit()700 static void prvDMARxDescListInit()
701 {
702     ETH_DMADescTypeDef * pxDMADescriptor;
703     BaseType_t xIndex;
704 
705     /*
706      * RX-descriptors.
707      */
708 
709     /* Get the pointer on the first member of the descriptor list */
710     pxDMADescriptor = DMARxDscrTab;
711 
712     /* Fill each DMA descriptor with the right values */
713     for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )
714     {
715         /* Set Buffer1 size and Second Address Chained bit */
716         pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | EMAC_DMA_BUFFER_SIZE;
717 
718         #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
719             {
720                 /* Set Buffer1 address pointer */
721                 NetworkBufferDescriptor_t * pxBuffer;
722 
723                 pxBuffer = pxGetNetworkBufferWithDescriptor( EMAC_DMA_BUFFER_SIZE, 100ul );
724 
725                 /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'
726                  * Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */
727                 configASSERT( pxBuffer != NULL );
728 
729                 if( pxBuffer != NULL )
730                 {
731                     pxDMADescriptor->Buffer1Addr = ( uint32_t ) pxBuffer->pucEthernetBuffer;
732                     pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
733                 }
734             }
735         #else /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
736             {
737                 /* Set Buffer1 address pointer */
738                 pxDMADescriptor->Buffer1Addr = ( uint32_t ) ( Rx_Buff[ xIndex ] );
739                 /* Set Own bit of the Rx descriptor Status */
740                 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
741             }
742         #endif /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
743 
744         /* Initialize the next descriptor with the Next Descriptor Polling Enable */
745         if( xIndex < ETH_RXBUFNB - 1 )
746         {
747             /* Set next descriptor address register with next descriptor base address */
748             pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );
749         }
750         else
751         {
752             /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
753             pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;
754         }
755     }
756 
757     /* Set Receive Descriptor List Address Register */
758     xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;
759 }
760 /*-----------------------------------------------------------*/
761 
762 
prvMACAddressConfig(ETH_HandleTypeDef * heth,uint32_t ulIndex,uint8_t * Addr)763 static void prvMACAddressConfig( ETH_HandleTypeDef * heth,
764                                  uint32_t ulIndex,
765                                  uint8_t * Addr )
766 {
767     uint32_t ulTempReg;
768 
769     ( void ) heth;
770 
771     /* Calculate the selected MAC address high register. */
772     ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
773 
774     /* Load the selected MAC address high register. */
775     ( *( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
776 
777     /* Calculate the selected MAC address low register. */
778     ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
779 
780     /* Load the selected MAC address low register */
781     ( *( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
782 }
783 
784 /*-----------------------------------------------------------*/
785 
xSTM32F_NetworkInterfaceOutput(NetworkInterface_t * pxInterface,NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t bReleaseAfterSend)786 static BaseType_t xSTM32F_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
787                                                   NetworkBufferDescriptor_t * const pxDescriptor,
788                                                   BaseType_t bReleaseAfterSend )
789 {
790     BaseType_t xReturn = pdFAIL;
791     uint32_t ulTransmitSize = 0;
792     __IO ETH_DMADescTypeDef * pxDmaTxDesc;
793 /* Do not wait too long for a free TX DMA buffer. */
794     const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
795 
796     /* As there is only a single instance of the EMAC, there is only one pxInterface object. */
797     ( void ) pxInterface;
798 
799     /* Open a do {} while ( 0 ) loop to be able to call break. */
800     do
801     {
802         if( xCheckLoopback( pxDescriptor, bReleaseAfterSend ) != 0 )
803         {
804             /* The packet has been sent back to the IP-task.
805              * The IP-task will further handle it.
806              * Do not release the descriptor. */
807             bReleaseAfterSend = pdFALSE;
808             break;
809         }
810 
811         #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
812             {
813                 const IPPacket_t * pxIPPacket;
814 
815                 pxIPPacket = ( const IPPacket_t * ) pxDescriptor->pucEthernetBuffer;
816                 #if ( ipconfigUSE_IPv6 != 0 )
817                     if( pxIPPacket->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
818                     {
819                         const IPHeader_IPv6_t * pxIPPacket_IPv6;
820 
821                         pxIPPacket_IPv6 = ( const IPHeader_IPv6_t * ) &( pxDescriptor->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] );
822 
823                         if( pxIPPacket_IPv6->ucNextHeader == ( uint8_t ) ipPROTOCOL_ICMP_IPv6 )
824                         {
825                             ICMPHeader_IPv6_t * pxICMPHeader_IPv6;
826 
827                             pxICMPHeader_IPv6 = ( ICMPHeader_IPv6_t * ) &( pxDescriptor->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ] );
828                             pxICMPHeader_IPv6->usChecksum = 0U;
829                         }
830                     }
831                     else
832                 #endif /* if ( ipconfigUSE_IPv6 != 0 ) */
833 
834                 if( pxIPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
835                 {
836                     if( pxIPPacket->xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
837                     {
838                         ICMPHeader_t * pxICMPHeader;
839 
840                         pxICMPHeader = ( ICMPHeader_t * ) &( pxDescriptor->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER ] );
841                         pxICMPHeader->usChecksum = ( uint16_t ) 0U;
842                     }
843                 }
844             }
845         #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */
846 
847         if( xPhyObject.ulLinkStatusMask != 0 )
848         {
849             if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
850             {
851                 /* Time-out waiting for a free TX descriptor. */
852                 break;
853             }
854 
855             /* This function does the actual transmission of the packet. The packet is
856              * contained in 'pxDescriptor' that is passed to the function. */
857             pxDmaTxDesc = xETH.TxDesc;
858 
859             /* Is this buffer available? */
860             configASSERT( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 );
861 
862             {
863                 /* Is this buffer available? */
864                 /* Get bytes in current buffer. */
865                 ulTransmitSize = pxDescriptor->xDataLength;
866 
867                 if( ulTransmitSize > EMAC_DMA_BUFFER_SIZE )
868                 {
869                     ulTransmitSize = EMAC_DMA_BUFFER_SIZE;
870                 }
871 
872                 #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
873                     {
874                         /* Copy the bytes. */
875                         memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );
876                     }
877                 #else
878                     {
879                         configASSERT( bReleaseAfterSend != 0 );
880 
881                         /* Move the buffer. */
882                         pxDmaTxDesc->Buffer1Addr = ( uint32_t ) pxDescriptor->pucEthernetBuffer;
883                         /* The Network Buffer has been passed to DMA, no need to release it. */
884                         bReleaseAfterSend = pdFALSE_UNSIGNED;
885                     }
886                 #endif /* ipconfigZERO_COPY_TX_DRIVER */
887 
888                 /* Ask to set the IPv4 checksum.
889                  * Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
890                 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
891                     {
892                         pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
893                     }
894                 #else
895                     {
896                         pxDmaTxDesc->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CIC );
897                         pxDmaTxDesc->Status |= ETH_DMATXDESC_IC;
898                     }
899                 #endif
900 
901 
902                 /* Prepare transmit descriptors to give to DMA. */
903 
904                 /* Set LAST and FIRST segment */
905                 pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;
906                 /* Set frame size */
907                 pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );
908 
909                 #if ( NETWORK_BUFFERS_CACHED != 0 )
910                     {
911                         BaseType_t xlength = CACHE_LINE_SIZE * ( ( ulTransmitSize + NETWORK_BUFFER_HEADER_SIZE + CACHE_LINE_SIZE - 1 ) / CACHE_LINE_SIZE );
912                         uint32_t * pulBuffer = ( uint32_t ) ( pxDescriptor->pucEthernetBuffer - NETWORK_BUFFER_HEADER_SIZE );
913                         cache_clean_invalidate_by_addr( pulBuffer, xlength );
914                     }
915                 #endif
916 
917                 /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
918                 pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;
919 
920                 /* Point to next descriptor */
921                 xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );
922                 /* Ensure completion of memory access */
923                 __DSB();
924                 /* Resume DMA transmission*/
925                 xETH.Instance->DMATPDR = 0;
926                 iptraceNETWORK_INTERFACE_TRANSMIT();
927                 xReturn = pdPASS;
928             }
929         }
930         else
931         {
932             /* The PHY has no Link Status, packet shall be dropped. */
933         }
934     } while( 0 );
935 
936     /* The buffer has been sent so can be released. */
937     if( bReleaseAfterSend != pdFALSE )
938     {
939         vReleaseNetworkBufferAndDescriptor( pxDescriptor );
940     }
941 
942     return xReturn;
943 }
944 /*-----------------------------------------------------------*/
945 
xMayAcceptPacket(uint8_t * pucEthernetBuffer)946 static BaseType_t xMayAcceptPacket( uint8_t * pucEthernetBuffer )
947 {
948     const ProtocolPacket_t * pxProtPacket = ( const ProtocolPacket_t * ) pucEthernetBuffer;
949 
950     switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )
951     {
952         case ipARP_FRAME_TYPE:
953             /* Check it later. */
954             return pdTRUE;
955 
956             #if ( ipconfigUSE_IPv6 != 0 )
957                 case ipIPv6_FRAME_TYPE:
958                     /* Check it later. */
959                     return pdTRUE;
960             #endif
961         case ipIPv4_FRAME_TYPE:
962             /* Check it here. */
963             break;
964 
965         default:
966             /* Refuse the packet. */
967             return pdFALSE;
968     }
969 
970     #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
971         {
972             const IPHeader_t * pxIPHeader = &( pxProtPacket->xTCPPacket.xIPHeader );
973             uint32_t ulDestinationIPAddress;
974 
975             /* Ensure that the incoming packet is not fragmented (only outgoing packets
976              * can be fragmented) as these are the only handled IP frames currently. */
977             if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )
978             {
979                 return pdFALSE;
980             }
981 
982             /* HT: Might want to make the following configurable because
983              * most IP messages have a standard length of 20 bytes */
984 
985             /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
986              * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
987             if( ( pxIPHeader->ucVersionHeaderLength < 0x45 ) || ( pxIPHeader->ucVersionHeaderLength > 0x4F ) )
988             {
989                 return pdFALSE;
990             }
991 
992             ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
993 
994             /* Is the packet for this node? */
995             if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
996                 /* Is it a broadcast address x.x.x.255 ? */
997                 ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&
998                 #if ( ipconfigUSE_LLMNR == 1 )
999                     ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
1000                 #endif
1001                 ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) )
1002             {
1003                 FreeRTOS_debug_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );
1004                 return pdFALSE;
1005             }
1006 
1007             if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )
1008             {
1009                 #if ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_MDNS == 1 ) || ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_DNS == 1 )
1010                     uint16_t usSourcePort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort );
1011                     uint16_t usDestinationPort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort );
1012                 #endif
1013 
1014                 if( ( xPortHasUDPSocket( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ) == pdFALSE )
1015                     #if ipconfigUSE_LLMNR == 1
1016                         && ( usDestinationPort != ipLLMNR_PORT ) &&
1017                         ( usSourcePort != ipLLMNR_PORT )
1018                     #endif
1019                     #if ipconfigUSE_MDNS == 1
1020                         && ( usDestinationPort != ipMDNS_PORT ) &&
1021                         ( usSourcePort != ipMDNS_PORT )
1022                     #endif
1023                     #if ipconfigUSE_NBNS == 1
1024                         && ( usDestinationPort != ipNBNS_PORT ) &&
1025                         ( usSourcePort != ipNBNS_PORT )
1026                     #endif
1027                     #if ipconfigUSE_DNS == 1
1028                         && ( usSourcePort != ipDNS_PORT )
1029                     #endif
1030                     )
1031                 {
1032                     /* Drop this packet, not for this device. */
1033                     /* FreeRTOS_printf( ( "Drop: UDP port %d -> %d\n", usSourcePort, usDestinationPort ) ); */
1034                     return pdFALSE;
1035                 }
1036             }
1037         }
1038     #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1039     return pdTRUE;
1040 }
1041 /*-----------------------------------------------------------*/
1042 
prvPassEthMessages(NetworkBufferDescriptor_t * pxDescriptor)1043 static void prvPassEthMessages( NetworkBufferDescriptor_t * pxDescriptor )
1044 {
1045     IPStackEvent_t xRxEvent;
1046 
1047     xRxEvent.eEventType = eNetworkRxEvent;
1048     xRxEvent.pvData = ( void * ) pxDescriptor;
1049 
1050     if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
1051     {
1052         /* The buffer could not be sent to the stack so must be released again.
1053          * This is a deferred handler task, not a real interrupt, so it is ok to
1054          * use the task level function here. */
1055         #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
1056             {
1057                 do
1058                 {
1059                     NetworkBufferDescriptor_t * pxNext = pxDescriptor->pxNextBuffer;
1060                     vReleaseNetworkBufferAndDescriptor( pxDescriptor );
1061                     pxDescriptor = pxNext;
1062                 } while( pxDescriptor != NULL );
1063             }
1064         #else
1065             {
1066                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
1067             }
1068         #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
1069         iptraceETHERNET_RX_EVENT_LOST();
1070         FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) );
1071     }
1072     else
1073     {
1074         iptraceNETWORK_INTERFACE_RECEIVE();
1075     }
1076 }
1077 
prvNetworkInterfaceInput(void)1078 static BaseType_t prvNetworkInterfaceInput( void )
1079 {
1080     #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
1081         NetworkBufferDescriptor_t * pxFirstDescriptor = NULL;
1082         NetworkBufferDescriptor_t * pxLastDescriptor = NULL;
1083     #endif
1084     BaseType_t xReceivedLength = 0;
1085     __IO ETH_DMADescTypeDef * pxDMARxDescriptor;
1086     const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( niDESCRIPTOR_WAIT_TIME_MS );
1087     uint8_t * pucBuffer;
1088 
1089     pxDMARxDescriptor = xETH.RxDesc;
1090 
1091     while( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0u )
1092     {
1093         NetworkBufferDescriptor_t * pxCurDescriptor;
1094         NetworkBufferDescriptor_t * pxNewDescriptor = NULL;
1095         BaseType_t xAccepted = pdTRUE;
1096 
1097         /* Get the Frame Length of the received packet: subtract 4 bytes of the CRC */
1098         xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;
1099 
1100         pucBuffer = ( uint8_t * ) pxDMARxDescriptor->Buffer1Addr;
1101 
1102         /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
1103         /* Chained Mode */
1104         /* Selects the next DMA Rx descriptor list for next buffer to read */
1105         xETH.RxDesc = ( ETH_DMADescTypeDef * ) pxDMARxDescriptor->Buffer2NextDescAddr;
1106 
1107         /* In order to make the code easier and faster, only packets in a single buffer
1108          * will be accepted.  This can be done by making the buffers large enough to
1109          * hold a complete Ethernet packet, minus ipBUFFER_PADDING.
1110          * Therefore, two sanity checks: */
1111         configASSERT( xReceivedLength <= EMAC_DMA_BUFFER_SIZE );
1112 
1113         if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )
1114         {
1115             /* Not an Ethernet frame-type or a checksum error. */
1116             xAccepted = pdFALSE;
1117         }
1118         else
1119         {
1120             /* See if this packet must be handled. */
1121             xAccepted = xMayAcceptPacket( pucBuffer );
1122         }
1123 
1124         if( xAccepted != pdFALSE )
1125         {
1126             /* The packet will be accepted, but check first if a new Network Buffer can
1127              * be obtained. If not, the packet will still be dropped. */
1128             pxNewDescriptor = pxGetNetworkBufferWithDescriptor( EMAC_DMA_BUFFER_SIZE, xDescriptorWaitTime );
1129 
1130             if( pxNewDescriptor == NULL )
1131             {
1132                 /* A new descriptor can not be allocated now. This packet will be dropped. */
1133                 xAccepted = pdFALSE;
1134             }
1135         }
1136 
1137         #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
1138             {
1139                 /* Find out which Network Buffer was originally passed to the descriptor. */
1140                 pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
1141                 configASSERT( pxCurDescriptor != NULL );
1142                 configASSERT( pxCurDescriptor->pucEthernetBuffer != NULL );
1143             }
1144         #else
1145             {
1146                 /* In this mode, the two descriptors are the same. */
1147                 pxCurDescriptor = pxNewDescriptor;
1148 
1149                 if( pxNewDescriptor != NULL )
1150                 {
1151                     /* The packet is accepted and a new Network Buffer was created,
1152                      * copy data to the Network Buffer. */
1153                     memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );
1154                 }
1155             }
1156         #endif /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
1157 
1158         if( xAccepted != pdFALSE )
1159         {
1160             pxCurDescriptor->xDataLength = xReceivedLength;
1161             pxCurDescriptor->pxInterface = pxMyInterface;
1162             pxCurDescriptor->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pxCurDescriptor->pucEthernetBuffer );
1163 
1164             #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
1165                 {
1166                     pxCurDescriptor->pxNextBuffer = NULL;
1167 
1168                     if( pxFirstDescriptor == NULL )
1169                     {
1170                         /* Becomes the first message */
1171                         pxFirstDescriptor = pxCurDescriptor;
1172                     }
1173                     else if( pxLastDescriptor != NULL )
1174                     {
1175                         /* Add to the tail */
1176                         pxLastDescriptor->pxNextBuffer = pxCurDescriptor;
1177                     }
1178 
1179                     pxLastDescriptor = pxCurDescriptor;
1180                 }
1181             #else /* if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) */
1182                 {
1183                     prvPassEthMessages( pxCurDescriptor );
1184                 }
1185             #endif /* if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) */
1186         }
1187 
1188         /* Release descriptors to DMA */
1189         #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
1190             {
1191                 /* Set Buffer1 address pointer */
1192                 if( pxNewDescriptor != NULL )
1193                 {
1194                     pxDMARxDescriptor->Buffer1Addr = ( uint32_t ) pxNewDescriptor->pucEthernetBuffer;
1195                 }
1196                 else
1197                 {
1198                     /* The packet was dropped and the same Network
1199                      * Buffer will be used to receive a new packet. */
1200                 }
1201             }
1202         #endif /* ipconfigZERO_COPY_RX_DRIVER */
1203 
1204         /* Set Buffer1 size and Second Address Chained bit */
1205         pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | EMAC_DMA_BUFFER_SIZE;
1206         pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;
1207 
1208         /* Ensure completion of memory access */
1209         __DSB();
1210 
1211         /* When Rx Buffer unavailable flag is set clear it and resume
1212          * reception. */
1213         if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )
1214         {
1215             /* Clear RBUS ETHERNET DMA flag. */
1216             xETH.Instance->DMASR = ETH_DMASR_RBUS;
1217 
1218             /* Resume DMA reception. */
1219             xETH.Instance->DMARPDR = 0;
1220         }
1221 
1222         pxDMARxDescriptor = xETH.RxDesc;
1223     }
1224 
1225     #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
1226         {
1227             if( pxFirstDescriptor != NULL )
1228             {
1229                 prvPassEthMessages( pxFirstDescriptor );
1230             }
1231         }
1232     #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
1233 
1234     return( xReceivedLength > 0 );
1235 }
1236 /*-----------------------------------------------------------*/
1237 
1238 
xSTM32_PhyRead(BaseType_t xAddress,BaseType_t xRegister,uint32_t * pulValue)1239 BaseType_t xSTM32_PhyRead( BaseType_t xAddress,
1240                            BaseType_t xRegister,
1241                            uint32_t * pulValue )
1242 {
1243     uint16_t usPrevAddress = xETH.Init.PhyAddress;
1244     BaseType_t xResult;
1245     HAL_StatusTypeDef xHALResult;
1246 
1247     xETH.Init.PhyAddress = xAddress;
1248     xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t ) xRegister, pulValue );
1249     xETH.Init.PhyAddress = usPrevAddress;
1250 
1251     if( xHALResult == HAL_OK )
1252     {
1253         xResult = 0;
1254     }
1255     else
1256     {
1257         xResult = -1;
1258     }
1259 
1260     return xResult;
1261 }
1262 /*-----------------------------------------------------------*/
1263 
xSTM32_PhyWrite(BaseType_t xAddress,BaseType_t xRegister,uint32_t ulValue)1264 BaseType_t xSTM32_PhyWrite( BaseType_t xAddress,
1265                             BaseType_t xRegister,
1266                             uint32_t ulValue )
1267 {
1268     uint16_t usPrevAddress = xETH.Init.PhyAddress;
1269     BaseType_t xResult;
1270     HAL_StatusTypeDef xHALResult;
1271 
1272     xETH.Init.PhyAddress = xAddress;
1273     xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t ) xRegister, ulValue );
1274     xETH.Init.PhyAddress = usPrevAddress;
1275 
1276     if( xHALResult == HAL_OK )
1277     {
1278         xResult = 0;
1279     }
1280     else
1281     {
1282         xResult = -1;
1283     }
1284 
1285     return xResult;
1286 }
1287 /*-----------------------------------------------------------*/
1288 
vMACBProbePhy(void)1289 void vMACBProbePhy( void )
1290 {
1291     vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );
1292     xPhyDiscover( &xPhyObject );
1293     xPhyConfigure( &xPhyObject, &xPHYProperties );
1294 }
1295 /*-----------------------------------------------------------*/
1296 
prvEthernetUpdateConfig(BaseType_t xForce)1297 static void prvEthernetUpdateConfig( BaseType_t xForce )
1298 {
1299     FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
1300                        xPhyObject.ulLinkStatusMask,
1301                        ( int ) xForce ) );
1302 
1303     if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
1304     {
1305         /* Restart the auto-negotiation. */
1306         if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )
1307         {
1308             xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
1309 
1310             /* Configure the MAC with the Duplex Mode fixed by the
1311              * auto-negotiation process. */
1312             if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
1313             {
1314                 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
1315             }
1316             else
1317             {
1318                 xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
1319             }
1320 
1321             /* Configure the MAC with the speed fixed by the
1322              * auto-negotiation process. */
1323             if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
1324             {
1325                 xETH.Init.Speed = ETH_SPEED_10M;
1326             }
1327             else
1328             {
1329                 xETH.Init.Speed = ETH_SPEED_100M;
1330             }
1331         }
1332         else /* AutoNegotiation Disable */
1333         {
1334             /* Check parameters */
1335             assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );
1336             assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );
1337 
1338             if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX )
1339             {
1340                 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;
1341             }
1342             else
1343             {
1344                 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;
1345             }
1346 
1347             if( xETH.Init.Speed == ETH_SPEED_10M )
1348             {
1349                 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;
1350             }
1351             else
1352             {
1353                 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;
1354             }
1355 
1356             xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;
1357 
1358             /* Use predefined (fixed) configuration. */
1359             xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
1360         }
1361 
1362         /* ETHERNET MAC Re-Configuration */
1363         HAL_ETH_ConfigMAC( &xETH, ( ETH_MACInitTypeDef * ) NULL );
1364 
1365         /* Optionally, pass all mutlicast */
1366         #if 0
1367             xETH.Instance->MACFFR |= ETH_MACFFR_PAM;
1368         #endif
1369 
1370         /* Restart MAC interface */
1371         HAL_ETH_Start( &xETH );
1372     }
1373     else
1374     {
1375         /* Stop MAC interface */
1376         HAL_ETH_Stop( &xETH );
1377     }
1378 }
1379 /*-----------------------------------------------------------*/
1380 
xSTM32F_GetPhyLinkStatus(NetworkInterface_t * pxInterface)1381 static BaseType_t xSTM32F_GetPhyLinkStatus( NetworkInterface_t * pxInterface )
1382 {
1383     BaseType_t xReturn;
1384 
1385     ( void ) pxInterface;
1386 
1387     if( xPhyObject.ulLinkStatusMask != 0 )
1388     {
1389         xReturn = pdPASS;
1390     }
1391     else
1392     {
1393         xReturn = pdFAIL;
1394     }
1395 
1396     return xReturn;
1397 }
1398 /*-----------------------------------------------------------*/
1399 
1400 /* Uncomment this in case BufferAllocation_1.c is used. */
1401 
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])1402 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
1403 {
1404     static
1405     #if defined( STM32F7xx )
1406         __attribute__( ( section( ".first_data" ) ) )
1407     #endif
1408     uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ETH_MAX_PACKET_SIZE ] __attribute__( ( aligned( 32 ) ) );
1409     uint8_t * ucRAMBuffer = ucNetworkPackets;
1410     uint32_t ul;
1411 
1412     for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
1413     {
1414         pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
1415         *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
1416         ucRAMBuffer += ETH_MAX_PACKET_SIZE;
1417     }
1418 }
1419 
1420 /*-----------------------------------------------------------*/
1421 
pxSTM32Fxx_FillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)1422 NetworkInterface_t * pxSTM32Fxx_FillInterfaceDescriptor( BaseType_t xEMACIndex,
1423                                                          NetworkInterface_t * pxInterface )
1424 {
1425     static char pcName[ 17 ];
1426 
1427 /* This function pxSTM32Fxx_FillInterfaceDescriptor() adds a network-interface.
1428  * Make sure that the object pointed to by 'pxInterface'
1429  * is declared static or global, and that it will remain to exist. */
1430 
1431     snprintf( pcName, sizeof( pcName ), "eth%u", ( unsigned ) xEMACIndex );
1432 
1433     memset( pxInterface, '\0', sizeof( *pxInterface ) );
1434     pxInterface->pcName = pcName;                    /* Just for logging, debugging. */
1435     pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
1436     pxInterface->pfInitialise = xSTM32F_NetworkInterfaceInitialise;
1437     pxInterface->pfOutput = xSTM32F_NetworkInterfaceOutput;
1438     pxInterface->pfGetPhyLinkStatus = xSTM32F_GetPhyLinkStatus;
1439 
1440     FreeRTOS_AddNetworkInterface( pxInterface );
1441 
1442     return pxInterface;
1443 }
1444 /*-----------------------------------------------------------*/
1445 
prvEMACHandlerTask(void * pvParameters)1446 static void prvEMACHandlerTask( void * pvParameters )
1447 {
1448     UBaseType_t uxCurrentCount;
1449     BaseType_t xResult;
1450     const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
1451     uint32_t ulISREvents = 0U;
1452 
1453     /* Remove compiler warnings about unused parameters. */
1454     ( void ) pvParameters;
1455 
1456     for( ; ; )
1457     {
1458         xResult = 0;
1459 
1460         #if ( ipconfigHAS_PRINTF != 0 )
1461             {
1462                 /* Call a function that monitors resources: the amount of free network
1463                  * buffers and the amount of free space on the heap.  See FreeRTOS_IP.c
1464                  * for more detailed comments. */
1465                 vPrintResourceStats();
1466             }
1467         #endif /* ( ipconfigHAS_PRINTF != 0 ) */
1468 
1469         if( xTXDescriptorSemaphore != NULL )
1470         {
1471             static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
1472 
1473             uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
1474 
1475             if( uxLowestSemCount > uxCurrentCount )
1476             {
1477                 uxLowestSemCount = uxCurrentCount;
1478                 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
1479             }
1480         }
1481 
1482         /* Wait for a new event or a time-out. */
1483         xTaskNotifyWait( 0U,                /* ulBitsToClearOnEntry */
1484                          EMAC_IF_ALL_EVENT, /* ulBitsToClearOnExit */
1485                          &( ulISREvents ),  /* pulNotificationValue */
1486                          ulMaxBlockTime );
1487 
1488         if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
1489         {
1490             xResult = prvNetworkInterfaceInput();
1491         }
1492 
1493         if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
1494         {
1495             /* Code to release TX buffers in case zero-copy is used. */
1496             /* Check if DMA packets have been delivered. */
1497             vClearTXBuffers();
1498         }
1499 
1500         if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
1501         {
1502             /* Future extension: logging about errors that occurred. */
1503         }
1504 
1505         if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
1506         {
1507             /* Something has changed to a Link Status, need re-check. */
1508             prvEthernetUpdateConfig( pdFALSE );
1509 
1510             #if ( ipconfigSUPPORT_NETWORK_DOWN_EVENT != 0 )
1511                 {
1512                     if( xGetPhyLinkStatus( pxMyInterface ) == pdFALSE )
1513                     {
1514                         FreeRTOS_NetworkDown( pxMyInterface );
1515                     }
1516                 }
1517             #endif /* ( ipconfigSUPPORT_NETWORK_DOWN_EVENT != 0 ) */
1518         }
1519     }
1520 }
1521 /*-----------------------------------------------------------*/
1522 
ETH_IRQHandler(void)1523 void ETH_IRQHandler( void )
1524 {
1525     HAL_ETH_IRQHandler( &xETH );
1526 }
1527