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