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