Skip to content

Commit b33224b

Browse files
htiboschHein Tiboschactions-user
authored
IPv4/single SAME70 emac race condition (#567)
* Implemented Maty's solution * Added a new statistic 'tx_write_fail' * Uncrustify: triggered by comment. Co-authored-by: Hein Tibosch <[email protected]> Co-authored-by: GitHub Action <[email protected]>
1 parent e4e236a commit b33224b

File tree

3 files changed

+130
-74
lines changed

3 files changed

+130
-74
lines changed

source/portable/NetworkInterface/DriverSAM/NetworkInterface.c

Lines changed: 64 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@
5353
/* This file is included to see if 'CONF_BOARD_ENABLE_CACHE' is defined. */
5454
#include "conf_board.h"
5555

56+
/* The SAME70 family has the possibility of caching RAM.
57+
* 'NETWORK_BUFFERS_CACHED' can be defined in either "conf_eth.h"
58+
* or in "FreeRTOSIPConfig.h".
59+
* For now, NETWORK_BUFFERS_CACHED should be defined as zero.
60+
* D-cache may be enabled.
61+
*/
62+
#if ( NETWORK_BUFFERS_CACHED != 0 )
63+
#error please define this macro as zero
64+
#endif
5665

5766
/* Interrupt events to process. Currently only the Rx event is processed
5867
* although code for other events is included to allow for possible future
@@ -95,10 +104,9 @@
95104
#define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
96105
#endif
97106

98-
#if ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE )
107+
#if ( NETWORK_BUFFERS_CACHED != 0 ) && ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE )
99108
#include "core_cm7.h"
100109
#warning This driver assumes the presence of DCACHE
101-
#define NETWORK_BUFFERS_CACHED 1
102110
#define CACHE_LINE_SIZE 32
103111
#define NETWORK_BUFFER_HEADER_SIZE ( ipconfigPACKET_FILLER_SIZE + 8 )
104112

@@ -113,26 +121,24 @@
113121
uint32_t size )
114122
{
115123
/* SAME70 does not have clean/invalidate per area. */
116-
/* SCB_CleanInvalidateDCache_by_Addr( ( uint32_t * )addr, size); */
117-
SCB_CleanInvalidateDCache();
124+
SCB_CleanInvalidateDCache_by_Addr( ( uint32_t * ) addr, size );
118125
}
119126
/*-----------------------------------------------------------*/
120127

121-
static void cache_invalidate_by_addr( addr,
122-
size ) \
128+
static void cache_invalidate_by_addr( uint32_t addr,
129+
uint32_t size )
123130
{
124131
/* SAME70 does not have clean/invalidate per area. */
125-
/* SCB_InvalidateDCache_by_Addr( ( uint32_t * )addr, size); */
126-
SCB_InvalidateDCache();
132+
SCB_InvalidateDCache_by_Addr( ( uint32_t * ) addr, size );
127133
}
128134
/*-----------------------------------------------------------*/
129135

130-
#else /* if ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) */
136+
#else /* The DMA buffers are located in non-cached RAM. */
131137
#warning Sure there is no caching?
132138
#define cache_clean_invalidate() do {} while( 0 )
133139
#define cache_clean_invalidate_by_addr( addr, size ) do {} while( 0 )
134140
#define cache_invalidate_by_addr( addr, size ) do {} while( 0 )
135-
#endif /* if ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) */
141+
#endif /* if ( NETWORK_BUFFERS_CACHED != 0 ) && ( __DCACHE_PRESENT != 0 ) && defined( CONF_BOARD_ENABLE_CACHE ) */
136142

137143
/*-----------------------------------------------------------*/
138144

@@ -186,13 +192,8 @@ static void hand_tx_errors( void );
186192

187193
/*-----------------------------------------------------------*/
188194

189-
/* Bit map of outstanding ETH interrupt events for processing. Currently only
190-
* the Rx interrupt is handled, although code is included for other events to
191-
* enable future expansion. */
192-
static volatile uint32_t ulISREvents;
193-
194195
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
195-
static volatile BaseType_t xGMACSwitchRequired;
196+
static BaseType_t xGMACSwitchRequired;
196197

197198
/* LLMNR multicast address. */
198199
static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
@@ -205,8 +206,9 @@ static gmac_device_t gs_gmac_dev;
205206
* related interrupts. */
206207
TaskHandle_t xEMACTaskHandle = NULL;
207208

209+
/* TX buffers that have been sent must be returned to the driver
210+
* using this queue. */
208211
static QueueHandle_t xTxBufferQueue;
209-
int tx_release_count[ 4 ];
210212

211213
/* xTXDescriptorSemaphore is a counting semaphore with
212214
* a maximum count of GMAC_TX_BUFFERS, which is the number of
@@ -271,21 +273,21 @@ void xRxCallback( uint32_t ulStatus )
271273
if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
272274
{
273275
/* let the prvEMACHandlerTask know that there was an RX event. */
274-
ulISREvents |= EMAC_IF_RX_EVENT;
275-
/* Only an RX interrupt can wakeup prvEMACHandlerTask. */
276-
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
276+
xTaskNotifyFromISR( xEMACTaskHandle, EMAC_IF_RX_EVENT, eSetBits, &( xGMACSwitchRequired ) );
277277
}
278278
}
279279
/*-----------------------------------------------------------*/
280280

281+
/* The following function can be called by gmac_reset_tx_mem().
282+
*/
281283
void returnTxBuffer( uint8_t * puc_buffer )
282284
{
283285
/* Called from a non-ISR context. */
284286
if( xTxBufferQueue != NULL )
285287
{
288+
/* return 'puc_buffer' to the pool of transmission buffers. */
286289
xQueueSend( xTxBufferQueue, &puc_buffer, 0 );
287-
xTaskNotifyGive( xEMACTaskHandle );
288-
ulISREvents |= EMAC_IF_TX_EVENT;
290+
xTaskNotify( xEMACTaskHandle, EMAC_IF_TX_EVENT, eSetBits );
289291
}
290292
}
291293

@@ -295,11 +297,21 @@ void xTxCallback( uint32_t ulStatus,
295297
if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
296298
{
297299
/* let the prvEMACHandlerTask know that there was an TX event. */
298-
ulISREvents |= EMAC_IF_TX_EVENT;
299300
/* Wakeup prvEMACHandlerTask. */
300-
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
301-
xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
302-
tx_release_count[ 2 ]++;
301+
if( puc_buffer == NULL )
302+
{
303+
/* (GMAC_TSR) Retry Limit Exceeded */
304+
/* Can not send logging, we're in an ISR. */
305+
}
306+
else
307+
{
308+
xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
309+
xTaskNotifyFromISR( xEMACTaskHandle, EMAC_IF_TX_EVENT, eSetBits, &( xGMACSwitchRequired ) );
310+
311+
/* TX statistics. Only works when 'GMAC_STATS'
312+
* is defined as 1. See gmac_SAM.h for more information. */
313+
TX_STAT_INCREMENT( tx_callback );
314+
}
303315
}
304316
}
305317
/*-----------------------------------------------------------*/
@@ -445,7 +457,9 @@ BaseType_t xNetworkInterfaceInitialise( void )
445457

446458
if( xTXDescriptorSemaphore == NULL )
447459
{
448-
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
460+
/* When there are N TX descriptors, we want to use
461+
* at most "N-1" simultaneously. */
462+
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS - 1U, ( UBaseType_t ) GMAC_TX_BUFFERS - 1U );
449463
configASSERT( xTXDescriptorSemaphore );
450464
}
451465

@@ -483,7 +497,6 @@ static void hand_tx_errors( void )
483497
gmac_enable_transmit( GMAC, false );
484498

485499
/* Reinit TX descriptors. */
486-
/* gmac_tx_init(ps_gmac_dev); */
487500
gmac_reset_tx_mem( &gs_gmac_dev );
488501
/* Clear error status. */
489502
gmac_clear_tx_status( GMAC, GMAC_TX_ERRORS );
@@ -498,7 +511,7 @@ BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescript
498511
BaseType_t bReleaseAfterSend )
499512
{
500513
/* Do not wait too long for a free TX DMA buffer. */
501-
const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
514+
const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50U );
502515
uint32_t ulTransmitSize;
503516

504517
ulTransmitSize = pxDescriptor->xDataLength;
@@ -514,6 +527,8 @@ BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescript
514527
* statement. */
515528
do
516529
{
530+
uint32_t ulResult;
531+
517532
if( xPhyObject.ulLinkStatusMask == 0ul )
518533
{
519534
/* Do not attempt to send packets as long as the Link Status is low. */
@@ -531,10 +546,11 @@ BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescript
531546
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
532547
{
533548
/* Time-out waiting for a free TX descriptor. */
534-
tx_release_count[ 3 ]++;
549+
TX_STAT_INCREMENT( tx_enqueue_fail );
535550
break;
536551
}
537552

553+
TX_STAT_INCREMENT( tx_enqueue_ok );
538554
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
539555
{
540556
/* Confirm that the pxDescriptor may be kept by the driver. */
@@ -550,7 +566,12 @@ BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescript
550566
}
551567
#endif
552568

553-
gmac_dev_write( &gs_gmac_dev, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
569+
ulResult = gmac_dev_write( &gs_gmac_dev, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
570+
571+
if( ulResult != GMAC_OK )
572+
{
573+
TX_STAT_INCREMENT( tx_write_fail );
574+
}
554575

555576
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
556577
{
@@ -594,7 +615,7 @@ static BaseType_t prvGMACInit( void )
594615

595616
{
596617
/* Set MDC clock divider. */
597-
gmac_set_mdc_clock( GMAC, sysclk_get_cpu_hz() );
618+
gmac_set_mdc_clock( GMAC, sysclk_get_peripheral_hz() );
598619

599620
vPhyInitialise( &xPhyObject, xPHY_Read, xPHY_Write );
600621
xPhyDiscover( &xPhyObject );
@@ -840,7 +861,7 @@ void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkB
840861
static void prvEMACHandlerTask( void * pvParameters )
841862
{
842863
UBaseType_t uxCount;
843-
UBaseType_t uxLowestSemCount = 0;
864+
UBaseType_t uxLowestSemCount = GMAC_TX_BUFFERS + 1;
844865

845866
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
846867
NetworkBufferDescriptor_t * pxBuffer;
@@ -849,6 +870,7 @@ static void prvEMACHandlerTask( void * pvParameters )
849870
BaseType_t xResult = 0;
850871
uint32_t xStatus;
851872
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
873+
uint32_t ulISREvents = 0U;
852874

853875
/* Remove compiler warnings about unused parameters. */
854876
( void ) pvParameters;
@@ -879,26 +901,21 @@ static void prvEMACHandlerTask( void * pvParameters )
879901
}
880902
#endif /* ( ipconfigHAS_PRINTF != 0 ) */
881903

882-
if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
883-
{
884-
/* No events to process now, wait for the next. */
885-
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
886-
}
904+
/* Wait for a new event or a time-out. */
905+
xTaskNotifyWait( 0U, /* ulBitsToClearOnEntry */
906+
EMAC_IF_ALL_EVENT, /* ulBitsToClearOnExit */
907+
&( ulISREvents ), /* pulNotificationValue */
908+
ulMaxBlockTime );
887909

888910
if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
889911
{
890-
ulISREvents &= ~EMAC_IF_RX_EVENT;
891-
892912
/* Wait for the EMAC interrupt to indicate that another packet has been
893913
* received. */
894914
xResult = prvEMACRxPoll();
895915
}
896916

897917
if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
898918
{
899-
/* Future extension: code to release TX buffers if zero-copy is used. */
900-
ulISREvents &= ~EMAC_IF_TX_EVENT;
901-
902919
while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
903920
{
904921
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
@@ -908,21 +925,21 @@ static void prvEMACHandlerTask( void * pvParameters )
908925
if( pxBuffer != NULL )
909926
{
910927
vReleaseNetworkBufferAndDescriptor( pxBuffer );
911-
tx_release_count[ 0 ]++;
928+
TX_STAT_INCREMENT( tx_release_ok );
912929
}
913930
else
914931
{
915-
tx_release_count[ 1 ]++;
932+
TX_STAT_INCREMENT( tx_release_bad );
916933
}
917934
}
918935
#else /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
919936
{
920-
tx_release_count[ 0 ]++;
937+
TX_STAT_INCREMENT( tx_release_ok );
921938
}
922939
#endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
923940
uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
924941

925-
if( uxCount < GMAC_TX_BUFFERS )
942+
if( uxCount < ( GMAC_TX_BUFFERS - 1 ) )
926943
{
927944
/* Tell the counting semaphore that one more TX descriptor is available. */
928945
xSemaphoreGive( xTXDescriptorSemaphore );
@@ -933,7 +950,6 @@ static void prvEMACHandlerTask( void * pvParameters )
933950
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
934951
{
935952
/* Future extension: logging about errors that occurred. */
936-
ulISREvents &= ~EMAC_IF_ERR_EVENT;
937953
}
938954

939955
gmac_enable_management( GMAC, true );

0 commit comments

Comments
 (0)