2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\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
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
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
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\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
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
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
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
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
58 /* Standard includes. */
\r
63 /* FreeRTOS includes. */
\r
64 #include "FreeRTOS.h"
\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
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
80 #include <ethernet_phy.h>
\r
82 #ifndef BMSR_LINK_STATUS
\r
83 #define BMSR_LINK_STATUS 0x0004 //!< Link status
\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
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
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
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
105 #define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
\r
107 #define HZ_PER_MHZ ( 1000000UL )
\r
109 #ifndef EMAC_MAX_BLOCK_TIME_MS
\r
110 #define EMAC_MAX_BLOCK_TIME_MS 100ul
\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
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
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
128 /*-----------------------------------------------------------*/
\r
131 * Wait a fixed time for the link status to indicate the network is up.
\r
133 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
\r
135 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
136 void vGMACGenerateChecksum( uint8_t *apBuffer );
\r
140 * Called from the ASF GMAC driver.
\r
142 static void prvRxCallback( uint32_t ulStatus );
\r
143 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
\r
146 * A deferred interrupt handler task that processes GMAC interrupts.
\r
148 static void prvEMACHandlerTask( void *pvParameters );
\r
151 * Initialise the ASF GMAC driver.
\r
153 static BaseType_t prvGMACInit( void );
\r
156 * Try to obtain an Rx packet from the hardware.
\r
158 static uint32_t prvEMACRxPoll( void );
\r
160 /*-----------------------------------------------------------*/
\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
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
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
176 /* LLMNR multicast address. */
\r
177 static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
179 /* The GMAC object as defined by the ASF drivers. */
\r
180 static gmac_device_t gs_gmac_dev;
\r
182 /* MAC address to use. */
\r
183 extern const uint8_t ucMACAddress[ 6 ];
\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
190 static QueueHandle_t xTxBufferQueue;
\r
191 int tx_release_count[ 4 ];
\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
198 /*-----------------------------------------------------------*/
\r
201 * GMAC interrupt handler.
\r
203 void GMAC_Handler(void)
\r
205 xGMACSwitchRequired = pdFALSE;
\r
207 /* gmac_handler() may call prvRxCallback() which may change
\r
208 the value of xGMACSwitchRequired. */
\r
209 gmac_handler( &gs_gmac_dev );
\r
211 if( xGMACSwitchRequired != pdFALSE )
\r
213 portEND_SWITCHING_ISR( xGMACSwitchRequired );
\r
216 /*-----------------------------------------------------------*/
\r
218 static void prvRxCallback( uint32_t ulStatus )
\r
220 if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
\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
228 /*-----------------------------------------------------------*/
\r
230 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
\r
232 if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
\r
234 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
235 ulISREvents |= EMAC_IF_TX_EVENT;
\r
237 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
238 xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
\r
239 tx_release_count[ 2 ]++;
\r
242 /*-----------------------------------------------------------*/
\r
244 BaseType_t xNetworkInterfaceInitialise( void )
\r
246 const TickType_t x5_Seconds = 5000UL;
\r
248 if( xEMACTaskHandle == NULL )
\r
252 /* Wait at most 5 seconds for a Link Status in the PHY. */
\r
253 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
\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
261 if( xTxBufferQueue == NULL )
\r
263 xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
\r
264 configASSERT( xTxBufferQueue );
\r
267 if( xTXDescriptorSemaphore == NULL )
\r
269 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
\r
270 configASSERT( xTXDescriptorSemaphore );
\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
276 /*-----------------------------------------------------------*/
\r
278 BaseType_t xGetPhyLinkStatus( void )
\r
280 BaseType_t xResult;
\r
282 /* This function returns true if the Link Status in the PHY is high. */
\r
283 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
294 /*-----------------------------------------------------------*/
\r
296 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
\r
298 /* Do not wait too long for a free TX DMA buffer. */
\r
299 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
\r
302 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
304 /* Do not attempt to send packets as long as the Link Status is low. */
\r
307 if( xTXDescriptorSemaphore == NULL )
\r
309 /* Semaphore has not been created yet? */
\r
312 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
314 /* Time-out waiting for a free TX descriptor. */
\r
315 tx_release_count[ 3 ]++;
\r
318 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
320 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
321 configASSERT( bReleaseAfterSend != pdFALSE );
\r
323 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
325 gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
\r
327 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
329 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
330 bReleaseAfterSend = pdFALSE;
\r
332 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
333 /* Not interested in a call-back after TX. */
\r
334 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
337 if( bReleaseAfterSend != pdFALSE )
\r
339 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
\r
343 /*-----------------------------------------------------------*/
\r
345 static BaseType_t prvGMACInit( void )
\r
349 gmac_options_t gmac_option;
\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
356 gs_gmac_dev.p_hw = GMAC;
\r
357 gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
\r
359 NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
360 NVIC_EnableIRQ( GMAC_IRQn );
\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
365 ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
\r
366 ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
\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
373 ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
\r
375 GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
\r
379 /*-----------------------------------------------------------*/
\r
381 static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
\r
383 uint32_t ulValue, ulReturn;
\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
391 ulReturn = ulValue;
\r
400 /*-----------------------------------------------------------*/
\r
402 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
\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
411 xEndTime = xTaskGetTickCount();
\r
413 if( ( xEndTime - xStartTime ) > xMaxTime )
\r
415 /* Wated more than xMaxTime, return. */
\r
420 /* Check the link status again. */
\r
421 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
423 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
425 /* Link is up - return. */
\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
435 FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
\r
438 sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
\r
442 /*-----------------------------------------------------------*/
\r
444 //#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
446 void vGMACGenerateChecksum( uint8_t *apBuffer )
\r
448 ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
\r
450 if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
\r
452 IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
\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
459 /* Calculate the TCP checksum for an outgoing packet. */
\r
460 usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
\r
465 /*-----------------------------------------------------------*/
\r
467 static uint32_t prvEMACRxPoll( void )
\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
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
482 pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
\r
485 if( pxNextNetworkBufferDescriptor != NULL )
\r
487 /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
\r
488 pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
\r
492 /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
\r
493 messages will be flushed and ignored. */
\r
494 pucUseBuffer = NULL;
\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
500 if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
\r
502 /* No data from the hardware. */
\r
506 if( pxNextNetworkBufferDescriptor == NULL )
\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
514 iptraceNETWORK_INTERFACE_RECEIVE();
\r
515 pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
\r
516 xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
\r
518 /* Send the descriptor to the IP task for processing. */
\r
519 if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
\r
521 /* The buffer could not be sent to the stack so must be released
\r
523 vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
\r
524 iptraceETHERNET_RX_EVENT_LOST();
\r
525 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
\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
534 return ulReturnValue;
\r
536 /*-----------------------------------------------------------*/
\r
538 void vCheckBuffersAndQueue( void )
\r
540 static UBaseType_t uxLastMinBufferCount = 0;
\r
541 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
542 static UBaseType_t uxLastMinQueueSpace;
\r
544 static UBaseType_t uxCurrentCount;
\r
546 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
548 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
549 if( uxLastMinQueueSpace != uxCurrentCount )
\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
557 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
558 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
559 if( uxLastMinBufferCount != uxCurrentCount )
\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
570 static void prvEMACHandlerTask( void *pvParameters )
\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
578 uint8_t *pucBuffer;
\r
579 BaseType_t xResult = 0;
\r
581 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
\r
583 /* Remove compiler warnings about unused parameters. */
\r
584 ( void ) pvParameters;
\r
586 configASSERT( xEMACTaskHandle );
\r
588 vTaskSetTimeOutState( &xPhyTime );
\r
589 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
593 vCheckBuffersAndQueue();
\r
595 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
597 /* No events to process now, wait for the next. */
\r
598 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
601 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
603 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
605 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
607 xResult = prvEMACRxPoll();
\r
610 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\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
616 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
618 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
\r
619 if( pxBuffer != NULL )
\r
621 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
622 tx_release_count[ 0 ]++;
\r
626 tx_release_count[ 1 ]++;
\r
631 tx_release_count[ 0 ]++;
\r
634 uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
\r
635 if( uxCount < GMAC_TX_BUFFERS )
\r
637 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
638 xSemaphoreGive( xTXDescriptorSemaphore );
\r
643 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
645 /* Future extension: logging about errors that occurred. */
\r
646 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\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
657 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
\r
659 /* Check the link status again. */
\r
660 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
662 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
664 ulPHYLinkStatus = xStatus;
\r
665 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
668 vTaskSetTimeOutState( &xPhyTime );
\r
669 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
671 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
675 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
680 /*-----------------------------------------------------------*/
\r