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
26 /* Standard includes. */
\r
31 /* FreeRTOS includes. */
\r
32 #include "FreeRTOS.h"
\r
37 /* FreeRTOS+TCP includes. */
\r
38 #include "FreeRTOS_IP.h"
\r
39 #include "FreeRTOS_Sockets.h"
\r
40 #include "FreeRTOS_IP_Private.h"
\r
41 #include "NetworkBufferManagement.h"
\r
42 #include "NetworkInterface.h"
\r
44 /* Some files from the Atmel Software Framework */
\r
45 /*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
\r
46 #include "instance/gmac.h"
\r
48 #include <ethernet_phy.h>
\r
50 #ifndef BMSR_LINK_STATUS
\r
51 #define BMSR_LINK_STATUS 0x0004 //!< Link status
\r
54 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
\r
55 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
56 receiving packets. */
\r
57 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
\r
60 #ifndef PHY_LS_LOW_CHECK_TIME_MS
\r
61 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
62 #define PHY_LS_LOW_CHECK_TIME_MS 1000
\r
65 /* Interrupt events to process. Currently only the Rx event is processed
\r
66 although code for other events is included to allow for possible future
\r
68 #define EMAC_IF_RX_EVENT 1UL
\r
69 #define EMAC_IF_TX_EVENT 2UL
\r
70 #define EMAC_IF_ERR_EVENT 4UL
\r
71 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
\r
73 #define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
\r
75 #define HZ_PER_MHZ ( 1000000UL )
\r
77 #ifndef EMAC_MAX_BLOCK_TIME_MS
\r
78 #define EMAC_MAX_BLOCK_TIME_MS 100ul
\r
81 #if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
\r
82 #error Please define GMAC_USES_TX_CALLBACK as 1
\r
85 /* Default the size of the stack used by the EMAC deferred handler task to 4x
\r
86 the size of the stack used by the idle task - but allow this to be overridden in
\r
87 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
88 #ifndef configEMAC_TASK_STACK_SIZE
\r
89 #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
\r
92 /*-----------------------------------------------------------*/
\r
95 * Wait a fixed time for the link status to indicate the network is up.
\r
97 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
\r
99 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
100 void vGMACGenerateChecksum( uint8_t *apBuffer );
\r
104 * Called from the ASF GMAC driver.
\r
106 static void prvRxCallback( uint32_t ulStatus );
\r
107 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
\r
110 * A deferred interrupt handler task that processes GMAC interrupts.
\r
112 static void prvEMACHandlerTask( void *pvParameters );
\r
115 * Initialise the ASF GMAC driver.
\r
117 static BaseType_t prvGMACInit( void );
\r
120 * Try to obtain an Rx packet from the hardware.
\r
122 static uint32_t prvEMACRxPoll( void );
\r
124 /*-----------------------------------------------------------*/
\r
126 /* Bit map of outstanding ETH interrupt events for processing. Currently only
\r
127 the Rx interrupt is handled, although code is included for other events to
\r
128 enable future expansion. */
\r
129 static volatile uint32_t ulISREvents;
\r
131 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
\r
132 static uint32_t ulPHYLinkStatus = 0;
\r
133 static volatile BaseType_t xGMACSwitchRequired;
\r
135 /* ethernet_phy_addr: the address of the PHY in use.
\r
136 Atmel was a bit ambiguous about it so the address will be stored
\r
137 in this variable, see ethernet_phy.c */
\r
138 extern int ethernet_phy_addr;
\r
140 /* LLMNR multicast address. */
\r
141 static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
143 /* The GMAC object as defined by the ASF drivers. */
\r
144 static gmac_device_t gs_gmac_dev;
\r
146 /* MAC address to use. */
\r
147 extern const uint8_t ucMACAddress[ 6 ];
\r
149 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
150 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
151 related interrupts. */
\r
152 TaskHandle_t xEMACTaskHandle = NULL;
\r
154 static QueueHandle_t xTxBufferQueue;
\r
155 int tx_release_count[ 4 ];
\r
157 /* xTXDescriptorSemaphore is a counting semaphore with
\r
158 a maximum count of GMAC_TX_BUFFERS, which is the number of
\r
159 DMA TX descriptors. */
\r
160 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
162 /*-----------------------------------------------------------*/
\r
165 * GMAC interrupt handler.
\r
167 void GMAC_Handler(void)
\r
169 xGMACSwitchRequired = pdFALSE;
\r
171 /* gmac_handler() may call prvRxCallback() which may change
\r
172 the value of xGMACSwitchRequired. */
\r
173 gmac_handler( &gs_gmac_dev );
\r
175 if( xGMACSwitchRequired != pdFALSE )
\r
177 portEND_SWITCHING_ISR( xGMACSwitchRequired );
\r
180 /*-----------------------------------------------------------*/
\r
182 static void prvRxCallback( uint32_t ulStatus )
\r
184 if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
\r
186 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
187 ulISREvents |= EMAC_IF_RX_EVENT;
\r
188 /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
\r
189 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
192 /*-----------------------------------------------------------*/
\r
194 static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
\r
196 if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
\r
198 /* let the prvEMACHandlerTask know that there was an RX event. */
\r
199 ulISREvents |= EMAC_IF_TX_EVENT;
\r
201 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
\r
202 xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
\r
203 tx_release_count[ 2 ]++;
\r
206 /*-----------------------------------------------------------*/
\r
208 BaseType_t xNetworkInterfaceInitialise( void )
\r
210 const TickType_t x5_Seconds = 5000UL;
\r
212 if( xEMACTaskHandle == NULL )
\r
216 /* Wait at most 5 seconds for a Link Status in the PHY. */
\r
217 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
\r
219 /* The handler task is created at the highest possible priority to
\r
220 ensure the interrupt handler can return directly to it. */
\r
221 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
222 configASSERT( xEMACTaskHandle );
\r
225 if( xTxBufferQueue == NULL )
\r
227 xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
\r
228 configASSERT( xTxBufferQueue );
\r
231 if( xTXDescriptorSemaphore == NULL )
\r
233 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
\r
234 configASSERT( xTXDescriptorSemaphore );
\r
236 /* When returning non-zero, the stack will become active and
\r
237 start DHCP (in configured) */
\r
238 return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
\r
240 /*-----------------------------------------------------------*/
\r
242 BaseType_t xGetPhyLinkStatus( void )
\r
244 BaseType_t xResult;
\r
246 /* This function returns true if the Link Status in the PHY is high. */
\r
247 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
258 /*-----------------------------------------------------------*/
\r
260 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
\r
262 /* Do not wait too long for a free TX DMA buffer. */
\r
263 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
\r
266 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
268 /* Do not attempt to send packets as long as the Link Status is low. */
\r
271 if( xTXDescriptorSemaphore == NULL )
\r
273 /* Semaphore has not been created yet? */
\r
276 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
278 /* Time-out waiting for a free TX descriptor. */
\r
279 tx_release_count[ 3 ]++;
\r
282 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
284 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
285 configASSERT( bReleaseAfterSend != pdFALSE );
\r
287 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
289 gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
\r
291 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
293 /* Confirm that the pxDescriptor may be kept by the driver. */
\r
294 bReleaseAfterSend = pdFALSE;
\r
296 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
297 /* Not interested in a call-back after TX. */
\r
298 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
301 if( bReleaseAfterSend != pdFALSE )
\r
303 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
\r
307 /*-----------------------------------------------------------*/
\r
309 static BaseType_t prvGMACInit( void )
\r
313 gmac_options_t gmac_option;
\r
315 memset( &gmac_option, '\0', sizeof( gmac_option ) );
\r
316 gmac_option.uc_copy_all_frame = 0;
\r
317 gmac_option.uc_no_boardcast = 0;
\r
318 memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
\r
320 gs_gmac_dev.p_hw = GMAC;
\r
321 gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
\r
323 NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
324 NVIC_EnableIRQ( GMAC_IRQn );
\r
326 /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
\r
327 ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
\r
329 ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
\r
330 ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
\r
332 /* The GMAC driver will call a hook prvRxCallback(), which
\r
333 in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
\r
334 gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
\r
335 gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
\r
337 ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
\r
339 GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
\r
343 /*-----------------------------------------------------------*/
\r
345 static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
\r
347 uint32_t ulValue, ulReturn;
\r
350 gmac_enable_management( GMAC, 1 );
\r
351 rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
\r
352 gmac_enable_management( GMAC, 0 );
\r
353 if( rc == GMAC_OK )
\r
355 ulReturn = ulValue;
\r
364 /*-----------------------------------------------------------*/
\r
366 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
\r
368 TickType_t xStartTime = xTaskGetTickCount();
\r
369 TickType_t xEndTime;
\r
370 BaseType_t xReturn;
\r
371 const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
\r
375 xEndTime = xTaskGetTickCount();
\r
377 if( ( xEndTime - xStartTime ) > xMaxTime )
\r
379 /* Wated more than xMaxTime, return. */
\r
384 /* Check the link status again. */
\r
385 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
387 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
389 /* Link is up - return. */
\r
394 /* Link is down - wait in the Blocked state for a short while (to allow
\r
395 other tasks to execute) before checking again. */
\r
396 vTaskDelay( xShortTime );
\r
399 FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
\r
402 sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
\r
406 /*-----------------------------------------------------------*/
\r
408 //#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
\r
410 void vGMACGenerateChecksum( uint8_t *apBuffer )
\r
412 ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
\r
414 if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
\r
416 IPHeader_t *pxIPHeader = &(xProtPacket->xTCPPacket.xIPHeader);
\r
418 /* Calculate the IP header checksum. */
\r
419 pxIPHeader->usHeaderChecksum = 0x00;
\r
420 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
421 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
423 /* Calculate the TCP checksum for an outgoing packet. */
\r
424 usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
\r
429 /*-----------------------------------------------------------*/
\r
431 static uint32_t prvEMACRxPoll( void )
\r
433 unsigned char *pucUseBuffer;
\r
434 uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
\r
435 static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
\r
436 const UBaseType_t xMinDescriptorsToLeave = 2UL;
\r
437 const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
\r
438 static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
442 /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
\r
443 descriptor then allocate one now. */
\r
444 if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
\r
446 pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
\r
449 if( pxNextNetworkBufferDescriptor != NULL )
\r
451 /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
\r
452 pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
\r
456 /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
\r
457 messages will be flushed and ignored. */
\r
458 pucUseBuffer = NULL;
\r
461 /* Read the next packet from the hardware into pucUseBuffer. */
\r
462 ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
\r
464 if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
\r
466 /* No data from the hardware. */
\r
470 if( pxNextNetworkBufferDescriptor == NULL )
\r
472 /* Data was read from the hardware, but no descriptor was available
\r
473 for it, so it will be dropped. */
\r
474 iptraceETHERNET_RX_EVENT_LOST();
\r
478 iptraceNETWORK_INTERFACE_RECEIVE();
\r
479 pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
\r
480 xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
\r
482 /* Send the descriptor to the IP task for processing. */
\r
483 if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
\r
485 /* The buffer could not be sent to the stack so must be released
\r
487 vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
\r
488 iptraceETHERNET_RX_EVENT_LOST();
\r
489 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
\r
492 /* Now the buffer has either been passed to the IP-task,
\r
493 or it has been released in the code above. */
\r
494 pxNextNetworkBufferDescriptor = NULL;
\r
498 return ulReturnValue;
\r
500 /*-----------------------------------------------------------*/
\r
502 static void prvEMACHandlerTask( void *pvParameters )
\r
504 TimeOut_t xPhyTime;
\r
505 TickType_t xPhyRemTime;
\r
506 UBaseType_t uxLastMinBufferCount = 0, uxCount;
\r
507 UBaseType_t uxCurrentCount;
\r
508 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
509 UBaseType_t uxLastMinQueueSpace;
\r
511 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
512 NetworkBufferDescriptor_t *pxBuffer;
\r
514 uint8_t *pucBuffer;
\r
515 BaseType_t xResult = 0;
\r
517 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
\r
519 /* Remove compiler warnings about unused parameters. */
\r
520 ( void ) pvParameters;
\r
522 configASSERT( xEMACTaskHandle );
\r
524 vTaskSetTimeOutState( &xPhyTime );
\r
525 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\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
539 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
541 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
542 if( uxLastMinQueueSpace != uxCurrentCount )
\r
544 /* The logging produced below may be helpful
\r
545 while tuning +TCP: see how many buffers are in use. */
\r
546 uxLastMinQueueSpace = uxCurrentCount;
\r
547 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
550 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
552 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
554 /* No events to process now, wait for the next. */
\r
555 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
558 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
560 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
562 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
564 xResult = prvEMACRxPoll();
\r
567 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\r
569 /* Future extension: code to release TX buffers if zero-copy is used. */
\r
570 ulISREvents &= ~EMAC_IF_TX_EVENT;
\r
571 while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
\r
573 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
575 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
\r
576 if( pxBuffer != NULL )
\r
578 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
579 tx_release_count[ 0 ]++;
\r
583 tx_release_count[ 1 ]++;
\r
588 tx_release_count[ 0 ]++;
\r
591 uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
\r
592 if( uxCount < GMAC_TX_BUFFERS )
\r
594 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
595 xSemaphoreGive( xTXDescriptorSemaphore );
\r
600 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
602 /* Future extension: logging about errors that occurred. */
\r
603 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\r
608 /* A packet was received. No need to check for the PHY status now,
\r
609 but set a timer to check it later on. */
\r
610 vTaskSetTimeOutState( &xPhyTime );
\r
611 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
614 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
\r
616 /* Check the link status again. */
\r
617 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
619 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
621 ulPHYLinkStatus = xStatus;
\r
622 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
625 vTaskSetTimeOutState( &xPhyTime );
\r
626 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
628 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
632 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
637 /*-----------------------------------------------------------*/
\r