xref: /FreeRTOS-Plus-TCP-v4.0.0/source/portable/NetworkInterface/STM32Hxx/NetworkInterface.c (revision f89112c49ee9e6c4c95b7d23228147e426a0798f)
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 V2.3.2
8  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy of
11  * this software and associated documentation files (the "Software"), to deal in
12  * the Software without restriction, including without limitation the rights to
13  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14  * the Software, and to permit persons to whom the Software is furnished to do so,
15  * subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in all
18  * copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
22  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
23  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * http://aws.amazon.com/freertos
28  * http://www.FreeRTOS.org
29  */
30 
31 #include <string.h>
32 
33 /* FreeRTOS includes. */
34 #include "FreeRTOS.h"
35 #include "task.h"
36 #include "queue.h"
37 #include "semphr.h"
38 
39 /* FreeRTOS+TCP includes. */
40 #include "FreeRTOS_IP.h"
41 #include "FreeRTOS_Sockets.h"
42 #include "FreeRTOS_IP_Private.h"
43 #include "FreeRTOS_DNS.h"
44 #include "FreeRTOS_Routing.h"
45 #include "NetworkBufferManagement.h"
46 #include "NetworkInterface.h"
47 
48 #include "phyHandling.h"
49 
50 /* ST includes. */
51 #include "stm32h7xx_hal.h"
52 
53 #ifndef STM32Hxx_HAL_ETH_H
54 
55 /*
56  * The ST HAL library provides stm32h7xx_hal_eth.{c,h}.
57  * This FreeRTOS+TCP driver renamed these files to stm32hxx_hal_eth.{c,h}
58  * by removing the '7'.
59  * Please make sure that "portable/NetworkInterface/STM32Hxx" is included
60  * in the include paths earlier than "STM32H7xx_HAL_Driver/Inc".
61  * and also make sure that you have defined 'HAL_ETH_MODULE_ENABLED'
62  * in your copy of "stm32h7xx_hal_conf".
63  */
64     #error stm32hxx_hal_eth.h is possibly not included
65 #endif
66 
67 /* Interrupt events to process: reception, transmission and error handling. */
68 #define EMAC_IF_RX_EVENT     1UL
69 #define EMAC_IF_TX_EVENT     2UL
70 #define EMAC_IF_ERR_EVENT    4UL
71 
72 
73 #ifndef niEMAC_HANDLER_TASK_NAME
74     #define niEMAC_HANDLER_TASK_NAME    "EMAC-task"
75 #endif
76 
77 #ifndef niEMAC_HANDLER_TASK_STACK_SIZE
78     #define niEMAC_HANDLER_TASK_STACK_SIZE    ( 4 * configMINIMAL_STACK_SIZE )
79 #endif
80 
81 #ifndef niEMAC_HANDLER_TASK_PRIORITY
82     #define niEMAC_HANDLER_TASK_PRIORITY    configMAX_PRIORITIES - 1
83 #endif
84 
85 
86 /* Bit map of outstanding ETH interrupt events for processing. */
87 static volatile uint32_t ulISREvents;
88 
89 typedef enum
90 {
91     eMACInit,   /* Must initialise MAC. */
92     eMACPass,   /* Initialisation was successful. */
93     eMACFailed, /* Initialisation failed. */
94 } eMAC_INIT_STATUS_TYPE;
95 
96 static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
97 
98 /* xTXDescriptorSemaphore is shared with stm32h7xx_hal_eth.c. */
99 SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
100 
101 /* Both the IP-task and the EMAC task use the TX channel.  Use
102  * a mutex to protect it against synchronous access by both tasks. */
103 static SemaphoreHandle_t xTransmissionMutex;
104 
105 /* Global Ethernet handle */
106 static ETH_HandleTypeDef xEthHandle;
107 static ETH_TxPacketConfig xTxConfig;
108 
109 static NetworkInterface_t * pxMyInterface = NULL;
110 
111 /*
112  * About the section ".ethernet_data" : the DMA wants the descriptors and buffers allocated in the
113  * RAM3 memory, which can be added to the .LD file as follows::
114  *
115  * RAM3 (xrw)      : ORIGIN = 0x24040000, LENGTH = 0x8000
116  *
117  * .ethernet_data :
118  * {
119  *  PROVIDE_HIDDEN (__ethernet_data_start = .);
120  *  KEEP (*(SORT(.ethernet_data.*)))
121  *  KEEP (*(.ethernet_data*))
122  *  PROVIDE_HIDDEN (__ethernet_data_end = .);
123  * } >RAM3
124  *
125  */
126 /* Ethernet Rx DMA Descriptors */
127 ETH_DMADescTypeDef DMARxDscrTab[ ETH_RX_DESC_CNT ]    __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
128 
129 /* Ethernet Receive Buffer */
130 #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
131     uint8_t Rx_Buff[ ETH_RX_DESC_CNT ][ ETH_RX_BUF_SIZE ] __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
132 #endif
133 
134 /* Ethernet Tx DMA Descriptors */
135 ETH_DMADescTypeDef DMATxDscrTab[ ETH_TX_DESC_CNT ]    __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
136 
137 /* Ethernet Transmit Buffer */
138 #if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
139     uint8_t Tx_Buff[ ETH_TX_DESC_CNT ][ ETH_TX_BUF_SIZE ]                __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
140 #endif
141 
142 /* This function binds PHY IO functions, then inits and configures */
143 static void prvMACBProbePhy( void );
144 
145 /* Force a negotiation with the Switch or Router and wait for LS. */
146 static void prvEthernetUpdateConfig( BaseType_t xForce );
147 
148 /* Holds the handle of the task used as a deferred interrupt processor.  The
149  * handle is used so direct notifications can be sent to the task for all EMAC/DMA
150  * related interrupts. */
151 static TaskHandle_t xEMACTaskHandle = NULL;
152 
153 /*
154  * A deferred interrupt handler task that processes
155  */
156 static void prvEMACHandlerTask( void * pvParameters );
157 
158 /*
159  * See if there is a new packet and forward it to the IP-task.
160  */
161 static BaseType_t prvNetworkInterfaceInput( void );
162 
163 /* Private PHY IO functions and properties */
164 static int32_t ETH_PHY_IO_ReadReg( uint32_t DevAddr,
165                                    uint32_t RegAddr,
166                                    uint32_t * pRegVal );
167 static int32_t ETH_PHY_IO_WriteReg( uint32_t DevAddr,
168                                     uint32_t RegAddr,
169                                     uint32_t RegVal );
170 
171 static void vClearOptionBit( volatile uint32_t * pulValue,
172                              uint32_t ulValue );
173 
174 #if ( ipconfigHAS_PRINTF != 0 )
175     static size_t uxGetOwnCount( ETH_HandleTypeDef * heth );
176 #endif
177 
178 /* FreeRTOS+TCP/multi :
179  * Each network device has 3 access functions:
180  * - Initialise the device
181  * - Output a network packet
182  * - Return the PHY Link-Status (LS)
183  * They can be defined as static because the function addresses
184  * addresses will be stored in struct NetworkInterface_t. */
185 
186 static BaseType_t xSTM32H_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface );
187 
188 static BaseType_t xSTM32H_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
189                                                   NetworkBufferDescriptor_t * const pxBuffer,
190                                                   BaseType_t xReleaseAfterSend );
191 
192 static BaseType_t xSTM32H_GetPhyLinkStatus( NetworkInterface_t * pxInterface );
193 
194 NetworkInterface_t * pxSTM32H_FillInterfaceDescriptor( BaseType_t xEMACIndex,
195                                                        NetworkInterface_t * pxInterface );
196 /*-----------------------------------------------------------*/
197 
198 static EthernetPhy_t xPhyObject;
199 /* For local use only: describe the PHY's properties: */
200 const PhyProperties_t xPHYProperties =
201 {
202     .ucSpeed  = PHY_SPEED_AUTO,
203     .ucDuplex = PHY_DUPLEX_AUTO,
204     .ucMDI_X  = PHY_MDIX_DIRECT
205 };
206 /*-----------------------------------------------------------*/
207 
prvMACAddressConfig(ETH_HandleTypeDef * heth,uint32_t ulIndex,const uint8_t * Addr)208 static void prvMACAddressConfig( ETH_HandleTypeDef * heth,
209                                  uint32_t ulIndex,
210                                  const uint8_t * Addr )
211 {
212     uint32_t ulTempReg;
213     uint32_t ulETH_MAC_ADDR_HBASE = ( uint32_t ) &( heth->Instance->MACA0HR );
214     uint32_t ulETH_MAC_ADDR_LBASE = ( uint32_t ) &( heth->Instance->MACA0LR );
215 
216     /* ETH_MAC_ADDRESS0 reserved for the primary MAC-address. */
217     configASSERT( ulIndex >= ETH_MAC_ADDRESS1 );
218 
219     /* STM32Hxx devices support 4 MAC address registers
220      * (ETH_MAC_ADDRESS0 - ETH_MAC_ADDRESS3), make sure ulIndex is not
221      * more than that. */
222     configASSERT( ulIndex <= ETH_MAC_ADDRESS3 );
223 
224     /* Calculate the selected MAC address high register. */
225     ulTempReg = 0xBF000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
226 
227     /* Load the selected MAC address high register. */
228     ( *( __IO uint32_t * ) ( ( uint32_t ) ( ulETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
229 
230     /* Calculate the selected MAC address low register. */
231     ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
232 
233     /* Load the selected MAC address low register */
234     ( *( __IO uint32_t * ) ( ( uint32_t ) ( ulETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
235 }
236 
237 /*-----------------------------------------------------------*/
238 
239 
240 /*******************************************************************************
241 *                      Network Interface API Functions
242 *******************************************************************************/
243 
pucGetRXBuffer(size_t uxSize)244 static uint8_t * pucGetRXBuffer( size_t uxSize )
245 {
246     TickType_t uxBlockTimeTicks = ipMS_TO_MIN_TICKS( 10U );
247     NetworkBufferDescriptor_t * pxBufferDescriptor;
248     uint8_t * pucReturn = NULL;
249 
250     pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( uxSize, uxBlockTimeTicks );
251 
252     if( pxBufferDescriptor != NULL )
253     {
254         pucReturn = pxBufferDescriptor->pucEthernetBuffer;
255     }
256 
257     return pucReturn;
258 }
259 /*-----------------------------------------------------------*/
260 
xSTM32H_NetworkInterfaceInitialise(NetworkInterface_t * pxInterface)261 static BaseType_t xSTM32H_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
262 {
263     BaseType_t xResult;
264     NetworkEndPoint_t * pxEndPoint;
265     HAL_StatusTypeDef xHalEthInitStatus;
266     size_t uxIndex = 0;
267     BaseType_t xMACEntry = ETH_MAC_ADDRESS1; /* ETH_MAC_ADDRESS0 reserved for the primary MAC-address. */
268 
269     if( xMacInitStatus == eMACInit )
270     {
271         pxMyInterface = pxInterface;
272 
273         pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
274         configASSERT( pxEndPoint != NULL );
275 
276         /*
277          * Initialize ETH Handler
278          * It assumes that Ethernet GPIO and clock configuration
279          * are already done in the ETH_MspInit()
280          */
281         xEthHandle.Instance = ETH;
282         xEthHandle.Init.MACAddr = ( uint8_t * ) pxEndPoint->xMACAddress.ucBytes;
283         xEthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE;
284         xEthHandle.Init.TxDesc = DMATxDscrTab;
285         xEthHandle.Init.RxDesc = DMARxDscrTab;
286         xEthHandle.Init.RxBuffLen = ( ETH_RX_BUF_SIZE - ipBUFFER_PADDING ) & ~( ( uint32_t ) 3U );
287 
288         /* Make sure that all unused fields are cleared. */
289         memset( &( DMATxDscrTab ), '\0', sizeof( DMATxDscrTab ) );
290         memset( &( DMARxDscrTab ), '\0', sizeof( DMARxDscrTab ) );
291 
292         xHalEthInitStatus = HAL_ETH_Init( &( xEthHandle ) );
293 
294         /* Only for inspection by debugger. */
295         ( void ) xHalEthInitStatus;
296 
297         /* Configuration for HAL_ETH_Transmit(_IT). */
298         memset( &( xTxConfig ), 0, sizeof( ETH_TxPacketConfig ) );
299         xTxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CRCPAD;
300 
301         #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
302             {
303                 /*xTxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC; */
304                 xTxConfig.Attributes |= ETH_TX_PACKETS_FEATURES_CSUM;
305                 xTxConfig.ChecksumCtrl = ETH_DMATXNDESCRF_CIC_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
306             }
307         #else
308             {
309                 xTxConfig.ChecksumCtrl = ETH_CHECKSUM_DISABLE;
310             }
311         #endif
312         xTxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
313 
314         /* This counting semaphore will count the number of free TX DMA descriptors. */
315         xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TX_DESC_CNT, ( UBaseType_t ) ETH_TX_DESC_CNT );
316         configASSERT( xTXDescriptorSemaphore );
317 
318         xTransmissionMutex = xSemaphoreCreateMutex();
319         configASSERT( xTransmissionMutex );
320 
321         /* Assign Rx memory buffers to a DMA Rx descriptor */
322         for( uxIndex = 0; uxIndex < ETH_RX_DESC_CNT; uxIndex++ )
323         {
324             uint8_t * pucBuffer;
325 
326             #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
327                 {
328                     pucBuffer = pucGetRXBuffer( ETH_RX_BUF_SIZE );
329                     configASSERT( pucBuffer != NULL );
330                 }
331             #else
332                 {
333                     pucBuffer = Rx_Buff[ uxIndex ];
334                 }
335             #endif
336 
337             HAL_ETH_DescAssignMemory( &( xEthHandle ), uxIndex, pucBuffer, NULL );
338         }
339 
340         #if ( ipconfigUSE_MDNS == 1 )
341             {
342                 /* Program the MDNS address. */
343                 prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xMDNS_MacAdress.ucBytes );
344                 xMACEntry += 8;
345             }
346         #endif
347         #if ( ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
348             {
349                 prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xMDNS_MACAdressIPv6.ucBytes );
350                 xMACEntry += 8;
351             }
352         #endif
353         #if ( ipconfigUSE_LLMNR == 1 )
354             {
355                 /* Program the LLMNR address. */
356                 prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xLLMNR_MacAdress.ucBytes );
357                 xMACEntry += 8;
358             }
359         #endif
360         #if ( ( ipconfigUSE_LLMNR == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
361             {
362                 prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xLLMNR_MacAdressIPv6.ucBytes );
363                 xMACEntry += 8;
364             }
365         #endif
366 
367         {
368             /* The EMAC address of the first end-point has been registered in HAL_ETH_Init(). */
369             for( ;
370                  pxEndPoint != NULL;
371                  pxEndPoint = FreeRTOS_NextEndPoint( pxMyInterface, pxEndPoint ) )
372             {
373                 switch( pxEndPoint->bits.bIPv6 )
374                 {
375                     #if ( ipconfigUSE_IPv4 != 0 )
376                         case pdFALSE_UNSIGNED:
377 
378                             if( xEthHandle.Init.MACAddr != ( uint8_t * ) pxEndPoint->xMACAddress.ucBytes )
379                             {
380                                 prvMACAddressConfig( &xEthHandle, xMACEntry, pxEndPoint->xMACAddress.ucBytes );
381                                 xMACEntry += 8;
382                             }
383                             break;
384                     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
385 
386                     #if ( ipconfigUSE_IPv6 != 0 )
387                         case pdTRUE_UNSIGNED:
388                            {
389                                uint8_t ucMACAddress[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 };
390 
391                                ucMACAddress[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ];
392                                ucMACAddress[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ];
393                                ucMACAddress[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ];
394 
395                                /* Allow traffic destined to Solicited-Node multicast address of this endpoint
396                                 * for Duplicate Address Detection (DAD) */
397                                prvMACAddressConfig( &xEthHandle, xMACEntry, ucMACAddress );
398                                xMACEntry += 8;
399                            }
400                            break;
401                     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
402 
403                     default:
404                         /* MISRA 16.4 Compliance */
405                         break;
406                 }
407 
408                 if( xMACEntry > ( BaseType_t ) ETH_MAC_ADDRESS3 )
409                 {
410                     /* No more locations available. */
411                     break;
412                 }
413             }
414         }
415 
416         #if ( ipconfigUSE_IPv6 != 0 )
417             {
418                 if( xMACEntry <= ( BaseType_t ) ETH_MAC_ADDRESS3 )
419                 {
420                     /* Allow traffic destined to IPv6 all nodes multicast MAC 33:33:00:00:00:01 */
421                     uint8_t ucMACAddress[ 6 ] = { 0x33, 0x33, 0, 0, 0, 0x01 };
422 
423                     prvMACAddressConfig( &xEthHandle, xMACEntry, ucMACAddress );
424                     xMACEntry += 8;
425                 }
426             }
427         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
428 
429         /* Initialize the MACB and set all PHY properties */
430         prvMACBProbePhy();
431 
432         /* Force a negotiation with the Switch or Router and wait for LS. */
433         prvEthernetUpdateConfig( pdTRUE );
434 
435         /* The deferred interrupt handler task is created at the highest
436          *  possible priority to ensure the interrupt handler can return directly
437          *  to it.  The task's handle is stored in xEMACTaskHandle so interrupts can
438          *  notify the task when there is something to process. */
439         if( xTaskCreate( prvEMACHandlerTask, niEMAC_HANDLER_TASK_NAME, niEMAC_HANDLER_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &( xEMACTaskHandle ) ) == pdPASS )
440         {
441             /* The task was created successfully. */
442             xMacInitStatus = eMACPass;
443         }
444         else
445         {
446             xMacInitStatus = eMACFailed;
447         }
448     } /* ( xMacInitStatus == eMACInit ) */
449 
450     if( xMacInitStatus != eMACPass )
451     {
452         /* EMAC initialisation failed, return pdFAIL. */
453         xResult = pdFAIL;
454     }
455     else
456     {
457         if( xPhyObject.ulLinkStatusMask != 0uL )
458         {
459             xResult = pdPASS;
460             FreeRTOS_printf( ( "Link Status is high\n" ) );
461         }
462         else
463         {
464             /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
465              * and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
466             xResult = pdFAIL;
467         }
468     }
469 
470     return xResult;
471 }
472 /*-----------------------------------------------------------*/
473 
xSTM32H_GetPhyLinkStatus(NetworkInterface_t * pxInterface)474 static BaseType_t xSTM32H_GetPhyLinkStatus( NetworkInterface_t * pxInterface )
475 {
476     BaseType_t xReturn;
477 
478     if( xPhyObject.ulLinkStatusMask != 0U )
479     {
480         xReturn = pdPASS;
481     }
482     else
483     {
484         xReturn = pdFAIL;
485     }
486 
487     return xReturn;
488 }
489 /*-----------------------------------------------------------*/
490 
491 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
492 
493 /* Do not call the following function directly. It is there for downward compatibility.
494  * The function FreeRTOS_IPInit() will call it to initialice the interface and end-point
495  * objects.  See the description in FreeRTOS_Routing.h. */
pxFillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)496     NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex,
497                                                     NetworkInterface_t * pxInterface )
498     {
499         return pxSTM32H_FillInterfaceDescriptor( xEMACIndex, pxInterface );
500     }
501 
502 #endif
503 /*-----------------------------------------------------------*/
504 
pxSTM32H_FillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)505 NetworkInterface_t * pxSTM32H_FillInterfaceDescriptor( BaseType_t xEMACIndex,
506                                                        NetworkInterface_t * pxInterface )
507 {
508     static char pcName[ 17 ];
509 
510 /* This function pxSTM32Hxx_FillInterfaceDescriptor() adds a network-interface.
511  * Make sure that the object pointed to by 'pxInterface'
512  * is declared static or global, and that it will remain to exist. */
513 
514     snprintf( pcName, sizeof( pcName ), "eth%u", ( unsigned ) xEMACIndex );
515 
516     memset( pxInterface, '\0', sizeof( *pxInterface ) );
517     pxInterface->pcName = pcName;                    /* Just for logging, debugging. */
518     pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
519     pxInterface->pfInitialise = xSTM32H_NetworkInterfaceInitialise;
520     pxInterface->pfOutput = xSTM32H_NetworkInterfaceOutput;
521     pxInterface->pfGetPhyLinkStatus = xSTM32H_GetPhyLinkStatus;
522 
523     FreeRTOS_AddNetworkInterface( pxInterface );
524 
525     return pxInterface;
526 }
527 /*-----------------------------------------------------------*/
528 
xSTM32H_NetworkInterfaceOutput(NetworkInterface_t * pxInterface,NetworkBufferDescriptor_t * const pxBuffer,BaseType_t xReleaseAfterSend)529 static BaseType_t xSTM32H_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
530                                                   NetworkBufferDescriptor_t * const pxBuffer,
531                                                   BaseType_t xReleaseAfterSend )
532 {
533     BaseType_t xResult = pdFAIL;
534     TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 100U );
535     uint8_t * pucTXBuffer;
536 
537     if( xSTM32H_GetPhyLinkStatus( pxInterface ) == pdPASS )
538     {
539         #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
540             /* Zero-copy method, pass the buffer. */
541             pucTXBuffer = pxBuffer->pucEthernetBuffer;
542 
543             /* As the buffer is passed to the driver, it must exist.
544              * The library takes care of this. */
545             configASSERT( xReleaseAfterSend != pdFALSE );
546         #else
547             pucTXBuffer = Tx_Buff[ xEthHandle.TxDescList.CurTxDesc ];
548             /* The copy method, left here for educational purposes. */
549             configASSERT( pxBuffer->xDataLength <= sizeof( Tx_Buff[ 0 ] ) );
550         #endif
551 
552         ETH_BufferTypeDef xTransmitBuffer =
553         {
554             .buffer = pucTXBuffer,
555             .len    = pxBuffer->xDataLength,
556             .next   = NULL /* FreeRTOS+TCP does not use linked buffers. */
557         };
558         /* This is the total length, which is equal to the buffer. */
559         xTxConfig.Length = pxBuffer->xDataLength;
560         xTxConfig.TxBuffer = &( xTransmitBuffer );
561 
562         /* This counting semaphore counts the number of free TX DMA descriptors. */
563         if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
564         {
565             /* If the logging routine is using the network, the following message
566              * may cause a new error message. */
567             FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
568         }
569         else
570         {
571             /* Memory barrier: Make sure that the data written to the packet buffer got written. */
572             __DSB();
573 
574             /* Get exclusive accces to the TX process.
575              * Both the IP-task and the EMAC task will work on the TX process. */
576             if( xSemaphoreTake( xTransmissionMutex, xBlockTimeTicks ) != pdFAIL )
577             {
578                 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
579                     {
580                         /* Do not release the buffer. */
581                         xReleaseAfterSend = pdFALSE;
582                     }
583                 #else
584                     {
585                         memcpy( pucTXBuffer, pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
586 
587                         /* A memory barrier to make sure that the outgoing packets has been written
588                          * to the physical memory. */
589                         __DSB();
590                     }
591                 #endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
592 
593                 if( HAL_ETH_Transmit_IT( &( xEthHandle ), &( xTxConfig ) ) == HAL_OK )
594                 {
595                     xResult = pdPASS;
596                 }
597 
598                 /* And release the mutex. */
599                 xSemaphoreGive( xTransmissionMutex );
600             }
601 
602             /* Call the standard trace macro to log the send event. */
603             iptraceNETWORK_INTERFACE_TRANSMIT();
604         }
605     }
606 
607     if( xReleaseAfterSend != pdFALSE )
608     {
609         vReleaseNetworkBufferAndDescriptor( pxBuffer );
610     }
611 
612     return xResult;
613 }
614 /*-----------------------------------------------------------*/
615 
616 /*******************************************************************************
617 *                      END Network Interface API Functions
618 *******************************************************************************/
619 
620 
621 
622 /*******************************************************************************
623 *                      Network Interface Static Functions
624 *******************************************************************************/
625 
prvMACBProbePhy(void)626 static void prvMACBProbePhy( void )
627 {
628     /* Bind the write and read access functions. */
629     vPhyInitialise( &( xPhyObject ),
630                     ( xApplicationPhyReadHook_t ) ETH_PHY_IO_ReadReg,
631                     ( xApplicationPhyWriteHook_t ) ETH_PHY_IO_WriteReg );
632     /* Poll the bus for all connected PHY's. */
633     xPhyDiscover( &( xPhyObject ) );
634     /* Configure them using the properties provided. */
635     xPhyConfigure( &( xPhyObject ), &( xPHYProperties ) );
636 }
637 /*-----------------------------------------------------------*/
638 
prvEthernetUpdateConfig(BaseType_t xForce)639 static void prvEthernetUpdateConfig( BaseType_t xForce )
640 {
641     ETH_MACConfigTypeDef MACConf;
642     uint32_t speed = 0, duplex = 0;
643 
644     FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
645                        xPhyObject.ulLinkStatusMask,
646                        ( int ) xForce ) );
647 
648     if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
649     {
650         /* Restart the auto-negotiation. */
651         xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &( xPhyObject ) ) );
652 
653         /* Configure the MAC with the Duplex Mode fixed by the
654          * auto-negotiation process. */
655         if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
656         {
657             duplex = ETH_FULLDUPLEX_MODE;
658         }
659         else
660         {
661             duplex = ETH_HALFDUPLEX_MODE;
662         }
663 
664         /* Configure the MAC with the speed fixed by the
665          * auto-negotiation process. */
666         if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
667         {
668             speed = ETH_SPEED_10M;
669         }
670         else
671         {
672             speed = ETH_SPEED_100M;
673         }
674 
675         /* Get MAC and configure it */
676         HAL_ETH_GetMACConfig( &( xEthHandle ), &( MACConf ) );
677         MACConf.DuplexMode = duplex;
678         MACConf.Speed = speed;
679         HAL_ETH_SetMACConfig( &( xEthHandle ), &( MACConf ) );
680         #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
681             {
682                 MACConf.ChecksumOffload = ENABLE;
683             }
684         #else
685             {
686                 MACConf.ChecksumOffload = DISABLE;
687             }
688         #endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 ) */
689 
690         /* Restart MAC interface */
691         HAL_ETH_Start_IT( &( xEthHandle ) );
692     }
693     else
694     {
695         /* Stop MAC interface */
696         HAL_ETH_Stop_IT( &( xEthHandle ) );
697     }
698 }
699 /*-----------------------------------------------------------*/
700 
prvNetworkInterfaceInput(void)701 static BaseType_t prvNetworkInterfaceInput( void )
702 {
703     BaseType_t xReturn = 0;
704 
705     /* For as long as a packet is immediately available. */
706     for( ; ; )
707     {
708         NetworkBufferDescriptor_t * pxBufferDescriptor;
709         NetworkBufferDescriptor_t * pxReceivedBuffer = NULL;
710         ETH_BufferTypeDef data_buffer;
711         size_t uxDataLength;
712         size_t uxLength;
713 
714         uxDataLength = HAL_ETH_GetRxData( &( xEthHandle ), &( data_buffer ) );
715 
716         if( uxDataLength == 0U )
717         {
718             /* No more packets received. */
719             break;
720         }
721 
722         xReturn++;
723 
724         #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
725             {
726                 /* Reserve the maximum length for the next reception. */
727                 uxLength = ETH_RX_BUF_SIZE;
728 
729                 if( data_buffer.buffer != NULL )
730                 {
731                     pxReceivedBuffer = pxPacketBuffer_to_NetworkBuffer( data_buffer.buffer );
732                     #if ( ipconfigTCP_IP_SANITY != 0 )
733                         {
734                             configASSERT( bIsValidNetworkDescriptor( pxReceivedBuffer ) != 0 );
735                         }
736                     #endif
737                 }
738 
739                 if( pxReceivedBuffer == NULL )
740                 {
741                     FreeRTOS_printf( ( "Strange: no descriptor received\n" ) );
742                 }
743             }
744         #else /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
745             {
746                 /* Reserve the length of the packet that was just received. */
747                 uxLength = uxDataLength;
748             }
749         #endif /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
750 
751         pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( uxLength, 0u );
752 
753         if( pxBufferDescriptor == NULL )
754         {
755             /* The event was lost because a network buffer was not available.
756              * Call the standard trace macro to log the occurrence. */
757             iptraceETHERNET_RX_EVENT_LOST();
758         }
759 
760         #if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
761             {
762                 if( pxBufferDescriptor == NULL )
763                 {
764                     /* Can not receive this packet. Buffer will be re-used. */
765                     pxReceivedBuffer = NULL;
766                 }
767                 else if( pxReceivedBuffer != NULL )
768                 {
769                     pxReceivedBuffer->xDataLength = uxDataLength;
770                 }
771                 else
772                 {
773                     /* Allocating a new buffer failed. */
774                 }
775             }
776         #else /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
777             {
778                 if( pxBufferDescriptor != NULL )
779                 {
780                     pxReceivedBuffer = pxBufferDescriptor;
781                     /* The copy method. */
782                     memcpy( pxReceivedBuffer->pucEthernetBuffer, data_buffer.buffer, uxDataLength );
783                     pxReceivedBuffer->xDataLength = uxDataLength;
784                     /* Make sure that the descriptor isn't used any more. */
785                     pxBufferDescriptor = NULL;
786                 }
787             }
788         #endif /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
789 
790         {
791             uint8_t * pucBuffer = NULL;
792 
793             if( pxBufferDescriptor != NULL )
794             {
795                 pucBuffer = pxBufferDescriptor->pucEthernetBuffer;
796             }
797 
798             /* Assign an RX buffer to the descriptor, so that
799              * a next packet can be received. */
800             HAL_ETH_BuildRxDescriptors( &( xEthHandle ), pucBuffer );
801         }
802 
803         /* See if the data contained in the received Ethernet frame needs
804         * to be processed.  NOTE! It is preferable to do this in
805         * the interrupt service routine itself, which would remove the need
806         * to unblock this task for packets that don't need processing. */
807 
808         if( pxReceivedBuffer != NULL )
809         {
810             BaseType_t xDoRelease = pdFALSE;
811 
812             if( eConsiderFrameForProcessing( pxReceivedBuffer->pucEthernetBuffer ) != eProcessBuffer )
813             {
814                 /* The Ethernet frame can be dropped, but the Ethernet buffer must be released. */
815                 xDoRelease = pdTRUE;
816             }
817             else
818             {
819                 /* The event about to be sent to the TCP/IP is an Rx event.
820                  * pvData is used to point to the network buffer descriptor that
821                  * now references the received data. */
822 
823                 IPStackEvent_t xRxEvent =
824                 {
825                     .eEventType = eNetworkRxEvent,
826                     .pvData     = ( void * ) pxReceivedBuffer
827                 };
828 
829                 pxReceivedBuffer->pxInterface = pxMyInterface;
830                 pxReceivedBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pxReceivedBuffer->pucEthernetBuffer );
831 
832                 /* Send the data to the TCP/IP stack. */
833                 if( xSendEventStructToIPTask( &( xRxEvent ), 0 ) != pdFALSE )
834                 {
835                     /* The message was successfully sent to the TCP/IP stack.
836                     * Call the standard trace macro to log the occurrence. */
837                     iptraceNETWORK_INTERFACE_RECEIVE();
838                 }
839                 else
840                 {
841                     xDoRelease = pdTRUE;
842 
843                     /* The buffer could not be sent to the IP task so the buffer
844                      * must be released. */
845 
846                     /* Make a call to the standard trace macro to log the
847                      * occurrence. */
848                     iptraceETHERNET_RX_EVENT_LOST();
849                 }
850             }
851 
852             if( xDoRelease != pdFALSE )
853             {
854                 vReleaseNetworkBufferAndDescriptor( pxReceivedBuffer );
855             }
856         }
857     }
858 
859     return xReturn;
860 }
861 /*-----------------------------------------------------------*/
862 
863 /*******************************************************************************
864 *                   END Network Interface Static Functions
865 *******************************************************************************/
866 
867 
868 
869 /*******************************************************************************
870 *                   PHY IO Functions
871 *******************************************************************************/
872 
873 /**
874  * @brief  Read a PHY register through the MDIO interface.
875  * @param  DevAddr: PHY port address
876  * @param  RegAddr: PHY register address
877  * @param  pRegVal: pointer to hold the register value
878  * @retval 0 if OK -1 if Error
879  */
ETH_PHY_IO_ReadReg(uint32_t ulDevAddr,uint32_t ulRegAddr,uint32_t * pulRegVal)880 static int32_t ETH_PHY_IO_ReadReg( uint32_t ulDevAddr,
881                                    uint32_t ulRegAddr,
882                                    uint32_t * pulRegVal )
883 {
884     int32_t iResult = -1;
885 
886     if( HAL_ETH_ReadPHYRegister( &( xEthHandle ), ulDevAddr, ulRegAddr, pulRegVal ) == HAL_OK )
887     {
888         iResult = 0;
889     }
890 
891     return iResult;
892 }
893 /*-----------------------------------------------------------*/
894 
895 /**
896  * @brief  Write a value to a PHY register through the MDIO interface.
897  * @param  DevAddr: PHY port address
898  * @param  RegAddr: PHY register address
899  * @param  RegVal: Value to be written
900  * @retval 0 if OK -1 if Error
901  */
ETH_PHY_IO_WriteReg(uint32_t ulDevAddr,uint32_t ulRegAddr,uint32_t pulRegVal)902 static int32_t ETH_PHY_IO_WriteReg( uint32_t ulDevAddr,
903                                     uint32_t ulRegAddr,
904                                     uint32_t pulRegVal )
905 {
906     int32_t iResult = -1;
907 
908     if( HAL_ETH_WritePHYRegister( &( xEthHandle ), ulDevAddr, ulRegAddr, pulRegVal ) == HAL_OK )
909     {
910         iResult = 0;
911     }
912 
913     return iResult;
914 }
915 /*-----------------------------------------------------------*/
916 
917 /*******************************************************************************
918 *                   END PHY IO Functions
919 *******************************************************************************/
920 
921 
922 
923 /*******************************************************************************
924 *                   Ethernet Handling Functions
925 *******************************************************************************/
926 
ETH_IRQHandler(void)927 void ETH_IRQHandler( void )
928 {
929     HAL_ETH_IRQHandler( &( xEthHandle ) );
930 }
931 /*-----------------------------------------------------------*/
932 
prvSetFlagsAndNotify(uint32_t ulFlags)933 static void prvSetFlagsAndNotify( uint32_t ulFlags )
934 {
935     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
936 
937     /* Ethernet RX-Complete callback function, elsewhere declared as weak.
938      * No critical section needed, this function is called from an ISR. */
939     ulISREvents |= ulFlags;
940 
941     /* Wakeup the prvEMACHandlerTask. */
942     if( xEMACTaskHandle != NULL )
943     {
944         vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xHigherPriorityTaskWoken ) );
945         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
946     }
947 }
948 /*-----------------------------------------------------------*/
949 
HAL_ETH_TxCpltCallback(ETH_HandleTypeDef * heth)950 void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef * heth )
951 {
952     ( void ) heth;
953     prvSetFlagsAndNotify( EMAC_IF_TX_EVENT );
954 }
955 /*-----------------------------------------------------------*/
956 
HAL_ETH_RxCpltCallback(ETH_HandleTypeDef * heth)957 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef * heth )
958 {
959     ( void ) heth;
960     prvSetFlagsAndNotify( EMAC_IF_RX_EVENT );
961 }
962 /*-----------------------------------------------------------*/
963 
HAL_ETH_DMAErrorCallback(ETH_HandleTypeDef * heth)964 void HAL_ETH_DMAErrorCallback( ETH_HandleTypeDef * heth )
965 {
966     ( void ) heth;
967     prvSetFlagsAndNotify( EMAC_IF_ERR_EVENT );
968 }
969 /*-----------------------------------------------------------*/
970 
971 /*******************************************************************************
972 *                   END Ethernet Handling Functions
973 *******************************************************************************/
974 
975 uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ETH_RX_BUF_SIZE ]
976 #if ( ipconfigZERO_COPY_RX_DRIVER != 0 || ipconfigZERO_COPY_TX_DRIVER != 0 )
977     __attribute__( ( section( ".ethernet_data" ) ) )
978 #endif /* ( ipconfigZERO_COPY_RX_DRIVER != 0 || ipconfigZERO_COPY_TX_DRIVER != 0 ) */
979 __attribute__( ( aligned( 32 ) ) );
980 
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])981 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
982 {
983     uint8_t * ucRAMBuffer = ucNetworkPackets;
984     uint32_t ul;
985 
986     for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
987     {
988         pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
989         *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
990         ucRAMBuffer += ETH_RX_BUF_SIZE;
991     }
992 }
993 /*-----------------------------------------------------------*/
994 
vClearOptionBit(volatile uint32_t * pulValue,uint32_t ulValue)995 static void vClearOptionBit( volatile uint32_t * pulValue,
996                              uint32_t ulValue )
997 {
998     portENTER_CRITICAL();
999     *( pulValue ) &= ~( ulValue );
1000     portEXIT_CRITICAL();
1001 }
1002 /*-----------------------------------------------------------*/
1003 
1004 #if ( ipconfigHAS_PRINTF != 0 )
uxGetOwnCount(ETH_HandleTypeDef * heth)1005     static size_t uxGetOwnCount( ETH_HandleTypeDef * heth )
1006     {
1007         BaseType_t xIndex;
1008         BaseType_t xCount = 0;
1009         ETH_RxDescListTypeDef * dmarxdesclist = &heth->RxDescList;
1010 
1011         /* Count the number of RX descriptors that are owned by DMA. */
1012         for( xIndex = 0; xIndex < ETH_RX_DESC_CNT; xIndex++ )
1013         {
1014             __IO const ETH_DMADescTypeDef * dmarxdesc =
1015                 ( __IO const ETH_DMADescTypeDef * )dmarxdesclist->RxDesc[ xIndex ];
1016 
1017             if( ( dmarxdesc->DESC3 & ETH_DMARXNDESCWBF_OWN ) != 0U )
1018             {
1019                 xCount++;
1020             }
1021         }
1022 
1023         return xCount;
1024     }
1025 #endif /* if ( ipconfigHAS_PRINTF != 0 ) */
1026 /*-----------------------------------------------------------*/
1027 
prvEMACHandlerTask(void * pvParameters)1028 static void prvEMACHandlerTask( void * pvParameters )
1029 {
1030 /* When sending a packet, all descriptors in the transmission channel may
1031  * be occupied.  In stat case, the program will wait (block) for the counting
1032  * semaphore. */
1033     const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
1034 
1035     #if ( ipconfigHAS_PRINTF != 0 )
1036         size_t uxTXDescriptorsUsed = 0U;
1037         size_t uxRXDescriptorsUsed = ETH_RX_DESC_CNT;
1038     #endif
1039 
1040     ( void ) pvParameters;
1041 
1042     for( ; ; )
1043     {
1044         BaseType_t xResult = 0;
1045 
1046         #if ( ipconfigHAS_PRINTF != 0 )
1047             {
1048                 size_t uxUsed;
1049                 size_t uxOwnCount;
1050 
1051                 /* Call a function that monitors resources: the amount of free network
1052                  * buffers and the amount of free space on the heap.  See FreeRTOS_IP.c
1053                  * for more detailed comments. */
1054                 vPrintResourceStats();
1055 
1056                 /* Some more statistics: number of free descriptors. */
1057                 uxUsed = ETH_TX_DESC_CNT - uxSemaphoreGetCount( xTXDescriptorSemaphore );
1058 
1059                 if( uxTXDescriptorsUsed < uxUsed )
1060                 {
1061                     uxTXDescriptorsUsed = uxUsed;
1062                     FreeRTOS_printf( ( "TX descriptors %u/%u\n",
1063                                        uxTXDescriptorsUsed,
1064                                        ETH_TX_DESC_CNT ) );
1065                 }
1066 
1067                 uxOwnCount = uxGetOwnCount( &( xEthHandle ) );
1068 
1069                 if( uxRXDescriptorsUsed > uxOwnCount )
1070                 {
1071                     uxRXDescriptorsUsed = uxOwnCount;
1072                     FreeRTOS_printf( ( "RX descriptors %u/%u\n",
1073                                        uxRXDescriptorsUsed,
1074                                        ETH_RX_DESC_CNT ) );
1075                 }
1076             }
1077         #endif /* ( ipconfigHAS_PRINTF != 0 ) */
1078 
1079         ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
1080 
1081         /* Wait for the Ethernet MAC interrupt to indicate that another packet
1082          * has been received. */
1083         if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0U )
1084         {
1085             vClearOptionBit( &( ulISREvents ), EMAC_IF_RX_EVENT );
1086             xResult = prvNetworkInterfaceInput();
1087         }
1088 
1089         /* When a packet has been transmitted, the descriptor must be
1090          * prepared for a next transmission.
1091          * When using zero-copy, the network buffer must be released
1092          * ( i.e. returned to the pool of network buffers ). */
1093 
1094         if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0U )
1095         {
1096             vClearOptionBit( &( ulISREvents ), EMAC_IF_TX_EVENT );
1097 
1098             if( xSemaphoreTake( xTransmissionMutex, 10000U ) != pdFAIL )
1099             {
1100                 ETH_Clear_Tx_Descriptors( &( xEthHandle ) );
1101                 xSemaphoreGive( xTransmissionMutex );
1102             }
1103         }
1104 
1105         /* Some error has occurred, possibly an overflow or an underflow. */
1106         if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0U )
1107         {
1108             vClearOptionBit( &( ulISREvents ), EMAC_IF_ERR_EVENT );
1109 
1110             xEthHandle.gState = HAL_ETH_STATE_READY;
1111             /* Enable all interrupts */
1112             HAL_ETH_Start_IT( &( xEthHandle ) );
1113             xResult += prvNetworkInterfaceInput();
1114         }
1115 
1116         if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
1117         {
1118             /*
1119              * The function xPhyCheckLinkStatus() returns pdTRUE if the
1120              * Link Status has changes since it was called the last time.
1121              */
1122             if( xSTM32H_GetPhyLinkStatus( pxMyInterface ) == pdFALSE )
1123             {
1124                 /* Stop the DMA transfer. */
1125                 HAL_ETH_Stop_IT( &( xEthHandle ) );
1126                 /* Clear the Transmit buffers. */
1127                 memset( &( DMATxDscrTab ), '\0', sizeof( DMATxDscrTab ) );
1128                 /* Since the link is down, clear the descriptors. */
1129                 ETH_Clear_Tx_Descriptors( &( xEthHandle ) );
1130             }
1131             else
1132             {
1133                 /* Something has changed to a Link Status, need re-check. */
1134                 prvEthernetUpdateConfig( pdFALSE );
1135             }
1136         }
1137     }
1138 }
1139 
1140 /*-----------------------------------------------------------*/
1141