]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / STM32Fxx / NetworkInterface.c
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.0.11
8 Copyright (C) 2017 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 /* Standard includes. */
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 /* FreeRTOS includes. */
37 #include "FreeRTOS.h"
38 #include "task.h"
39 #include "queue.h"
40 #include "semphr.h"
41
42 /* FreeRTOS+TCP includes. */
43 #include "FreeRTOS_IP.h"
44 #include "FreeRTOS_Sockets.h"
45 #include "FreeRTOS_IP_Private.h"
46 #include "FreeRTOS_DNS.h"
47 #include "FreeRTOS_ARP.h"
48 #include "NetworkBufferManagement.h"
49 #include "NetworkInterface.h"
50 #include "phyHandling.h"
51
52 /* ST includes. */
53 #if defined( STM32F7xx )
54         #include "stm32f7xx_hal.h"
55 #elif defined( STM32F4xx )
56         #include "stm32f4xx_hal.h"
57 #elif defined( STM32F2xx )
58         #include "stm32f2xx_hal.h"
59 #elif !defined( _lint ) /* Lint does not like an #error */
60         #error What part?
61 #endif
62
63 #include "stm32fxx_hal_eth.h"
64
65 /* Interrupt events to process.  Currently only the Rx event is processed
66 although code for other events is included to allow for possible future
67 expansion. */
68 #define EMAC_IF_RX_EVENT        1UL
69 #define EMAC_IF_TX_EVENT        2UL
70 #define EMAC_IF_ERR_EVENT       4UL
71 #define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
72
73 #define ETH_DMA_ALL_INTS \
74         ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \
75           ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \
76           ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )
77
78 #ifndef niEMAC_HANDLER_TASK_PRIORITY
79         #define niEMAC_HANDLER_TASK_PRIORITY    configMAX_PRIORITIES - 1
80 #endif
81
82 #define ipFRAGMENT_OFFSET_BIT_MASK              ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */
83
84 #if( ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )
85         #warning Consider enabling checksum offloading
86 #endif
87
88 #ifndef niDESCRIPTOR_WAIT_TIME_MS
89         #define niDESCRIPTOR_WAIT_TIME_MS               250uL
90 #endif
91
92 /*
93  * Most users will want a PHY that negotiates about
94  * the connection properties: speed, dmix and duplex.
95  * On some rare cases, you want to select what is being
96  * advertised, properties like MDIX and duplex.
97  */
98
99 #if !defined( ipconfigETHERNET_AN_ENABLE )
100         /* Enable auto-negotiation */
101         #define ipconfigETHERNET_AN_ENABLE                              1
102 #endif
103
104 #if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )
105         #define ipconfigETHERNET_AUTO_CROSS_ENABLE              1
106 #endif
107
108 #if( ipconfigETHERNET_AN_ENABLE == 0 )
109         /*
110          * The following three defines are only used in case there
111          * is no auto-negotiation.
112          */
113         #if !defined( ipconfigETHERNET_CROSSED_LINK )
114                 #define ipconfigETHERNET_CROSSED_LINK                   1
115         #endif
116
117         #if !defined( ipconfigETHERNET_USE_100MB )
118                 #define ipconfigETHERNET_USE_100MB                              1
119         #endif
120
121         #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
122                 #define ipconfigETHERNET_USE_FULL_DUPLEX                1
123         #endif
124 #endif /* ipconfigETHERNET_AN_ENABLE == 0 */
125
126 /* Default the size of the stack used by the EMAC deferred handler task to twice
127 the size of the stack used by the idle task - but allow this to be overridden in
128 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
129 #ifndef configEMAC_TASK_STACK_SIZE
130         #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
131 #endif
132
133 /* Two choices must be made: RMII versus MII,
134 and the index of the PHY in use ( between 0 and 31 ). */
135 #ifndef ipconfigUSE_RMII
136         #ifdef STM32F7xx
137                 #define ipconfigUSE_RMII        1
138         #else
139                 #define ipconfigUSE_RMII        0
140         #endif /* STM32F7xx */
141 #endif /* ipconfigUSE_RMII */
142
143 #if( ipconfigUSE_RMII != 0 )
144         #warning Using RMII, make sure if this is correct
145 #else
146         #warning Using MII, make sure if this is correct
147 #endif
148
149 typedef enum
150 {
151     eMACInit,   /* Must initialise MAC. */
152     eMACPass,   /* Initialisation was successful. */
153     eMACFailed, /* Initialisation failed. */
154 } eMAC_INIT_STATUS_TYPE;
155
156 static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
157
158 /*-----------------------------------------------------------*/
159
160 /*
161  * A deferred interrupt handler task that processes
162  */
163 static void prvEMACHandlerTask( void *pvParameters );
164
165 /*
166  * Force a negotiation with the Switch or Router and wait for LS.
167  */
168 static void prvEthernetUpdateConfig( BaseType_t xForce );
169
170 /*
171  * See if there is a new packet and forward it to the IP-task.
172  */
173 static BaseType_t prvNetworkInterfaceInput( void );
174
175 #if( ipconfigUSE_LLMNR != 0 )
176         /*
177          * For LLMNR, an extra MAC-address must be configured to
178          * be able to receive the multicast messages.
179          */
180         static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);
181 #endif
182
183 /*
184  * Check if a given packet should be accepted.
185  */
186 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );
187
188 /*
189  * Initialise the TX descriptors.
190  */
191 static void prvDMATxDescListInit( void );
192
193 /*
194  * Initialise the RX descriptors.
195  */
196 static void prvDMARxDescListInit( void );
197
198 /* After packets have been sent, the network
199 buffers will be released. */
200 static void vClearTXBuffers( void );
201
202 /*-----------------------------------------------------------*/
203
204 /* Bit map of outstanding ETH interrupt events for processing.  Currently only
205 the Rx interrupt is handled, although code is included for other events to
206 enable future expansion. */
207 static volatile uint32_t ulISREvents;
208
209 #if( ipconfigUSE_LLMNR == 1 )
210         static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
211 #endif
212
213 static EthernetPhy_t xPhyObject;
214
215 /* Ethernet handle. */
216 static ETH_HandleTypeDef xETH;
217
218 /* xTXDescriptorSemaphore is a counting semaphore with
219 a maximum count of ETH_TXBUFNB, which is the number of
220 DMA TX descriptors. */
221 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
222
223 /*
224  * Note: it is adviced to define both
225  *
226  *     #define  ipconfigZERO_COPY_RX_DRIVER   1
227  *     #define  ipconfigZERO_COPY_TX_DRIVER   1
228  *
229  * The method using memcpy is slower and probaly uses more RAM memory.
230  * The possibility is left in the code just for comparison.
231  *
232  * It is adviced to define ETH_TXBUFNB at least 4. Note that no
233  * TX buffers are allocated in a zero-copy driver.
234  */
235 /* MAC buffers: ---------------------------------------------------------*/
236
237 /* Put the DMA descriptors in '.first_data'.
238 This is important for STM32F7, which has an L1 data cache.
239 The first 64KB of the SRAM is not cached.
240 See README.TXT in this folder. */
241
242 /* Ethernet Rx MA Descriptor */
243 __attribute__ ((aligned (32)))
244 #if defined(STM32F7xx)
245         __attribute__ ((section(".first_data")))
246 #endif
247         ETH_DMADescTypeDef  DMARxDscrTab[ ETH_RXBUFNB ];
248
249 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )
250         /* Ethernet Receive Buffer */
251         __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END;
252 #endif
253
254 /* Ethernet Tx DMA Descriptor */
255 __attribute__ ((aligned (32)))
256 #if defined(STM32F7xx)
257         __attribute__ ((section(".first_data")))
258 #endif
259         ETH_DMADescTypeDef  DMATxDscrTab[ ETH_TXBUFNB ];
260
261 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
262         /* Ethernet Transmit Buffer */
263         __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END;
264 #endif
265
266 /* DMATxDescToClear points to the next TX DMA descriptor
267 that must be cleared by vClearTXBuffers(). */
268 static __IO ETH_DMADescTypeDef  *DMATxDescToClear;
269
270 /* Holds the handle of the task used as a deferred interrupt processor.  The
271 handle is used so direct notifications can be sent to the task for all EMAC/DMA
272 related interrupts. */
273 static TaskHandle_t xEMACTaskHandle = NULL;
274
275 /* For local use only: describe the PHY's properties: */
276 const PhyProperties_t xPHYProperties =
277 {
278         #if( ipconfigETHERNET_AN_ENABLE != 0 )
279                 .ucSpeed = PHY_SPEED_AUTO,
280                 .ucDuplex = PHY_DUPLEX_AUTO,
281         #else
282                 #if( ipconfigETHERNET_USE_100MB != 0 )
283                         .ucSpeed = PHY_SPEED_100,
284                 #else
285                         .ucSpeed = PHY_SPEED_10,
286                 #endif
287
288                 #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
289                         .ucDuplex = PHY_DUPLEX_FULL,
290                 #else
291                         .ucDuplex = PHY_DUPLEX_HALF,
292                 #endif
293         #endif
294
295         #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
296                 .ucMDI_X = PHY_MDIX_AUTO,
297         #elif( ipconfigETHERNET_CROSSED_LINK != 0 )
298                 .ucMDI_X = PHY_MDIX_CROSSED,
299         #else
300                 .ucMDI_X = PHY_MDIX_DIRECT,
301         #endif
302 };
303
304 /*-----------------------------------------------------------*/
305
306 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )
307 {
308 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
309
310         ( void ) heth;
311
312         /* Ethernet RX-Complete callback function, elsewhere declared as weak. */
313     ulISREvents |= EMAC_IF_RX_EVENT;
314         /* Wakeup the prvEMACHandlerTask. */
315         if( xEMACTaskHandle != NULL )
316         {
317                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
318                 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
319         }
320 }
321 /*-----------------------------------------------------------*/
322
323 void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )
324 {
325 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
326
327         ( void ) heth;
328
329         /* This call-back is only useful in case packets are being sent
330         zero-copy.  Once they're sent, the buffers will be released
331         by the function vClearTXBuffers(). */
332         ulISREvents |= EMAC_IF_TX_EVENT;
333         /* Wakeup the prvEMACHandlerTask. */
334         if( xEMACTaskHandle != NULL )
335         {
336                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
337                 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
338         }
339 }
340 /*-----------------------------------------------------------*/
341
342 static void vClearTXBuffers()
343 {
344 __IO ETH_DMADescTypeDef  *txLastDescriptor = xETH.TxDesc;
345 size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
346 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
347         NetworkBufferDescriptor_t *pxNetworkBuffer;
348         uint8_t *ucPayLoad;
349 #endif
350
351         /* This function is called after a TX-completion interrupt.
352         It will release each Network Buffer used in xNetworkInterfaceOutput().
353         'uxCount' represents the number of descriptors given to DMA for transmission.
354         After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */
355         while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )
356         {
357                 if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )
358                 {
359                         break;
360                 }
361                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
362                 {
363                         ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;
364
365                         if( ucPayLoad != NULL )
366                         {
367                                 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
368                                 if( pxNetworkBuffer != NULL )
369                                 {
370                                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;
371                                 }
372                                 DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;
373                         }
374                 }
375                 #endif /* ipconfigZERO_COPY_TX_DRIVER */
376
377                 DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );
378
379                 uxCount--;
380                 /* Tell the counting semaphore that one more TX descriptor is available. */
381                 xSemaphoreGive( xTXDescriptorSemaphore );
382         }
383 }
384 /*-----------------------------------------------------------*/
385
386 BaseType_t xNetworkInterfaceInitialise( void )
387 {
388 HAL_StatusTypeDef hal_eth_init_status;
389 BaseType_t xResult;
390
391     if( xMacInitStatus == eMACInit )
392         {
393                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
394                 if( xTXDescriptorSemaphore == NULL )
395                 {
396                         xMacInitStatus = eMACFailed;
397                 }
398                 else
399                 {
400                         /* Initialise ETH */
401
402                         xETH.Instance = ETH;
403                         xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
404                         xETH.Init.Speed = ETH_SPEED_100M;
405                         xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
406                         /* Value of PhyAddress doesn't matter, will be probed for. */
407                         xETH.Init.PhyAddress = 0;
408
409                         xETH.Init.MACAddr = ( uint8_t * ) FreeRTOS_GetMACAddress();
410                         xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;
411
412                         #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
413                         {
414                                 /* using the ETH_CHECKSUM_BY_HARDWARE option:
415                                 both the IP and the protocol checksums will be calculated
416                                 by the peripheral. */
417                                 xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
418                         }
419                         #else
420                         {
421                                 xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
422                         }
423                         #endif
424
425                         #if( ipconfigUSE_RMII != 0 )
426                         {
427                                 xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
428                         }
429                         #else
430                         {
431                                 xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
432                         }
433                         #endif /* ipconfigUSE_RMII */
434
435                         hal_eth_init_status = HAL_ETH_Init( &xETH );
436
437                         /* Only for inspection by debugger. */
438                         ( void ) hal_eth_init_status;
439
440                         /* Set the TxDesc and RxDesc pointers. */
441                         xETH.TxDesc = DMATxDscrTab;
442                         xETH.RxDesc = DMARxDscrTab;
443
444                         /* Make sure that all unused fields are cleared. */
445                         memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
446                         memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );
447
448                         /* Initialize Tx Descriptors list: Chain Mode */
449                         DMATxDescToClear = DMATxDscrTab;
450
451                         /* Initialise TX-descriptors. */
452                         prvDMATxDescListInit();
453
454                         /* Initialise RX-descriptors. */
455                         prvDMARxDescListInit();
456
457                         #if( ipconfigUSE_LLMNR != 0 )
458                         {
459                                 /* Program the LLMNR address at index 1. */
460                                 prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );
461                         }
462                         #endif
463
464                         /* Force a negotiation with the Switch or Router and wait for LS. */
465                         prvEthernetUpdateConfig( pdTRUE );
466
467                         /* The deferred interrupt handler task is created at the highest
468                         possible priority to ensure the interrupt handler can return directly
469                         to it.  The task's handle is stored in xEMACTaskHandle so interrupts can
470                         notify the task when there is something to process. */
471                         if( xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ) == pdPASS )
472                         {
473                                 /* The xTXDescriptorSemaphore and the task are created successfully. */
474                                 xMacInitStatus = eMACPass;
475                         }
476                         else
477                         {
478                                 xMacInitStatus = eMACFailed;
479                         }
480                 }
481         } /* if( xEMACTaskHandle == NULL ) */
482
483         if( xMacInitStatus != eMACPass )
484         {
485                 /* EMAC initialisation failed, return pdFAIL. */
486                 xResult = pdFAIL;
487         }
488         else
489         {
490                 if( xPhyObject.ulLinkStatusMask != 0uL )
491                 {
492                         xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
493                         xResult = pdPASS;
494                         FreeRTOS_printf( ( "Link Status is high\n" ) ) ;
495                 }
496                 else
497                 {
498                         /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
499                         and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
500                         xResult = pdFAIL;
501                 }
502         }
503         /* When returning non-zero, the stack will become active and
504     start DHCP (in configured) */
505         return xResult;
506 }
507 /*-----------------------------------------------------------*/
508
509 static void prvDMATxDescListInit()
510 {
511 ETH_DMADescTypeDef *pxDMADescriptor;
512 BaseType_t xIndex;
513
514         /* Get the pointer on the first member of the descriptor list */
515         pxDMADescriptor = DMATxDscrTab;
516
517         /* Fill each DMA descriptor with the right values */
518         for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )
519         {
520                 /* Set Second Address Chained bit */
521                 pxDMADescriptor->Status = ETH_DMATXDESC_TCH;
522
523                 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
524                 {
525                         /* Set Buffer1 address pointer */
526                         pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );
527                 }
528                 #endif
529
530                 if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )
531                 {
532                         /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */
533                         pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
534                 }
535                 else
536                 {
537                         pxDMADescriptor->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL );
538                 }
539
540                 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
541                 if( xIndex < ETH_TXBUFNB - 1 )
542                 {
543                         /* Set next descriptor address register with next descriptor base address */
544                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );
545                 }
546                 else
547                 {
548                         /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
549                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;
550                 }
551         }
552
553         /* Set Transmit Descriptor List Address Register */
554         xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;
555 }
556 /*-----------------------------------------------------------*/
557
558 static void prvDMARxDescListInit()
559 {
560 ETH_DMADescTypeDef *pxDMADescriptor;
561 BaseType_t xIndex;
562         /*
563          * RX-descriptors.
564          */
565
566         /* Get the pointer on the first member of the descriptor list */
567         pxDMADescriptor = DMARxDscrTab;
568
569         /* Fill each DMA descriptor with the right values */
570         for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )
571         {
572
573                 /* Set Buffer1 size and Second Address Chained bit */
574                 pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;  
575
576                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
577                 {
578                 /* Set Buffer1 address pointer */
579                 NetworkBufferDescriptor_t *pxBuffer;
580
581                         pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );
582                         /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'
583                         Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */
584                         configASSERT( pxBuffer != NULL );
585                         if( pxBuffer != NULL )
586                         {
587                                 pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;
588                                 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
589                         }
590                 }
591                 #else
592                 {
593                         /* Set Buffer1 address pointer */
594                         pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );
595                         /* Set Own bit of the Rx descriptor Status */
596                         pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
597                 }
598                 #endif
599
600                 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
601                 if( xIndex < ETH_RXBUFNB - 1 )
602                 {
603                         /* Set next descriptor address register with next descriptor base address */
604                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );
605                 }
606                 else
607                 {
608                         /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
609                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;
610                 }
611
612         }
613         /* Set Receive Descriptor List Address Register */
614         xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;
615 }
616 /*-----------------------------------------------------------*/
617
618 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr)
619 {
620 uint32_t ulTempReg;
621
622         ( void ) heth;
623
624         /* Calculate the selected MAC address high register. */
625         ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
626
627         /* Load the selected MAC address high register. */
628         ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
629
630         /* Calculate the selected MAC address low register. */
631         ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
632
633         /* Load the selected MAC address low register */
634         ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
635 }
636 /*-----------------------------------------------------------*/
637
638 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
639 {
640 BaseType_t xReturn = pdFAIL;
641 uint32_t ulTransmitSize = 0;
642 __IO ETH_DMADescTypeDef *pxDmaTxDesc;
643 /* Do not wait too long for a free TX DMA buffer. */
644 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
645
646         /* Open a do {} while ( 0 ) loop to be able to call break. */
647         do
648         {
649                 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
650                 {
651                 ProtocolPacket_t *pxPacket;
652
653                         /* If the peripheral must calculate the checksum, it wants
654                         the protocol checksum to have a value of zero. */
655                         pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );
656
657                         if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
658                         {
659                                 pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;
660                         }
661                 }
662                 #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */
663                 if( xPhyObject.ulLinkStatusMask != 0 )
664                 {
665                         if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
666                         {
667                                 /* Time-out waiting for a free TX descriptor. */
668                                 break;
669                         }
670
671                         /* This function does the actual transmission of the packet. The packet is
672                         contained in 'pxDescriptor' that is passed to the function. */
673                         pxDmaTxDesc = xETH.TxDesc;
674
675                         /* Is this buffer available? */
676                         configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 );
677
678                         {
679                                 /* Is this buffer available? */
680                                 /* Get bytes in current buffer. */
681                                 ulTransmitSize = pxDescriptor->xDataLength;
682
683                                 if( ulTransmitSize > ETH_TX_BUF_SIZE )
684                                 {
685                                         ulTransmitSize = ETH_TX_BUF_SIZE;
686                                 }
687
688                                 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
689                                 {
690                                         /* Copy the bytes. */
691                                         memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );
692                                 }
693                                 #else
694                                 {
695                                         configASSERT( bReleaseAfterSend != 0 );
696
697                                         /* Move the buffer. */
698                                         pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;
699                                         /* The Network Buffer has been passed to DMA, no need to release it. */
700                                         bReleaseAfterSend = pdFALSE_UNSIGNED;
701                                 }
702                                 #endif /* ipconfigZERO_COPY_TX_DRIVER */
703
704                                 /* Ask to set the IPv4 checksum.
705                                 Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
706                                 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
707                                 {
708                                         pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
709                                 }
710                                 #else
711                                 {
712                                         pxDmaTxDesc->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CIC );
713                                         pxDmaTxDesc->Status |= ETH_DMATXDESC_IC;
714                                 }
715                                 #endif
716                                 
717
718                                 /* Prepare transmit descriptors to give to DMA. */
719
720                                 /* Set LAST and FIRST segment */
721                                 pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;
722                                 /* Set frame size */
723                                 pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );
724
725                                 #if( NETWORK_BUFFERS_CACHED     != 0 )
726                                 {
727                                 BaseType_t xlength = CACHE_LINE_SIZE * ( ( ulTransmitSize + NETWORK_BUFFER_HEADER_SIZE + CACHE_LINE_SIZE - 1 ) / CACHE_LINE_SIZE );
728                                 uint32_t *pulBuffer = ( uint32_t )( pxDescriptor->pucEthernetBuffer - NETWORK_BUFFER_HEADER_SIZE );
729                                         cache_clean_invalidate_by_addr( pulBuffer, xlength );
730                                 }
731                                 #endif
732
733                                 /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
734                                 pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;
735
736                                 /* Point to next descriptor */
737                                 xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );
738                                 /* Ensure completion of memory access */
739                                 __DSB();
740                                 /* Resume DMA transmission*/
741                                 xETH.Instance->DMATPDR = 0;
742                                 iptraceNETWORK_INTERFACE_TRANSMIT();
743                                 xReturn = pdPASS;
744                         }
745                 }
746                 else
747                 {
748                         /* The PHY has no Link Status, packet shall be dropped. */
749                 }
750         } while( 0 );
751         /* The buffer has been sent so can be released. */
752         if( bReleaseAfterSend != pdFALSE )
753         {
754                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
755         }
756
757         return xReturn;
758 }
759 /*-----------------------------------------------------------*/
760
761 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer )
762 {
763 const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;
764
765         switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )
766         {
767         case ipARP_FRAME_TYPE:
768                 /* Check it later. */
769                 return pdTRUE;
770         case ipIPv4_FRAME_TYPE:
771                 /* Check it here. */
772                 break;
773         default:
774                 /* Refuse the packet. */
775                 return pdFALSE;
776         }
777
778         #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
779         {
780                 const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);
781                 uint32_t ulDestinationIPAddress;
782
783                 /* Ensure that the incoming packet is not fragmented (only outgoing packets
784                  * can be fragmented) as these are the only handled IP frames currently. */
785                 if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U )
786                 {
787                         return pdFALSE;
788                 }
789                 /* HT: Might want to make the following configurable because
790                  * most IP messages have a standard length of 20 bytes */
791
792                 /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
793                  * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
794                 if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F )
795                 {
796                         return pdFALSE;
797                 }
798
799                 ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
800                 /* Is the packet for this node? */
801                 if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
802                         /* Is it a broadcast address x.x.x.255 ? */
803                         ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&
804                 #if( ipconfigUSE_LLMNR == 1 )
805                         ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
806                 #endif
807                         ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {
808                         FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );
809                         return pdFALSE;
810                 }
811
812                 if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )
813                 {
814                 uint16_t usSourcePort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort );
815                 uint16_t usDestinationPort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort );
816
817                         if( ( xPortHasUDPSocket( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ) == pdFALSE )
818                         #if ipconfigUSE_LLMNR == 1
819                                 && ( usDestinationPort != ipLLMNR_PORT )
820                                 && ( usSourcePort != ipLLMNR_PORT )
821                         #endif
822                         #if ipconfigUSE_NBNS == 1
823                                 && ( usDestinationPort != ipNBNS_PORT )
824                                 && ( usSourcePort != ipNBNS_PORT )
825                         #endif
826                         #if ipconfigUSE_DNS == 1
827                                 && ( usSourcePort != ipDNS_PORT )
828                         #endif
829                                 ) {
830                                 /* Drop this packet, not for this device. */
831                                 FreeRTOS_printf( ( "Drop: UDP port %d -> %d\n", usSourcePort, usDestinationPort ) );
832                                 return pdFALSE;
833                         }
834                 }
835         }
836         #endif  /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
837         return pdTRUE;
838 }
839 /*-----------------------------------------------------------*/
840
841 static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor )
842 {
843 IPStackEvent_t xRxEvent;
844
845         xRxEvent.eEventType = eNetworkRxEvent;
846         xRxEvent.pvData = ( void * ) pxDescriptor;
847
848         if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
849         {
850                 /* The buffer could not be sent to the stack so must be released again.
851                 This is a deferred handler taskr, not a real interrupt, so it is ok to
852                 use the task level function here. */
853                 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
854                 {
855                         do
856                         {
857                                 NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer;
858                                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
859                                 pxDescriptor = pxNext;
860                         } while( pxDescriptor != NULL );
861                 }
862                 #else
863                 {
864                         vReleaseNetworkBufferAndDescriptor( pxDescriptor );
865                 }
866                 #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */
867                 iptraceETHERNET_RX_EVENT_LOST();
868                 FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) );
869         }
870         else
871         {
872                 iptraceNETWORK_INTERFACE_RECEIVE();
873         }
874 }
875
876 static BaseType_t prvNetworkInterfaceInput( void )
877 {
878 NetworkBufferDescriptor_t *pxCurDescriptor;
879 NetworkBufferDescriptor_t *pxNewDescriptor = NULL;
880 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
881         NetworkBufferDescriptor_t *pxFirstDescriptor = NULL;
882         NetworkBufferDescriptor_t *pxLastDescriptor = NULL;
883 #endif
884 BaseType_t xReceivedLength = 0;
885 __IO ETH_DMADescTypeDef *pxDMARxDescriptor;
886 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( niDESCRIPTOR_WAIT_TIME_MS );
887 uint8_t *pucBuffer;
888
889         pxDMARxDescriptor = xETH.RxDesc;
890
891         while( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0u )
892         {
893         BaseType_t xAccepted = pdTRUE;
894                 /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
895                 xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;
896
897                 pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;
898
899                 /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
900                 /* Chained Mode */    
901                 /* Selects the next DMA Rx descriptor list for next buffer to read */ 
902                 xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;
903
904                 /* In order to make the code easier and faster, only packets in a single buffer
905                 will be accepted.  This can be done by making the buffers large enough to
906                 hold a complete Ethernet packet (1536 bytes).
907                 Therefore, two sanity checks: */
908                 configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE );
909
910                 if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )
911                 {
912                         /* Not an Ethernet frame-type or a checmsum error. */
913                         xAccepted = pdFALSE;
914                 }
915                 else
916                 {
917                         /* See if this packet must be handled. */
918                         xAccepted = xMayAcceptPacket( pucBuffer );
919                 }
920
921                 if( xAccepted != pdFALSE )
922                 {
923                         /* The packet wil be accepted, but check first if a new Network Buffer can
924                         be obtained. If not, the packet will still be dropped. */
925                         pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );
926
927                         if( pxNewDescriptor == NULL )
928                         {
929                                 /* A new descriptor can not be allocated now. This packet will be dropped. */
930                                 xAccepted = pdFALSE;
931                         }
932                 }
933                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
934                 {
935                         /* Find out which Network Buffer was originally passed to the descriptor. */
936                         pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
937                         configASSERT( pxCurDescriptor != NULL );
938                 }
939                 #else
940                 {
941                         /* In this mode, the two descriptors are the same. */
942                         pxCurDescriptor = pxNewDescriptor;
943                         if( pxNewDescriptor != NULL )
944                         {
945                                 /* The packet is acepted and a new Network Buffer was created,
946                                 copy data to the Network Bufffer. */
947                                 memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );
948                         }
949                 }
950                 #endif
951
952                 if( xAccepted != pdFALSE )
953                 {
954                         pxCurDescriptor->xDataLength = xReceivedLength;
955                         #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
956                         {
957                                 pxCurDescriptor->pxNextBuffer = NULL;
958
959                                 if( pxFirstDescriptor == NULL )
960                                 {
961                                         // Becomes the first message
962                                         pxFirstDescriptor = pxCurDescriptor;
963                                 }
964                                 else if( pxLastDescriptor != NULL )
965                                 {
966                                         // Add to the tail
967                                         pxLastDescriptor->pxNextBuffer = pxCurDescriptor;
968                                 }
969
970                                 pxLastDescriptor = pxCurDescriptor;
971                         }
972                         #else
973                         {
974                                 prvPassEthMessages( pxCurDescriptor );
975                         }
976                         #endif
977                 }
978
979                 /* Release descriptors to DMA */
980                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
981                 {
982                         /* Set Buffer1 address pointer */
983                         if( pxNewDescriptor != NULL )
984                         {
985                                 pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;
986                         }
987                         else
988                         {
989                                 /* The packet was dropped and the same Network
990                                 Buffer will be used to receive a new packet. */
991                         }
992                 }
993                 #endif /* ipconfigZERO_COPY_RX_DRIVER */
994
995                 /* Set Buffer1 size and Second Address Chained bit */
996                 pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;  
997                 pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;
998
999                 /* Ensure completion of memory access */
1000                 __DSB();
1001                 /* When Rx Buffer unavailable flag is set clear it and resume
1002                 reception. */
1003                 if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )
1004                 {
1005                         /* Clear RBUS ETHERNET DMA flag. */
1006                         xETH.Instance->DMASR = ETH_DMASR_RBUS;
1007
1008                         /* Resume DMA reception. */
1009                         xETH.Instance->DMARPDR = 0;
1010                 }
1011                 pxDMARxDescriptor = xETH.RxDesc;
1012         }
1013
1014         #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
1015         {
1016                 if( pxFirstDescriptor != NULL )
1017                 {
1018                         prvPassEthMessages( pxFirstDescriptor );
1019                 }
1020         }
1021         #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */
1022
1023         return ( xReceivedLength > 0 );
1024 }
1025 /*-----------------------------------------------------------*/
1026
1027
1028 BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue )
1029 {
1030 uint16_t usPrevAddress = xETH.Init.PhyAddress;
1031 BaseType_t xResult;
1032 HAL_StatusTypeDef xHALResult;
1033
1034         xETH.Init.PhyAddress = xAddress;
1035         xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue );
1036         xETH.Init.PhyAddress = usPrevAddress;
1037
1038         if( xHALResult == HAL_OK )
1039         {
1040                 xResult = 0;
1041         }
1042         else
1043         {
1044                 xResult = -1;
1045         }
1046         return xResult;
1047 }
1048 /*-----------------------------------------------------------*/
1049
1050 BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue )
1051 {
1052 uint16_t usPrevAddress = xETH.Init.PhyAddress;
1053 BaseType_t xResult;
1054 HAL_StatusTypeDef xHALResult;
1055
1056         xETH.Init.PhyAddress = xAddress;
1057         xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue );
1058         xETH.Init.PhyAddress = usPrevAddress;
1059
1060         if( xHALResult == HAL_OK )
1061         {
1062                 xResult = 0;
1063         }
1064         else
1065         {
1066                 xResult = -1;
1067         }
1068         return xResult;
1069 }
1070 /*-----------------------------------------------------------*/
1071
1072 void vMACBProbePhy( void )
1073 {
1074         vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );
1075         xPhyDiscover( &xPhyObject );
1076         xPhyConfigure( &xPhyObject, &xPHYProperties );
1077 }
1078 /*-----------------------------------------------------------*/
1079
1080 static void prvEthernetUpdateConfig( BaseType_t xForce )
1081 {
1082         FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
1083                 xPhyObject.ulLinkStatusMask,
1084                 ( int )xForce ) );
1085
1086         if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
1087         {
1088                 /* Restart the auto-negotiation. */
1089                 if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )
1090                 {
1091                         xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
1092
1093                         /* Configure the MAC with the Duplex Mode fixed by the
1094                         auto-negotiation process. */
1095                         if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
1096                         {
1097                                 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
1098                         }
1099                         else
1100                         {
1101                                 xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
1102                         }
1103
1104                         /* Configure the MAC with the speed fixed by the
1105                         auto-negotiation process. */
1106                         if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
1107                         {
1108                                 xETH.Init.Speed = ETH_SPEED_10M;
1109                         }
1110                         else
1111                         {
1112                                 xETH.Init.Speed = ETH_SPEED_100M;
1113                         }
1114                 }
1115                 else /* AutoNegotiation Disable */
1116                 {
1117                         /* Check parameters */
1118                         assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );
1119                         assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );
1120
1121                         if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX )
1122                         {
1123                                 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;
1124                         }
1125                         else
1126                         {
1127                                 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;
1128                         }
1129
1130                         if( xETH.Init.Speed == ETH_SPEED_10M )
1131                         {
1132                                 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;
1133                         }
1134                         else
1135                         {
1136                                 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;
1137                         }
1138
1139                         xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;
1140
1141                         /* Use predefined (fixed) configuration. */
1142                         xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
1143                 }
1144
1145                 /* ETHERNET MAC Re-Configuration */
1146                 HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);
1147
1148                 /* Restart MAC interface */
1149                 HAL_ETH_Start( &xETH);
1150         }
1151         else
1152         {
1153                 /* Stop MAC interface */
1154                 HAL_ETH_Stop( &xETH );
1155         }
1156 }
1157 /*-----------------------------------------------------------*/
1158
1159 BaseType_t xGetPhyLinkStatus( void )
1160 {
1161 BaseType_t xReturn;
1162
1163         if( xPhyObject.ulLinkStatusMask != 0 )
1164         {
1165                 xReturn = pdPASS;
1166         }
1167         else
1168         {
1169                 xReturn = pdFAIL;
1170         }
1171
1172         return xReturn;
1173 }
1174 /*-----------------------------------------------------------*/
1175
1176 /* Uncomment this in case BufferAllocation_1.c is used. */
1177
1178 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
1179 {
1180 static
1181 #if defined(STM32F7xx)
1182         __attribute__ ((section(".first_data")))
1183 #endif
1184         uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ETH_MAX_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
1185 uint8_t *ucRAMBuffer = ucNetworkPackets;
1186 uint32_t ul;
1187
1188         for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
1189         {
1190                 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
1191                 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
1192                 ucRAMBuffer += ETH_MAX_PACKET_SIZE;
1193         }
1194 }
1195 /*-----------------------------------------------------------*/
1196
1197 static void prvEMACHandlerTask( void *pvParameters )
1198 {
1199 UBaseType_t uxLastMinBufferCount = 0;
1200 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1201 UBaseType_t uxLastMinQueueSpace = 0;
1202 #endif
1203 UBaseType_t uxCurrentCount;
1204 BaseType_t xResult;
1205 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
1206
1207         /* Remove compiler warnings about unused parameters. */
1208         ( void ) pvParameters;
1209
1210         for( ;; )
1211         {
1212                 xResult = 0;
1213                 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
1214                 if( uxLastMinBufferCount != uxCurrentCount )
1215                 {
1216                         /* The logging produced below may be helpful
1217                         while tuning +TCP: see how many buffers are in use. */
1218                         uxLastMinBufferCount = uxCurrentCount;
1219                         FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
1220                                 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
1221                 }
1222
1223                 if( xTXDescriptorSemaphore != NULL )
1224                 {
1225                 static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
1226
1227                         uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
1228                         if( uxLowestSemCount > uxCurrentCount )
1229                         {
1230                                 uxLowestSemCount = uxCurrentCount;
1231                                 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
1232                         }
1233
1234                 }
1235
1236                 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1237                 {
1238                         uxCurrentCount = uxGetMinimumIPQueueSpace();
1239                         if( uxLastMinQueueSpace != uxCurrentCount )
1240                         {
1241                                 /* The logging produced below may be helpful
1242                                 while tuning +TCP: see how many buffers are in use. */
1243                                 uxLastMinQueueSpace = uxCurrentCount;
1244                                 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
1245                         }
1246                 }
1247                 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
1248
1249                 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
1250                 {
1251                         /* No events to process now, wait for the next. */
1252                         ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
1253                 }
1254
1255                 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
1256                 {
1257                         ulISREvents &= ~EMAC_IF_RX_EVENT;
1258
1259                         xResult = prvNetworkInterfaceInput();
1260                 }
1261
1262                 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
1263                 {
1264                         /* Code to release TX buffers if zero-copy is used. */
1265                         ulISREvents &= ~EMAC_IF_TX_EVENT;
1266                         /* Check if DMA packets have been delivered. */
1267                         vClearTXBuffers();
1268                 }
1269
1270                 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
1271                 {
1272                         /* Future extension: logging about errors that occurred. */
1273                         ulISREvents &= ~EMAC_IF_ERR_EVENT;
1274                 }
1275                 if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
1276                 {
1277                         /* Something has changed to a Link Status, need re-check. */
1278                         prvEthernetUpdateConfig( pdFALSE );
1279                 }
1280         }
1281 }
1282 /*-----------------------------------------------------------*/
1283
1284 void ETH_IRQHandler( void )
1285 {
1286         HAL_ETH_IRQHandler( &xETH );
1287 }
1288