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