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