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