diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface')
18 files changed, 4296 insertions, 91 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c index 83c96a07c..dc70ed993 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -219,19 +219,19 @@ const TickType_t x5_Seconds = 5000UL; /* The handler task is created at the highest possible priority to
ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
- configASSERT( xEMACTaskHandle );
+ configASSERT( xEMACTaskHandle != NULL );
}
if( xTxBufferQueue == NULL )
{
xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
- configASSERT( xTxBufferQueue );
+ configASSERT( xTxBufferQueue != NULL );
}
if( xTXDescriptorSemaphore == NULL )
{
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
- configASSERT( xTXDescriptorSemaphore );
+ configASSERT( xTXDescriptorSemaphore != NULL );
}
/* When returning non-zero, the stack will become active and
start DHCP (in configured) */
@@ -296,7 +296,7 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); #endif /* ipconfigZERO_COPY_TX_DRIVER */
/* Not interested in a call-back after TX. */
iptraceNETWORK_INTERFACE_TRANSMIT();
- } while( 0 );
+ } while( ipFALSE_BOOL );
if( bReleaseAfterSend != pdFALSE )
{
@@ -417,7 +417,7 @@ const TickType_t xShortTime = pdMS_TO_TICKS( 100UL ); /* Calculate the IP header checksum. */
pxIPHeader->usHeaderChecksum = 0x00;
- pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+ pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
/* Calculate the TCP checksum for an outgoing packet. */
@@ -519,7 +519,7 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS ); /* Remove compiler warnings about unused parameters. */
( void ) pvParameters;
- configASSERT( xEMACTaskHandle );
+ configASSERT( xEMACTaskHandle != NULL );
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c index 948f9a661..87b837702 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c @@ -141,7 +141,7 @@ typedef struct gmac_dev_mem { /** Circular buffer is empty ? */
#define CIRC_EMPTY( head, tail ) ( head == tail )
/** Clear circular buffer */
-#define CIRC_CLEAR( head, tail ) do { ( head ) = 0; ( tail ) = 0; } while( 0 )
+#define CIRC_CLEAR( head, tail ) do { ( head ) = 0; ( tail ) = 0; } while( ipFALSE_BOOL )
/** Increment head or tail */
static __inline void circ_inc32( int32_t *lHeadOrTail, uint32_t ulSize )
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c index fa7695942..5d77b8bbe 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c @@ -34,60 +34,60 @@ #ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS
/* Check if the LinkStatus in the PHY is still high after 15 seconds of not
receiving packets. */
- #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000uL
+ #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000UL
#endif
#ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS
/* Check if the LinkStatus in the PHY is still low every second. */
- #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000uL
+ #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000UL
#endif
/* As the following 3 macro's are OK in most situations, and so they're not
included in 'FreeRTOSIPConfigDefaults.h'.
Users can change their values in the project's 'FreeRTOSIPConfig.h'. */
#ifndef phyPHY_MAX_RESET_TIME_MS
- #define phyPHY_MAX_RESET_TIME_MS 1000uL
+ #define phyPHY_MAX_RESET_TIME_MS 1000UL
#endif
#ifndef phyPHY_MAX_NEGOTIATE_TIME_MS
- #define phyPHY_MAX_NEGOTIATE_TIME_MS 3000uL
+ #define phyPHY_MAX_NEGOTIATE_TIME_MS 3000UL
#endif
#ifndef phySHORT_DELAY_MS
- #define phySHORT_DELAY_MS 50uL
+ #define phySHORT_DELAY_MS 50UL
#endif
/* Naming and numbering of basic PHY registers. */
-#define phyREG_00_BMCR 0x00u /* Basic Mode Control Register. */
-#define phyREG_01_BMSR 0x01u /* Basic Mode Status Register. */
-#define phyREG_02_PHYSID1 0x02u /* PHYS ID 1 */
-#define phyREG_03_PHYSID2 0x03u /* PHYS ID 2 */
-#define phyREG_04_ADVERTISE 0x04u /* Advertisement control reg */
+#define phyREG_00_BMCR 0x00U /* Basic Mode Control Register. */
+#define phyREG_01_BMSR 0x01U /* Basic Mode Status Register. */
+#define phyREG_02_PHYSID1 0x02U /* PHYS ID 1 */
+#define phyREG_03_PHYSID2 0x03U /* PHYS ID 2 */
+#define phyREG_04_ADVERTISE 0x04U /* Advertisement control reg */
/* Naming and numbering of extended PHY registers. */
-#define PHYREG_10_PHYSTS 0x10u /* 16 PHY status register Offset */
-#define phyREG_19_PHYCR 0x19u /* 25 RW PHY Control Register */
-#define phyREG_1F_PHYSPCS 0x1Fu /* 31 RW PHY Special Control Status */
+#define PHYREG_10_PHYSTS 0x10U /* 16 PHY status register Offset */
+#define phyREG_19_PHYCR 0x19U /* 25 RW PHY Control Register */
+#define phyREG_1F_PHYSPCS 0x1FU /* 31 RW PHY Special Control Status */
/* Bit fields for 'phyREG_00_BMCR', the 'Basic Mode Control Register'. */
-#define phyBMCR_FULL_DUPLEX 0x0100u /* Full duplex. */
-#define phyBMCR_AN_RESTART 0x0200u /* Auto negotiation restart. */
-#define phyBMCR_ISOLATE 0x0400u /* 1 = Isolates 0 = Normal operation. */
-#define phyBMCR_AN_ENABLE 0x1000u /* Enable auto negotiation. */
-#define phyBMCR_SPEED_100 0x2000u /* Select 100Mbps. */
-#define phyBMCR_RESET 0x8000u /* Reset the PHY. */
+#define phyBMCR_FULL_DUPLEX 0x0100U /* Full duplex. */
+#define phyBMCR_AN_RESTART 0x0200U /* Auto negotiation restart. */
+#define phyBMCR_ISOLATE 0x0400U /* 1 = Isolates 0 = Normal operation. */
+#define phyBMCR_AN_ENABLE 0x1000U /* Enable auto negotiation. */
+#define phyBMCR_SPEED_100 0x2000U /* Select 100Mbps. */
+#define phyBMCR_RESET 0x8000U /* Reset the PHY. */
/* Bit fields for 'phyREG_19_PHYCR', the 'PHY Control Register'. */
-#define PHYCR_MDIX_EN 0x8000u /* Enable Auto MDIX. */
-#define PHYCR_MDIX_FORCE 0x4000u /* Force MDIX crossed. */
+#define PHYCR_MDIX_EN 0x8000U /* Enable Auto MDIX. */
+#define PHYCR_MDIX_FORCE 0x4000U /* Force MDIX crossed. */
-#define phyBMSR_AN_COMPLETE 0x0020u /* Auto-Negotiation process completed */
+#define phyBMSR_AN_COMPLETE 0x0020U /* Auto-Negotiation process completed */
-#define phyBMSR_LINK_STATUS 0x0004u
+#define phyBMSR_LINK_STATUS 0x0004U
-#define phyPHYSTS_LINK_STATUS 0x0001u /* PHY Link mask */
-#define phyPHYSTS_SPEED_STATUS 0x0002u /* PHY Speed mask */
-#define phyPHYSTS_DUPLEX_STATUS 0x0004u /* PHY Duplex mask */
+#define phyPHYSTS_LINK_STATUS 0x0001U /* PHY Link mask */
+#define phyPHYSTS_SPEED_STATUS 0x0002U /* PHY Speed mask */
+#define phyPHYSTS_DUPLEX_STATUS 0x0004U /* PHY Duplex mask */
/* Bit fields for 'phyREG_1F_PHYSPCS
001 = 10BASE-T half-duplex
@@ -95,20 +95,20 @@ Users can change their values in the project's 'FreeRTOSIPConfig.h'. */ 010 = 100BASE-TX half-duplex
110 = 100BASE-TX full-duplex
*/
-#define phyPHYSPCS_SPEED_MASK 0x000Cu
-#define phyPHYSPCS_SPEED_10 0x0004u
-#define phyPHYSPCS_FULL_DUPLEX 0x0010u
+#define phyPHYSPCS_SPEED_MASK 0x000CU
+#define phyPHYSPCS_SPEED_10 0x0004U
+#define phyPHYSPCS_FULL_DUPLEX 0x0010U
/*
* Description of all capabilities that can be advertised to
* the peer (usually a switch or router).
*/
-#define phyADVERTISE_CSMA 0x0001u /* Supports IEEE 802.3u: Fast Ethernet at 100 Mbit/s */
-#define phyADVERTISE_10HALF 0x0020u /* Try for 10mbps half-duplex. */
-#define phyADVERTISE_10FULL 0x0040u /* Try for 10mbps full-duplex. */
-#define phyADVERTISE_100HALF 0x0080u /* Try for 100mbps half-duplex. */
-#define phyADVERTISE_100FULL 0x0100u /* Try for 100mbps full-duplex. */
+#define phyADVERTISE_CSMA 0x0001U /* Supports IEEE 802.3u: Fast Ethernet at 100 Mbit/s */
+#define phyADVERTISE_10HALF 0x0020U /* Try for 10mbps half-duplex. */
+#define phyADVERTISE_10FULL 0x0040U /* Try for 10mbps full-duplex. */
+#define phyADVERTISE_100HALF 0x0080U /* Try for 100mbps half-duplex. */
+#define phyADVERTISE_100FULL 0x0100U /* Try for 100mbps full-duplex. */
#define phyADVERTISE_ALL ( phyADVERTISE_10HALF | phyADVERTISE_10FULL | \
phyADVERTISE_100HALF | phyADVERTISE_100FULL | \
@@ -167,7 +167,7 @@ BaseType_t xResult; /* Initialise the struct and assign a PHY-read and -write function. */
void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhyRead, xApplicationPhyWriteHook_t fnPhyWrite )
{
- memset( ( void * )pxPhyObject, '\0', sizeof( *pxPhyObject ) );
+ memset( ( void * )pxPhyObject, 0, sizeof( *pxPhyObject ) );
pxPhyObject->fnPhyRead = fnPhyRead;
pxPhyObject->fnPhyWrite = fnPhyWrite;
@@ -187,7 +187,7 @@ BaseType_t xPhyAddress; pxPhyObject->fnPhyRead( xPhyAddress, phyREG_03_PHYSID2, &ulLowerID );
/* A valid PHY id can not be all zeros or all ones. */
- if( ( ulLowerID != ( uint16_t )~0u ) && ( ulLowerID != ( uint16_t )0u ) )
+ if( ( ulLowerID != ( uint16_t ) ~0U ) && ( ulLowerID != ( uint16_t ) 0U ) )
{
uint32_t ulUpperID;
uint32_t ulPhyID;
@@ -225,7 +225,7 @@ TimeOut_t xTimer; BaseType_t xPhyIndex;
/* A bit-mask of PHY ports that are ready. */
- ulDoneMask = 0ul;
+ ulDoneMask = 0UL;
/* Set the RESET bits high. */
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
@@ -251,7 +251,7 @@ BaseType_t xPhyIndex; if( ( ulConfig & phyBMCR_RESET ) == 0 )
{
FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET %d ready\n", (int)xPhyIndex ) );
- ulDoneMask |= ( 1ul << xPhyIndex );
+ ulDoneMask |= ( 1UL << xPhyIndex );
}
}
if( ulDoneMask == ulPhyMask )
@@ -270,7 +270,7 @@ BaseType_t xPhyIndex; /* Clear the reset bits. */
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
- if( ( ulDoneMask & ( 1ul << xPhyIndex ) ) == 0uL )
+ if( ( ulDoneMask & ( 1UL << xPhyIndex ) ) == 0UL )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
@@ -454,9 +454,9 @@ with ulPhyMask. */ BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
{
BaseType_t xPhyIndex;
-uint32_t ulValue, ulBitMask = ( uint32_t )1u;
+uint32_t ulValue, ulBitMask = ( uint32_t )1U;
- ulValue = ( uint32_t )0u;
+ ulValue = ( uint32_t ) 0U;
if( pxPhyObject->xPhyPreferences.ucDuplex == PHY_DUPLEX_FULL )
{
@@ -491,7 +491,7 @@ uint32_t ulPHYLinkStatus, ulRegValue; TickType_t xRemainingTime;
TimeOut_t xTimer;
- if( ulPhyMask == ( uint32_t )0u )
+ if( ulPhyMask == ( uint32_t ) 0U )
{
return 0;
}
@@ -512,7 +512,7 @@ TimeOut_t xTimer; /* Wait until the auto-negotiation will be completed */
for( ;; )
{
- ulBitMask = ( uint32_t )1u;
+ ulBitMask = ( uint32_t ) 1U;
for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
if( ( ulPhyMask & ulBitMask ) != 0lu )
@@ -541,16 +541,16 @@ TimeOut_t xTimer; vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );
}
- if( ulDoneMask != ( uint32_t)0u )
+ if( ulDoneMask != ( uint32_t) 0U )
{
- ulBitMask = ( uint32_t )1u;
+ ulBitMask = ( uint32_t ) 1U;
pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask );
for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
- if( ( ulDoneMask & ulBitMask ) == ( uint32_t )0u )
+ if( ( ulDoneMask & ulBitMask ) == ( uint32_t ) 0U )
{
continue;
}
@@ -632,7 +632,7 @@ TimeOut_t xTimer; ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half",
( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100,
( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0) ? "high" : "low" ) );
- if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t )0u )
+ if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t ) 0U )
{
pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL;
}
@@ -650,7 +650,7 @@ TimeOut_t xTimer; pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100;
}
}
- } /* if( ulDoneMask != ( uint32_t)0u ) */
+ } /* if( ulDoneMask != ( uint32_t) 0U ) */
return 0;
}
@@ -658,7 +658,7 @@ TimeOut_t xTimer; BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception )
{
-uint32_t ulStatus, ulBitMask = 1u;
+uint32_t ulStatus, ulBitMask = 1U;
BaseType_t xPhyIndex;
BaseType_t xNeedCheck = pdFALSE;
@@ -670,7 +670,7 @@ BaseType_t xNeedCheck = pdFALSE; pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
- if( ( pxPhyObject->ulLinkStatusMask & ulBitMask ) == 0ul )
+ if( ( pxPhyObject->ulLinkStatusMask & ulBitMask ) == 0UL )
{
pxPhyObject->ulLinkStatusMask |= ulBitMask;
FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
@@ -705,7 +705,7 @@ BaseType_t xNeedCheck = pdFALSE; }
}
vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
- if( ( pxPhyObject->ulLinkStatusMask & phyBMSR_LINK_STATUS ) != 0 )
+ if( ( pxPhyObject->ulLinkStatusMask & ( ulBitMask >> 1 ) ) != 0 )
{
/* The link status is high, so don't poll the PHY too often. */
pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/NetworkInterface.c new file mode 100644 index 000000000..543cc1d62 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/NetworkInterface.c @@ -0,0 +1,928 @@ +/* +FreeRTOS+TCP V2.2.1 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/* Standard includes. */ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_ARP.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +/* Some files from the Atmel Software Framework */ +/* gmac_SAM.[ch] is a combination of the gmac.[ch] for both SAM4E and SAME70. */ +#include "gmac_SAM.h" +#include <sysclk.h> +#include "phyhandling.h" + +/* This file is included to see if 'CONF_BOARD_ENABLE_CACHE' is defined. */ +#include "conf_board.h" + + +/* Interrupt events to process. Currently only the Rx event is processed +although code for other events is included to allow for possible future +expansion. */ +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +/* 1536 bytes is more than needed, 1524 would be enough. +But 1536 is a multiple of 32, which gives a great alignment for +cached memories. */ + +#define NETWORK_BUFFER_SIZE 1536 + +#ifndef EMAC_MAX_BLOCK_TIME_MS + /* The task 'prvEMACHandlerTask()' will wake-up every 100 ms, to see + if something has to be done, mostly checking if the PHY has a + change in Link Status. */ + #define EMAC_MAX_BLOCK_TIME_MS 100ul +#endif + +#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + #error This driver works optimal if ipconfigZERO_COPY_RX_DRIVER is defined as 1 +#endif + +#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + #error This driver works optimal if ipconfigZERO_COPY_TX_DRIVER is defined as 1 +#endif + +/* Default the size of the stack used by the EMAC deferred handler task to 4x +the size of the stack used by the idle task - but allow this to be overridden in +FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ +#ifndef configEMAC_TASK_STACK_SIZE + #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE ) +#endif + +#ifndef niEMAC_HANDLER_TASK_PRIORITY + #define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1 +#endif + +#if( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) + #include "core_cm7.h" + #warning This driver assumes the presence of DCACHE + #define NETWORK_BUFFERS_CACHED 1 + #define CACHE_LINE_SIZE 32 + #define NETWORK_BUFFER_HEADER_SIZE ( ipconfigPACKET_FILLER_SIZE + 8 ) + + static void cache_clean_invalidate() + { + /* If you application crashes here, make sure that SCB_EnableDCache() has been called. */ + SCB_CleanInvalidateDCache(); + } + /*-----------------------------------------------------------*/ + + static void cache_clean_invalidate_by_addr(uint32_t addr, uint32_t size) + { + /* SAME70 does not have clean/invalidate per area. */ + /* SCB_CleanInvalidateDCache_by_Addr( ( uint32_t * )addr, size); */ + SCB_CleanInvalidateDCache(); + } + /*-----------------------------------------------------------*/ + + static void cache_invalidate_by_addr(addr, size) \ + { + /* SAME70 does not have clean/invalidate per area. */ + /* SCB_InvalidateDCache_by_Addr( ( uint32_t * )addr, size); */ + SCB_InvalidateDCache(); + } + /*-----------------------------------------------------------*/ + +#else + #warning Sure there is no caching? + #define cache_clean_invalidate() do {} while( 0 ) + #define cache_clean_invalidate_by_addr(addr, size) do {} while( 0 ) + #define cache_invalidate_by_addr(addr, size) do {} while( 0 ) +#endif + +/*-----------------------------------------------------------*/ + +/* + * Update settings in GMAC for speed and duplex. + */ +static void prvEthernetUpdateConfig( BaseType_t xForce ); + +/* + * Access functions to the PHY's: read() and write() to be used by + * phyHandling.c. + */ +static BaseType_t xPHY_Read( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ); +static BaseType_t xPHY_Write( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ); + +#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 ) + void vGMACGenerateChecksum( uint8_t *apBuffer, size_t uxLength ); +#endif + +/* + * Called from the ASF GMAC driver. + */ +void xRxCallback( uint32_t ulStatus ); +void xTxCallback( uint32_t ulStatus, uint8_t *puc_buffer ); + +/* + * A deferred interrupt handler task that processes GMAC interrupts. + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/* + * Initialise the ASF GMAC driver. + */ +static BaseType_t prvGMACInit( void ); + +/* + * Try to obtain an Rx packet from the hardware. + */ +static uint32_t prvEMACRxPoll( void ); + +/* + * Handle transmission errors. + */ +static void hand_tx_errors( void ); + +/*-----------------------------------------------------------*/ + +/* Bit map of outstanding ETH interrupt events for processing. Currently only +the Rx interrupt is handled, although code is included for other events to +enable future expansion. */ +static volatile uint32_t ulISREvents; + +/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ +static volatile BaseType_t xGMACSwitchRequired; + +/* LLMNR multicast address. */ +static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; + +/* The GMAC object as defined by the ASF drivers. */ +static gmac_device_t gs_gmac_dev; + +/* MAC address to use. */ +extern const uint8_t ucMACAddress[ 6 ]; + +/* Holds the handle of the task used as a deferred interrupt processor. The +handle is used so direct notifications can be sent to the task for all EMAC/DMA +related interrupts. */ +TaskHandle_t xEMACTaskHandle = NULL; + +static QueueHandle_t xTxBufferQueue; +int tx_release_count[ 4 ]; + +/* xTXDescriptorSemaphore is a counting semaphore with +a maximum count of GMAC_TX_BUFFERS, which is the number of +DMA TX descriptors. */ +static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; + +/* For local use only: describe the PHY's properties: */ +const PhyProperties_t xPHYProperties = +{ + #if( ipconfigETHERNET_AN_ENABLE != 0 ) + .ucSpeed = PHY_SPEED_AUTO, + .ucDuplex = PHY_DUPLEX_AUTO, + #else + #if( ipconfigETHERNET_USE_100MB != 0 ) + .ucSpeed = PHY_SPEED_100, + #else + .ucSpeed = PHY_SPEED_10, + #endif + + #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 ) + .ucDuplex = PHY_DUPLEX_FULL, + #else + .ucDuplex = PHY_DUPLEX_HALF, + #endif + #endif + + #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 ) + .ucMDI_X = PHY_MDIX_AUTO, + #elif( ipconfigETHERNET_CROSSED_LINK != 0 ) + .ucMDI_X = PHY_MDIX_CROSSED, + #else + .ucMDI_X = PHY_MDIX_DIRECT, + #endif +}; + +/* All PHY handling code has now been separated from the NetworkInterface.c, +see "../Common/phyHandling.c". */ +static EthernetPhy_t xPhyObject; + +/*-----------------------------------------------------------*/ + +/* + * GMAC interrupt handler. + */ +void GMAC_Handler(void) +{ + xGMACSwitchRequired = pdFALSE; + + /* gmac_handler() may call xRxCallback() which may change + the value of xGMACSwitchRequired. */ + gmac_handler( &gs_gmac_dev ); + + if( xGMACSwitchRequired != pdFALSE ) + { + portEND_SWITCHING_ISR( xGMACSwitchRequired ); + } +} +/*-----------------------------------------------------------*/ + +void xRxCallback( uint32_t ulStatus ) +{ + if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) ) + { + /* let the prvEMACHandlerTask know that there was an RX event. */ + ulISREvents |= EMAC_IF_RX_EVENT; + /* Only an RX interrupt can wakeup prvEMACHandlerTask. */ + vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired ); + } +} +/*-----------------------------------------------------------*/ + +void returnTxBuffer(uint8_t *puc_buffer) +{ + /* Called from a non-ISR context. */ + if( xTxBufferQueue != NULL ) + { + xQueueSend( xTxBufferQueue, &puc_buffer, 0 ); + xTaskNotifyGive( xEMACTaskHandle ); + ulISREvents |= EMAC_IF_TX_EVENT; + } +} + +void xTxCallback( uint32_t ulStatus, uint8_t *puc_buffer ) +{ + if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) ) + { + /* let the prvEMACHandlerTask know that there was an TX event. */ + ulISREvents |= EMAC_IF_TX_EVENT; + /* Wakeup prvEMACHandlerTask. */ + vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired ); + xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired ); + tx_release_count[ 2 ]++; + } +} +/*-----------------------------------------------------------*/ + + +/* + The two standard defines 'GMAC_MAN_RW_TYPE' and 'GMAC_MAN_READ_ONLY' + are incorrect. + Therefore, use the following: +*/ + +#define GMAC_MAINTENANCE_READ_ACCESS (2) +#define GMAC_MAINTENANCE_WRITE_ACCESS (1) + +static BaseType_t xPHY_Read( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ) +{ +BaseType_t xReturn; +UBaseType_t uxWasEnabled; + + /* Wait until bus idle */ + while ((GMAC->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Write maintain register */ + /* + * OP: Operation: 10 is read. 01 is write. + */ + uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u; + if( uxWasEnabled == 0u ) + { + /* Enable further GMAC maintenance. */ + GMAC->GMAC_NCR |= GMAC_NCR_MPE; + } + GMAC->GMAC_MAN = GMAC_MAN_WTN(GMAC_MAN_CODE_VALUE) + | GMAC_MAN_CLTTO + | GMAC_MAN_PHYA(xAddress) + | GMAC_MAN_REGA(xRegister) + | GMAC_MAN_OP(GMAC_MAINTENANCE_READ_ACCESS) + | GMAC_MAN_DATA( (uint16_t)0u ); + + if (gmac_wait_phy(GMAC, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) + { + *pulValue = (uint32_t)0xffffu; + xReturn = -1; + } + else + { + /* Wait until bus idle */ + while ((GMAC->GMAC_NSR & GMAC_NSR_IDLE) == 0); + + /* Return data */ + *pulValue = (uint32_t)(GMAC->GMAC_MAN & GMAC_MAN_DATA_Msk); + + xReturn = 0; + } + if( uxWasEnabled == 0u ) + { + /* Disable further GMAC maintenance. */ + GMAC->GMAC_NCR &= ~GMAC_NCR_MPE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t xPHY_Write( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ) +{ +BaseType_t xReturn; +UBaseType_t uxWasEnabled; + + /* Wait until bus idle */ + while ((GMAC->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Write maintain register */ + uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u; + if( uxWasEnabled == 0u ) + { + /* Enable further GMAC maintenance. */ + GMAC->GMAC_NCR |= GMAC_NCR_MPE; + } + GMAC->GMAC_MAN = GMAC_MAN_WTN(GMAC_MAN_CODE_VALUE) + | GMAC_MAN_CLTTO + | GMAC_MAN_PHYA(xAddress) + | GMAC_MAN_REGA(xRegister) + | GMAC_MAN_OP(GMAC_MAINTENANCE_WRITE_ACCESS) + | GMAC_MAN_DATA( (uint16_t)ulValue ); + + if (gmac_wait_phy(GMAC, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT ) + { + xReturn = -1; + } + else + { + xReturn = 0; + } + if( uxWasEnabled == 0u ) + { + /* Disable further GMAC maintenance. */ + GMAC->GMAC_NCR &= ~GMAC_NCR_MPE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +const TickType_t x5_Seconds = 5000UL; + + if( xEMACTaskHandle == NULL ) + { + prvGMACInit(); + + cache_clean_invalidate(); + + /* The handler task is created at the highest possible priority to + ensure the interrupt handler can return directly to it. */ + xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ); + configASSERT( xEMACTaskHandle ); + } + + if( xTxBufferQueue == NULL ) + { + xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) ); + configASSERT( xTxBufferQueue ); + } + + if( xTXDescriptorSemaphore == NULL ) + { + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS ); + configASSERT( xTXDescriptorSemaphore ); + } + /* When returning non-zero, the stack will become active and + start DHCP (in configured) */ + return xGetPhyLinkStatus(); +} +/*-----------------------------------------------------------*/ + +BaseType_t xGetPhyLinkStatus( void ) +{ +BaseType_t xReturn; + + if( xPhyObject.ulLinkStatusMask != 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/** The GMAC TX errors to handle */ +#define GMAC_TX_ERRORS (GMAC_TSR_TFC | GMAC_TSR_HRESP) + +static void hand_tx_errors( void ) +{ +/* Handle GMAC underrun or AHB errors. */ + if (gmac_get_tx_status(GMAC) & GMAC_TX_ERRORS) { + + gmac_enable_transmit(GMAC, false); + + /* Reinit TX descriptors. */ +// gmac_tx_init(ps_gmac_dev); + gmac_reset_tx_mem(&gs_gmac_dev); + /* Clear error status. */ + gmac_clear_tx_status(GMAC, GMAC_TX_ERRORS); + + gmac_enable_transmit(GMAC, true); + } +} + +volatile IPPacket_t *pxSendPacket; + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend ) +{ +/* Do not wait too long for a free TX DMA buffer. */ +const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); +uint32_t ulTransmitSize; + + ulTransmitSize = pxDescriptor->xDataLength; + + pxSendPacket = (IPPacket_t *)pxDescriptor->pucEthernetBuffer; + + if( ulTransmitSize > NETWORK_BUFFER_SIZE ) + { + ulTransmitSize = NETWORK_BUFFER_SIZE; + } + /* A do{}while(0) loop is introduced to allow the use of multiple break + statement. */ + do { + if( xPhyObject.ulLinkStatusMask == 0ul ) + { + /* Do not attempt to send packets as long as the Link Status is low. */ + break; + } + if( xTXDescriptorSemaphore == NULL ) + { + /* Semaphore has not been created yet? */ + break; + } + hand_tx_errors(); + if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) + { + /* Time-out waiting for a free TX descriptor. */ + tx_release_count[ 3 ]++; + break; + } + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* Confirm that the pxDescriptor may be kept by the driver. */ + configASSERT( bReleaseAfterSend != pdFALSE ); + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + #if( NETWORK_BUFFERS_CACHED != 0 ) + { + uint32_t xlength = CACHE_LINE_SIZE * ( ( ulTransmitSize + NETWORK_BUFFER_HEADER_SIZE + CACHE_LINE_SIZE - 1 ) / CACHE_LINE_SIZE ); + uint32_t xAddress = ( uint32_t )( pxDescriptor->pucEthernetBuffer - NETWORK_BUFFER_HEADER_SIZE ); + cache_clean_invalidate_by_addr( xAddress, xlength ); + } + #endif + + gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength ); + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* Confirm that the pxDescriptor may be kept by the driver. */ + bReleaseAfterSend = pdFALSE; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + /* Not interested in a call-back after TX. */ + iptraceNETWORK_INTERFACE_TRANSMIT(); + } while( ipFALSE_BOOL ); + + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvGMACInit( void ) +{ +uint32_t ncfgr; + + gmac_options_t gmac_option; + + gmac_enable_management(GMAC, true); + /* Enable further GMAC maintenance. */ + GMAC->GMAC_NCR |= GMAC_NCR_MPE; + + memset( &gmac_option, '\0', sizeof( gmac_option ) ); + gmac_option.uc_copy_all_frame = 0; + gmac_option.uc_no_boardcast = 0; + memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) ); + + gs_gmac_dev.p_hw = GMAC; + gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option ); + + NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY ); + NVIC_EnableIRQ( GMAC_IRQn ); + + { + /* Set MDC clock divider. */ + gmac_set_mdc_clock( GMAC, sysclk_get_cpu_hz() ); + + vPhyInitialise( &xPhyObject, xPHY_Read, xPHY_Write ); + xPhyDiscover( &xPhyObject ); + xPhyConfigure( &xPhyObject, &xPHYProperties ); + + /* For a reset / reconfigure of the EMAC. */ + prvEthernetUpdateConfig( pdTRUE ); + + /* Select Media Independent Interface type */ + #if( SAME70 != 0 ) + { + /* Selecting RMII mode. */ + GMAC->GMAC_UR &= ~GMAC_UR_RMII; + } + #else + { + gmac_select_mii_mode(GMAC, ETH_PHY_MODE); + } + #endif + + gmac_enable_transmit(GMAC, true); + gmac_enable_receive(GMAC, true); + + } + + gmac_enable_management(GMAC, true); + + gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address ); + + gmac_enable_management(GMAC, false); + /* Disable further GMAC maintenance. */ + GMAC->GMAC_NCR &= ~GMAC_NCR_MPE; + + return 1; +} +/*-----------------------------------------------------------*/ + +static void prvEthernetUpdateConfig( BaseType_t xForce ) +{ + FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n", + xPhyObject.ulLinkStatusMask, + ( int )xForce ) ); + + if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) ) + { + #if( ipconfigETHERNET_AN_ENABLE != 0 ) + { + UBaseType_t uxWasEnabled; + + /* Restart the auto-negotiation. */ + uxWasEnabled = ( GMAC->GMAC_NCR & GMAC_NCR_MPE ) != 0u; + if( uxWasEnabled == 0u ) + { + /* Enable further GMAC maintenance. */ + GMAC->GMAC_NCR |= GMAC_NCR_MPE; + } + xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) ); + + /* Configure the MAC with the Duplex Mode fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL ) + { + gmac_enable_full_duplex(GMAC, pdTRUE); + } + else + { + gmac_enable_full_duplex(GMAC, pdFALSE); + } + + /* Configure the MAC with the speed fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 ) + { + gmac_set_speed(GMAC, pdFALSE); + } + else + { + gmac_set_speed(GMAC, pdTRUE); + } + if( uxWasEnabled == 0u ) + { + /* Enable further GMAC maintenance. */ + GMAC->GMAC_NCR &= ~GMAC_NCR_MPE; + } + } + #else + { + if( xPHYProperties.ucDuplex == PHY_DUPLEX_FULL ) + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL; + gmac_enable_full_duplex(GMAC, pdTRUE); + } + else + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF; + gmac_enable_full_duplex(GMAC, pdFALSE); + } + + if( xPHYProperties.ucSpeed == PHY_SPEED_100 ) + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100; + gmac_set_speed(GMAC, pdTRUE); + } + else + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10; + gmac_set_speed(GMAC, pdFALSE); + } + + xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO; + + /* Use predefined (fixed) configuration. */ + xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) ); + } + #endif + + } +} +/*-----------------------------------------------------------*/ + +void vGMACGenerateChecksum( uint8_t *pucBuffer, size_t uxLength ) +{ +ProtocolPacket_t *xProtPacket = ( ProtocolPacket_t * ) pucBuffer; + + if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) + { + IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader ); + + /* Calculate the IP header checksum. */ + pxIPHeader->usHeaderChecksum = 0x00; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + + /* Calculate the TCP checksum for an outgoing packet. */ + usGenerateProtocolChecksum( pucBuffer, uxLength, pdTRUE ); + } +} +/*-----------------------------------------------------------*/ + +static uint32_t prvEMACRxPoll( void ) +{ +unsigned char *pucUseBuffer; +uint32_t ulReceiveCount, ulResult, ulReturnValue = 0; +static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL; +const UBaseType_t xMinDescriptorsToLeave = 2UL; +const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL ); +static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; +uint8_t *pucDMABuffer = NULL; + + for( ;; ) + { + /* If pxNextNetworkBufferDescriptor was not left pointing at a valid + descriptor then allocate one now. */ + if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) ) + { + pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime ); + } + + if( pxNextNetworkBufferDescriptor != NULL ) + { + /* Point pucUseBuffer to the buffer pointed to by the descriptor. */ + pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE ); + } + else + { + /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming + messages will be flushed and ignored. */ + pucUseBuffer = NULL; + } + + /* Read the next packet from the hardware into pucUseBuffer. */ + ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount, &pucDMABuffer ); + + if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) ) + { + /* No data from the hardware. */ + break; + } + + if( pxNextNetworkBufferDescriptor == NULL ) + { + /* Data was read from the hardware, but no descriptor was available + for it, so it will be dropped. */ + iptraceETHERNET_RX_EVENT_LOST(); + continue; + } + + iptraceNETWORK_INTERFACE_RECEIVE(); + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + pxNextNetworkBufferDescriptor = pxPacketBuffer_to_NetworkBuffer( pucDMABuffer ); + if( pxNextNetworkBufferDescriptor == NULL ) + { + /* STrange: can not translate from a DMA buffer to a Network Buffer. */ + break; + } + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount; + xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor; + + /* Send the descriptor to the IP task for processing. */ + if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE ) + { + /* The buffer could not be sent to the stack so must be released + again. */ + vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor ); + iptraceETHERNET_RX_EVENT_LOST(); + FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) ); + } + + /* Now the buffer has either been passed to the IP-task, + or it has been released in the code above. */ + pxNextNetworkBufferDescriptor = NULL; + ulReturnValue++; + } + + return ulReturnValue; +} +/*-----------------------------------------------------------*/ + +volatile UBaseType_t uxLastMinBufferCount = 0; +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + volatile UBaseType_t uxLastMinQueueSpace; +#endif +volatile UBaseType_t uxCurrentSemCount; +volatile UBaseType_t uxLowestSemCount; + +void vCheckBuffersAndQueue( void ) +{ +static UBaseType_t uxCurrentCount; + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + uxCurrentCount = uxGetMinimumIPQueueSpace(); + if( uxLastMinQueueSpace != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinQueueSpace = uxCurrentCount; + FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) ); + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); + } + if( xTXDescriptorSemaphore != NULL ) + { + uxCurrentSemCount = uxSemaphoreGetCount( xTXDescriptorSemaphore ); + if( uxLowestSemCount > uxCurrentSemCount ) + { + uxLowestSemCount = uxCurrentSemCount; + FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) ); + } + + } + +} +/*-----------------------------------------------------------*/ + +extern uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE ]; +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ +uint8_t *ucRAMBuffer = ucNetworkPackets; +uint32_t ulIndex; + + for( ulIndex = 0; ulIndex < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ulIndex++ ) + { + pxNetworkBuffers[ ulIndex ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING; + *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ulIndex ] ) ); + ucRAMBuffer += NETWORK_BUFFER_SIZE; + } + cache_clean_invalidate(); +} +/*-----------------------------------------------------------*/ + +static void prvEMACHandlerTask( void *pvParameters ) +{ +UBaseType_t uxCount; +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxBuffer; +#endif +uint8_t *pucBuffer; +BaseType_t xResult = 0; +uint32_t xStatus; +const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS ); + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + configASSERT( xEMACTaskHandle ); + + for( ;; ) + { + xResult = 0; + vCheckBuffersAndQueue(); + + if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 ) + { + /* No events to process now, wait for the next. */ + ulTaskNotifyTake( pdFALSE, ulMaxBlockTime ); + } + + if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 ) + { + ulISREvents &= ~EMAC_IF_RX_EVENT; + + /* Wait for the EMAC interrupt to indicate that another packet has been + received. */ + xResult = prvEMACRxPoll(); + } + + if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) + { + /* Future extension: code to release TX buffers if zero-copy is used. */ + ulISREvents &= ~EMAC_IF_TX_EVENT; + while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE ) + { + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer ); + if( pxBuffer != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxBuffer ); + tx_release_count[ 0 ]++; + } + else + { + tx_release_count[ 1 ]++; + } + } + #else + { + tx_release_count[ 0 ]++; + } + #endif + uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore ); + if( uxCount < GMAC_TX_BUFFERS ) + { + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); + } + } + } + + if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) + { + /* Future extension: logging about errors that occurred. */ + ulISREvents &= ~EMAC_IF_ERR_EVENT; + } + gmac_enable_management(GMAC, true); + if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 ) + { + /* Something has changed to a Link Status, need re-check. */ + prvEthernetUpdateConfig( pdFALSE ); + } + gmac_enable_management(GMAC, false); + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/gmac_SAM.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/gmac_SAM.c new file mode 100644 index 000000000..6732ec51b --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/gmac_SAM.c @@ -0,0 +1,924 @@ +/** + * \file + * + * \brief GMAC (Ethernet MAC) driver for SAM. + * + * Copyright (c) 2015-2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> + */ + + +/* Standard includes. */ +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +#include "FreeRTOSIPConfig.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_ARP.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "compiler.h" +#include "gmac_SAM.h" + +#if( SAME70 != 0 ) + /* This file is included to see if 'CONF_BOARD_ENABLE_CACHE' is defined. */ + #include "conf_board.h" + #include "core_cm7.h" +#endif + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +#ifndef ARRAY_SIZE + #define ARRAY_SIZE(x) (int)( sizeof(x) / sizeof(x)[0] ) +#endif + +#if( GMAC_RX_BUFFERS <= 1 ) + #error Configuration error +#endif + +#if( GMAC_TX_BUFFERS <= 1 ) + #error Configuration error +#endif + +/** + * \defgroup gmac_group Ethernet Media Access Controller + * + * See \ref gmac_quickstart. + * + * Driver for the GMAC (Ethernet Media Access Controller). + * This file contains basic functions for the GMAC, with support for all modes, settings + * and clock speeds. + * + * \section dependencies Dependencies + * This driver does not depend on other modules. + * + * @{ + */ + +#define NETWORK_BUFFER_SIZE 1536 + +__attribute__ ( ( aligned( 32 ) ) ) +__attribute__ ( ( section( ".first_data" ) ) ) + uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * NETWORK_BUFFER_SIZE ]; + +/** TX descriptor lists */ +__attribute__ ((section(".first_data"))) +COMPILER_ALIGNED(8) +static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ]; + +#if( SAME70 != 0 ) + __attribute__ ((section(".first_data"))) + COMPILER_ALIGNED(8) + static gmac_tx_descriptor_t gs_tx_desc_null; +#endif + +/** RX descriptors lists */ +__attribute__ ((section(".first_data"))) +COMPILER_ALIGNED(8) +static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ]; + +#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + /** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the + * 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits + * of the address shall be set to 0. + */ + __attribute__ ((section(".first_data"))) + COMPILER_ALIGNED(8) + static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ]; +#endif /* ipconfigZERO_COPY_TX_DRIVER */ + +#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + /** Receive Buffer */ + __attribute__ ((section(".first_data"))) + COMPILER_ALIGNED(8) + static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ]; +#endif /* ipconfigZERO_COPY_RX_DRIVER */ + +/** Return count in buffer */ +#define CIRC_CNT( head, tail, size ) ( ( ( head ) - ( tail ) ) % ( size ) ) + +/* + * Return space available, from 0 to size-1. + * Always leave one free char as a completely full buffer that has (head == tail), + * which is the same as empty. + */ +#define CIRC_SPACE( head, tail, size ) CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) ) + +/** Circular buffer is empty ? */ +#define CIRC_EMPTY( head, tail ) ( ( head ) == ( tail ) ) +/** Clear circular buffer */ +#define CIRC_CLEAR( head, tail ) do { ( head ) = 0; ( tail ) = 0; } while( 0 ) + +/* Two call-back functions that should be defined in NetworkInterface.c */ +extern void xRxCallback( uint32_t ulStatus ); +extern void xTxCallback( uint32_t ulStatus, uint8_t *puc_buffer ); +extern void returnTxBuffer(uint8_t *puc_buffer); + + +/** Increment head or tail */ +static __inline void circ_inc32( int32_t *lHeadOrTail, uint32_t ulSize ) +{ + ( *lHeadOrTail ) ++; + if( ( *lHeadOrTail ) >= ( int32_t )ulSize ) + { + ( *lHeadOrTail ) = 0; + } +} + +/** + * \brief Wait PHY operation to be completed. + * + * \param p_gmac HW controller address. + * \param ul_retry The retry times, 0 to wait forever until completeness. + * + * Return GMAC_OK if the operation is completed successfully. + */ +uint8_t gmac_wait_phy(Gmac* p_gmac, const uint32_t ul_retry) +{ + volatile uint32_t ul_retry_count = 0; + const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul ); + + while (!gmac_is_phy_idle(p_gmac)) { + if (ul_retry == 0) { + continue; + } + + ul_retry_count++; + + if (ul_retry_count >= ul_retry) { + return GMAC_TIMEOUT; + } + + /* Block the task to allow other tasks to execute while the PHY + is not connected. */ + vTaskDelay( xPHYPollDelay ); + } + return GMAC_OK; +} + +/** + * \brief Disable transfer, reset registers and descriptor lists. + * + * \param p_dev Pointer to GMAC driver instance. + * + */ +void gmac_reset_tx_mem(gmac_device_t* p_dev) +{ + Gmac *p_hw = p_dev->p_hw; + + uint32_t ul_index; + uint32_t ul_address; + + /* Disable TX */ + gmac_enable_transmit(p_hw, 0); + + { + for( ul_index = 0; ul_index < ARRAY_SIZE(gs_tx_desc); ul_index++ ) + { + uint32_t ulAddr = gs_tx_desc[ul_index].addr; + if (ulAddr) { + returnTxBuffer ((uint8_t *)ulAddr); + } + } + } + /* Set up the TX descriptors */ + CIRC_CLEAR(p_dev->l_tx_head, p_dev->l_tx_tail); + for( ul_index = 0; ul_index < GMAC_TX_BUFFERS; ul_index++ ) + { + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + ul_address = (uint32_t) 0u; + } + #else + { + ul_address = (uint32_t) (&(gs_uc_tx_buffer[ul_index * GMAC_TX_UNITSIZE])); + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + gs_tx_desc[ul_index].addr = ul_address; + gs_tx_desc[ul_index].status.val = GMAC_TXD_USED; + } + /* Set the WRAP bit in the last descriptor. */ + gs_tx_desc[GMAC_TX_BUFFERS - 1].status.val = GMAC_TXD_USED | GMAC_TXD_WRAP; + + /* Set transmit buffer queue */ + gmac_set_tx_queue(p_hw, (uint32_t) gs_tx_desc); + #if( SAME70 != 0 ) + { + gmac_set_tx_priority_queue(p_hw, (uint32_t)&gs_tx_desc_null, GMAC_QUE_1); + gmac_set_tx_priority_queue(p_hw, (uint32_t)&gs_tx_desc_null, GMAC_QUE_2); + /* Note that SAME70 REV B had 6 priority queues. */ + gmac_set_tx_priority_queue(p_hw, (uint32_t)&gs_tx_desc_null, GMAC_QUE_3); + gmac_set_tx_priority_queue(p_hw, (uint32_t)&gs_tx_desc_null, GMAC_QUE_4); + gmac_set_tx_priority_queue(p_hw, (uint32_t)&gs_tx_desc_null, GMAC_QUE_5); + } + #endif +} + +/** + * \brief Disable receiver, reset registers and descriptor list. + * + * \param p_dev Pointer to GMAC Driver instance. + */ +static void gmac_reset_rx_mem(gmac_device_t* p_dev) +{ + Gmac *p_hw = p_dev->p_hw; + + uint32_t ul_index; + uint32_t ul_address; + + /* Disable RX */ + gmac_enable_receive(p_hw, 0); + + /* Set up the RX descriptors */ + p_dev->ul_rx_idx = 0; + for( ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++ ) + { + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor; + + pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( GMAC_RX_UNITSIZE, 0ul ); + configASSERT( pxNextNetworkBufferDescriptor != NULL ); + ul_address = ( uint32_t )( pxNextNetworkBufferDescriptor->pucEthernetBuffer ); + } + #else + { + ul_address = ( uint32_t ) ( &( gs_uc_rx_buffer[ ul_index * GMAC_RX_UNITSIZE ] ) ); + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + gs_rx_desc[ul_index].addr.val = ul_address & GMAC_RXD_ADDR_MASK; + gs_rx_desc[ul_index].status.val = 0; + } + /* Set the WRAP bit in the last descriptor. */ + gs_rx_desc[GMAC_RX_BUFFERS - 1].addr.bm.b_wrap = 1; + + /* Set receive buffer queue */ + gmac_set_rx_queue(p_hw, (uint32_t)gs_rx_desc); +} + + +/** + * \brief Initialize the allocated buffer lists for GMAC driver to transfer data. + * Must be invoked after gmac_dev_init() but before RX/TX starts. + * + * \note If input address is not 8-byte aligned, the address is automatically + * adjusted and the list size is reduced by one. + * + * \param p_gmac Pointer to GMAC instance. + * \param p_gmac_dev Pointer to GMAC device instance. + * \param p_dev_mm Pointer to the GMAC memory management control block. + * + * \return GMAC_OK or GMAC_PARAM. + */ +static uint8_t gmac_init_mem(Gmac* p_gmac, gmac_device_t* p_gmac_dev) +{ + /* Assign TX buffers */ +#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + if ((((uint32_t) gs_uc_tx_buffer) & 0x7) + || ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) { + p_dev_mm->ul_tx_size--; + } + p_gmac_dev->p_tx_buffer = + (uint8_t *) (((uint32_t) gs_uc_tx_buffer) & 0xFFFFFFF8); +#endif + + /* Reset TX & RX Memory */ + gmac_reset_rx_mem(p_gmac_dev); + gmac_reset_tx_mem(p_gmac_dev); + + /* Enable Rx and Tx, plus the statistics register */ + gmac_enable_transmit(p_gmac, true); + gmac_enable_receive(p_gmac, true); + gmac_enable_statistics_write(p_gmac, true); + + /* Set up the interrupts for transmission and errors */ + gmac_enable_interrupt(p_gmac, + GMAC_IER_RLEX | /* Enable retry limit exceeded interrupt. */ + GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */ + GMAC_IER_ROVR | /* Enable receive overrun interrupt. */ + GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */ + GMAC_IER_TUR | /* Enable transmit underrun interrupt. */ + GMAC_IER_TFC | /* Enable transmit buffers exhausted in mid-frame interrupt. */ + GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */ + GMAC_IER_PFNZ | /* Enable pause frame received interrupt. */ + GMAC_IER_PTZ | /* Enable pause time zero interrupt. */ + GMAC_IER_RCOMP); /* Enable receive complete interrupt. */ + + return GMAC_OK; +} + +/** + * \brief Initialize the GMAC driver. + * + * \param p_gmac Pointer to the GMAC instance. + * \param p_gmac_dev Pointer to the GMAC device instance. + * \param p_opt GMAC configure options. + */ +void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev, + gmac_options_t* p_opt) +{ + /* Disable TX & RX and more */ + gmac_network_control(p_gmac, 0); + gmac_disable_interrupt(p_gmac, ~0u); + + gmac_clear_statistics(p_gmac); + + /* Clear all status bits in the receive status register. */ + gmac_clear_rx_status(p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA + | GMAC_RSR_HNO); + +#ifndef GMAC_TSR_UND + /* GMAC_TSR_UND is only defined by SAM4E. */ + #define GMAC_TSR_UND 0ul +#endif + /* Clear all status bits in the transmit status register */ + gmac_clear_tx_status(p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE + | GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND); + + /* Clear interrupts */ + gmac_get_interrupt_status(p_gmac); +#if !defined(ETHERNET_CONF_DATA_OFFSET) + /* Receive Buffer Offset + * Indicates the number of bytes by which the received data + * is offset from the start of the receive buffer + * which can be handy for alignment reasons */ + /* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */ + #error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0 +#endif + /* Enable the copy of data into the buffers + ignore broadcasts, and not copy FCS. */ + + gmac_set_config(p_gmac, + ( gmac_get_config(p_gmac) & ~GMAC_NCFGR_RXBUFO_Msk ) | + GMAC_NCFGR_RFCS | /* Remove FCS, frame check sequence (last 4 bytes) */ + GMAC_NCFGR_PEN | /* Pause Enable */ + GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) | /* Set Ethernet Offset */ + GMAC_RXD_RXCOEN ); /* RXCOEN related function */ + + /* + * GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable. + * Note: SAM4E/SAME70 do have RX checksum offloading + * but TX checksum offloading has NOT been implemented, + * at least on a SAM4E. + * http://community.atmel.com/forum/sam4e-gmac-transmit-checksum-offload-enablesolved + */ + + { + uint32_t ulValue = gmac_get_dma(p_gmac); + + /* Let the GMAC set TX checksum's. */ + ulValue |= GMAC_DCFGR_TXCOEN; + #if( SAME70 != 0 ) + { + /* Transmitter Packet Buffer Memory Size Select: + Use full configured addressable space (4 Kbytes). */ + ulValue |= GMAC_DCFGR_TXPBMS; + } + #endif + + /* Clear the DMA Receive Buffer Size (DRBS) field: */ + ulValue &= ~( GMAC_DCFGR_DRBS_Msk ); + /* And set it: */ + ulValue |= ( GMAC_RX_UNITSIZE / 64 ) << GMAC_DCFGR_DRBS_Pos; + + gmac_set_dma(p_gmac, ulValue); + } + + /* Enable/Disable Copy(Receive) All Valid Frames. */ + gmac_enable_copy_all(p_gmac, p_opt->uc_copy_all_frame); + + /* Disable/Enable broadcast receiving */ + gmac_disable_broadcast(p_gmac, p_opt->uc_no_boardcast); + + + /* Initialize memory */ + gmac_init_mem(p_gmac, p_gmac_dev); + + /* Set Mac Address */ + gmac_set_address(p_gmac, 0, p_opt->uc_mac_addr); +} + +/** + * \brief Frames can be read from the GMAC in multiple sections. + * + * Returns > 0 if a complete frame is available + * It also it cleans up incomplete older frames + */ + +static uint32_t gmac_dev_poll(gmac_device_t* p_gmac_dev) +{ + uint32_t ulReturn = 0; + int32_t ulIndex = p_gmac_dev->ul_rx_idx; + gmac_rx_descriptor_t *pxHead = &gs_rx_desc[ulIndex]; + +// #warning Just for debugging +// if((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) +// { +// NVIC_DisableIRQ( GMAC_IRQn ); +// } + + #if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + { + /* Discard any incomplete frames */ + while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) && + (pxHead->status.val & GMAC_RXD_SOF) == 0) + { + pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP); + circ_inc32 (&ulIndex, GMAC_RX_BUFFERS); + pxHead = &gs_rx_desc[ulIndex]; + p_gmac_dev->ul_rx_idx = ulIndex; + #if( GMAC_STATS != 0 ) + { + gmacStats.incompCount++; + } + #endif + } + } + #endif /* ipconfigZERO_COPY_RX_DRIVER == 0 */ + + while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) + { + #if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + { + if ((pxHead->status.val & GMAC_RXD_EOF) != 0) { + /* Here a complete frame has been seen with SOF and EOF */ + ulReturn = pxHead->status.bm.b_len; + break; + } + circ_inc32 (&ulIndex, GMAC_RX_BUFFERS); + pxHead = &gs_rx_desc[ulIndex]; + if ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) == 0) { + /* CPU is not the owner (yet) */ + break; + } + if ((pxHead->status.val & GMAC_RXD_SOF) != 0) { + /* Strange, we found a new Start Of Frame + * discard previous segments */ + int32_t ulPrev = p_gmac_dev->ul_rx_idx; + pxHead = &gs_rx_desc[ulPrev]; + do { + pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP); + circ_inc32 (&ulPrev, GMAC_RX_BUFFERS); + pxHead = &gs_rx_desc[ulPrev]; + #if( GMAC_STATS != 0 ) + { + gmacStats.truncCount++; + } + #endif + } while (ulPrev != ulIndex); + p_gmac_dev->ul_rx_idx = ulIndex; + } + } + #else /* ipconfigZERO_COPY_RX_DRIVER */ + { + if ((pxHead->status.val & (GMAC_RXD_SOF|GMAC_RXD_EOF)) == (GMAC_RXD_SOF|GMAC_RXD_EOF)) { + /* Here a complete frame in a single segment. */ + ulReturn = pxHead->status.bm.b_len; + break; + } + /* Return the buffer to DMA. */ + pxHead->addr.bm.b_ownership = 0; + + /* Let ulIndex/pxHead point to the next buffer. */ + circ_inc32 (&ulIndex, GMAC_RX_BUFFERS); + pxHead = &gs_rx_desc[ulIndex]; + /* And remember this index. */ + p_gmac_dev->ul_rx_idx = ulIndex; + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + } + return ulReturn; +} + +/** + * \brief Frames can be read from the GMAC in multiple sections. + * Read ul_frame_size bytes from the GMAC receive buffers to pcTo. + * p_rcv_size is the size of the entire frame. Generally gmac_read + * will be repeatedly called until the sum of all the ul_frame_size equals + * the value of p_rcv_size. + * + * \param p_gmac_dev Pointer to the GMAC device instance. + * \param p_frame Address of the frame buffer. + * \param ul_frame_size Length of the frame. + * \param p_rcv_size Received frame size. + * + * \return GMAC_OK if receiving frame successfully, otherwise failed. + */ +uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame, + uint32_t ul_frame_size, uint32_t* p_rcv_size, + uint8_t** pp_recv_frame) +{ + int32_t nextIdx; /* A copy of the Rx-index 'ul_rx_idx' */ + int32_t bytesLeft = gmac_dev_poll (p_gmac_dev); + gmac_rx_descriptor_t *pxHead; + + if (bytesLeft == 0 ) + { + return GMAC_RX_NO_DATA; + } + + /* gmac_dev_poll has confirmed that there is a complete frame at + * the current position 'ul_rx_idx' + */ + nextIdx = p_gmac_dev->ul_rx_idx; + + /* Read +2 bytes because buffers are aligned at -2 bytes */ + bytesLeft = min( bytesLeft + 2, ( int32_t )ul_frame_size ); + +#if( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) + SCB_InvalidateDCache(); +#endif + + #if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + { + + /* The frame will be copied in 1 or 2 memcpy's */ + if( ( p_frame != NULL ) && ( bytesLeft != 0 ) ) + { + const uint8_t *source; + int32_t left; + int32_t toCopy; + + source = gs_uc_rx_buffer + nextIdx * GMAC_RX_UNITSIZE; + left = bytesLeft; + toCopy = ( GMAC_RX_BUFFERS - nextIdx ) * GMAC_RX_UNITSIZE; + if(toCopy > left ) + { + toCopy = left; + } + memcpy (p_frame, source, toCopy); + left -= toCopy; + + if( left != 0ul ) + { + memcpy (p_frame + toCopy, (void*)gs_uc_rx_buffer, left); + } + } + } + #else /* ipconfigZERO_COPY_RX_DRIVER */ + { + if( p_frame != NULL ) + { + /* Return a pointer to the earlier DMA buffer. */ + *( pp_recv_frame ) = ( uint8_t * ) + ( ( ( gs_rx_desc[nextIdx].addr.val ) & ~( 0x03ul ) ) + 2 ); + /* Set the new DMA-buffer. */ + gs_rx_desc[nextIdx].addr.bm.addr_dw = ( ( uint32_t )p_frame ) / 4; + } + else + { + /* The driver couldn't not allocate a buffer to receive a packet. + Leave the current DMA buffer in place. */ + } + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + do + { + pxHead = &gs_rx_desc[nextIdx]; + pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP); + circ_inc32 (&nextIdx, GMAC_RX_BUFFERS); + } while ((pxHead->status.val & GMAC_RXD_EOF) == 0); + + p_gmac_dev->ul_rx_idx = nextIdx; + + *p_rcv_size = bytesLeft; + +// #warning Just for debugging +// NVIC_EnableIRQ( GMAC_IRQn ); + + return GMAC_OK; +} + +extern void vGMACGenerateChecksum( uint8_t *apBuffer, size_t uxLength ); + +/** + * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the + * GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready. + * If lEndOfFrame is true then the data being copied is the end of the frame + * and the frame can be transmitted. + * + * \param p_gmac_dev Pointer to the GMAC device instance. + * \param p_buffer Pointer to the data buffer. + * \param ul_size Length of the frame. + * + * \return Length sent. + */ +uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer, + uint32_t ul_size) +{ + volatile gmac_tx_descriptor_t *p_tx_td; + + Gmac *p_hw = p_gmac_dev->p_hw; + + + /* Check parameter */ + if (ul_size > GMAC_TX_UNITSIZE) { + return GMAC_PARAM; + } + + /* Pointers to the current transmit descriptor */ + p_tx_td = &gs_tx_desc[p_gmac_dev->l_tx_head]; + + /* If no free TxTd, buffer can't be sent, schedule the wakeup callback */ + if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) + { + return GMAC_TX_BUSY; + } + + /* Set up/copy data to transmission buffer */ + if (p_buffer && ul_size) { + /* Driver manages the ring buffer */ + /* Calculating the checksum here is faster than calculating it from the GMAC buffer + * because withing p_buffer, it is well aligned */ + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* Zero-copy... */ + p_tx_td->addr = ( uint32_t ) p_buffer; + } + #else + { + /* Or memcopy... */ + memcpy((void *)p_tx_td->addr, p_buffer, ul_size); + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr, ( size_t ) ul_size ); + } + + //#warning Trying out + gmac_start_transmission(p_hw); + + /* Update transmit descriptor status */ + + /* The buffer size defined is the length of ethernet frame, + so it's always the last buffer of the frame. */ + if( p_gmac_dev->l_tx_head == ( int32_t )( GMAC_TX_BUFFERS - 1 ) ) + { + /* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked + GMAC_TXD_USED will now be cleared. */ + p_tx_td->status.val = + ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP; + } else { + /* GMAC_TXD_USED will now be cleared. */ + p_tx_td->status.val = + ul_size | GMAC_TXD_LAST; + } + + circ_inc32( &p_gmac_dev->l_tx_head, GMAC_TX_BUFFERS ); + + /* Now start to transmit if it is still not done */ + gmac_start_transmission(p_hw); + + return GMAC_OK; +} + +/** + * \brief Get current load of transmit. + * + * \param p_gmac_dev Pointer to the GMAC device instance. + * + * \return Current load of transmit. + */ +uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev) +{ + uint16_t us_head = p_gmac_dev->l_tx_head; + uint16_t us_tail = p_gmac_dev->l_tx_tail; + return CIRC_CNT(us_head, us_tail, GMAC_TX_BUFFERS); +} + +/** + * \brief Register/Clear TX wakeup callback. + * + * When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application + * task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and + * enters suspend state. The callback is in charge to resume the task once + * several transmit descriptors have been released. The next time gmac_dev_write() will be called, + * it shall be successful. + * + * This function is usually invoked with NULL callback from the TX wakeup + * callback itself, to unregister. Once the callback has resumed the + * application task, there is no need to invoke the callback again. + * + * \param p_gmac_dev Pointer to GMAC device instance. + * \param func_wakeup Pointer to wakeup callback function. + * \param uc_threshold Number of free transmit descriptor before wakeup callback invoked. + * + * \return GMAC_OK, GMAC_PARAM on parameter error. + */ +#if( GMAC_USES_WAKEUP_CALLBACK ) +uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev, + gmac_dev_wakeup_cb_t func_wakeup_cb, uint8_t uc_threshold) +{ + if (func_wakeup_cb == NULL) { + p_gmac_dev->func_wakeup_cb = NULL; + } else { + if (uc_threshold <= GMAC_TX_BUFFERS) { + p_gmac_dev->func_wakeup_cb = func_wakeup_cb; + p_gmac_dev->ul_wakeup_threshold = ( uint32_t )uc_threshold; + } else { + return GMAC_PARAM; + } + } + + return GMAC_OK; +} +#endif /* GMAC_USES_WAKEUP_CALLBACK */ + +/** + * \brief Reset TX & RX queue & statistics. + * + * \param p_gmac_dev Pointer to GMAC device instance. + */ +void gmac_dev_reset(gmac_device_t* p_gmac_dev) +{ + Gmac *p_hw = p_gmac_dev->p_hw; + + gmac_reset_rx_mem(p_gmac_dev); + gmac_reset_tx_mem(p_gmac_dev); + gmac_network_control(p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN + | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT); +} + +void gmac_dev_halt(Gmac* p_gmac); + +void gmac_dev_halt(Gmac* p_gmac) +{ + gmac_network_control(p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT); + gmac_disable_interrupt(p_gmac, ~0u); +} + + +/** + * \brief GMAC Interrupt handler. + * + * \param p_gmac_dev Pointer to GMAC device instance. + */ + +#if( GMAC_STATS != 0 ) + extern int logPrintf( const char *pcFormat, ... ); + + void gmac_show_irq_counts () + { + int index; + for (index = 0; index < ARRAY_SIZE(intPairs); index++) { + if (gmacStats.intStatus[intPairs[index].index]) { + logPrintf("%s : %6u\n", intPairs[index].name, gmacStats.intStatus[intPairs[index].index]); + } + } + } +#endif + +void gmac_handler(gmac_device_t* p_gmac_dev) +{ + Gmac *p_hw = p_gmac_dev->p_hw; + + gmac_tx_descriptor_t *p_tx_td; + uint32_t ul_tx_status_flag; +#if( GMAC_STATS != 0 ) + int index; +#endif + + uint32_t ul_isr = gmac_get_interrupt_status(p_hw); + uint32_t ul_rsr = gmac_get_rx_status(p_hw); + uint32_t ul_tsr = gmac_get_tx_status(p_hw); + + #if( GMAC_STATS != 0 ) + { + for (index = 0; index < ARRAY_SIZE(intPairs); index++) { + if (ul_isr & intPairs[index].mask) + gmacStats.intStatus[intPairs[index].index]++; + } + } + #endif /* GMAC_STATS != 0 */ + + /* RX packet */ + if ((ul_isr & GMAC_ISR_RCOMP) || (ul_rsr & (GMAC_RSR_REC|GMAC_RSR_RXOVR|GMAC_RSR_BNA))) { + /* Clear status */ + gmac_clear_rx_status(p_hw, ul_rsr); + + if (ul_isr & GMAC_ISR_RCOMP) + ul_rsr |= GMAC_RSR_REC; + /* Invoke callbacks which can be useful to wake op a task */ + xRxCallback( ul_rsr ); + } + + /* TX packet */ + if ((ul_isr & GMAC_ISR_TCOMP) || (ul_tsr & (GMAC_TSR_TXCOMP|GMAC_TSR_COL|GMAC_TSR_RLE|GMAC_TSR_UND))) { + + ul_tx_status_flag = GMAC_TSR_TXCOMP; + /* A frame transmitted */ + + /* Check RLE */ + if (ul_tsr & GMAC_TSR_RLE) { + /* Status RLE & Number of discarded buffers */ + ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT(p_gmac_dev->l_tx_head, + p_gmac_dev->l_tx_tail, GMAC_TX_BUFFERS); + gmac_reset_tx_mem(p_gmac_dev); + gmac_enable_transmit(p_hw, 1); + } + /* Clear status */ + gmac_clear_tx_status(p_hw, ul_tsr); + + if (!CIRC_EMPTY(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail)) { + /* Check the buffers */ + do { + p_tx_td = &gs_tx_desc[p_gmac_dev->l_tx_tail]; + /* Any error? Exit if buffer has not been sent yet */ + if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) { + break; + } + + /* Notify upper layer that a packet has been sent */ + xTxCallback(ul_tx_status_flag, (void*)p_tx_td->addr); // Function call prvTxCallback + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + p_tx_td->addr = 0ul; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + circ_inc32(&p_gmac_dev->l_tx_tail, GMAC_TX_BUFFERS); + } while (CIRC_CNT(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail, + GMAC_TX_BUFFERS)); + } + + if (ul_tsr & GMAC_TSR_RLE) { + /* Notify upper layer RLE */ + xTxCallback(ul_tx_status_flag, NULL); + } + +#if( GMAC_USES_WAKEUP_CALLBACK ) + /* If a wakeup has been scheduled, notify upper layer that it can + send other packets, and the sending will be successful. */ + if ((CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail, + GMAC_TX_BUFFERS) >= p_gmac_dev->ul_wakeup_threshold) + && p_gmac_dev->func_wakeup_cb) { + p_gmac_dev->func_wakeup_cb(); + } +#endif + } +} + +//@} + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/gmac_SAM.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/gmac_SAM.h new file mode 100644 index 000000000..1965889b1 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/DriverSAM/gmac_SAM.h @@ -0,0 +1,1418 @@ + /** + * \file + * + * \brief GMAC (Ethernet MAC) driver for SAM. + * + * Copyright (c) 2013-2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> + */ + +#ifndef GMAC_H_INCLUDED +#define GMAC_H_INCLUDED + +#include "compiler.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/** The buffer addresses written into the descriptors must be aligned, so the + last few bits are zero. These bits have special meaning for the GMAC + peripheral and cannot be used as part of the address. */ +#define GMAC_RXD_ADDR_MASK 0xFFFFFFFC +#define GMAC_RXD_WRAP (1ul << 1) /**< Wrap bit */ +#define GMAC_RXD_OWNERSHIP (1ul << 0) /**< Ownership bit */ + +#define GMAC_RXD_BROADCAST (1ul << 31) /**< Broadcast detected */ +#define GMAC_RXD_MULTIHASH (1ul << 30) /**< Multicast hash match */ +#define GMAC_RXD_UNIHASH (1ul << 29) /**< Unicast hash match */ +#define GMAC_RXD_ADDR_FOUND (1ul << 27) /**< Specific address match found */ +#define GMAC_RXD_ADDR (3ul << 25) /**< Address match */ +#define GMAC_RXD_RXCOEN (1ul << 24) /**< RXCOEN related function */ +#define GMAC_RXD_TYPE (3ul << 22) /**< Type ID match */ +#define GMAC_RXD_VLAN (1ul << 21) /**< VLAN tag detected */ +#define GMAC_RXD_PRIORITY (1ul << 20) /**< Priority tag detected */ +#define GMAC_RXD_PRIORITY_MASK (3ul << 17) /**< VLAN priority */ +#define GMAC_RXD_CFI (1ul << 16) /**< Concatenation Format Indicator only if bit 21 is set */ +#define GMAC_RXD_EOF (1ul << 15) /**< End of frame */ +#define GMAC_RXD_SOF (1ul << 14) /**< Start of frame */ +#define GMAC_RXD_FCS (1ul << 13) /**< Frame check sequence */ +#define GMAC_RXD_OFFSET_MASK /**< Receive buffer offset */ +#define GMAC_RXD_LEN_MASK (0xFFF) /**< Length of frame including FCS (if selected) */ +#define GMAC_RXD_LENJUMBO_MASK (0x3FFF) /**< Jumbo frame length */ + +#define GMAC_TXD_USED (1ul << 31) /**< Frame is transmitted */ +#define GMAC_TXD_WRAP (1ul << 30) /**< Last descriptor */ +#define GMAC_TXD_ERROR (1ul << 29) /**< Retry limit exceeded, error */ +#define GMAC_TXD_UNDERRUN (1ul << 28) /**< Transmit underrun */ +#define GMAC_TXD_EXHAUSTED (1ul << 27) /**< Buffer exhausted */ +#define GMAC_TXD_LATE (1ul << 26) /**< Late collision,transmit error */ +#define GMAC_TXD_CHECKSUM_ERROR (7ul << 20) /**< Checksum error */ +#define GMAC_TXD_NOCRC (1ul << 16) /**< No CRC */ +#define GMAC_TXD_LAST (1ul << 15) /**< Last buffer in frame */ +#define GMAC_TXD_LEN_MASK (0x1FFF) /**< Length of buffer */ + +/** The MAC can support frame lengths up to 1536 bytes */ +#define GMAC_FRAME_LENTGH_MAX 1536 + +//#define GMAC_RX_UNITSIZE 128 /**< Fixed size for RX buffer */ +#define GMAC_RX_UNITSIZE 1536 /**< Fixed size for RX buffer */ + +//#define GMAC_TX_UNITSIZE 1518 /**< Size for ETH frame length */ +#define GMAC_TX_UNITSIZE 1536 /**< Size for ETH frame length */ + +/** GMAC clock speed */ +#define GMAC_MCK_SPEED_240MHZ (240*1000*1000) +#define GMAC_MCK_SPEED_160MHZ (160*1000*1000) +#define GMAC_MCK_SPEED_120MHZ (120*1000*1000) +#define GMAC_MCK_SPEED_80MHZ (80*1000*1000) +#define GMAC_MCK_SPEED_40MHZ (40*1000*1000) +#define GMAC_MCK_SPEED_20MHZ (20*1000*1000) + +/** GMAC maintain code default value*/ +#define GMAC_MAN_CODE_VALUE (10) + +/** GMAC maintain start of frame default value*/ +#define GMAC_MAN_SOF_VALUE (1) + +/** GMAC maintain read/write*/ +#define GMAC_MAN_RW_TYPE (2) + +/** GMAC maintain read only*/ +#define GMAC_MAN_READ_ONLY (1) + +/** GMAC address length */ +#define GMAC_ADDR_LENGTH (6) + + +#define GMAC_DUPLEX_HALF 0 +#define GMAC_DUPLEX_FULL 1 + +#define GMAC_SPEED_10M 0 +#define GMAC_SPEED_100M 1 + +/** + * \brief Return codes for GMAC APIs. + */ +typedef enum { + GMAC_OK = 0, /** 0 Operation OK */ + GMAC_TIMEOUT = 1, /** 1 GMAC operation timeout */ + GMAC_TX_BUSY, /** 2 TX in progress */ + GMAC_RX_NO_DATA, /** 3 No data received */ + GMAC_SIZE_TOO_SMALL, /** 4 Buffer size not enough */ + GMAC_PARAM, /** 5 Parameter error, TX packet invalid or RX size too small */ + GMAC_RX_ERROR, /** 6 RX error */ + GMAC_INVALID = 0xFF, /* Invalid */ +} gmac_status_t; + +/** + * \brief Media Independent Interface (MII) type. + */ +typedef enum { + GMAC_PHY_MII = 0, /** MII mode */ + GMAC_PHY_RMII = 1, /** Reduced MII mode */ + GMAC_PHY_INVALID = 0xFF, /* Invalid mode*/ +} gmac_mii_mode_t; + +/* This is the list of GMAC priority queue */ +typedef enum { + GMAC_QUE_0 = 0, +#if !(SAM4E) + GMAC_QUE_1 = 1, + GMAC_QUE_2 = 2, + /* Only SAM E70 Rev-B. */ + GMAC_QUE_3 = 3, + GMAC_QUE_4 = 4, + GMAC_QUE_5 = 5, +#endif +# if !defined(__DOXYGEN__) + GMAC_QUE_N, +# endif + +}gmac_quelist_t; + +/** Receive buffer descriptor struct */ +COMPILER_PACK_SET(8) +typedef struct gmac_rx_descriptor { + union gmac_rx_addr { + uint32_t val; + struct gmac_rx_addr_bm { + uint32_t b_ownership:1, /**< User clear, GMAC sets this to 1 once it has successfully written a frame to memory */ + b_wrap:1, /**< Marks last descriptor in receive buffer */ + addr_dw:30; /**< Address in number of DW */ + } bm; + } addr; /**< Address, Wrap & Ownership */ + union gmac_rx_status { + uint32_t val; + struct gmac_rx_status_bm { + uint32_t b_len:13, /** 0..12 Length of frame including FCS */ + b_fcs:1, /** 13 Receive buffer offset, bits 13:12 of frame length for jumbo frame */ + b_sof:1, /** 14 Start of frame */ + b_eof:1, /** 15 End of frame */ + b_cfi:1, /** 16 Concatenation Format Indicator */ + b_vlan_priority:3, /** 17..19 VLAN priority (if VLAN detected) */ + b_priority_detected:1, /** 20 Priority tag detected */ + b_vlan_detected:1, /** 21 VLAN tag detected */ + b_type_id_match:2, /** 22..23 Type ID match */ + b_checksumoffload:1, /** 24 Checksum offload specific function */ + b_addrmatch:2, /** 25..26 Address register match */ + b_ext_addr_match:1, /** 27 External address match found */ + reserved:1, /** 28 */ + b_uni_hash_match:1, /** 29 Unicast hash match */ + b_multi_hash_match:1, /** 30 Multicast hash match */ + b_boardcast_detect:1; /** 31 Global broadcast address detected */ + } bm; + } status; +} gmac_rx_descriptor_t; + +/** Transmit buffer descriptor struct */ +COMPILER_PACK_SET(8) +typedef struct gmac_tx_descriptor { + uint32_t addr; + union gmac_tx_status { + uint32_t val; + struct gmac_tx_status_bm { + uint32_t b_len:14, /** 0..13 Length of buffer */ + reserved:1, /** 14 */ + b_last_buffer:1, /** 15 Last buffer (in the current frame) */ + b_no_crc:1, /** 16 No CRC */ + reserved1:3, /** 17..19 */ + b_checksumoffload:3, /** 20..22 Transmit checksum generation offload errors */ + reserved2:3, /** 23..25 */ + b_lco:1, /** 26 Late collision, transmit error detected */ + b_exhausted:1, /** 27 Buffer exhausted in mid frame */ + b_underrun:1, /** 28 Transmit underrun */ + b_error:1, /** 29 Retry limit exceeded, error detected */ + b_wrap:1, /** 30 Marks last descriptor in TD list */ + b_used:1; /** 31 User clear, GMAC sets this to 1 once a frame has been successfully transmitted */ + } bm; + } status; +} gmac_tx_descriptor_t; + +COMPILER_PACK_RESET() + +/** + * \brief Input parameters when initializing the gmac module mode. + */ +typedef struct gmac_options { + /* Enable/Disable CopyAllFrame */ + uint8_t uc_copy_all_frame; + /* Enable/Disable NoBroadCast */ + uint8_t uc_no_boardcast; + /* MAC address */ + uint8_t uc_mac_addr[GMAC_ADDR_LENGTH]; +} gmac_options_t; + +/** Wakeup callback */ +typedef void (*gmac_dev_wakeup_cb_t) (void); + +/** + * GMAC driver structure. + */ +typedef struct gmac_device { + + /** Pointer to HW register base */ + Gmac *p_hw; + /** + * Pointer to allocated TX buffer. + * Section 3.6 of AMBA 2.0 spec states that burst should not cross + * 1K Boundaries. + * Receive buffer manager writes are burst of 2 words => 3 lsb bits + * of the address shall be set to 0. + */ +#if( GMAC_USES_WAKEUP_CALLBACK != 0 ) + /** Optional callback to be invoked once several TDs have been released */ + gmac_dev_wakeup_cb_t func_wakeup_cb; +#endif + /** RX index for current processing TD */ + uint32_t ul_rx_idx; + /** Circular buffer head pointer by upper layer (buffer to be sent) */ + int32_t l_tx_head; + /** Circular buffer tail pointer incremented by handlers (buffer sent) */ + int32_t l_tx_tail; + + /** Number of free TD before wakeup callback is invoked */ + uint32_t ul_wakeup_threshold; +} gmac_device_t; + +uint8_t gmac_wait_phy(Gmac* p_gmac, const uint32_t ul_retry); + +/** + * \brief Write network control value. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_ncr Network control value. + */ +static inline void gmac_network_control(Gmac* p_gmac, uint32_t ul_ncr) +{ + p_gmac->GMAC_NCR = ul_ncr; +} + +/** + * \brief Get network control value. + * + * \param p_gmac Pointer to the GMAC instance. + */ + +static inline uint32_t gmac_get_network_control(Gmac* p_gmac) +{ + return p_gmac->GMAC_NCR; +} + +/** + * \brief Enable/Disable GMAC receive. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC receiver, else to enable it. + */ +static inline void gmac_enable_receive(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_RXEN; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_RXEN; + } +} + +/** + * \brief Enable/Disable GMAC transmit. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC transmit, else to enable it. + */ +static inline void gmac_enable_transmit(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_TXEN; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_TXEN; + } +} + +/** + * \brief Enable/Disable GMAC management. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC management, else to enable it. + */ +static inline void gmac_enable_management(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_MPE; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_MPE; + } +} + +/** + * \brief Clear all statistics registers. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_clear_statistics(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_CLRSTAT; +} + +/** + * \brief Increase all statistics registers. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_increase_statistics(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_INCSTAT; +} + +/** + * \brief Enable/Disable statistics registers writing. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the statistics registers writing, else to enable it. + */ +static inline void gmac_enable_statistics_write(Gmac* p_gmac, + uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_WESTAT; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_WESTAT; + } +} + +/** + * \brief In half-duplex mode, forces collisions on all received frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the back pressure, else to enable it. + */ +static inline void gmac_enable_back_pressure(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_BP; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_BP; + } +} + +/** + * \brief Start transmission. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_start_transmission(Gmac* p_gmac) +{ + __DSB(); + p_gmac->GMAC_NCR |= GMAC_NCR_TSTART; +} + +/** + * \brief Halt transmission. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_halt_transmission(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_THALT; +} + +/** + * \brief Transmit pause frame. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_tx_pause_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXPF; +} + +/** + * \brief Transmit zero quantum pause frame. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_tx_pause_zero_quantum_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXZQPF; +} + +/** + * \brief Store receivetime stamp to memory. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to normal operation, else to enable the store. + */ +static inline void gmac_store_rx_time_stamp(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_SRTSM; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_SRTSM; + } +} + +/** + * \brief Enable PFC priority-based pause reception. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 1 to set the reception, 0 to disable. + */ +static inline void gmac_enable_pfc_pause_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_ENPBPR; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_ENPBPR; + } +} + +/** + * \brief Transmit PFC priority-based pause reception. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_transmit_pfc_pause_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXPBPF; +} + +/** + * \brief Flush next packet. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_flush_next_packet(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_FNP; +} + +/** + * \brief Set up network configuration register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_cfg Network configuration value. + */ +static inline void gmac_set_config(Gmac* p_gmac, uint32_t ul_cfg) +{ + p_gmac->GMAC_NCFGR = ul_cfg; +} + +/* Get and set DMA Configuration Register */ +static inline void gmac_set_dma(Gmac* p_gmac, uint32_t ul_cfg) +{ + p_gmac->GMAC_DCFGR = ul_cfg; +} + +static inline uint32_t gmac_get_dma(Gmac* p_gmac) +{ + return p_gmac->GMAC_DCFGR; +} + +/** + * \brief Get network configuration. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Network configuration. + */ +static inline uint32_t gmac_get_config(Gmac* p_gmac) +{ + return p_gmac->GMAC_NCFGR; +} + +/** + * \brief Set speed. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_speed 1 to indicate 100Mbps, 0 to 10Mbps. + */ +static inline void gmac_set_speed(Gmac* p_gmac, uint8_t uc_speed) +{ + if (uc_speed) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_SPD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_SPD; + } +} + +/** + * \brief Enable/Disable Full-Duplex mode. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the Full-Duplex mode, else to enable it. + */ +static inline void gmac_enable_full_duplex(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_FD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_FD; + } +} + +/** + * \brief Enable/Disable Copy(Receive) All Valid Frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable copying all valid frames, else to enable it. + */ +static inline void gmac_enable_copy_all(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_CAF; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_CAF; + } +} + +/** + * \brief Enable/Disable jumbo frames (up to 10240 bytes). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the jumbo frames, else to enable it. + */ +static inline void gmac_enable_jumbo_frames(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_JFRAME; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_JFRAME; + } +} + +/** + * \brief Disable/Enable broadcast receiving. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 1 to disable the broadcast, else to enable it. + */ +static inline void gmac_disable_broadcast(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_NBC; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_NBC; + } +} + +/** + * \brief Enable/Disable multicast hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the multicast hash, else to enable it. + */ +static inline void gmac_enable_multicast_hash(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_UNIHEN; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_UNIHEN; + } +} + +/** + * \brief Enable/Disable big frames (over 1518, up to 1536). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable big frames else to enable it. + */ +static inline void gmac_enable_big_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_MAXFS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_MAXFS; + } +} + +/** + * \brief Set MDC clock divider. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_mck GMAC MCK. + * + * \return GMAC_OK if successfully. + */ +static inline uint8_t gmac_set_mdc_clock(Gmac* p_gmac, uint32_t ul_mck) +{ + uint32_t ul_clk, ul_value; + + if (ul_mck > GMAC_MCK_SPEED_240MHZ) { + return GMAC_INVALID; + } else if (ul_mck > GMAC_MCK_SPEED_160MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_96; + } else if (ul_mck > GMAC_MCK_SPEED_120MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_64; + } else if (ul_mck > GMAC_MCK_SPEED_80MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_48; + } else if (ul_mck > GMAC_MCK_SPEED_40MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_32; + } else if (ul_mck > GMAC_MCK_SPEED_20MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_16; + } else { + ul_clk = GMAC_NCFGR_CLK_MCK_8; + } + ul_value = p_gmac->GMAC_NCFGR; + ul_value &= ~GMAC_NCFGR_CLK_Msk; + ul_value |= ul_clk; + p_gmac->GMAC_NCFGR = ul_value; + return GMAC_OK; +} + +/** + * \brief Enable/Disable retry test. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the GMAC receiver, else to enable it. + */ +static inline void gmac_enable_retry_test(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RTY; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RTY; + } +} + +/** + * \brief Enable/Disable pause (when a valid pause frame is received). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable pause frame, else to enable it. + */ +static inline void gmac_enable_pause_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_PEN; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_PEN; + } +} + +/** + * \brief Set receive buffer offset to 0 ~ 3. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_set_rx_buffer_offset(Gmac* p_gmac, uint8_t uc_offset) +{ + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RXBUFO_Msk; + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(uc_offset); +} + +/** + * \brief Enable/Disable receive length field checking. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable receive length field checking, else to enable it. + */ +static inline void gmac_enable_rx_length_check(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_LFERD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_LFERD; + } +} + +/** + * \brief Enable/Disable discarding FCS field of received frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable discarding FCS field of received frames, else to enable it. + */ +static inline void gmac_enable_discard_fcs(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RFCS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RFCS; + } +} + + +/** + * \brief Enable/Disable frames to be received in half-duplex mode + * while transmitting. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the received in half-duplex mode, else to enable it. + */ +static inline void gmac_enable_efrhd(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_EFRHD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_EFRHD; + } +} + +/** + * \brief Enable/Disable ignore RX FCS. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable ignore RX FCS, else to enable it. + */ +static inline void gmac_enable_ignore_rx_fcs(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_IRXFCS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_IRXFCS; + } +} + +/** + * \brief Get Network Status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Network status. + */ +static inline uint32_t gmac_get_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_NSR; +} + +/** + * \brief Get MDIO IN pin status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return MDIO IN pin status. + */ +static inline uint8_t gmac_get_MDIO(Gmac* p_gmac) +{ + return ((p_gmac->GMAC_NSR & GMAC_NSR_MDIO) > 0); +} + +/** + * \brief Check if PHY is idle. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return 1 if PHY is idle. + */ +static inline uint8_t gmac_is_phy_idle(Gmac* p_gmac) +{ + return ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) > 0); +} + +/** + * \brief Return transmit status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Transmit status. + */ +static inline uint32_t gmac_get_tx_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_TSR; +} + +/** + * \brief Clear transmit status. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_status Transmit status. + */ +static inline void gmac_clear_tx_status(Gmac* p_gmac, uint32_t ul_status) +{ + p_gmac->GMAC_TSR = ul_status; +} + +/** + * \brief Return receive status. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline uint32_t gmac_get_rx_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_RSR; +} + +/** + * \brief Clear receive status. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_status Receive status. + */ +static inline void gmac_clear_rx_status(Gmac* p_gmac, uint32_t ul_status) +{ + p_gmac->GMAC_RSR = ul_status; +} + +/** + * \brief Set Rx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_addr Rx queue address. + */ +static inline void gmac_set_rx_queue(Gmac* p_gmac, uint32_t ul_addr) +{ + p_gmac->GMAC_RBQB = GMAC_RBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Set Rx buffer size. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_addr Rx buffer. + */ +static inline void gmac_set_rx_bufsize(Gmac* p_gmac, uint32_t ul_code) +{ + p_gmac->GMAC_DCFGR = (p_gmac->GMAC_DCFGR & ~GMAC_DCFGR_DRBS_Msk) + | GMAC_DCFGR_DRBS(ul_code); +} + +/** + * \brief Get Rx Queue Address. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Rx queue address. + */ +static inline uint32_t gmac_get_rx_queue(Gmac* p_gmac) +{ + return p_gmac->GMAC_RBQB; +} + +/** + * \brief Set Tx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_addr Tx queue address. + */ +static inline void gmac_set_tx_queue(Gmac* p_gmac, uint32_t ul_addr) +{ + p_gmac->GMAC_TBQB = GMAC_TBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Get Tx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Rx queue address. + */ +static inline uint32_t gmac_get_tx_queue(Gmac* p_gmac) +{ + return p_gmac->GMAC_TBQB; +} + +/** + * \brief Enable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be enabled. + */ +static inline void gmac_enable_interrupt(Gmac* p_gmac, uint32_t ul_source) +{ + p_gmac->GMAC_IER = ul_source; +} + +/** + * \brief Disable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be disabled. + */ +static inline void gmac_disable_interrupt(Gmac* p_gmac, uint32_t ul_source) +{ + p_gmac->GMAC_IDR = ul_source; +} + +/** + * \brief Return interrupt status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Interrupt status. + */ +static inline uint32_t gmac_get_interrupt_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_ISR; +} + +/** + * \brief Return interrupt mask. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Interrupt mask. + */ +static inline uint32_t gmac_get_interrupt_mask(Gmac* p_gmac) +{ + return p_gmac->GMAC_IMR; +} + +/** + * \brief Execute PHY maintenance command. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param uc_reg_addr Register address. + * \param uc_rw 1 to Read, 0 to write. + * \param us_data Data to be performed, write only. + */ +static inline void gmac_maintain_phy(Gmac* p_gmac, + uint8_t uc_phy_addr, uint8_t uc_reg_addr, uint8_t uc_rw, + uint16_t us_data) +{ + /* Wait until bus idle */ + while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Write maintain register */ + p_gmac->GMAC_MAN = GMAC_MAN_WTN(GMAC_MAN_CODE_VALUE) + | GMAC_MAN_CLTTO + | GMAC_MAN_PHYA(uc_phy_addr) + | GMAC_MAN_REGA(uc_reg_addr) + | GMAC_MAN_OP((uc_rw ? GMAC_MAN_RW_TYPE : GMAC_MAN_READ_ONLY)) + | GMAC_MAN_DATA(us_data); +} + +/** + * \brief Get PHY maintenance data returned. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Get PHY data. + */ +static inline uint16_t gmac_get_phy_data(Gmac* p_gmac) +{ + /* Wait until bus idle */ + while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Return data */ + return (uint16_t) (p_gmac->GMAC_MAN & GMAC_MAN_DATA_Msk); +} + +/** + * \brief Set Hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_hash_top Hash top. + * \param ul_hash_bottom Hash bottom. + */ +static inline void gmac_set_hash(Gmac* p_gmac, uint32_t ul_hash_top, + uint32_t ul_hash_bottom) +{ + p_gmac->GMAC_HRB = ul_hash_bottom; + p_gmac->GMAC_HRT = ul_hash_top; +} + +/** + * \brief Set 64 bits Hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ull_hash 64 bits hash value. + */ +static inline void gmac_set_hash64(Gmac* p_gmac, uint64_t ull_hash) +{ + p_gmac->GMAC_HRB = (uint32_t) ull_hash; + p_gmac->GMAC_HRT = (uint32_t) (ull_hash >> 32); +} + +/** + * \brief Set MAC Address. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param p_mac_addr GMAC address. + */ +static inline void gmac_set_address(Gmac* p_gmac, uint8_t uc_index, + const uint8_t* p_mac_addr) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = (p_mac_addr[3] << 24) + | (p_mac_addr[2] << 16) + | (p_mac_addr[1] << 8) + | (p_mac_addr[0]); + p_gmac->GMAC_SA[uc_index].GMAC_SAT = (p_mac_addr[5] << 8) + | (p_mac_addr[4]); +} + +/** + * \brief Set MAC Address via 2 dword. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param ul_mac_top GMAC top address. + * \param ul_mac_bottom GMAC bottom address. + */ +static inline void gmac_set_address32(Gmac* p_gmac, uint8_t uc_index, + uint32_t ul_mac_top, uint32_t ul_mac_bottom) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = ul_mac_bottom; + p_gmac->GMAC_SA[uc_index].GMAC_SAT = ul_mac_top; +} + +/** + * \brief Set MAC Address via int64. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param ull_mac 64-bit GMAC address. + */ +static inline void gmac_set_address64(Gmac* p_gmac, uint8_t uc_index, + uint64_t ull_mac) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = (uint32_t) ull_mac; + p_gmac->GMAC_SA[uc_index].GMAC_SAT = (uint32_t) (ull_mac >> 32); +} + +/** + * \brief Select media independent interface mode. + * + * \param p_gmac Pointer to the GMAC instance. + * \param mode Media independent interface mode. + */ +#if (SAM4E) +static inline void gmac_select_mii_mode(Gmac* p_gmac, gmac_mii_mode_t mode) +{ + switch (mode) { + case GMAC_PHY_MII: + case GMAC_PHY_RMII: + p_gmac->GMAC_UR |= GMAC_UR_RMIIMII; + break; + + default: + p_gmac->GMAC_UR &= ~GMAC_UR_RMIIMII; + break; + } +} +#else +static inline void gmac_select_mii_mode(Gmac* p_gmac, gmac_mii_mode_t mode) +{ + switch (mode) { + case GMAC_PHY_MII: + p_gmac->GMAC_UR |= GMAC_UR_RMII; + break; + + case GMAC_PHY_RMII: + default: + p_gmac->GMAC_UR &= ~GMAC_UR_RMII; + break; + } +} +#endif + +#if !(SAM4E) +/** + * \brief Set 1588 timer comparison. + * + * \param p_gmac Pointer to the GMAC instance. + * \param seconds47 Second comparison high + * \param seconds31 Second comparison low + * \param nanosec Nanosecond Comparison + */ +static inline void gmac_set_tsu_compare(Gmac *p_gmac, uint32_t seconds47, uint32_t seconds31, uint32_t nanosec) +{ + p_gmac->GMAC_SCH = seconds47; + p_gmac->GMAC_SCL = seconds31; + p_gmac->GMAC_NSC = nanosec; +} + +/** + * \brief Get interrupt status. + * + * \param p_gmac Pointer to the GMAC instance. + * \param queue_idx Index of queue, start from 1 + * + * \return Interrupt status. + */ +static inline uint32_t gmac_get_priority_interrupt_status(Gmac* p_gmac, gmac_quelist_t queue_idx) +{ + return p_gmac->GMAC_ISRPQ[queue_idx - 1]; +} + +/** + * \brief Set base address of TX buffer. + * + * \param p_gmac Pointer to the GMAC instance. + * \param queue_idx Index of queue, start from 1 + */ +static inline void gmac_set_tx_priority_queue(Gmac* p_gmac, uint32_t ul_addr, gmac_quelist_t queue_idx) +{ + p_gmac->GMAC_TBQBAPQ[queue_idx - 1] = GMAC_TBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Get base address of TX buffer. + * + * \param p_gmac Pointer to the GMAC instance. + * \param queue_idx Index of queue, start from 1 + * + * \return Base address. + */ +static inline uint32_t gmac_get_tx_priority_queue(Gmac* p_gmac, gmac_quelist_t queue_idx) +{ + return p_gmac->GMAC_TBQBAPQ[queue_idx - 1]; +} + +/** + * \brief Set base address of RX buffer. + * + * \param p_gmac Pointer to the GMAC instance. + * \param queue_idx Index of queue, start from 1 + */ +static inline void gmac_set_rx_priority_queue(Gmac* p_gmac, uint32_t ul_addr, gmac_quelist_t queue_idx) +{ + p_gmac->GMAC_RBQBAPQ[queue_idx - 1] = GMAC_RBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Get base address of RX buffer. + * + * \param p_gmac Pointer to the GMAC instance. + * \param queue_idx Index of queue, start from 1 + * + * \return Base address. + */ +static inline uint32_t gmac_get_rx_priority_queue(Gmac* p_gmac, gmac_quelist_t queue_idx) +{ + return p_gmac->GMAC_RBQBAPQ[queue_idx - 1]; +} + +/** + * \brief Set size of RX buffer. + * + * \param p_gmac Pointer to the GMAC instance. + * \param queue_idx Index of queue, start from 1 + */ +static inline void gmac_set_rx_priority_bufsize(Gmac* p_gmac, uint32_t ul_size, gmac_quelist_t queue_idx) +{ + p_gmac->GMAC_RBSRPQ[queue_idx - 1] = ul_size; +} + +/** + * \brief Enable or disable credit-based shaping on the second highest priority queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable, 1 to enable it + */ +static inline void gmac_enable_cbsque_a(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_CBSCR |= GMAC_CBSCR_QAE; + } else { + p_gmac->GMAC_CBSCR &= ~GMAC_CBSCR_QAE; + } +} + +/** + * \brief Enable or disable credit-based shaping on the highest priority queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable, 1 to enable it + */ +static inline void gmac_enable_cbsque_b(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_CBSCR |= GMAC_CBSCR_QBE; + } else { + p_gmac->GMAC_CBSCR &= ~GMAC_CBSCR_QBE; + } +} + +/** + * \brief Set credit-based shaping on the highest priority queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param idleslope_a Value for queue A in bytes/second + */ +static inline void gmac_config_idleslope_a(Gmac* p_gmac, uint32_t idleslope_a) +{ + p_gmac->GMAC_CBSISQA = idleslope_a; +} + +/** + * \brief Set credit-based shaping on the highest priority queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param idleslope_b Value for queue B in bytes/second + */ +static inline void gmac_config_idleslope_b(Gmac* p_gmac, uint32_t idleslope_b) +{ + p_gmac->GMAC_CBSISQB = idleslope_b; +} + +/** + * \brief Set screening type 1 register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param reg_val Value for screening type 1 + * \param index Index of register + */ +static inline void gmac_write_screener_reg_1(Gmac* p_gmac, uint32_t reg_val, uint32_t index) +{ + p_gmac->GMAC_ST1RPQ[index] = reg_val; +} + +/** + * \brief Set screening type 2 register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param reg_val Value for screening type 2 + * \param index Index of register + */ +static inline void gmac_write_screener_reg_2 (Gmac* p_gmac, uint32_t reg_val, uint32_t index) +{ + p_gmac->GMAC_ST2RPQ[index] = reg_val; +} + +/** + * \brief Enable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be enabled. + * \param queue_idx Index of queue, start from 1 + */ +static inline void gmac_enable_priority_interrupt(Gmac* p_gmac, uint32_t ul_source, gmac_quelist_t queue_idx) +{ + p_gmac->GMAC_IERPQ[queue_idx - 1] = ul_source; +} + +/** + * \brief Disable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be disabled. + * \param queue_idx Index of queue, start from 1 + */ +static inline void gmac_disable_priority_interrupt(Gmac* p_gmac, uint32_t ul_source, gmac_quelist_t queue_idx) +{ + p_gmac->GMAC_IDRPQ[queue_idx - 1] = ul_source; +} + +/** + * \brief Get interrupt mask. + * + * \param p_gmac Pointer to the GMAC instance. + * \param queue_idx Index of queue, start from 1 + * + * \return Interrupt mask. + */ +static inline uint32_t gmac_get_priority_interrupt_mask(Gmac* p_gmac, gmac_quelist_t queue_idx) +{ + return p_gmac->GMAC_IMRPQ[queue_idx - 1]; +} + +/** + * \brief Set screening type 2 eherType register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ethertype Ethertype compare value + * \param index Index of register + */ +static inline void gmac_write_ethtype_reg(Gmac* p_gmac, uint16_t ethertype, uint32_t index) +{ + p_gmac->GMAC_ST2ER[index] = (uint32_t)ethertype; +} + +/** + * \brief Set screening type 2 compare word register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param c0reg Compare value 0 + * \param c1reg Compare value 1 + * \param index Index of register + */ +static inline void gmac_write_screen_compare_reg(Gmac* p_gmac, uint32_t c0reg, uint16_t c1reg, uint32_t index) +{ + volatile uint32_t *p_PRAS; + uint32_t ul_dlt; + + ul_dlt = (uint32_t)&(p_gmac->GMAC_ST2CW01); + ul_dlt = ul_dlt - (uint32_t)&(p_gmac->GMAC_ST2CW00); + + p_PRAS = (volatile uint32_t *)((uint32_t)&(p_gmac->GMAC_ST2CW00) + + index * ul_dlt); + *p_PRAS = c0reg; + p_PRAS = (volatile uint32_t *)((uint32_t)&(p_gmac->GMAC_ST2CW10) + + index * ul_dlt); + *p_PRAS = (uint32_t)c1reg; +} + +#endif /* !(SAM4E) */ + +uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address, + uint32_t* p_value); +uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address, + uint8_t uc_address, uint32_t ul_value); +void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev, + gmac_options_t* p_opt); +uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame, + uint32_t ul_frame_size, uint32_t* p_rcv_size, uint8_t** pp_recv_frame); +uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer, + uint32_t ul_size); +uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev); +uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev, + gmac_dev_wakeup_cb_t func_wakeup, uint8_t uc_threshold); +void gmac_dev_reset(gmac_device_t* p_gmac_dev); +void gmac_handler(gmac_device_t* p_gmac_dev); + +void gmac_reset_tx_mem(gmac_device_t* p_dev); + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + + +# define GMAC_STATS 0 + +#if( GMAC_STATS != 0 ) + + /* Here below some code to study the types and + frequencies of GMAC interrupts. */ + #define GMAC_IDX_RXUBR 0 + #define GMAC_IDX_TUR 1 + #define GMAC_IDX_RLEX 2 + #define GMAC_IDX_TFC 3 + #define GMAC_IDX_RCOMP 4 + #define GMAC_IDX_TCOMP 5 + #define GMAC_IDX_ROVR 6 + #define GMAC_IDX_HRESP 7 + #define GMAC_IDX_PFNZ 8 + #define GMAC_IDX_PTZ 9 + + struct SGmacStats { + unsigned recvCount; + unsigned rovrCount; + unsigned bnaCount; + unsigned sendCount; + unsigned sovrCount; + unsigned incompCount; + unsigned truncCount; + + unsigned intStatus[10]; + }; + extern struct SGmacStats gmacStats; + + struct SIntPair { + const char *name; + unsigned mask; + int index; + }; + + #define MK_PAIR( NAME ) #NAME, GMAC_IER_##NAME, GMAC_IDX_##NAME + static const struct SIntPair intPairs[] = { + { MK_PAIR( RXUBR ) }, /* Enable receive used bit read interrupt. */ + { MK_PAIR( TUR ) }, /* Enable transmit underrun interrupt. */ + { MK_PAIR( RLEX ) }, /* Enable retry limit exceeded interrupt. */ + { MK_PAIR( TFC ) }, /* Enable transmit buffers exhausted in mid-frame interrupt. */ + { MK_PAIR( RCOMP ) }, /* Receive complete */ + { MK_PAIR( TCOMP ) }, /* Enable transmit complete interrupt. */ + { MK_PAIR( ROVR ) }, /* Enable receive overrun interrupt. */ + { MK_PAIR( HRESP ) }, /* Enable Hresp not OK interrupt. */ + { MK_PAIR( PFNZ ) }, /* Enable pause frame received interrupt. */ + { MK_PAIR( PTZ ) } /* Enable pause time zero interrupt. */ + }; + + void gmac_show_irq_counts (); + +#endif + +#endif /* GMAC_H_INCLUDED */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c index e0d04e454..8bd539614 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -100,7 +100,7 @@ extern uint8_t ucMACAddress[ 6 ]; if( xStatus != ERROR )
{
vSemaphoreCreateBinary( xEMACRxEventSemaphore );
- configASSERT( xEMACRxEventSemaphore );
+ configASSERT( xEMACRxEventSemaphore != NULL );
/* The handler task is created at the highest possible priority to
ensure the interrupt handler can return directly to it. */
@@ -212,7 +212,7 @@ IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; extern uint8_t *EMAC_NextPacketToRead( void );
( void ) pvParameters;
- configASSERT( xEMACRxEventSemaphore );
+ configASSERT( xEMACRxEventSemaphore != NULL );
for( ;; )
{
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c index ac01d41af..e01602b9d 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -81,7 +81,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #endif
#ifndef iptraceEMAC_TASK_STARTING
- #define iptraceEMAC_TASK_STARTING() do { } while( 0 )
+ #define iptraceEMAC_TASK_STARTING() do { } while( ipFALSE_BOOL )
#endif
/* Define the bits of .STATUS that indicate a reception error. */
@@ -284,7 +284,7 @@ BaseType_t xReturn = pdPASS; if( xRxHanderTask == NULL )
{
xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", nwRX_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );
- configASSERT( xReturn );
+ configASSERT( xReturn != NULL );
}
if( xTXDescriptorSemaphore == NULL )
@@ -292,7 +292,7 @@ BaseType_t xReturn = pdPASS; /* Create a counting semaphore, with a value of 'configNUM_TX_DESCRIPTORS'
and a maximum of 'configNUM_TX_DESCRIPTORS'. */
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) configNUM_TX_DESCRIPTORS, ( UBaseType_t ) configNUM_TX_DESCRIPTORS );
- configASSERT( xTXDescriptorSemaphore );
+ configASSERT( xTXDescriptorSemaphore != NULL );
}
/* Enable MAC interrupts. */
@@ -526,7 +526,7 @@ BaseType_t x; /* Use an assert to check the allocation as +TCP applications will
often not use a malloc() failed hook as the TCP stack will recover
from allocation failures. */
- configASSERT( xDMATxDescriptors[ x ].B1ADD );
+ configASSERT( xDMATxDescriptors[ x ].B1ADD != 0U );
}
#endif
@@ -592,7 +592,7 @@ BaseType_t x; /* Use an assert to check the allocation as +TCP applications will often
not use a malloc failed hook as the TCP stack will recover from
allocation failures. */
- configASSERT( xDMARxDescriptors[ x ].B1ADD );
+ configASSERT( xDMARxDescriptors[ x ].B1ADD != 0U );
xDMARxDescriptors[ x ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ x + 1 ] );
xDMARxDescriptors[ x ].CTRL = ( uint32_t ) RDES_ENH_BS1( ipTOTAL_ETHERNET_FRAME_SIZE ) | RDES_ENH_RCH;
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c index e759141cc..2149a7bdd 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c index 44d19f3a9..92b1573f7 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c index 84019d637..aa3a1f58e 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c @@ -4,7 +4,7 @@ */ /* -FreeRTOS+TCP V2.0.11 +FreeRTOS+TCP V2.2.1 Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -828,7 +828,7 @@ const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer; #endif ) { /* Drop this packet, not for this device. */ - FreeRTOS_printf( ( "Drop: UDP port %d -> %d\n", usSourcePort, usDestinationPort ) ); + /* FreeRTOS_printf( ( "Drop: UDP port %d -> %d\n", usSourcePort, usDestinationPort ) ); */ return pdFALSE; } } @@ -1178,9 +1178,9 @@ BaseType_t xReturn; void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) { static -#if defined(STM32F7xx) - __attribute__ ((section(".first_data"))) -#endif + #if defined(STM32F7xx) + __attribute__ ((section(".first_data"))) + #endif uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ETH_MAX_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); uint8_t *ucRAMBuffer = ucNetworkPackets; uint32_t ul; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c index 474629e46..511b27859 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -445,6 +445,11 @@ void pcap_callback( u_char *user, const struct pcap_pkthdr *pkt_header, const u_ if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) )
{
+ /* The received packets will be written to a C source file,
+ only if 'ipconfigUSE_DUMP_PACKETS' is defined.
+ Otherwise, there is no action. */
+ iptraceDUMP_PACKET( ( const uint8_t* ) pkt_data, ( size_t ) pkt_header->caplen, pdTRUE );
+
uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_header, sizeof( *pkt_header ) );
uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_data, ( size_t ) pkt_header->caplen );
}
@@ -489,6 +494,10 @@ const DWORD xMaxMSToWait = 1000; {
uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE );
uxStreamBufferGet( xSendBuffer, 0, ( uint8_t* ) ucBuffer, xLength, pdFALSE );
+ /* The packets sent will be written to a C source file,
+ only if 'ipconfigUSE_DUMP_PACKETS' is defined.
+ Otherwise, there is no action. */
+ iptraceDUMP_PACKET( ucBuffer, xLength, pdFALSE );
if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 )
{
ulWinPCAPSendFailures++;
@@ -498,6 +507,31 @@ const DWORD xMaxMSToWait = 1000; }
/*-----------------------------------------------------------*/
+static BaseType_t xPacketBouncedBack( const uint8_t *pucBuffer )
+{
+EthernetHeader_t *pxEtherHeader;
+BaseType_t xResult;
+
+ pxEtherHeader = ( EthernetHeader_t * ) pucBuffer;
+ if( memcmp( ucMACAddress, pxEtherHeader->xSourceAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 )
+ {
+ FreeRTOS_printf( ( "Bounced back: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pxEtherHeader->xSourceAddress.ucBytes[ 0 ],
+ pxEtherHeader->xSourceAddress.ucBytes[ 1 ],
+ pxEtherHeader->xSourceAddress.ucBytes[ 2 ],
+ pxEtherHeader->xSourceAddress.ucBytes[ 3 ],
+ pxEtherHeader->xSourceAddress.ucBytes[ 4 ],
+ pxEtherHeader->xSourceAddress.ucBytes[ 5 ] ) );
+ xResult = pdTRUE;
+ }
+ else
+ {
+ xResult = pdFALSE;
+ }
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
static void prvInterruptSimulatorTask( void *pvParameters )
{
struct pcap_pkthdr xHeader;
@@ -545,7 +579,14 @@ eFrameProcessingResult_t eResult; is ok to call the task level function here, but note that
some buffer implementations cannot be called from a real
interrupt. */
- pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 );
+ if( xPacketBouncedBack( pucPacketData ) == pdFALSE )
+ {
+ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 );
+ }
+ else
+ {
+ pxNetworkBuffer = NULL;
+ }
if( pxNetworkBuffer != NULL )
{
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c index 4a6af81f9..dab007ba8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c @@ -238,7 +238,7 @@ BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, }
}
#endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */
- if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0uL )
+ if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0UL )
{
iptraceNETWORK_INTERFACE_TRANSMIT();
emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend );
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt index 10a72b464..a1185c104 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt @@ -10,6 +10,11 @@ Please include the following source files: $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_hw.c +The file uncached_memory.c can also be found in: + + vendors\xilinx\boards\microzed\aws_demos\application_code\xilinx_code + vendors\xilinx\boards\microzed\aws_tests\application_code\xilinx_code + And include the following source files from the Xilinx library: $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps.c diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/NetworkInterface.c index aa0a646b4..251640d7e 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/board_family/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -41,23 +41,23 @@ considers need processing. */ BaseType_t xNetworkInterfaceInitialise( void )
{
- /* FIX ME. */
- return pdFALSE;
+ /* FIX ME. */
+ return pdFALSE;
}
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t xReleaseAfterSend )
{
- /* FIX ME. */
- return pdFALSE;
+ /* FIX ME. */
+ return pdFALSE;
}
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
- /* FIX ME. */
+ /* FIX ME. */
}
BaseType_t xGetPhyLinkStatus( void )
{
- /* FIX ME. */
- return pdFALSE;
+ /* FIX ME. */
+ return pdFALSE;
}
\ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c index 544e5ba09..4df3ac370 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -351,7 +351,7 @@ const TickType_t x5_Seconds = 5000UL; /* The handler task is created at the highest possible priority to
ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
- configASSERT( xEMACTaskHandle );
+ configASSERT( xEMACTaskHandle != NULL );
}
/* When returning non-zero, the stack will become active and
@@ -1059,7 +1059,7 @@ static void ksz8851snl_low_level_init( void ) if( ksz8851snl_init() < 0 )
{
FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) );
- configASSERT(0 == 1);
+ configASSERT( ipFALSE_BOOL );
}
memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) );
ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) );
@@ -1166,7 +1166,7 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS ); /* Remove compiler warnings about unused parameters. */
( void ) pvParameters;
- configASSERT( xEMACTaskHandle );
+ configASSERT( xEMACTaskHandle != NULL );
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux/NetworkInterface.c new file mode 100644 index 000000000..41f28a0d2 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/linux/NetworkInterface.c @@ -0,0 +1,889 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/* ========================= FreeRTOS includes ============================== */ +#include "FreeRTOS.h" +#include "event_groups.h" +#include "task.h" +#include "semphr.h" + +/* ========================= FreeRTOS+TCP includes ========================== */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* ======================== Standard Library inludes ======================== */ +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <pthread.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/sysinfo.h> +#include <signal.h> +#include <pcap.h> + +/* ========================== Local includes =================================*/ +#include "utils/wait_for_event.h" + +/* ======================== Macro Definitions =============================== */ +#if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 ) + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) \ + eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +/* ============================== Definitions =============================== */ +#define xSEND_BUFFER_SIZE 32768 +#define xRECV_BUFFER_SIZE 32768 +#define MAX_CAPTURE_LEN 65535 +#define IP_SIZE 100 + +/* ================== Static Function Prototypes ============================ */ +static int prvConfigureCaptureBehaviour( void ); +static int prvCreateThreadSafeBuffers( void ); +static void * prvLinuxPcapSendThread( void *pvParam ); +static void * prvLinuxPcapRecvThread( void *pvParam ); +static void prvInterruptSimulatorTask( void *pvParameters ); +static void prvPrintAvailableNetworkInterfaces( pcap_if_t * pxAllNetworkInterfaces ); +static pcap_if_t * prvGetAvailableNetworkInterfaces( void ); +static const char * prvRemoveSpaces( char *pcBuffer, + int aBuflen, + const char *pcMessage ); +static int prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); +static int prvCreateWorkerThreads( void ); +static int prvSetDeviceModes( void ); +static void print_hex( unsigned const char * const bin_data, + size_t len ); + +/* ======================== Static Global Variables ========================= */ +static StreamBuffer_t *xSendBuffer = NULL; +static StreamBuffer_t *xRecvBuffer = NULL; +extern uint8_t ucMACAddress[ 6 ]; +static char errbuf[ PCAP_ERRBUF_SIZE ]; +static pcap_t *pxOpenedInterfaceHandle = NULL; +static struct event *pvSendEvent = NULL; +static uint32_t ulPCAPSendFailures = 0; +static BaseType_t xConfigNetworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE; +static BaseType_t xInvalidInterfaceDetected = pdFALSE; + +/* ======================= API Function definitions ========================= */ + +/*! + * @brief API call, called from reeRTOS_IP.c to initialize the capture device + * to be able to send and receive packets + * @return pdPASS if successful else pdFAIL + */ +BaseType_t xNetworkInterfaceInitialise( void ) +{ +BaseType_t ret = pdFAIL; +pcap_if_t *pxAllNetworkInterfaces; + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvGetAvailableNetworkInterfaces(); + + if( pxAllNetworkInterfaces != NULL ) + { + prvPrintAvailableNetworkInterfaces( pxAllNetworkInterfaces ); + ret = prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + + if( ret == pdPASS ) + { + ret = prvCreateThreadSafeBuffers(); + + if( ret == pdPASS ) + { + ret = prvCreateWorkerThreads(); + } + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + } + + if( ( pxOpenedInterfaceHandle != NULL ) && ( ret == pdPASS ) ) + { + ret = pdPASS; + } + + return ret; +} + +/*! + * @brief API call, called from reeRTOS_IP.c to send a network packet over the + * selected interface + * @return pdTRUE if successful else pdFALSE + */ +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, + BaseType_t bReleaseAfterSend ) +{ +size_t xSpace; + + iptraceNETWORK_INTERFACE_TRANSMIT(); + configASSERT( xIsCallingFromIPTask() == pdTRUE ); + + /* Both the length of the data being sent and the actual data being sent + are placed in the thread safe buffer used to pass data between the FreeRTOS + tasks and the pthread that sends data via the pcap library. Drop + the packet if there is insufficient space in the buffer to hold both. */ + xSpace = uxStreamBufferGetSpace( xSendBuffer ); + + if( ( pxNetworkBuffer->xDataLength <= + ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) && + ( xSpace >= ( pxNetworkBuffer->xDataLength + + sizeof( pxNetworkBuffer->xDataLength ) ) ) ) + { + /* First write in the length of the data, then write in the data + itself. */ + uxStreamBufferAdd( xSendBuffer, + 0, + ( const uint8_t * ) &( pxNetworkBuffer->xDataLength ), + sizeof( pxNetworkBuffer->xDataLength ) ); + uxStreamBufferAdd( xSendBuffer, + 0, + ( const uint8_t * ) pxNetworkBuffer->pucEthernetBuffer, + pxNetworkBuffer->xDataLength ); + } + else + { + FreeRTOS_printf( ( "xNetworkInterfaceOutput: send buffers full to store %lu\n", + pxNetworkBuffer->xDataLength ) ); + } + + /* Kick the Tx task in either case in case it doesn't know the buffer is + full. */ + event_signal( pvSendEvent ); + + /* The buffer has been sent so can be released. */ + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + + return pdPASS; +} + +/* ====================== Static Function definitions ======================= */ + +/*! + * @brief create thread safe buffers to send/receive packets between threads + * @returns + */ +static int prvCreateThreadSafeBuffers( void ) +{ +int ret = pdFAIL; + + /* The buffer used to pass data to be transmitted from a FreeRTOS task to + the linux thread that sends via the pcap library. */ + do + { + if( xSendBuffer == NULL ) + { + xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 ); + + if( xSendBuffer == NULL ) + { + break; + } + + configASSERT( xSendBuffer ); + memset( xSendBuffer, '\0', sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) ); + xSendBuffer->LENGTH = xSEND_BUFFER_SIZE + 1; + } + + /* The buffer used to pass received data from the pthread that receives + via the pcap library to the FreeRTOS task. */ + if( xRecvBuffer == NULL ) + { + xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 ); + + if( xRecvBuffer == NULL ) + { + break; + } + + configASSERT( xRecvBuffer ); + memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) ); + xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1; + } + + ret = pdPASS; + } while( 0 ); + + return ret; +} + +/*! + * @brief print network interfaces available on the system + * @param[in] pxAllNetworkInterfaces interface structure list to print + */ +static void prvPrintAvailableNetworkInterfaces( pcap_if_t * pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +int32_t lInterfaceNumber = 1; +char cBuffer[ 512 ]; + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; + xInterface != NULL; xInterface = xInterface->next ) + { + /* The descriptions of the devices can be full of spaces, clean them + a little. printf() can only be used here because the network is not + up yet - so no other network tasks will be running. */ + printf( "Interface %d - %s\n", + lInterfaceNumber, + prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->name ) ); + printf( " (%s)\n", + prvRemoveSpaces( cBuffer, + sizeof( cBuffer ), + xInterface->description ? xInterface->description : + "No description" ) ); + printf( "\n" ); + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \nNo network interfaces were found.\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by " ); + printf( "\"configNETWORK_INTERFACE_TO_USE\", which\r\nshould be defined in FreeRTOSConfig.h\r\n" ); + + if( ( xConfigNetworkInterfaceToUse < 1L ) || ( xConfigNetworkInterfaceToUse >= lInterfaceNumber ) ) + { + printf( "\r\nERROR: configNETWORK_INTERFACE_TO_USE is set to %ld, which is an invalid value.\r\n", xConfigNetworkInterfaceToUse ); + printf( "Please set configNETWORK_INTERFACE_TO_USE to one of the interface numbers listed above,\r\n" ); + printf( "then re-compile and re-start the application. Only Ethernet (as opposed to WiFi)\r\n" ); + printf( "interfaces are supported.\r\n\r\nHALTING\r\n\r\n\r\n" ); + xInvalidInterfaceDetected = pdTRUE; + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + else + { + printf( "Attempting to open interface number %ld.\n", xConfigNetworkInterfaceToUse ); + } +} + +/*! + * @brief get network interfaces from the system + * @returns the structure list containing all found devices + */ +static pcap_if_t * prvGetAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL; + + if( xInvalidInterfaceDetected == pdFALSE ) + { + int ret; + ret = pcap_findalldevs( &pxAllNetworkInterfaces, errbuf ); + + if( ret == PCAP_ERROR ) + { + FreeRTOS_printf( ( "Could not obtain a list of network interfaces\n%s\n", + errbuf ) ); + pxAllNetworkInterfaces = NULL; + } + else + { + printf( "\r\n\r\nThe following network interfaces are available:\r\n\r\n" ); + } + } + + return pxAllNetworkInterfaces; +} + +/*! + * @brief set device operation modes + * @returns pdPASS on success pdFAIL on failure + */ +static int prvSetDeviceModes() +{ +int ret = pdFAIL; + + /* + Open in promiscuous mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + traffic to the simulated IP address to be routed + to uIP, and traffic to the real IP address to be + routed to the Linux TCP/IP stack. + */ + FreeRTOS_debug_printf( ( "setting device modes of operation...\n" ) ); + + do + { + ret = pcap_set_promisc( pxOpenedInterfaceHandle, 1 ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not activate promisuous mode\n" ) ); + break; + } + + ret = pcap_set_snaplen( pxOpenedInterfaceHandle, + ipTOTAL_ETHERNET_FRAME_SIZE ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not set snaplen\n" ) ); + break; + } + + ret = pcap_set_timeout( pxOpenedInterfaceHandle, 200 ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not set timeout\n" ) ); + break; + } + + ret = pcap_set_buffer_size( pxOpenedInterfaceHandle, + ipTOTAL_ETHERNET_FRAME_SIZE * 1100 ); + + if( ( ret != 0 ) && ( ret != PCAP_ERROR_ACTIVATED ) ) + { + FreeRTOS_printf( ( "coult not set buffer size\n" ) ); + break; + } + + ret = pdPASS; + } while( 0 ); + + return ret; +} + +/*! + * @brief open selected interface given its name + * @param [in] pucName interface name to pen + * @returns pdPASS on success pdFAIL on failure + */ +static int prvOpenInterface( const char *pucName ) +{ +static char pucInterfaceName[ 256 ]; +int ret = pdFAIL; + + if( pucName != NULL ) + { + ( void ) strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) ); + pucInterfaceName[ sizeof( pucInterfaceName ) - ( size_t ) 1 ] = '\0'; + + FreeRTOS_debug_printf( ( "opening interface %s\n", pucInterfaceName ) ); + + pxOpenedInterfaceHandle = pcap_create( pucInterfaceName, errbuf ); + + if( pxOpenedInterfaceHandle != NULL ) + { + ret = prvSetDeviceModes(); + + if( ret == pdPASS ) + { + if( pcap_activate( pxOpenedInterfaceHandle ) == 0 ) + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + ret = prvConfigureCaptureBehaviour(); + } + else + { + FreeRTOS_debug_printf( ( "pcap activate error %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ) ); + ret = pdFAIL; + } + } + } + else + { + FreeRTOS_printf( ( "\n%s is not supported by pcap and cannot be opened %s\n", + pucInterfaceName, errbuf ) ); + } + } + else + { + FreeRTOS_printf( ( "could not open interface: name is null\n" ) ); + } + + return ret; +} + +/*! + * @brief Open the network interface. The number of the interface to be opened is + * set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h + * Calling this function will set the pxOpenedInterfaceHandle variable + * If, after calling this function, pxOpenedInterfaceHandle + * is equal to NULL, then the interface could not be opened. + * @param [in] pxAllNetworkInterfaces network interface list to choose from + * @returns pdPASS on success or pdFAIL when something goes wrong + */ +static int prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *pxInterface; +int32_t x; +int ret = pdFAIL; + + /* Walk the list of devices until the selected device is located. */ + pxInterface = pxAllNetworkInterfaces; + + for( x = 0L; x < ( xConfigNetworkInterfaceToUse - 1L ); x++ ) + { + pxInterface = pxInterface->next; + } + + /* Open the selected interface. */ + if( prvOpenInterface( pxInterface->name ) == pdPASS ) + { + FreeRTOS_debug_printf( ( "Successfully opened interface number %d.\n", x + 1 ) ); + ret = pdPASS; + } + else + { + FreeRTOS_printf( ( "Failed to open interface number %d.\n", x + 1 ) ); + } + + return ret; +} + +/*! + * @brief launch 2 linux threads, one for Tx and one for Rx + * and one FreeRTOS thread that will simulate an interrupt + * and notify the tcp/ip stack of new data + * @return pdPASS on success otherwise pdFAIL + */ +static int prvCreateWorkerThreads( void ) +{ +pthread_t vPcapRecvThreadHandle; +pthread_t vPcapSendThreadHandle; +int ret = pdPASS; + + if( pvSendEvent == NULL ) + { + FreeRTOS_debug_printf( ( "Creating Threads ..\n" ) ); + ret = pdFAIL; + /* Create event used to signal the pcap Tx thread. */ + pvSendEvent = event_create(); + + do + { + /* Create the thread that handles pcap Rx. */ + ret = pthread_create( &vPcapRecvThreadHandle, + NULL, + prvLinuxPcapRecvThread, + NULL ); + + if( ret != 0 ) + { + FreeRTOS_printf( ( "pthread error %d", ret ) ); + break; + } + + /* Create the thread that handles pcap Tx. */ + ret = pthread_create( &vPcapSendThreadHandle, + NULL, + prvLinuxPcapSendThread, + NULL ); + + if( ret != 0 ) + { + FreeRTOS_printf( ( "pthread error %d", ret ) ); + break; + } + + ret = pdPASS; + } while( 0 ); + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the IP task when data + is available. */ + if( xTaskCreate( prvInterruptSimulatorTask, + "MAC_ISR", + configMINIMAL_STACK_SIZE, + NULL, + configMAC_ISR_SIMULATOR_PRIORITY, + NULL ) != pdPASS ) + { + ret = pdFAIL; + FreeRTOS_printf( ( "xTaskCreate could not create a new task\n" ) ); + } + } + + return ret; +} + +/*! + * @brief Create the buffers used to pass packets between the FreeRTOS simulator + * and the pthreads that are handling pcap as well as the FreeRTOS task + * responsible of simulating an interrupt. + * @returns pdPASS when successful and pdFAIL when there is a failure + */ +static int prvConfigureCaptureBehaviour( void ) +{ + struct bpf_program xFilterCode; + uint32_t ulNetMask; + char pcap_filter[ 500 ]; + int ret = pdFAIL; + + FreeRTOS_debug_printf( ( "Configuring Capture behaviour\n" ) ); + + /* Set up a filter so only the packets of interest are passed to the IP + stack. errbuf is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( pcap_filter, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x", + ucMACAddress[ 0 ], + ucMACAddress[ 1 ], + ucMACAddress[ 2 ], + ucMACAddress[ 3 ], + ucMACAddress[ 4 ], + ucMACAddress[ 5 ] ); + FreeRTOS_debug_printf( ( "pcap filter to compile: %s\n", pcap_filter ) ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + ret = pcap_compile( pxOpenedInterfaceHandle, + &xFilterCode, + pcap_filter, + 1, + ulNetMask ); + + if( ret < 0 ) + { + ( void ) printf( "\nThe packet filter string is invalid %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ); + } + else + { + ret = pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ); + + if( ret < 0 ) + { + ( void ) printf( "\nAn error occurred setting the packet filter. %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ); + } + else + { + ret = pdPASS; + } + + /* When pcap_compile() succeeds, it allocates memory for the memory pointed to by the bpf_program struct + parameter.pcap_freecode() will free that memory. */ + pcap_freecode( &xFilterCode ); + } + + return ret; +} + +/*! + * @brief callback function called from pcap_dispatch function when new + * data arrives on the interface + * @param [in] user data sent to pcap_dispatch + * @param [in] pkt_header received packet header + * @param [in] pkt_data received packet data + * @warning this is called from a Linux thread, do not attempt any FreeRTOS calls + */ +static void pcap_callback( unsigned char *user, + const struct pcap_pkthdr *pkt_header, + const u_char *pkt_data ) +{ + FreeRTOS_debug_printf( ( "Receiving < =========== network callback user: %s len: %d caplen: %d\n", + user, + pkt_header->len, + pkt_header->caplen ) ); + print_hex( pkt_data, pkt_header->len ); + + /* Pass data to the FreeRTOS simulator on a thread safe circular buffer. */ + if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) && + ( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) ) + { + uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t * ) pkt_header, sizeof( *pkt_header ) ); + uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t * ) pkt_data, ( size_t ) pkt_header->caplen ); + } +} + +/*! + * @brief infinite loop pthread to read from pcap + * @param [in] pvParam not used + * @returns NULL + * @warning this is called from a Linux thread, do not attempt any FreeRTOS calls + * @remarks This function disables signal, to prevent it from being put into + * sleep byt the posix port + */ +static void * prvLinuxPcapRecvThread( void *pvParam ) +{ +int ret; + + ( void ) pvParam; + + /* Disable signals to this thread since this is a Linux pthread to be able to + * printf and other blocking operations without being interruped and put in + * suspension mode by the linux port signals + */ + sigset_t set; + sigfillset( &set ); + pthread_sigmask( SIG_SETMASK, &set, NULL ); + + for( ; ; ) + { + ret = pcap_dispatch( pxOpenedInterfaceHandle, 1, + pcap_callback, ( u_char * ) "mydata" ); + + if( ret == -1 ) + { + FreeRTOS_printf( ( "pcap_dispatch error received: %s\n", + pcap_geterr( pxOpenedInterfaceHandle ) ) ); + } + } + + return NULL; +} + +/*! + * @brief Infinite loop thread that waits for events when there is data + * available then sends the data on the interface + * @param [in] pvParam not used + * @returns NULL + * @warning this is called from a Linux thread, do not attempt any FreeRTOS calls + */ +static void * prvLinuxPcapSendThread( void *pvParam ) +{ +size_t xLength; +uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ]; +const time_t xMaxMSToWait = 1000; + + ( void ) pvParam; + + /* disable signals to avoid treating this thread as a FreeRTOS task and puting + * it to sleep by the scheduler */ + sigset_t set; + sigfillset( &set ); + pthread_sigmask( SIG_SETMASK, &set, NULL ); + + for( ; ; ) + { + /* Wait until notified of something to send. */ + event_wait_timed( pvSendEvent, xMaxMSToWait ); + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this pthread?*/ + while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) ) + { + uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) ucBuffer, xLength, pdFALSE ); + FreeRTOS_debug_printf( ( "Sending ========== > data pcap_sendpadcket %lu\n", xLength ) ); + print_hex( ucBuffer, xLength ); + + if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 ) + { + FreeRTOS_printf( ( "pcap_sendpackeet: send failed %d\n", ulPCAPSendFailures ) ); + ulPCAPSendFailures++; + } + } + } + + return NULL; +} + +/*! + * @brief FreeRTOS infinite loop thread that simulates a network interrupt to notify the + * network stack of the presence of new data + * @param [in] pvParameters not used + */ +static void prvInterruptSimulatorTask( void *pvParameters ) +{ + struct pcap_pkthdr xHeader; + static struct pcap_pkthdr *pxHeader; + const uint8_t *pucPacketData; + uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ]; + NetworkBufferDescriptor_t *pxNetworkBuffer; + IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + eFrameProcessingResult_t eResult; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + for( ; ; ) + { + /* Does the circular buffer used to pass data from the pthread thread that + handles pacap Rx into the FreeRTOS simulator contain another packet? */ + if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) ) + { + /* Get the next packet. */ + uxStreamBufferGet( xRecvBuffer, 0, ( uint8_t * ) &xHeader, sizeof( xHeader ), pdFALSE ); + uxStreamBufferGet( xRecvBuffer, 0, ( uint8_t * ) ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE ); + pucPacketData = ucRecvBuffer; + pxHeader = &xHeader; + + iptraceNETWORK_INTERFACE_RECEIVE(); + + /* Check for minimal size. */ + if( pxHeader->len >= sizeof( EthernetHeader_t ) ) + { + eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData ); + } + else + { + eResult = eReleaseBuffer; + } + + if( eResult == eProcessBuffer ) + { + /* Will the data fit into the frame buffer? */ + if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE ) + { + /* Obtain a buffer into which the data can be placed. This + is only an interrupt simulator, not a real interrupt, so it + is ok to call the task level function here, but note that + some buffer implementations cannot be called from a real + interrupt. */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 ); + + if( pxNetworkBuffer != NULL ) + { + memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len ); + pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len; + + #if ( niDISRUPT_PACKETS == 1 ) + { + pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData ); + } + #endif /* niDISRUPT_PACKETS */ + + if( pxNetworkBuffer != NULL ) + { + xRxEvent.pvData = ( void * ) pxNetworkBuffer; + + /* Data was received and stored. Send a message to + the IP task to let it know. */ + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL ) + { + /* The buffer could not be sent to the stack so + must be released again. This is only an + interrupt simulator, not a real interrupt, so it + is ok to use the task level function here, but + note no all buffer implementations will allow + this function to be executed from a real + interrupt. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + iptraceETHERNET_RX_EVENT_LOST(); + } + } + else + { + /* The packet was already released or stored inside + vRxFaultInjection(). Don't release it here. */ + } + } + else + { + iptraceETHERNET_RX_EVENT_LOST(); + } + } + else + { + /* Log that a packet was dropped because it would have + overflowed the buffer, but there may be more buffers to + process. */ + } + } + } + else + { + /* There is no real way of simulating an interrupt. Make sure + other tasks can run. */ + vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ); + } + } +} + +/*! + * @brief remove spacces from pcMessage into pcBuffer + * @param [out] pcBuffer buffer to fill up + * @param [in] aBuflen length of pcBuffer + * @param [in] pcMessage original message + * @returns + */ +static const char * prvRemoveSpaces( char *pcBuffer, + int aBuflen, + const char *pcMessage ) +{ +char *pcTarget = pcBuffer; + + /* Utility function used to formap messages being printed only. */ + while( ( *pcMessage != 0 ) && ( pcTarget < ( &pcBuffer[ aBuflen - 1 ] ) ) ) + { + *( pcTarget++ ) = *pcMessage; + + if( isspace( *pcMessage ) != pdFALSE ) + { + while( isspace( *pcMessage ) != pdFALSE ) + { + pcMessage++; + } + } + else + { + pcMessage++; + } + } + + *pcTarget = '\0'; + + return pcBuffer; +} + +/*! + * @brief print binary packet in hex + * @param [in] bin_daa data to print + * @param [in] len length of the data + */ +static void print_hex( unsigned const char * const bin_data, + size_t len ) +/*static void print_hex(unsigned char *bin_data, size_t len) */ +{ +size_t i; + + for( i = 0; i < len; ++i ) + { + FreeRTOS_debug_printf( ( "%.2X ", bin_data[ i ] ) ); + } + + FreeRTOS_debug_printf( ( "\n" ) ); +} diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/mw300_rd/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/mw300_rd/NetworkInterface.c index 87161fd39..f6d152a8c 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/mw300_rd/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/mw300_rd/NetworkInterface.c @@ -1,5 +1,5 @@ /*
-FreeRTOS+TCP V2.0.11
+FreeRTOS+TCP V2.2.1
Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
|