From: richardbarry Date: Sun, 17 Nov 2013 14:09:17 +0000 (+0000) Subject: Add basic SAM4E driver. X-Git-Tag: V7.6.0~7 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=8f6cf54e29775f4a84c611e3f74a59c479d52b3a;p=freertos Add basic SAM4E driver. Add ipconfigETHERNET_DRIVER_ADDS_UDP_CHECKSUM, ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM, ipconfigETHERNET_DRIVER_CHECKS_IP_CHECKSUM and ipconfigETHERNET_DRIVER_CHECKS_UDP_CHECKSUM definitions. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2100 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/FreeRTOS_UDP_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/FreeRTOS_UDP_IP.c index f85b96cbb..0388026df 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/FreeRTOS_UDP_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/FreeRTOS_UDP_IP.c @@ -220,7 +220,7 @@ static void prvReturnEthernetFrame( xNetworkBufferDescriptor_t * const pxNetwork /* * Return the checksum generated over usDataLengthBytes from pucNextData. */ -static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes ); +static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes, portBASE_TYPE xChecksumIsOffloaded ); /* * The callback function that is assigned to all periodic processing timers - @@ -246,7 +246,7 @@ static void prvRefreshARPCacheEntry( const xMACAddress_t * const pxMACAddress, c * Creates the pseudo header necessary then generate the checksum over the UDP * packet. Returns the calculated checksum. */ -static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket ); +static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket, portBASE_TYPE xChecksumIsOffloaded ); /* * Look for ulIPAddress in the ARP cache. If the IP address exists, copy the @@ -665,7 +665,7 @@ void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetM memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend ); /* The message is complete, calculate the checksum. */ - pxICMPHeader->usChecksum = prvGenerateChecksum( ( uint8_t * ) pxICMPHeader, ( uint16_t ) ( xNumberOfBytesToSend + sizeof( xICMPHeader_t ) ) ); + pxICMPHeader->usChecksum = prvGenerateChecksum( ( uint8_t * ) pxICMPHeader, ( uint16_t ) ( xNumberOfBytesToSend + sizeof( xICMPHeader_t ) ), pdFALSE ); /* Complete the network buffer information. */ pxNetworkBuffer->ulIPAddress = ulIPAddress; @@ -985,7 +985,7 @@ xUDPHeader_t *pxUDPHeader; if( ( ucSocketOptions & FREERTOS_SO_UDPCKSUM_OUT ) != 0U ) { - pxUDPHeader->usChecksum = prvGenerateUDPChecksum( pxUDPPacket ); + pxUDPHeader->usChecksum = prvGenerateUDPChecksum( pxUDPPacket, ipconfigETHERNET_DRIVER_ADDS_UDP_CHECKSUM ); if( pxUDPHeader->usChecksum == 0x00 ) { /* A calculated checksum of 0 must be inverted as 0 means the @@ -1117,7 +1117,7 @@ xUDPHeader_t *pxUDPHeader; pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength ); pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress; pxIPHeader->usIdentification = usPacketIdentifier; - pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH ); + pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH, ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM ); } else if ( eReturned == eARPCacheMiss ) { @@ -1234,7 +1234,7 @@ xUDPHeader_t *pxUDPHeader; pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( xEthernetHeader_t ); pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength ); pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress; - pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH ); + pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH, ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM ); } else if ( eReturned == eARPCacheMiss ) { @@ -1493,7 +1493,7 @@ portBASE_TYPE xChecksumIsCorrect; if( ( pxIPHeader->ucVersionHeaderLength == ipIP_VERSION_AND_HEADER_LENGTH_BYTE ) && ( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) == 0U ) ) { /* Is the IP header checksum correct? */ - if( prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH ) == 0 ) + if( prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH, ipconfigETHERNET_DRIVER_CHECKS_IP_CHECKSUM ) == 0 ) { /* Add the IP and MAC addresses to the ARP table if they are not already there - otherwise refresh the age of the existing @@ -1535,7 +1535,7 @@ portBASE_TYPE xChecksumIsCorrect; { xChecksumIsCorrect = pdTRUE; } - else if( prvGenerateUDPChecksum( pxUDPPacket ) == 0 ) + else if( prvGenerateUDPChecksum( pxUDPPacket, ipconfigETHERNET_DRIVER_CHECKS_UDP_CHECKSUM ) == 0 ) { xChecksumIsCorrect = pdTRUE; } @@ -1569,26 +1569,36 @@ portBASE_TYPE xChecksumIsCorrect; } /*-----------------------------------------------------------*/ -static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket ) +static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket, portBASE_TYPE xChecksumIsOffloaded ) { xPseudoHeader_t *pxPseudoHeader; uint16_t usLength, usReturn; - /* Map the pseudo header into the correct place within the real IP - header. */ - pxPseudoHeader = ( xPseudoHeader_t * ) &( pxUDPPacket->xIPHeader.ucTimeToLive ); - - /* Ordering here is important so as not to overwrite data that is required - but has not yet been used as the pseudo header overlaps the information - that is being copied into it. */ - pxPseudoHeader->ulSourceAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress; - pxPseudoHeader->ulDestinationAddress = pxUDPPacket->xIPHeader.ulDestinationIPAddress; - pxPseudoHeader->ucZeros = 0x00; - pxPseudoHeader->ucProtocol = ipPROTOCOL_UDP; - pxPseudoHeader->usUDPLength = pxUDPPacket->xUDPHeader.usLength; - - usLength = FreeRTOS_ntohs( pxPseudoHeader->usUDPLength ); - usReturn = prvGenerateChecksum( ( uint8_t * ) pxPseudoHeader, usLength + sizeof( xPseudoHeader_t ) ); + if( xChecksumIsOffloaded == pdFALSE ) + { + /* Map the pseudo header into the correct place within the real IP + header. */ + pxPseudoHeader = ( xPseudoHeader_t * ) &( pxUDPPacket->xIPHeader.ucTimeToLive ); + + /* Ordering here is important so as not to overwrite data that is required + but has not yet been used as the pseudo header overlaps the information + that is being copied into it. */ + pxPseudoHeader->ulSourceAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress; + pxPseudoHeader->ulDestinationAddress = pxUDPPacket->xIPHeader.ulDestinationIPAddress; + pxPseudoHeader->ucZeros = 0x00; + pxPseudoHeader->ucProtocol = ipPROTOCOL_UDP; + pxPseudoHeader->usUDPLength = pxUDPPacket->xUDPHeader.usLength; + + usLength = FreeRTOS_ntohs( pxPseudoHeader->usUDPLength ); + usReturn = prvGenerateChecksum( ( uint8_t * ) pxPseudoHeader, usLength + sizeof( xPseudoHeader_t ), pdFALSE ); + } + else + { + /* The hardware will check the checksum. Returning 0 allows this + function to be used to both check an incoming checksum and set an + outgoing checksum in this case. */ + usReturn = 0; + } return usReturn; } @@ -1610,7 +1620,7 @@ uint16_t usLength, usReturn; message itself. */ usDataLength -= sizeof( xIPHeader_t ); - if( prvGenerateChecksum( ( uint8_t * ) &( pxICMPPacket->xICMPHeader ), usDataLength ) != 0 ) + if( prvGenerateChecksum( ( uint8_t * ) &( pxICMPPacket->xICMPHeader ), usDataLength, pdFALSE ) != 0 ) { eStatus = eInvalidChecksum; } @@ -1717,42 +1727,53 @@ uint16_t usLength, usReturn; #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ /*-----------------------------------------------------------*/ -static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes ) +static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes, portBASE_TYPE xChecksumIsOffloaded ) { uint32_t ulChecksum = 0; -uint16_t us, usDataLength16BitWords, *pusNextData; +uint16_t us, usDataLength16BitWords, *pusNextData, usReturn; - /* There are half as many 16 bit words than bytes. */ - usDataLength16BitWords = ( usDataLengthBytes >> 1U ); + if( xChecksumIsOffloaded == pdFALSE ) + { + /* There are half as many 16 bit words than bytes. */ + usDataLength16BitWords = ( usDataLengthBytes >> 1U ); - pusNextData = ( uint16_t * ) pucNextData; + pusNextData = ( uint16_t * ) pucNextData; - for( us = 0U; us < usDataLength16BitWords; us++ ) - { - ulChecksum += ( uint32_t ) pusNextData[ us ]; - } + for( us = 0U; us < usDataLength16BitWords; us++ ) + { + ulChecksum += ( uint32_t ) pusNextData[ us ]; + } - if( ( usDataLengthBytes & 0x01U ) != 0x00 ) - { - /* There is one byte left over. */ - #if ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN + if( ( usDataLengthBytes & 0x01U ) != 0x00 ) { - ulChecksum += ( uint32_t ) pucNextData[ usDataLengthBytes - 1 ]; + /* There is one byte left over. */ + #if ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN + { + ulChecksum += ( uint32_t ) pucNextData[ usDataLengthBytes - 1 ]; + } + #else + { + us = ( uint16_t ) pucNextData[ usDataLengthBytes - 1 ]; + ulChecksum += ( uint32_t ) ( us << 8 ); + } + #endif } - #else + + while( ( ulChecksum >> 16UL ) != 0x00UL ) { - us = ( uint16_t ) pucNextData[ usDataLengthBytes - 1 ]; - ulChecksum += ( uint32_t ) ( us << 8 ); + ulChecksum = ( ulChecksum & 0xffffUL ) + ( ulChecksum >> 16UL ); } - #endif + + usReturn = ~( ( uint16_t ) ulChecksum ); } - - while( ( ulChecksum >> 16UL ) != 0x00UL ) + else { - ulChecksum = ( ulChecksum & 0xffffUL ) + ( ulChecksum >> 16UL ); + /* The checksum is calculated by the hardware. Return 0 here to ensure + this works for both incoming and outgoing checksums. */ + usReturn = 0; } - return ~( ( uint16_t ) ulChecksum ); + return usReturn; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/History.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/History.txt index 33f9d9f47..4cd0588a2 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/History.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/History.txt @@ -3,6 +3,13 @@ Changes between V1.0.1 and V1.0.2 + Increase the size of the critical section in the function that obtains a private port number. + Add defaults for more trace macros. + + Update network interfaces so all compile with latest code revision. + + Added the following definitions for improved performance on hardware that + has the ability to offload checksum generation and/or checking: + ipconfigETHERNET_DRIVER_ADDS_UDP_CHECKSUM + ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM + ipconfigETHERNET_DRIVER_CHECKS_IP_CHECKSUM + ipconfigETHERNET_DRIVER_CHECKS_UDP_CHECKSUM Changes between V1.0.0 and V1.0.1 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOSIPConfigDefaults.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOSIPConfigDefaults.h index e6411c578..e4d435495 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOSIPConfigDefaults.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOSIPConfigDefaults.h @@ -5,11 +5,11 @@ * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license * terms are different to the FreeRTOS license terms. * - * FreeRTOS+UDP uses a dual license model that allows the software to be used - * under a standard GPL open source license, or a commercial license. The - * standard GPL license (unlike the modified GPL license under which FreeRTOS - * itself is distributed) requires that all software statically linked with - * FreeRTOS+UDP is also distributed under the same GPL V2 license terms. + * FreeRTOS+UDP uses a dual license model that allows the software to be used + * under a standard GPL open source license, or a commercial license. The + * standard GPL license (unlike the modified GPL license under which FreeRTOS + * itself is distributed) requires that all software statically linked with + * FreeRTOS+UDP is also distributed under the same GPL V2 license terms. * Details of both license options follow: * * - Open source licensing - @@ -21,9 +21,9 @@ * * - Commercial licensing - * Businesses and individuals that for commercial or other reasons cannot comply - * with the terms of the GPL V2 license must obtain a commercial license before - * incorporating FreeRTOS+UDP into proprietary software for distribution in any - * form. Commercial licenses can be purchased from http://shop.freertos.org/udp + * with the terms of the GPL V2 license must obtain a commercial license before + * incorporating FreeRTOS+UDP into proprietary software for distribution in any + * form. Commercial licenses can be purchased from http://shop.freertos.org/udp * and do not require any source files to be changed. * * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot @@ -151,5 +151,21 @@ from the FreeRTOSIPConfig.h configuration header file. */ #ifndef ipconfigSUPPORT_SELECT_FUNCTION #define ipconfigSUPPORT_SELECT_FUNCTION 0 #endif + +#ifndef ipconfigETHERNET_DRIVER_ADDS_UDP_CHECKSUM + #define ipconfigETHERNET_DRIVER_ADDS_UDP_CHECKSUM 0 +#endif + +#ifndef ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM + #define ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM 0 +#endif + +#ifndef ipconfigETHERNET_DRIVER_CHECKS_IP_CHECKSUM + #define ipconfigETHERNET_DRIVER_CHECKS_IP_CHECKSUM 0 +#endif + +#ifndef ipconfigETHERNET_DRIVER_CHECKS_UDP_CHECKSUM + #define ipconfigETHERNET_DRIVER_CHECKS_UDP_CHECKSUM 0 +#endif #endif /* FREERTOS_DEFAULT_IP_CONFIG_H */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOS_Sockets.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOS_Sockets.h index 3cc00c192..d1043302d 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOS_Sockets.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/include/FreeRTOS_Sockets.h @@ -114,10 +114,10 @@ struct freertos_sockaddr #define FreeRTOS_inet_ntoa( ulIPAddress, pucBuffer ) \ sprintf( ( char * ) ( pucBuffer ), "%d.%d.%d.%d", \ - ( ( ulIPAddress ) & 0xffUL ), \ - ( ( ( ulIPAddress ) >> 8UL ) & 0xffUL ), \ - ( ( ( ulIPAddress ) >> 16UL ) & 0xffUL ), \ - ( ( ( ulIPAddress ) >> 24UL ) & 0xffUL ) ) + ( int ) ( ( ulIPAddress ) & 0xffUL ), \ + ( int ) ( ( ( ulIPAddress ) >> 8UL ) & 0xffUL ),\ + ( int ) ( ( ( ulIPAddress ) >> 16UL ) & 0xffUL ),\ + ( int ) ( ( ( ulIPAddress ) >> 24UL ) & 0xffUL ) ) #else /* ipconfigBYTE_ORDER */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/NetworkInterface/SAM4E/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/NetworkInterface/SAM4E/NetworkInterface.c new file mode 100644 index 000000000..3da074ab2 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/NetworkInterface/SAM4E/NetworkInterface.c @@ -0,0 +1,296 @@ +/* + * FreeRTOS+UDP V1.0.2 (C) 2013 Real Time Engineers ltd. + * All rights reserved + * + * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license + * terms are different to the FreeRTOS license terms. + * + * FreeRTOS+UDP uses a dual license model that allows the software to be used + * under a pure GPL open source license (as opposed to the modified GPL license + * under which FreeRTOS is distributed) or a commercial license. Details of + * both license options follow: + * + * - Open source licensing - + * FreeRTOS+UDP is a free download and may be used, modified, evaluated and + * distributed without charge provided the user adheres to version two of the + * GNU General Public License (GPL) and does not remove the copyright notice or + * this text. The GPL V2 text is available on the gnu.org web site, and on the + * following URL: http://www.FreeRTOS.org/gpl-2.0.txt. + * + * - Commercial licensing - + * Businesses and individuals that for commercial or other reasons cannot comply + * with the terms of the GPL V2 license must obtain a commercial license before + * incorporating FreeRTOS+UDP into proprietary software for distribution in any + * form. Commercial licenses can be purchased from http://shop.freertos.org/udp + * and do not require any source files to be changed. + * + * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot + * use FreeRTOS+UDP unless you agree that you use the software 'as is'. + * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied + * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they + * implied, expressed, or statutory. + * + * 1 tab == 4 spaces! + * + * http://www.FreeRTOS.org + * http://www.FreeRTOS.org/udp + * + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+UDP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_Sockets.h" +#include "NetworkBufferManagement.h" + +/* Demo includes. */ +#include "NetworkInterface.h" + +/* If a packet cannot be sent immediately then the task performing the send +operation will be held in the Blocked state (so other tasks can execute) for +niTX_BUFFER_FREE_WAIT ticks. It will do this a maximum of niMAX_TX_ATTEMPTS +before giving up. */ +#define niTX_BUFFER_FREE_WAIT ( ( portTickType ) 2UL / portTICK_RATE_MS ) +#define niMAX_TX_ATTEMPTS ( 5 ) + +/*-----------------------------------------------------------*/ + +/* + * A deferred interrupt handler task that processes received frames. + */ +static void prvGMACDeferredInterruptHandlerTask( void *pvParameters ); + +/* + * Called by the ASF GMAC driver when a packet is received. + */ +static void prvGMACRxCallback( uint32_t ulStatus ); + +/*-----------------------------------------------------------*/ + +/* The queue used to communicate Ethernet events to the IP task. */ +extern xQueueHandle xNetworkEventQueue; + +/* The semaphore used to wake the deferred interrupt handler task when an Rx +interrupt is received. */ +static xSemaphoreHandle xGMACRxEventSemaphore = NULL; + +/* The GMAC driver instance. */ +static gmac_device_t xGMACStruct; + +/*-----------------------------------------------------------*/ + +portBASE_TYPE xNetworkInterfaceInitialise( void ) +{ +gmac_options_t xGMACOptions; +extern uint8_t ucMACAddress[ 6 ]; +const portTickType xPHYDelay_400ms = 400UL; +portBASE_TYPE xReturn = pdFALSE; + + /* Ensure PHY is ready. */ + vTaskDelay( xPHYDelay_400ms / portTICK_RATE_MS ); + + /* Enable GMAC clock. */ + pmc_enable_periph_clk( ID_GMAC ); + + /* Fill in GMAC options */ + xGMACOptions.uc_copy_all_frame = 0; + xGMACOptions.uc_no_boardcast = 0; + memcpy( xGMACOptions.uc_mac_addr, ucMACAddress, sizeof( ucMACAddress ) ); + + xGMACStruct.p_hw = GMAC; + + /* Init GMAC driver structure. */ + gmac_dev_init( GMAC, &xGMACStruct, &xGMACOptions ); + + /* Init MAC PHY driver. */ + if( ethernet_phy_init( GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz() ) == GMAC_OK ) + { + /* Auto Negotiate, work in RMII mode. */ + if( ethernet_phy_auto_negotiate( GMAC, BOARD_GMAC_PHY_ADDR ) == GMAC_OK ) + { + /* Establish Ethernet link. */ + vTaskDelay( xPHYDelay_400ms * 2UL ); + if( ethernet_phy_set_link( GMAC, BOARD_GMAC_PHY_ADDR, 1 ) == GMAC_OK ) + { + /* Create the event semaphore if it has not already been + created. */ + if( xGMACRxEventSemaphore == NULL ) + { + vSemaphoreCreateBinary( xGMACRxEventSemaphore ); + #if ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 + { + /* If the trace recorder code is included name the semaphore for + viewing in FreeRTOS+Trace. */ + vTraceSetQueueName( xGMACRxEventSemaphore, "MAC_RX" ); + } + #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */ + } + + /* Register the callbacks. */ + gmac_dev_set_rx_callback( &xGMACStruct, prvGMACRxCallback ); + + /* The Rx deferred interrupt handler task is created at the + highest possible priority to ensure the interrupt handler can + return directly to it no matter which task was running when the + interrupt occurred. */ + xTaskCreate( prvGMACDeferredInterruptHandlerTask,/* The function that implements the task. */ + ( const signed char * const ) "MACTsk", + configMINIMAL_STACK_SIZE, /* Stack allocated to the task (defined in words, not bytes). */ + NULL, /* The task parameter is not used. */ + configMAX_PRIORITIES - 1, /* The priority assigned to the task. */ + NULL ); /* The handle is not required, so NULL is passed. */ + + /* Enable the interrupt and set its priority as configured. + THIS DRIVER REQUIRES configMAC_INTERRUPT_PRIORITY TO BE DEFINED, + PREFERABLY IN FreeRTOSConfig.h. */ + NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY ); + NVIC_EnableIRQ( GMAC_IRQn ); + xReturn = pdPASS; + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvGMACRxCallback( uint32_t ulStatus ) +{ +portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + + /* Unblock the deferred interrupt handler task if the event was an Rx. */ + if( ulStatus != 0 ) + { + xSemaphoreGiveFromISR( xGMACRxEventSemaphore, &xHigherPriorityTaskWoken ); + } + + portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +portBASE_TYPE xReturn = pdFAIL; +int32_t x; + + /* Attempt to obtain access to a Tx descriptor. */ + for( x = 0; x < niMAX_TX_ATTEMPTS; x++ ) + { + if( gmac_dev_write( &xGMACStruct, pxNetworkBuffer->pucEthernetBuffer, ( uint32_t ) pxNetworkBuffer->xDataLength, NULL ) == GMAC_OK ) + { + /* The Tx has been initiated. */ + xReturn = pdPASS; + break; + } + else + { + iptraceWAITING_FOR_TX_DMA_DESCRIPTOR(); + vTaskDelay( niTX_BUFFER_FREE_WAIT ); + } + } + + /* Finished with the network buffer. */ + vNetworkBufferRelease( pxNetworkBuffer ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void GMAC_Handler( void ) +{ + gmac_handler( &xGMACStruct ); +} +/*-----------------------------------------------------------*/ + +static void prvGMACDeferredInterruptHandlerTask( void *pvParameters ) +{ +xNetworkBufferDescriptor_t *pxNetworkBuffer; +xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL }; + + ( void ) pvParameters; + configASSERT( xGMACRxEventSemaphore ); + + for( ;; ) + { + /* Wait for the GMAC interrupt to indicate that another packet has been + received. The while() loop is only needed if INCLUDE_vTaskSuspend is + set to 0 in FreeRTOSConfig.h. If INCLUDE_vTaskSuspend is set to 1 + then portMAX_DELAY would be an indefinite block time and + xSemaphoreTake() would only return when the semaphore was actually + obtained. */ + while( xSemaphoreTake( xGMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE ); + + /* The buffer filled by the DMA is going to be passed into the IP + stack. Allocate another buffer for the DMA descriptor. */ + pxNetworkBuffer = pxNetworkBufferGet( ipTOTAL_ETHERNET_FRAME_SIZE, portMAX_DELAY ); + + if( pxNetworkBuffer != NULL ) + { + /* At least one packet has been received. */ + if( gmac_dev_read( &xGMACStruct, pxNetworkBuffer->pucEthernetBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, ( uint32_t * ) &( pxNetworkBuffer->xDataLength ) ) == GMAC_OK ) + { + #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 1 + { + if( pxNetworkBuffer->xDataLength > 0 ) + { + /* If the frame would not be processed by the IP stack then + don't even bother sending it to the IP stack. */ + if( eConsiderFrameForProcessing( pxNetworkBuffer->pucEthernetBuffer ) != eProcessBuffer ) + { + pxNetworkBuffer->xDataLength = 0; + } + } + } + #endif + + if( pxNetworkBuffer->xDataLength > 0 ) + { + /* Store a pointer to the network buffer structure in the + padding space that was left in front of the Ethernet frame. + The pointer is needed to ensure the network buffer structure + can be located when it is time for it to be freed if the + Ethernet frame gets used as a zero copy buffer. */ + *( ( xNetworkBufferDescriptor_t ** ) ( ( pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING ) ) ) = pxNetworkBuffer; + + /* Data was received and stored. Send it to the IP task + for processing. */ + xRxEvent.pvData = ( void * ) pxNetworkBuffer; + if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( portTickType ) 0 ) == pdFALSE ) + { + /* The buffer could not be sent to the IP task so the + buffer must be released. */ + vNetworkBufferRelease( pxNetworkBuffer ); + iptraceETHERNET_RX_EVENT_LOST(); + } + else + { + iptraceNETWORK_INTERFACE_RECEIVE(); + } + } + else + { + /* The buffer does not contain any data so there is no + point sending it to the IP task. Just release it. */ + vNetworkBufferRelease( pxNetworkBuffer ); + iptraceETHERNET_RX_EVENT_LOST(); + } + } + else + { + iptraceETHERNET_RX_EVENT_LOST(); + } + } + } +} +/*-----------------------------------------------------------*/ +