2 * FreeRTOS+TCP V2.0.1
\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://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* Standard includes. */
\r
33 /* FreeRTOS includes. */
\r
34 #include "FreeRTOS.h"
\r
39 /* FreeRTOS+TCP includes. */
\r
40 #include "FreeRTOS_IP.h"
\r
41 #include "FreeRTOS_Sockets.h"
\r
42 #include "FreeRTOS_IP_Private.h"
\r
43 #include "NetworkBufferManagement.h"
\r
44 #include "NetworkInterface.h"
\r
46 /* Some files from the Atmel Software Framework */
\r
47 /*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
\r
48 #include "instance/gmac.h"
\r
50 #include <ethernet_phy.h>
\r
52 #ifndef BMSR_LINK_STATUS
\r
53 #define BMSR_LINK_STATUS 0x0004 //!< Link status
\r
56 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
\r
57 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
58 receiving packets. */
\r
59 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
\r
62 #ifndef PHY_LS_LOW_CHECK_TIME_MS
\r
63 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
64 #define PHY_LS_LOW_CHECK_TIME_MS 1000
\r
67 /* Interrupt events to process. Currently only the Rx event is processed
\r
68 although code for other events is included to allow for possible future
\r
70 #define EMAC_IF_RX_EVENT 1UL
\r
71 #define EMAC_IF_TX_EVENT 2UL
\r
72 #define EMAC_IF_ERR_EVENT 4UL
\r
73 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
\r
75 #define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
\r
77 #define HZ_PER_MHZ ( 1000000UL )
\r
79 #ifndef EMAC_MAX_BLOCK_TIME_MS
\r
80 #define EMAC_MAX_BLOCK_TIME_MS 100ul
\r
83 #if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
\r
84 #error Please define GMAC_USES_TX_CALLBACK as 1
\r
87 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
88 #warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible
\r
91 /* Default the size of the stack used by the EMAC deferred handler task to 4x
\r
92 the size of the stack used by the idle task - but allow this to be overridden in
\r
93 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
94 #ifndef configEMAC_TASK_STACK_SIZE
\r
95 #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
\r
98 /*-----------------------------------------------------------*/
\r
101 * Wait a fixed time for the link status to indicate the network is up.
\r
103 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
\r
105 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
106 void vGMACGenerateChecksum( uint8_t *apBuffer );
\r
110 * Called from the ASF GMAC driver.
\r
112 static void prvRxCallback( uint32_t ulStatus );
\r
113 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
\r
116 * A deferred interrupt handler task that processes GMAC interrupts.
\r
118 static void prvEMACHandlerTask( void *pvParameters );
\r
121 * Initialise the ASF GMAC driver.
\r
123 static BaseType_t prvGMACInit( void );
\r
126 * Try to obtain an Rx packet from the hardware.
\r
128 static uint32_t prvEMACRxPoll( void );
\r
130 /*-----------------------------------------------------------*/
\r
132 /* Bit map of outstanding ETH interrupt events for processing. Currently only
\r
133 the Rx interrupt is handled, although code is included for other events to
\r
134 enable future expansion. */
\r
135 static volatile uint32_t ulISREvents;
\r
137 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
\r
138 static uint32_t ulPHYLinkStatus = 0;
\r
139 static volatile BaseType_t xGMACSwitchRequired;
\r
141 /* ethernet_phy_addr: the address of the PHY in use.
\r
142 Atmel was a bit ambiguous about it so the address will be stored
\r
143 in this variable, see ethernet_phy.c */
\r
144 extern int ethernet_phy_addr;
\r
146 /* LLMNR multicast address. */
\r
147 static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
149 /* The GMAC object as defined by the ASF drivers. */
\r
150 static gmac_device_t gs_gmac_dev;
\r
152 /* MAC address to use. */
\r
153 extern const uint8_t ucMACAddress[ 6 ];
\r
155 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
156 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
157 related interrupts. */
\r
158 TaskHandle_t xEMACTaskHandle = NULL;
\r
160 static QueueHandle_t xTxBufferQueue;
\r
161 int tx_release_count[ 4 ];
\r
163 /* xTXDescriptorSemaphore is a counting semaphore with
\r
164 a maximum count of GMAC_TX_BUFFERS, which is the number of
\r
165 DMA TX descriptors. */
\r
166 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
168 /*-----------------------------------------------------------*/
\r
171 * GMAC interrupt handler.
\r
173 void GMAC_Handler(void)
\r
175 xGMACSwitchRequired = pdFALSE;
\r
177 /* gmac_handler() may call prvRxCallback() which may change
\r
178 the value of xGMACSwitchRequired. */
\r
179 gmac_handler( &gs_gmac_dev );
\r
181 if( xGMACSwitchRequired != pdFALSE )
\r
183 portEND_SWITCHING_ISR( xGMACSwitchRequired );
\r
186 /*-----------------------------------------------------------*/
\r
188 static void prvRxCallback( uint32_t ulStatus )
\r
190 if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
\r
192 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
193 ulISREvents |= EMAC_IF_RX_EVENT;
\r
194 /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
\r
195 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
198 /*-----------------------------------------------------------*/
\r
200 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
\r
202 if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
\r
204 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
205 ulISREvents |= EMAC_IF_TX_EVENT;
\r
207 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
208 xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
\r
209 tx_release_count[ 2 ]++;
\r
212 /*-----------------------------------------------------------*/
\r
214 BaseType_t xNetworkInterfaceInitialise( void )
\r
216 const TickType_t x5_Seconds = 5000UL;
\r
218 if( xEMACTaskHandle == NULL )
\r
222 /* Wait at most 5 seconds for a Link Status in the PHY. */
\r
223 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
\r
225 /* The handler task is created at the highest possible priority to
\r
226 ensure the interrupt handler can return directly to it. */
\r
227 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
228 configASSERT( xEMACTaskHandle );
\r
231 if( xTxBufferQueue == NULL )
\r
233 xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
\r
234 configASSERT( xTxBufferQueue );
\r
237 if( xTXDescriptorSemaphore == NULL )
\r
239 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
\r
240 configASSERT( xTXDescriptorSemaphore );
\r
242 /* When returning non-zero, the stack will become active and
\r
243 start DHCP (in configured) */
\r
244 return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
\r
246 /*-----------------------------------------------------------*/
\r
248 BaseType_t xGetPhyLinkStatus( void )
\r
250 BaseType_t xResult;
\r
252 /* This function returns true if the Link Status in the PHY is high. */
\r
253 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
264 /*-----------------------------------------------------------*/
\r
266 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
\r
268 /* Do not wait too long for a free TX DMA buffer. */
\r
269 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
\r
272 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
274 /* Do not attempt to send packets as long as the Link Status is low. */
\r
277 if( xTXDescriptorSemaphore == NULL )
\r
279 /* Semaphore has not been created yet? */
\r
282 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
284 /* Time-out waiting for a free TX descriptor. */
\r
285 tx_release_count[ 3 ]++;
\r
288 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
290 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
291 configASSERT( bReleaseAfterSend != pdFALSE );
\r
293 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
295 gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
\r
297 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
299 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
300 bReleaseAfterSend = pdFALSE;
\r
302 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
303 /* Not interested in a call-back after TX. */
\r
304 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
307 if( bReleaseAfterSend != pdFALSE )
\r
309 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
\r
313 /*-----------------------------------------------------------*/
\r
315 static BaseType_t prvGMACInit( void )
\r
319 gmac_options_t gmac_option;
\r
321 memset( &gmac_option, '\0', sizeof( gmac_option ) );
\r
322 gmac_option.uc_copy_all_frame = 0;
\r
323 gmac_option.uc_no_boardcast = 0;
\r
324 memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
\r
326 gs_gmac_dev.p_hw = GMAC;
\r
327 gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
\r
329 NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
330 NVIC_EnableIRQ( GMAC_IRQn );
\r
332 /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
\r
333 ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
\r
335 ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
\r
336 ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
\r
338 /* The GMAC driver will call a hook prvRxCallback(), which
\r
339 in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
\r
340 gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
\r
341 gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
\r
343 ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
\r
345 GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
\r
349 /*-----------------------------------------------------------*/
\r
351 static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
\r
353 uint32_t ulValue, ulReturn;
\r
356 gmac_enable_management( GMAC, 1 );
\r
357 rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
\r
358 gmac_enable_management( GMAC, 0 );
\r
359 if( rc == GMAC_OK )
\r
361 ulReturn = ulValue;
\r
370 /*-----------------------------------------------------------*/
\r
372 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
\r
374 TickType_t xStartTime = xTaskGetTickCount();
\r
375 TickType_t xEndTime;
\r
376 BaseType_t xReturn;
\r
377 const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
\r
381 xEndTime = xTaskGetTickCount();
\r
383 if( ( xEndTime - xStartTime ) > xMaxTime )
\r
385 /* Wated more than xMaxTime, return. */
\r
390 /* Check the link status again. */
\r
391 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
393 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
395 /* Link is up - return. */
\r
400 /* Link is down - wait in the Blocked state for a short while (to allow
\r
401 other tasks to execute) before checking again. */
\r
402 vTaskDelay( xShortTime );
\r
405 FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
\r
408 sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
\r
412 /*-----------------------------------------------------------*/
\r
414 //#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
416 void vGMACGenerateChecksum( uint8_t *apBuffer )
\r
418 ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
\r
420 if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
\r
422 IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
\r
424 /* Calculate the IP header checksum. */
\r
425 pxIPHeader->usHeaderChecksum = 0x00;
\r
426 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
427 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
429 /* Calculate the TCP checksum for an outgoing packet. */
\r
430 usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
\r
435 /*-----------------------------------------------------------*/
\r
437 static uint32_t prvEMACRxPoll( void )
\r
439 unsigned char *pucUseBuffer;
\r
440 uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
\r
441 static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
\r
442 const UBaseType_t xMinDescriptorsToLeave = 2UL;
\r
443 const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
\r
444 static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
448 /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
\r
449 descriptor then allocate one now. */
\r
450 if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
\r
452 pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
\r
455 if( pxNextNetworkBufferDescriptor != NULL )
\r
457 /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
\r
458 pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
\r
462 /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
\r
463 messages will be flushed and ignored. */
\r
464 pucUseBuffer = NULL;
\r
467 /* Read the next packet from the hardware into pucUseBuffer. */
\r
468 ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
\r
470 if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
\r
472 /* No data from the hardware. */
\r
476 if( pxNextNetworkBufferDescriptor == NULL )
\r
478 /* Data was read from the hardware, but no descriptor was available
\r
479 for it, so it will be dropped. */
\r
480 iptraceETHERNET_RX_EVENT_LOST();
\r
484 iptraceNETWORK_INTERFACE_RECEIVE();
\r
485 pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
\r
486 xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
\r
488 /* Send the descriptor to the IP task for processing. */
\r
489 if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
\r
491 /* The buffer could not be sent to the stack so must be released
\r
493 vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
\r
494 iptraceETHERNET_RX_EVENT_LOST();
\r
495 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
\r
498 /* Now the buffer has either been passed to the IP-task,
\r
499 or it has been released in the code above. */
\r
500 pxNextNetworkBufferDescriptor = NULL;
\r
504 return ulReturnValue;
\r
506 /*-----------------------------------------------------------*/
\r
508 void vCheckBuffersAndQueue( void )
\r
510 static UBaseType_t uxLastMinBufferCount = 0;
\r
511 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
512 static UBaseType_t uxLastMinQueueSpace;
\r
514 static UBaseType_t uxCurrentCount;
\r
516 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
518 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
519 if( uxLastMinQueueSpace != uxCurrentCount )
\r
521 /* The logging produced below may be helpful
\r
522 while tuning +TCP: see how many buffers are in use. */
\r
523 uxLastMinQueueSpace = uxCurrentCount;
\r
524 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
527 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
528 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
529 if( uxLastMinBufferCount != uxCurrentCount )
\r
531 /* The logging produced below may be helpful
\r
532 while tuning +TCP: see how many buffers are in use. */
\r
533 uxLastMinBufferCount = uxCurrentCount;
\r
534 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
\r
535 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
\r
540 static void prvEMACHandlerTask( void *pvParameters )
\r
542 TimeOut_t xPhyTime;
\r
543 TickType_t xPhyRemTime;
\r
544 UBaseType_t uxCount;
\r
545 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
546 NetworkBufferDescriptor_t *pxBuffer;
\r
548 uint8_t *pucBuffer;
\r
549 BaseType_t xResult = 0;
\r
551 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
\r
553 /* Remove compiler warnings about unused parameters. */
\r
554 ( void ) pvParameters;
\r
556 configASSERT( xEMACTaskHandle );
\r
558 vTaskSetTimeOutState( &xPhyTime );
\r
559 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
563 vCheckBuffersAndQueue();
\r
565 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
567 /* No events to process now, wait for the next. */
\r
568 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
571 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
573 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
575 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
577 xResult = prvEMACRxPoll();
\r
580 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\r
582 /* Future extension: code to release TX buffers if zero-copy is used. */
\r
583 ulISREvents &= ~EMAC_IF_TX_EVENT;
\r
584 while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
\r
586 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
588 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
\r
589 if( pxBuffer != NULL )
\r
591 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
592 tx_release_count[ 0 ]++;
\r
596 tx_release_count[ 1 ]++;
\r
601 tx_release_count[ 0 ]++;
\r
604 uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
\r
605 if( uxCount < GMAC_TX_BUFFERS )
\r
607 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
608 xSemaphoreGive( xTXDescriptorSemaphore );
\r
613 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
615 /* Future extension: logging about errors that occurred. */
\r
616 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\r
621 /* A packet was received. No need to check for the PHY status now,
\r
622 but set a timer to check it later on. */
\r
623 vTaskSetTimeOutState( &xPhyTime );
\r
624 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
627 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
\r
629 /* Check the link status again. */
\r
630 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
632 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
634 ulPHYLinkStatus = xStatus;
\r
635 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
638 vTaskSetTimeOutState( &xPhyTime );
\r
639 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
641 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
645 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
650 /*-----------------------------------------------------------*/
\r