Skip to content

Commit 8492a50

Browse files
authored
Zynq driver: avoid race conditions (#1286)
* Zynq driver: avoid race conditions * Corrected a comment
1 parent 4b5f938 commit 8492a50

File tree

4 files changed

+57
-40
lines changed

4 files changed

+57
-40
lines changed

source/portable/NetworkInterface/Zynq/NetworkInterface.c

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,20 @@ static BaseType_t xZynqNetworkInterfaceOutput( NetworkInterface_t * pxInterface,
431431
iptraceNETWORK_INTERFACE_TRANSMIT();
432432

433433
/* emacps_send_message() will take ownership of pxBuffer, and
434-
* make sure it will get release when bReleaseAfterSend is pdTRUE. */
435-
emacps_send_message( &( xEMACpsifs[ xEMACIndex ] ), pxBuffer, bReleaseAfterSend );
434+
* make sure it will get release when bReleaseAfterSend is pdTRUE.
435+
* The calls to emacps_check_tx() and emacps_send_message()
436+
* must be synchronised because they act on the same DMA descriptors.
437+
*/
438+
if( xSemaphoreTake( xEMACpsifs[ xEMACIndex ].tx_mutex, 1000U ) == pdPASS )
439+
{
440+
emacps_send_message( &( xEMACpsifs[ xEMACIndex ] ), pxBuffer, bReleaseAfterSend );
441+
xSemaphoreGive( xEMACpsifs[ xEMACIndex ].tx_mutex );
442+
/* The function emacps_send_message() has released the packet. */
443+
bReleaseAfterSend = pdFALSE;
444+
}
436445
}
437-
else if( bReleaseAfterSend != pdFALSE )
446+
447+
if( bReleaseAfterSend != pdFALSE )
438448
{
439449
/* No link. */
440450
vReleaseNetworkBufferAndDescriptor( pxBuffer );
@@ -598,9 +608,10 @@ static void prvEMACHandlerTask( void * pvParameters )
598608
TickType_t xPhyRemTime;
599609
BaseType_t xResult = 0;
600610
uint32_t xStatus;
601-
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
611+
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100U );
602612
BaseType_t xEMACIndex = ( BaseType_t ) pvParameters;
603613
xemacpsif_s * pxEMAC_PS;
614+
uint32_t ulISREvents = 0U;
604615

605616
configASSERT( xEMACIndex >= 0 );
606617
configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES );
@@ -629,27 +640,27 @@ static void prvEMACHandlerTask( void * pvParameters )
629640
}
630641
#endif /* ( ipconfigHAS_PRINTF != 0 ) */
631642

632-
if( ( pxEMAC_PS->isr_events & EMAC_IF_ALL_EVENT ) == 0 )
633-
{
634-
/* No events to process now, wait for the next. */
635-
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
636-
}
643+
xTaskNotifyWait( 0U, /* ulBitsToClearOnEntry */
644+
EMAC_IF_ALL_EVENT, /* ulBitsToClearOnExit */
645+
&( ulISREvents ), /* pulNotificationValue */
646+
ulMaxBlockTime );
637647

638-
if( ( pxEMAC_PS->isr_events & EMAC_IF_RX_EVENT ) != 0 )
648+
if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
639649
{
640-
pxEMAC_PS->isr_events &= ~EMAC_IF_RX_EVENT;
641650
xResult = emacps_check_rx( pxEMAC_PS, pxMyInterfaces[ xEMACIndex ] );
642651
}
643652

644-
if( ( pxEMAC_PS->isr_events & EMAC_IF_TX_EVENT ) != 0 )
653+
if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0U )
645654
{
646-
pxEMAC_PS->isr_events &= ~EMAC_IF_TX_EVENT;
647-
emacps_check_tx( pxEMAC_PS );
655+
if( xSemaphoreTake( pxEMAC_PS->tx_mutex, 1000U ) == pdPASS )
656+
{
657+
emacps_check_tx( pxEMAC_PS );
658+
xSemaphoreGive( pxEMAC_PS->tx_mutex );
659+
}
648660
}
649661

650-
if( ( pxEMAC_PS->isr_events & EMAC_IF_ERR_EVENT ) != 0 )
662+
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0U )
651663
{
652-
pxEMAC_PS->isr_events &= ~EMAC_IF_ERR_EVENT;
653664
emacps_check_errors( pxEMAC_PS );
654665
}
655666

source/portable/NetworkInterface/Zynq/x_emacpsif.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,14 @@
115115
volatile int rxHead, rxTail;
116116
volatile int txHead, txTail;
117117

118-
volatile int txBusy;
119-
120-
volatile uint32_t isr_events;
121-
122118
unsigned int last_rx_frms_cntr;
119+
120+
/* Both the IP- and the EMAC task work on DMA descriptors
121+
* for transmission. These function will be protected by 'tx_mutex':
122+
* emacps_send_message()
123+
* emacps_check_tx()
124+
*/
125+
SemaphoreHandle_t tx_mutex;
123126
} xemacpsif_s;
124127

125128
/*extern xemacpsif_s xemacpsif; */

source/portable/NetworkInterface/Zynq/x_emacpsif_dma.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ void emacps_check_tx( xemacpsif_s * xemacpsif )
205205

206206
void emacps_send_handler( void * arg )
207207
{
208+
/* This function is running in ISR mode,
209+
* called to handle a TX interrupt. */
208210
xemacpsif_s * xemacpsif;
209211
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
210212
BaseType_t xEMACIndex;
@@ -217,15 +219,9 @@ void emacps_send_handler( void * arg )
217219
* But it forgets to do a read-back. Do so now to avoid ever-returning ISR's. */
218220
( void ) XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET );
219221

220-
/* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
221-
* "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
222-
*/
223-
xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
224-
xemacpsif->txBusy = pdFALSE;
225-
226222
if( xEMACTaskHandles[ xEMACIndex ] != NULL )
227223
{
228-
vTaskNotifyGiveFromISR( xEMACTaskHandles[ xEMACIndex ], &xHigherPriorityTaskWoken );
224+
xTaskNotifyFromISR( xEMACTaskHandles[ xEMACIndex ], EMAC_IF_TX_EVENT, eSetBits, &( xHigherPriorityTaskWoken ) );
229225
}
230226

231227
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
@@ -252,7 +248,6 @@ XStatus emacps_send_message( xemacpsif_s * xemacpsif,
252248
int iReleaseAfterSend )
253249
{
254250
int txHead = xemacpsif->txHead;
255-
int iHasSent = 0;
256251
uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
257252
BaseType_t xEMACIndex = get_xEMACIndex( &xemacpsif->emacps );
258253
TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000U );
@@ -315,8 +310,6 @@ XStatus emacps_send_message( xemacpsif_s * xemacpsif,
315310
{
316311
}
317312

318-
iHasSent = pdTRUE;
319-
320313
txHead++;
321314

322315
if( txHead == ipconfigNIC_N_TX_DESC )
@@ -331,13 +324,12 @@ XStatus emacps_send_message( xemacpsif_s * xemacpsif,
331324
/* Data Synchronization Barrier */
332325
dsb();
333326

334-
if( iHasSent == pdTRUE )
335327
{
336328
/* Make STARTTX high */
337329
uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );
338-
/* Start transmit */
339-
xemacpsif->txBusy = pdTRUE;
340-
XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
330+
/* Start transmit. */
331+
ulValue |= XEMACPS_NWCTRL_STARTTX_MASK;
332+
XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ulValue );
341333
/* Read back the register to make sure the data is flushed. */
342334
( void ) XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );
343335
}
@@ -356,12 +348,13 @@ XStatus emacps_send_message( xemacpsif_s * xemacpsif,
356348

357349
void emacps_recv_handler( void * arg )
358350
{
351+
/* This function is running in ISR mode,
352+
* called to handle an RX interrupt. */
359353
xemacpsif_s * xemacpsif;
360354
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
361355
BaseType_t xEMACIndex;
362356

363357
xemacpsif = ( xemacpsif_s * ) arg;
364-
xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
365358
xEMACIndex = get_xEMACIndex( &xemacpsif->emacps );
366359

367360
/* The driver has already cleared the FRAMERX, BUFFNA and error bits
@@ -371,7 +364,7 @@ void emacps_recv_handler( void * arg )
371364

372365
if( xEMACTaskHandles[ xEMACIndex ] != NULL )
373366
{
374-
vTaskNotifyGiveFromISR( xEMACTaskHandles[ xEMACIndex ], &xHigherPriorityTaskWoken );
367+
xTaskNotifyFromISR( xEMACTaskHandles[ xEMACIndex ], EMAC_IF_RX_EVENT, eSetBits, &( xHigherPriorityTaskWoken ) );
375368
}
376369

377370
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
@@ -685,6 +678,19 @@ XStatus init_dma( xemacpsif_s * xemacpsif )
685678
configASSERT( xTXDescriptorSemaphores[ xEMACIndex ] );
686679
}
687680

681+
if( xemacpsif->tx_mutex == NULL )
682+
{
683+
/* Both the IP- and the EMAC-task handle TX descriptors.
684+
* The IP-task sends packets, and the EMAC task clear
685+
* TX descriptors that are done.
686+
* A mutex is used so that either emacps_send_message() or
687+
* emacps_check_tx() can become active a a time.
688+
*/
689+
xemacpsif->tx_mutex = xSemaphoreCreateBinary();
690+
configASSERT( xemacpsif->tx_mutex != NULL );
691+
xSemaphoreGive( xemacpsif->tx_mutex );
692+
}
693+
688694
/*
689695
* Allocate RX descriptors, 1 RxBD at a time.
690696
*/

source/portable/NetworkInterface/Zynq/x_emacpsif_hw.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,11 @@ void emacps_error_handler( void * arg,
107107
xErrorList[ xErrorHead ].ErrorWord = ErrorWord;
108108

109109
xErrorHead = xNextHead;
110-
111-
xemacpsif = ( xemacpsif_s * ) ( arg );
112-
xemacpsif->isr_events |= EMAC_IF_ERR_EVENT;
113110
}
114111

115112
if( xEMACTaskHandles[ xEMACIndex ] != NULL )
116113
{
117-
vTaskNotifyGiveFromISR( xEMACTaskHandles[ xEMACIndex ], &xHigherPriorityTaskWoken );
114+
xTaskNotifyFromISR( xEMACTaskHandles[ xEMACIndex ], EMAC_IF_ERR_EVENT, eSetBits, &( xHigherPriorityTaskWoken ) );
118115
}
119116
}
120117

0 commit comments

Comments
 (0)