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