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