From faecf41106123ac62c06475ef3a61bc1dabfcad2 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 24 Jun 2016 15:39:52 +0800 Subject: [PATCH] mmc: dw_mmc: fix unmap sg twice when finding data err DATA_OVER(the same for RI/TI of IDMAC) interrupt may come up together with data error interrupts. If so, the interrupt routine set EVENT_DATA_ERR to the pending_events and schedule the tasklet but we may still fallback to the IDMAC interrupt case as the tasklet may come up a little late, namely right after the IDMAC interrupt checking. This will casue dw_mmc unmap sg twice. We can easily see it with CONFIG_DMA_API_DEBUG enabled. WARNING: CPU: 0 PID: 0 at lib/dma-debug.c:1096 check_unmap+0x7bc/0xb38 dwmmc_exynos 12200000.mmc: DMA-API: device driver tries to free DMA memory it has not allocated [device address=0x000000006d9d2200] [size=128 bytes] Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.7.0-rc4 #26 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [] (show_stack) from [] (dump_stack+0x80/0x94) [] (dump_stack) from [] (__warn+0xf8/0x110) [] (__warn) from [] (warn_slowpath_fmt+0x48/0x50) [] (warn_slowpath_fmt) from [] (check_unmap+0x7bc/0xb38) [] (check_unmap) from [] (debug_dma_unmap_sg+0x118/0x148) [] (debug_dma_unmap_sg) from [] (dw_mci_dma_cleanup+0x7c/0xb8) [] (dw_mci_dma_cleanup) from [] (dw_mci_stop_dma+0x40/0x50) [] (dw_mci_stop_dma) from [] (dw_mci_tasklet_func+0x130/0x3b4) [] (dw_mci_tasklet_func) from [] (tasklet_action+0xb4/0x150) ..[snip].. ---[ end trace 256f83eed365daf0 ]--- Reported-by: Seung-Woo Kim Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index e857beb43144..2dfdc58bae13 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2506,7 +2506,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); - host->dma_ops->complete((void *)host); + if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) + host->dma_ops->complete((void *)host); } } else { pending = mci_readl(host, IDSTS); @@ -2514,7 +2515,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); - host->dma_ops->complete((void *)host); + if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) + host->dma_ops->complete((void *)host); } }