]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
4b549b08435cb8b6a0fbcd42ffb25e4b0f00a5af
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / ATSAM4E / NetworkInterface.c
1 /*\r
2  * FreeRTOS+TCP V2.0.11\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 \r
27 /* Standard includes. */\r
28 #include <stdint.h>\r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 \r
32 /* FreeRTOS includes. */\r
33 #include "FreeRTOS.h"\r
34 #include "task.h"\r
35 #include "queue.h"\r
36 #include "semphr.h"\r
37 \r
38 /* FreeRTOS+TCP includes. */\r
39 #include "FreeRTOS_IP.h"\r
40 #include "FreeRTOS_Sockets.h"\r
41 #include "FreeRTOS_IP_Private.h"\r
42 #include "NetworkBufferManagement.h"\r
43 #include "NetworkInterface.h"\r
44 \r
45 /* Some files from the Atmel Software Framework */\r
46 /*_RB_ The SAM4E portable layer has three different header files called gmac.h! */\r
47 #include "instance/gmac.h"\r
48 #include <sysclk.h>\r
49 #include <ethernet_phy.h>\r
50 \r
51 #ifndef BMSR_LINK_STATUS\r
52         #define BMSR_LINK_STATUS            0x0004  //!< Link status\r
53 #endif\r
54 \r
55 #ifndef PHY_LS_HIGH_CHECK_TIME_MS\r
56         /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not\r
57         receiving packets. */\r
58         #define PHY_LS_HIGH_CHECK_TIME_MS       15000\r
59 #endif\r
60 \r
61 #ifndef PHY_LS_LOW_CHECK_TIME_MS\r
62         /* Check if the LinkSStatus in the PHY is still low every second. */\r
63         #define PHY_LS_LOW_CHECK_TIME_MS        1000\r
64 #endif\r
65 \r
66 /* Interrupt events to process.  Currently only the Rx event is processed\r
67 although code for other events is included to allow for possible future\r
68 expansion. */\r
69 #define EMAC_IF_RX_EVENT        1UL\r
70 #define EMAC_IF_TX_EVENT        2UL\r
71 #define EMAC_IF_ERR_EVENT       4UL\r
72 #define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
73 \r
74 #define ETHERNET_CONF_PHY_ADDR  BOARD_GMAC_PHY_ADDR\r
75 \r
76 #define HZ_PER_MHZ                              ( 1000000UL )\r
77 \r
78 #ifndef EMAC_MAX_BLOCK_TIME_MS\r
79         #define EMAC_MAX_BLOCK_TIME_MS  100ul\r
80 #endif\r
81 \r
82 #if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )\r
83         #error Please define GMAC_USES_TX_CALLBACK as 1\r
84 #endif\r
85 \r
86 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
87         #warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible\r
88 #endif\r
89 \r
90 /* Default the size of the stack used by the EMAC deferred handler task to 4x\r
91 the size of the stack used by the idle task - but allow this to be overridden in\r
92 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */\r
93 #ifndef configEMAC_TASK_STACK_SIZE\r
94         #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )\r
95 #endif\r
96 \r
97 /*-----------------------------------------------------------*/\r
98 \r
99 /*\r
100  * Wait a fixed time for the link status to indicate the network is up.\r
101  */\r
102 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );\r
103 \r
104 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )\r
105         void vGMACGenerateChecksum( uint8_t *apBuffer );\r
106 #endif\r
107 \r
108 /*\r
109  * Called from the ASF GMAC driver.\r
110  */\r
111 static void prvRxCallback( uint32_t ulStatus );\r
112 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );\r
113 \r
114 /*\r
115  * A deferred interrupt handler task that processes GMAC interrupts.\r
116  */\r
117 static void prvEMACHandlerTask( void *pvParameters );\r
118 \r
119 /*\r
120  * Initialise the ASF GMAC driver.\r
121  */\r
122 static BaseType_t prvGMACInit( void );\r
123 \r
124 /*\r
125  * Try to obtain an Rx packet from the hardware.\r
126  */\r
127 static uint32_t prvEMACRxPoll( void );\r
128 \r
129 /*-----------------------------------------------------------*/\r
130 \r
131 /* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
132 the Rx interrupt is handled, although code is included for other events to\r
133 enable future expansion. */\r
134 static volatile uint32_t ulISREvents;\r
135 \r
136 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */\r
137 static uint32_t ulPHYLinkStatus = 0;\r
138 static volatile BaseType_t xGMACSwitchRequired;\r
139 \r
140 /* ethernet_phy_addr: the address of the PHY in use.\r
141 Atmel was a bit ambiguous about it so the address will be stored\r
142 in this variable, see ethernet_phy.c */\r
143 extern int ethernet_phy_addr;\r
144 \r
145 /* LLMNR multicast address. */\r
146 static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };\r
147 \r
148 /* The GMAC object as defined by the ASF drivers. */\r
149 static gmac_device_t gs_gmac_dev;\r
150 \r
151 /* MAC address to use. */\r
152 extern const uint8_t ucMACAddress[ 6 ];\r
153 \r
154 /* Holds the handle of the task used as a deferred interrupt processor.  The\r
155 handle is used so direct notifications can be sent to the task for all EMAC/DMA\r
156 related interrupts. */\r
157 TaskHandle_t xEMACTaskHandle = NULL;\r
158 \r
159 static QueueHandle_t xTxBufferQueue;\r
160 int tx_release_count[ 4 ];\r
161 \r
162 /* xTXDescriptorSemaphore is a counting semaphore with\r
163 a maximum count of GMAC_TX_BUFFERS, which is the number of\r
164 DMA TX descriptors. */\r
165 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
166 \r
167 /*-----------------------------------------------------------*/\r
168 \r
169 /*\r
170  * GMAC interrupt handler.\r
171  */\r
172 void GMAC_Handler(void)\r
173 {\r
174         xGMACSwitchRequired = pdFALSE;\r
175 \r
176         /* gmac_handler() may call prvRxCallback() which may change\r
177         the value of xGMACSwitchRequired. */\r
178         gmac_handler( &gs_gmac_dev );\r
179 \r
180         if( xGMACSwitchRequired != pdFALSE )\r
181         {\r
182                 portEND_SWITCHING_ISR( xGMACSwitchRequired );\r
183         }\r
184 }\r
185 /*-----------------------------------------------------------*/\r
186 \r
187 static void prvRxCallback( uint32_t ulStatus )\r
188 {\r
189         if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )\r
190         {\r
191                 /* let the prvEMACHandlerTask know that there was an RX event. */\r
192                 ulISREvents |= EMAC_IF_RX_EVENT;\r
193                 /* Only an RX interrupt can wakeup prvEMACHandlerTask. */\r
194                 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );\r
195         }\r
196 }\r
197 /*-----------------------------------------------------------*/\r
198 \r
199 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )\r
200 {\r
201         if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )\r
202         {\r
203                 /* let the prvEMACHandlerTask know that there was an RX event. */\r
204                 ulISREvents |= EMAC_IF_TX_EVENT;\r
205 \r
206                 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );\r
207                 xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );\r
208                 tx_release_count[ 2 ]++;\r
209         }\r
210 }\r
211 /*-----------------------------------------------------------*/\r
212 \r
213 BaseType_t xNetworkInterfaceInitialise( void )\r
214 {\r
215 const TickType_t x5_Seconds = 5000UL;\r
216 \r
217         if( xEMACTaskHandle == NULL )\r
218         {\r
219                 prvGMACInit();\r
220 \r
221                 /* Wait at most 5 seconds for a Link Status in the PHY. */\r
222                 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );\r
223 \r
224                 /* The handler task is created at the highest possible priority to\r
225                 ensure the interrupt handler can return directly to it. */\r
226                 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );\r
227                 configASSERT( xEMACTaskHandle );\r
228         }\r
229 \r
230         if( xTxBufferQueue == NULL )\r
231         {\r
232                 xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );\r
233                 configASSERT( xTxBufferQueue );\r
234         }\r
235 \r
236         if( xTXDescriptorSemaphore == NULL )\r
237         {\r
238                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );\r
239                 configASSERT( xTXDescriptorSemaphore );\r
240         }\r
241         /* When returning non-zero, the stack will become active and\r
242         start DHCP (in configured) */\r
243         return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;\r
244 }\r
245 /*-----------------------------------------------------------*/\r
246 \r
247 BaseType_t xGetPhyLinkStatus( void )\r
248 {\r
249 BaseType_t xResult;\r
250 \r
251         /* This function returns true if the Link Status in the PHY is high. */\r
252         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
253         {\r
254                 xResult = pdTRUE;\r
255         }\r
256         else\r
257         {\r
258                 xResult = pdFALSE;\r
259         }\r
260 \r
261         return xResult;\r
262 }\r
263 /*-----------------------------------------------------------*/\r
264 \r
265 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )\r
266 {\r
267 /* Do not wait too long for a free TX DMA buffer. */\r
268 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );\r
269 \r
270         do {\r
271                 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )\r
272                 {\r
273                         /* Do not attempt to send packets as long as the Link Status is low. */\r
274                         break;\r
275                 }\r
276                 if( xTXDescriptorSemaphore == NULL )\r
277                 {\r
278                         /* Semaphore has not been created yet? */\r
279                         break;\r
280                 }\r
281                 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
282                 {\r
283                         /* Time-out waiting for a free TX descriptor. */\r
284                         tx_release_count[ 3 ]++;\r
285                         break;\r
286                 }\r
287                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
288                 {\r
289                         /* Confirm that the pxDescriptor may be kept by the driver. */\r
290                         configASSERT( bReleaseAfterSend != pdFALSE );\r
291                 }\r
292                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
293 \r
294                 gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );\r
295 \r
296                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
297                 {\r
298                         /* Confirm that the pxDescriptor may be kept by the driver. */\r
299                         bReleaseAfterSend = pdFALSE;\r
300                 }\r
301                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
302                 /* Not interested in a call-back after TX. */\r
303                 iptraceNETWORK_INTERFACE_TRANSMIT();\r
304         } while( 0 );\r
305 \r
306         if( bReleaseAfterSend != pdFALSE )\r
307         {\r
308                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
309         }\r
310         return pdTRUE;\r
311 }\r
312 /*-----------------------------------------------------------*/\r
313 \r
314 static BaseType_t prvGMACInit( void )\r
315 {\r
316 uint32_t ncfgr;\r
317 \r
318         gmac_options_t gmac_option;\r
319 \r
320         memset( &gmac_option, '\0', sizeof( gmac_option ) );\r
321         gmac_option.uc_copy_all_frame = 0;\r
322         gmac_option.uc_no_boardcast = 0;\r
323         memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );\r
324 \r
325         gs_gmac_dev.p_hw = GMAC;\r
326         gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );\r
327 \r
328         NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );\r
329         NVIC_EnableIRQ( GMAC_IRQn );\r
330 \r
331         /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */\r
332         ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );\r
333 \r
334         ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );\r
335         ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );\r
336 \r
337         /* The GMAC driver will call a hook prvRxCallback(), which\r
338         in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */\r
339         gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );\r
340         gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );\r
341 \r
342         ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;\r
343 \r
344         GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;\r
345 \r
346         return 1;\r
347 }\r
348 /*-----------------------------------------------------------*/\r
349 \r
350 static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )\r
351 {\r
352 uint32_t ulValue, ulReturn;\r
353 int rc;\r
354 \r
355         gmac_enable_management( GMAC, 1 );\r
356         rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );\r
357         gmac_enable_management( GMAC, 0 );\r
358         if( rc == GMAC_OK )\r
359         {\r
360                 ulReturn = ulValue;\r
361         }\r
362         else\r
363         {\r
364                 ulReturn = 0UL;\r
365         }\r
366 \r
367         return ulReturn;\r
368 }\r
369 /*-----------------------------------------------------------*/\r
370 \r
371 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )\r
372 {\r
373 TickType_t xStartTime = xTaskGetTickCount();\r
374 TickType_t xEndTime;\r
375 BaseType_t xReturn;\r
376 const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );\r
377 \r
378         for( ;; )\r
379         {\r
380                 xEndTime = xTaskGetTickCount();\r
381 \r
382                 if( ( xEndTime - xStartTime ) > xMaxTime )\r
383                 {\r
384                         /* Wated more than xMaxTime, return. */\r
385                         xReturn = pdFALSE;\r
386                         break;\r
387                 }\r
388 \r
389                 /* Check the link status again. */\r
390                 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
391 \r
392                 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
393                 {\r
394                         /* Link is up - return. */\r
395                         xReturn = pdTRUE;\r
396                         break;\r
397                 }\r
398 \r
399                 /* Link is down - wait in the Blocked state for a short while (to allow\r
400                 other tasks to execute) before checking again. */\r
401                 vTaskDelay( xShortTime );\r
402         }\r
403 \r
404         FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",\r
405                 xReturn,\r
406                 ethernet_phy_addr,\r
407                 sysclk_get_cpu_hz() / HZ_PER_MHZ ) );\r
408 \r
409         return xReturn;\r
410 }\r
411 /*-----------------------------------------------------------*/\r
412 \r
413 //#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )\r
414 \r
415         void vGMACGenerateChecksum( uint8_t *apBuffer )\r
416         {\r
417         ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;\r
418 \r
419                 if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )\r
420                 {\r
421                         IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );\r
422 \r
423                         /* Calculate the IP header checksum. */\r
424                         pxIPHeader->usHeaderChecksum = 0x00;\r
425                         pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );\r
426                         pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );\r
427 \r
428                         /* Calculate the TCP checksum for an outgoing packet. */\r
429                         usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );\r
430                 }\r
431         }\r
432 \r
433 //#endif\r
434 /*-----------------------------------------------------------*/\r
435 \r
436 static uint32_t prvEMACRxPoll( void )\r
437 {\r
438 unsigned char *pucUseBuffer;\r
439 uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;\r
440 static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;\r
441 const UBaseType_t xMinDescriptorsToLeave = 2UL;\r
442 const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );\r
443 static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
444 \r
445         for( ;; )\r
446         {\r
447                 /* If pxNextNetworkBufferDescriptor was not left pointing at a valid\r
448                 descriptor then allocate one now. */\r
449                 if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )\r
450                 {\r
451                         pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );\r
452                 }\r
453 \r
454                 if( pxNextNetworkBufferDescriptor != NULL )\r
455                 {\r
456                         /* Point pucUseBuffer to the buffer pointed to by the descriptor. */\r
457                         pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );\r
458                 }\r
459                 else\r
460                 {\r
461                         /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming\r
462                         messages will be flushed and ignored. */\r
463                         pucUseBuffer = NULL;\r
464                 }\r
465 \r
466                 /* Read the next packet from the hardware into pucUseBuffer. */\r
467                 ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );\r
468 \r
469                 if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )\r
470                 {\r
471                         /* No data from the hardware. */\r
472                         break;\r
473                 }\r
474 \r
475                 if( pxNextNetworkBufferDescriptor == NULL )\r
476                 {\r
477                         /* Data was read from the hardware, but no descriptor was available\r
478                         for it, so it will be dropped. */\r
479                         iptraceETHERNET_RX_EVENT_LOST();\r
480                         continue;\r
481                 }\r
482 \r
483                 iptraceNETWORK_INTERFACE_RECEIVE();\r
484                 pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;\r
485                 xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;\r
486 \r
487                 /* Send the descriptor to the IP task for processing. */\r
488                 if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )\r
489                 {\r
490                         /* The buffer could not be sent to the stack so must be released\r
491                         again. */\r
492                         vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );\r
493                         iptraceETHERNET_RX_EVENT_LOST();\r
494                         FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );\r
495                 }\r
496 \r
497                 /* Now the buffer has either been passed to the IP-task,\r
498                 or it has been released in the code above. */\r
499                 pxNextNetworkBufferDescriptor = NULL;\r
500                 ulReturnValue++;\r
501         }\r
502 \r
503         return ulReturnValue;\r
504 }\r
505 /*-----------------------------------------------------------*/\r
506 \r
507 void vCheckBuffersAndQueue( void )\r
508 {\r
509 static UBaseType_t uxLastMinBufferCount = 0;\r
510 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
511         static UBaseType_t uxLastMinQueueSpace;\r
512 #endif\r
513 static UBaseType_t uxCurrentCount;\r
514 \r
515         #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
516         {\r
517                 uxCurrentCount = uxGetMinimumIPQueueSpace();\r
518                 if( uxLastMinQueueSpace != uxCurrentCount )\r
519                 {\r
520                         /* The logging produced below may be helpful\r
521                         while tuning +TCP: see how many buffers are in use. */\r
522                         uxLastMinQueueSpace = uxCurrentCount;\r
523                         FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
524                 }\r
525         }\r
526         #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
527         uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
528         if( uxLastMinBufferCount != uxCurrentCount )\r
529         {\r
530                 /* The logging produced below may be helpful\r
531                 while tuning +TCP: see how many buffers are in use. */\r
532                 uxLastMinBufferCount = uxCurrentCount;\r
533                 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
534                         uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
535         }\r
536 \r
537 }\r
538 \r
539 static void prvEMACHandlerTask( void *pvParameters )\r
540 {\r
541 TimeOut_t xPhyTime;\r
542 TickType_t xPhyRemTime;\r
543 UBaseType_t uxCount;\r
544 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
545         NetworkBufferDescriptor_t *pxBuffer;\r
546 #endif\r
547 uint8_t *pucBuffer;\r
548 BaseType_t xResult = 0;\r
549 uint32_t xStatus;\r
550 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );\r
551 \r
552         /* Remove compiler warnings about unused parameters. */\r
553         ( void ) pvParameters;\r
554 \r
555         configASSERT( xEMACTaskHandle );\r
556 \r
557         vTaskSetTimeOutState( &xPhyTime );\r
558         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
559 \r
560         for( ;; )\r
561         {\r
562                 vCheckBuffersAndQueue();\r
563 \r
564                 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )\r
565                 {\r
566                         /* No events to process now, wait for the next. */\r
567                         ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );\r
568                 }\r
569 \r
570                 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
571                 {\r
572                         ulISREvents &= ~EMAC_IF_RX_EVENT;\r
573 \r
574                         /* Wait for the EMAC interrupt to indicate that another packet has been\r
575                         received. */\r
576                         xResult = prvEMACRxPoll();\r
577                 }\r
578 \r
579                 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
580                 {\r
581                         /* Future extension: code to release TX buffers if zero-copy is used. */\r
582                         ulISREvents &= ~EMAC_IF_TX_EVENT;\r
583                         while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )\r
584                         {\r
585                                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
586                                 {\r
587                                         pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );\r
588                                         if( pxBuffer != NULL )\r
589                                         {\r
590                                                 vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
591                                                 tx_release_count[ 0 ]++;\r
592                                         }\r
593                                         else\r
594                                         {\r
595                                                 tx_release_count[ 1 ]++;\r
596                                         }\r
597                                 }\r
598                                 #else\r
599                                 {\r
600                                         tx_release_count[ 0 ]++;\r
601                                 }\r
602                                 #endif\r
603                                 uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );\r
604                                 if( uxCount < GMAC_TX_BUFFERS )\r
605                                 {\r
606                                         /* Tell the counting semaphore that one more TX descriptor is available. */\r
607                                         xSemaphoreGive( xTXDescriptorSemaphore );\r
608                                 }\r
609                         }\r
610                 }\r
611 \r
612                 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )\r
613                 {\r
614                         /* Future extension: logging about errors that occurred. */\r
615                         ulISREvents &= ~EMAC_IF_ERR_EVENT;\r
616                 }\r
617 \r
618                 if( xResult > 0 )\r
619                 {\r
620                         /* A packet was received. No need to check for the PHY status now,\r
621                         but set a timer to check it later on. */\r
622                         vTaskSetTimeOutState( &xPhyTime );\r
623                         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
624                         xResult = 0;\r
625                 }\r
626                 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )\r
627                 {\r
628                         /* Check the link status again. */\r
629                         xStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
630 \r
631                         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )\r
632                         {\r
633                                 ulPHYLinkStatus = xStatus;\r
634                                 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );\r
635                         }\r
636 \r
637                         vTaskSetTimeOutState( &xPhyTime );\r
638                         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
639                         {\r
640                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
641                         }\r
642                         else\r
643                         {\r
644                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
645                         }\r
646                 }\r
647         }\r
648 }\r
649 /*-----------------------------------------------------------*/\r