From a5d104e0d646f5acb7f68311ee840839b00e36e5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 18 Jul 2017 15:30:48 +0100 Subject: [PATCH] bcm2835-mmc: Prevent DMA race condition The end of a read operation is triggered by the completion of the DMA transfer, but writes are complete when the data IRQ is raised. The bcm2835-mmc driver contains a race between the handling of the DMA completion interrupt and the submission of the next request. Fix the race by deferring the completion of the request until the DMA transfer finishes. Signed-off-by: Phil Elwell --- drivers/mmc/host/bcm2835-mmc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c index 981db05de1ff..c4a5e992c6fb 100644 --- a/drivers/mmc/host/bcm2835-mmc.c +++ b/drivers/mmc/host/bcm2835-mmc.c @@ -115,6 +115,7 @@ struct bcm2835_host { bool have_dma; bool use_dma; + bool wait_for_dma; /*end of DMA part*/ int max_delay; /* maximum length of time spent waiting */ @@ -341,6 +342,8 @@ static void bcm2835_mmc_dma_complete(void *param) spin_lock_irqsave(&host->lock, flags); + host->use_dma = false; + if (host->data && !(host->data->flags & MMC_DATA_WRITE)) { /* otherwise handled in SDHCI IRQ */ dma_chan = host->dma_chan_rxtx; @@ -351,6 +354,9 @@ static void bcm2835_mmc_dma_complete(void *param) dir_data); bcm2835_mmc_finish_data(host); + } else if (host->wait_for_dma) { + host->wait_for_dma = false; + tasklet_schedule(&host->finish_tasklet); } spin_unlock_irqrestore(&host->lock, flags); @@ -690,6 +696,7 @@ void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd mod_timer(&host->timer, timeout); host->cmd = cmd; + host->use_dma = false; bcm2835_mmc_prepare_data(host, cmd); @@ -759,8 +766,11 @@ static void bcm2835_mmc_finish_data(struct bcm2835_host *host) } bcm2835_mmc_send_command(host, data->stop); - } else + } else if (host->use_dma) { + host->wait_for_dma = true; + } else { tasklet_schedule(&host->finish_tasklet); + } } static void bcm2835_mmc_finish_command(struct bcm2835_host *host) -- 2.30.2