2 * FreeRTOS+TCP V2.0.3
\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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 /* Standard includes. */
\r
32 /* FreeRTOS includes. */
\r
33 #include "FreeRTOS.h"
\r
38 /* FreeRTOS+TCP includes. */
\r
39 #include "FreeRTOS_IP.h"
\r
40 #include "FreeRTOS_Sockets.h"
\r
41 #include "FreeRTOS_IP_Private.h"
\r
42 #include "NetworkBufferManagement.h"
\r
43 #include "NetworkInterface.h"
\r
45 /* Some files from the Atmel Software Framework */
\r
46 /*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
\r
47 #include "instance/gmac.h"
\r
49 #include <ethernet_phy.h>
\r
51 #ifndef BMSR_LINK_STATUS
\r
52 #define BMSR_LINK_STATUS 0x0004 //!< Link status
\r
55 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
\r
56 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
57 receiving packets. */
\r
58 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
\r
61 #ifndef PHY_LS_LOW_CHECK_TIME_MS
\r
62 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
63 #define PHY_LS_LOW_CHECK_TIME_MS 1000
\r
66 /* Interrupt events to process. Currently only the Rx event is processed
\r
67 although code for other events is included to allow for possible future
\r
69 #define EMAC_IF_RX_EVENT 1UL
\r
70 #define EMAC_IF_TX_EVENT 2UL
\r
71 #define EMAC_IF_ERR_EVENT 4UL
\r
72 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
\r
74 #define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
\r
76 #define HZ_PER_MHZ ( 1000000UL )
\r
78 #ifndef EMAC_MAX_BLOCK_TIME_MS
\r
79 #define EMAC_MAX_BLOCK_TIME_MS 100ul
\r
82 #if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
\r
83 #error Please define GMAC_USES_TX_CALLBACK as 1
\r
86 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
87 #warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible
\r
90 /* Default the size of the stack used by the EMAC deferred handler task to 4x
\r
91 the size of the stack used by the idle task - but allow this to be overridden in
\r
92 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
93 #ifndef configEMAC_TASK_STACK_SIZE
\r
94 #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
\r
97 /*-----------------------------------------------------------*/
\r
100 * Wait a fixed time for the link status to indicate the network is up.
\r
102 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
\r
104 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
105 void vGMACGenerateChecksum( uint8_t *apBuffer );
\r
109 * Called from the ASF GMAC driver.
\r
111 static void prvRxCallback( uint32_t ulStatus );
\r
112 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
\r
115 * A deferred interrupt handler task that processes GMAC interrupts.
\r
117 static void prvEMACHandlerTask( void *pvParameters );
\r
120 * Initialise the ASF GMAC driver.
\r
122 static BaseType_t prvGMACInit( void );
\r
125 * Try to obtain an Rx packet from the hardware.
\r
127 static uint32_t prvEMACRxPoll( void );
\r
129 /*-----------------------------------------------------------*/
\r
131 /* Bit map of outstanding ETH interrupt events for processing. Currently only
\r
132 the Rx interrupt is handled, although code is included for other events to
\r
133 enable future expansion. */
\r
134 static volatile uint32_t ulISREvents;
\r
136 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
\r
137 static uint32_t ulPHYLinkStatus = 0;
\r
138 static volatile BaseType_t xGMACSwitchRequired;
\r
140 /* ethernet_phy_addr: the address of the PHY in use.
\r
141 Atmel was a bit ambiguous about it so the address will be stored
\r
142 in this variable, see ethernet_phy.c */
\r
143 extern int ethernet_phy_addr;
\r
145 /* LLMNR multicast address. */
\r
146 static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
148 /* The GMAC object as defined by the ASF drivers. */
\r
149 static gmac_device_t gs_gmac_dev;
\r
151 /* MAC address to use. */
\r
152 extern const uint8_t ucMACAddress[ 6 ];
\r
154 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
155 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
156 related interrupts. */
\r
157 TaskHandle_t xEMACTaskHandle = NULL;
\r
159 static QueueHandle_t xTxBufferQueue;
\r
160 int tx_release_count[ 4 ];
\r
162 /* xTXDescriptorSemaphore is a counting semaphore with
\r
163 a maximum count of GMAC_TX_BUFFERS, which is the number of
\r
164 DMA TX descriptors. */
\r
165 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
167 /*-----------------------------------------------------------*/
\r
170 * GMAC interrupt handler.
\r
172 void GMAC_Handler(void)
\r
174 xGMACSwitchRequired = pdFALSE;
\r
176 /* gmac_handler() may call prvRxCallback() which may change
\r
177 the value of xGMACSwitchRequired. */
\r
178 gmac_handler( &gs_gmac_dev );
\r
180 if( xGMACSwitchRequired != pdFALSE )
\r
182 portEND_SWITCHING_ISR( xGMACSwitchRequired );
\r
185 /*-----------------------------------------------------------*/
\r
187 static void prvRxCallback( uint32_t ulStatus )
\r
189 if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
\r
191 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
192 ulISREvents |= EMAC_IF_RX_EVENT;
\r
193 /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
\r
194 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
197 /*-----------------------------------------------------------*/
\r
199 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
\r
201 if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
\r
203 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
204 ulISREvents |= EMAC_IF_TX_EVENT;
\r
206 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
207 xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
\r
208 tx_release_count[ 2 ]++;
\r
211 /*-----------------------------------------------------------*/
\r
213 BaseType_t xNetworkInterfaceInitialise( void )
\r
215 const TickType_t x5_Seconds = 5000UL;
\r
217 if( xEMACTaskHandle == NULL )
\r
221 /* Wait at most 5 seconds for a Link Status in the PHY. */
\r
222 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
\r
224 /* The handler task is created at the highest possible priority to
\r
225 ensure the interrupt handler can return directly to it. */
\r
226 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
227 configASSERT( xEMACTaskHandle );
\r
230 if( xTxBufferQueue == NULL )
\r
232 xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
\r
233 configASSERT( xTxBufferQueue );
\r
236 if( xTXDescriptorSemaphore == NULL )
\r
238 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
\r
239 configASSERT( xTXDescriptorSemaphore );
\r
241 /* When returning non-zero, the stack will become active and
\r
242 start DHCP (in configured) */
\r
243 return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
\r
245 /*-----------------------------------------------------------*/
\r
247 BaseType_t xGetPhyLinkStatus( void )
\r
249 BaseType_t xResult;
\r
251 /* This function returns true if the Link Status in the PHY is high. */
\r
252 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
263 /*-----------------------------------------------------------*/
\r
265 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
\r
267 /* Do not wait too long for a free TX DMA buffer. */
\r
268 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
\r
271 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
273 /* Do not attempt to send packets as long as the Link Status is low. */
\r
276 if( xTXDescriptorSemaphore == NULL )
\r
278 /* Semaphore has not been created yet? */
\r
281 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
283 /* Time-out waiting for a free TX descriptor. */
\r
284 tx_release_count[ 3 ]++;
\r
287 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
289 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
290 configASSERT( bReleaseAfterSend != pdFALSE );
\r
292 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
294 gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
\r
296 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
298 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
299 bReleaseAfterSend = pdFALSE;
\r
301 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
302 /* Not interested in a call-back after TX. */
\r
303 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
306 if( bReleaseAfterSend != pdFALSE )
\r
308 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
\r
312 /*-----------------------------------------------------------*/
\r
314 static BaseType_t prvGMACInit( void )
\r
318 gmac_options_t gmac_option;
\r
320 memset( &gmac_option, '\0', sizeof( gmac_option ) );
\r
321 gmac_option.uc_copy_all_frame = 0;
\r
322 gmac_option.uc_no_boardcast = 0;
\r
323 memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
\r
325 gs_gmac_dev.p_hw = GMAC;
\r
326 gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
\r
328 NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
329 NVIC_EnableIRQ( GMAC_IRQn );
\r
331 /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
\r
332 ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
\r
334 ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
\r
335 ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
\r
337 /* The GMAC driver will call a hook prvRxCallback(), which
\r
338 in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
\r
339 gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
\r
340 gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
\r
342 ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
\r
344 GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
\r
348 /*-----------------------------------------------------------*/
\r
350 static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
\r
352 uint32_t ulValue, ulReturn;
\r
355 gmac_enable_management( GMAC, 1 );
\r
356 rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
\r
357 gmac_enable_management( GMAC, 0 );
\r
358 if( rc == GMAC_OK )
\r
360 ulReturn = ulValue;
\r
369 /*-----------------------------------------------------------*/
\r
371 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
\r
373 TickType_t xStartTime = xTaskGetTickCount();
\r
374 TickType_t xEndTime;
\r
375 BaseType_t xReturn;
\r
376 const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
\r
380 xEndTime = xTaskGetTickCount();
\r
382 if( ( xEndTime - xStartTime ) > xMaxTime )
\r
384 /* Wated more than xMaxTime, return. */
\r
389 /* Check the link status again. */
\r
390 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
392 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
394 /* Link is up - return. */
\r
399 /* Link is down - wait in the Blocked state for a short while (to allow
\r
400 other tasks to execute) before checking again. */
\r
401 vTaskDelay( xShortTime );
\r
404 FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
\r
407 sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
\r
411 /*-----------------------------------------------------------*/
\r
413 //#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
415 void vGMACGenerateChecksum( uint8_t *apBuffer )
\r
417 ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
\r
419 if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
\r
421 IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
\r
423 /* Calculate the IP header checksum. */
\r
424 pxIPHeader->usHeaderChecksum = 0x00;
\r
425 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
426 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
428 /* Calculate the TCP checksum for an outgoing packet. */
\r
429 usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
\r
434 /*-----------------------------------------------------------*/
\r
436 static uint32_t prvEMACRxPoll( void )
\r
438 unsigned char *pucUseBuffer;
\r
439 uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
\r
440 static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
\r
441 const UBaseType_t xMinDescriptorsToLeave = 2UL;
\r
442 const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
\r
443 static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
447 /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
\r
448 descriptor then allocate one now. */
\r
449 if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
\r
451 pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
\r
454 if( pxNextNetworkBufferDescriptor != NULL )
\r
456 /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
\r
457 pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
\r
461 /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
\r
462 messages will be flushed and ignored. */
\r
463 pucUseBuffer = NULL;
\r
466 /* Read the next packet from the hardware into pucUseBuffer. */
\r
467 ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
\r
469 if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
\r
471 /* No data from the hardware. */
\r
475 if( pxNextNetworkBufferDescriptor == NULL )
\r
477 /* Data was read from the hardware, but no descriptor was available
\r
478 for it, so it will be dropped. */
\r
479 iptraceETHERNET_RX_EVENT_LOST();
\r
483 iptraceNETWORK_INTERFACE_RECEIVE();
\r
484 pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
\r
485 xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
\r
487 /* Send the descriptor to the IP task for processing. */
\r
488 if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
\r
490 /* The buffer could not be sent to the stack so must be released
\r
492 vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
\r
493 iptraceETHERNET_RX_EVENT_LOST();
\r
494 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
\r
497 /* Now the buffer has either been passed to the IP-task,
\r
498 or it has been released in the code above. */
\r
499 pxNextNetworkBufferDescriptor = NULL;
\r
503 return ulReturnValue;
\r
505 /*-----------------------------------------------------------*/
\r
507 void vCheckBuffersAndQueue( void )
\r
509 static UBaseType_t uxLastMinBufferCount = 0;
\r
510 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
511 static UBaseType_t uxLastMinQueueSpace;
\r
513 static UBaseType_t uxCurrentCount;
\r
515 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
517 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
518 if( uxLastMinQueueSpace != uxCurrentCount )
\r
520 /* The logging produced below may be helpful
\r
521 while tuning +TCP: see how many buffers are in use. */
\r
522 uxLastMinQueueSpace = uxCurrentCount;
\r
523 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
526 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
527 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
528 if( uxLastMinBufferCount != uxCurrentCount )
\r
530 /* The logging produced below may be helpful
\r
531 while tuning +TCP: see how many buffers are in use. */
\r
532 uxLastMinBufferCount = uxCurrentCount;
\r
533 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
\r
534 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
\r
539 static void prvEMACHandlerTask( void *pvParameters )
\r
541 TimeOut_t xPhyTime;
\r
542 TickType_t xPhyRemTime;
\r
543 UBaseType_t uxCount;
\r
544 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
545 NetworkBufferDescriptor_t *pxBuffer;
\r
547 uint8_t *pucBuffer;
\r
548 BaseType_t xResult = 0;
\r
550 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
\r
552 /* Remove compiler warnings about unused parameters. */
\r
553 ( void ) pvParameters;
\r
555 configASSERT( xEMACTaskHandle );
\r
557 vTaskSetTimeOutState( &xPhyTime );
\r
558 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
562 vCheckBuffersAndQueue();
\r
564 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
566 /* No events to process now, wait for the next. */
\r
567 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
570 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
572 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
574 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
576 xResult = prvEMACRxPoll();
\r
579 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\r
581 /* Future extension: code to release TX buffers if zero-copy is used. */
\r
582 ulISREvents &= ~EMAC_IF_TX_EVENT;
\r
583 while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
\r
585 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
587 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
\r
588 if( pxBuffer != NULL )
\r
590 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
591 tx_release_count[ 0 ]++;
\r
595 tx_release_count[ 1 ]++;
\r
600 tx_release_count[ 0 ]++;
\r
603 uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
\r
604 if( uxCount < GMAC_TX_BUFFERS )
\r
606 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
607 xSemaphoreGive( xTXDescriptorSemaphore );
\r
612 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
614 /* Future extension: logging about errors that occurred. */
\r
615 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\r
620 /* A packet was received. No need to check for the PHY status now,
\r
621 but set a timer to check it later on. */
\r
622 vTaskSetTimeOutState( &xPhyTime );
\r
623 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
626 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
\r
628 /* Check the link status again. */
\r
629 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
631 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
633 ulPHYLinkStatus = xStatus;
\r
634 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
637 vTaskSetTimeOutState( &xPhyTime );
\r
638 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
640 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
644 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
649 /*-----------------------------------------------------------*/
\r