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