2 * FreeRTOS+TCP V2.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
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
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
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* Standard includes. */
\r
34 /* FreeRTOS includes. */
\r
35 #include "FreeRTOS.h"
\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
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
51 #include <ethernet_phy.h>
\r
53 #ifndef BMSR_LINK_STATUS
\r
54 #define BMSR_LINK_STATUS 0x0004 //!< Link status
\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
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
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
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
76 #define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
\r
78 #define HZ_PER_MHZ ( 1000000UL )
\r
80 #ifndef EMAC_MAX_BLOCK_TIME_MS
\r
81 #define EMAC_MAX_BLOCK_TIME_MS 100ul
\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
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
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
99 /*-----------------------------------------------------------*/
\r
102 * Wait a fixed time for the link status to indicate the network is up.
\r
104 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
\r
106 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
107 void vGMACGenerateChecksum( uint8_t *apBuffer );
\r
111 * Called from the ASF GMAC driver.
\r
113 static void prvRxCallback( uint32_t ulStatus );
\r
114 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
\r
117 * A deferred interrupt handler task that processes GMAC interrupts.
\r
119 static void prvEMACHandlerTask( void *pvParameters );
\r
122 * Initialise the ASF GMAC driver.
\r
124 static BaseType_t prvGMACInit( void );
\r
127 * Try to obtain an Rx packet from the hardware.
\r
129 static uint32_t prvEMACRxPoll( void );
\r
131 /*-----------------------------------------------------------*/
\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
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
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
147 /* LLMNR multicast address. */
\r
148 static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
150 /* The GMAC object as defined by the ASF drivers. */
\r
151 static gmac_device_t gs_gmac_dev;
\r
153 /* MAC address to use. */
\r
154 extern const uint8_t ucMACAddress[ 6 ];
\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
161 static QueueHandle_t xTxBufferQueue;
\r
162 int tx_release_count[ 4 ];
\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
169 /*-----------------------------------------------------------*/
\r
172 * GMAC interrupt handler.
\r
174 void GMAC_Handler(void)
\r
176 xGMACSwitchRequired = pdFALSE;
\r
178 /* gmac_handler() may call prvRxCallback() which may change
\r
179 the value of xGMACSwitchRequired. */
\r
180 gmac_handler( &gs_gmac_dev );
\r
182 if( xGMACSwitchRequired != pdFALSE )
\r
184 portEND_SWITCHING_ISR( xGMACSwitchRequired );
\r
187 /*-----------------------------------------------------------*/
\r
189 static void prvRxCallback( uint32_t ulStatus )
\r
191 if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
\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
199 /*-----------------------------------------------------------*/
\r
201 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
\r
203 if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
\r
205 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
206 ulISREvents |= EMAC_IF_TX_EVENT;
\r
208 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
209 xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
\r
210 tx_release_count[ 2 ]++;
\r
213 /*-----------------------------------------------------------*/
\r
215 BaseType_t xNetworkInterfaceInitialise( void )
\r
217 const TickType_t x5_Seconds = 5000UL;
\r
219 if( xEMACTaskHandle == NULL )
\r
223 /* Wait at most 5 seconds for a Link Status in the PHY. */
\r
224 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
\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
232 if( xTxBufferQueue == NULL )
\r
234 xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
\r
235 configASSERT( xTxBufferQueue );
\r
238 if( xTXDescriptorSemaphore == NULL )
\r
240 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
\r
241 configASSERT( xTXDescriptorSemaphore );
\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
247 /*-----------------------------------------------------------*/
\r
249 BaseType_t xGetPhyLinkStatus( void )
\r
251 BaseType_t xResult;
\r
253 /* This function returns true if the Link Status in the PHY is high. */
\r
254 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
265 /*-----------------------------------------------------------*/
\r
267 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
\r
269 /* Do not wait too long for a free TX DMA buffer. */
\r
270 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
\r
273 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
275 /* Do not attempt to send packets as long as the Link Status is low. */
\r
278 if( xTXDescriptorSemaphore == NULL )
\r
280 /* Semaphore has not been created yet? */
\r
283 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
285 /* Time-out waiting for a free TX descriptor. */
\r
286 tx_release_count[ 3 ]++;
\r
289 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
291 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
292 configASSERT( bReleaseAfterSend != pdFALSE );
\r
294 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
296 gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
\r
298 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
300 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
301 bReleaseAfterSend = pdFALSE;
\r
303 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
304 /* Not interested in a call-back after TX. */
\r
305 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
308 if( bReleaseAfterSend != pdFALSE )
\r
310 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
\r
314 /*-----------------------------------------------------------*/
\r
316 static BaseType_t prvGMACInit( void )
\r
320 gmac_options_t gmac_option;
\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
327 gs_gmac_dev.p_hw = GMAC;
\r
328 gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
\r
330 NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
331 NVIC_EnableIRQ( GMAC_IRQn );
\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
336 ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
\r
337 ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
\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
344 ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
\r
346 GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
\r
350 /*-----------------------------------------------------------*/
\r
352 static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
\r
354 uint32_t ulValue, ulReturn;
\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
362 ulReturn = ulValue;
\r
371 /*-----------------------------------------------------------*/
\r
373 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
\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
382 xEndTime = xTaskGetTickCount();
\r
384 if( ( xEndTime - xStartTime ) > xMaxTime )
\r
386 /* Wated more than xMaxTime, return. */
\r
391 /* Check the link status again. */
\r
392 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
394 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
396 /* Link is up - return. */
\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
406 FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
\r
409 sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
\r
413 /*-----------------------------------------------------------*/
\r
415 //#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
417 void vGMACGenerateChecksum( uint8_t *apBuffer )
\r
419 ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
\r
421 if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
\r
423 IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
\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
430 /* Calculate the TCP checksum for an outgoing packet. */
\r
431 usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
\r
436 /*-----------------------------------------------------------*/
\r
438 static uint32_t prvEMACRxPoll( void )
\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
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
453 pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
\r
456 if( pxNextNetworkBufferDescriptor != NULL )
\r
458 /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
\r
459 pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
\r
463 /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
\r
464 messages will be flushed and ignored. */
\r
465 pucUseBuffer = NULL;
\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
471 if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
\r
473 /* No data from the hardware. */
\r
477 if( pxNextNetworkBufferDescriptor == NULL )
\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
485 iptraceNETWORK_INTERFACE_RECEIVE();
\r
486 pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
\r
487 xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
\r
489 /* Send the descriptor to the IP task for processing. */
\r
490 if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
\r
492 /* The buffer could not be sent to the stack so must be released
\r
494 vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
\r
495 iptraceETHERNET_RX_EVENT_LOST();
\r
496 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
\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
505 return ulReturnValue;
\r
507 /*-----------------------------------------------------------*/
\r
509 void vCheckBuffersAndQueue( void )
\r
511 static UBaseType_t uxLastMinBufferCount = 0;
\r
512 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
513 static UBaseType_t uxLastMinQueueSpace;
\r
515 static UBaseType_t uxCurrentCount;
\r
517 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
519 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
520 if( uxLastMinQueueSpace != uxCurrentCount )
\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
528 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
529 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
530 if( uxLastMinBufferCount != uxCurrentCount )
\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
541 static void prvEMACHandlerTask( void *pvParameters )
\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
549 uint8_t *pucBuffer;
\r
550 BaseType_t xResult = 0;
\r
552 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
\r
554 /* Remove compiler warnings about unused parameters. */
\r
555 ( void ) pvParameters;
\r
557 configASSERT( xEMACTaskHandle );
\r
559 vTaskSetTimeOutState( &xPhyTime );
\r
560 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
564 vCheckBuffersAndQueue();
\r
566 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
568 /* No events to process now, wait for the next. */
\r
569 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
572 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
574 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
576 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
578 xResult = prvEMACRxPoll();
\r
581 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\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
587 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
589 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
\r
590 if( pxBuffer != NULL )
\r
592 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
593 tx_release_count[ 0 ]++;
\r
597 tx_release_count[ 1 ]++;
\r
602 tx_release_count[ 0 ]++;
\r
605 uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
\r
606 if( uxCount < GMAC_TX_BUFFERS )
\r
608 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
609 xSemaphoreGive( xTXDescriptorSemaphore );
\r
614 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
616 /* Future extension: logging about errors that occurred. */
\r
617 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\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
628 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
\r
630 /* Check the link status again. */
\r
631 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
633 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
635 ulPHYLinkStatus = xStatus;
\r
636 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
639 vTaskSetTimeOutState( &xPhyTime );
\r
640 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
642 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
646 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
651 /*-----------------------------------------------------------*/
\r