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