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