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