mmc: tmio_mmc: fix card eject during IO with DMA
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Fri, 6 Jan 2012 12:06:51 +0000 (13:06 +0100)
committerChris Ball <cjb@laptop.org>
Tue, 14 Feb 2012 01:39:03 +0000 (20:39 -0500)
When DMA is in use and the card is ejected during IO, DMA transfers have to
be terminated, otherwise the dmaengine driver fails to operate properly,
when the card is re-inserted.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c

index a95e6d901726031275066ca7b394fc9be7b6a96c..f96c536d130a287768c6317d1dfa9611d30297ac 100644 (file)
@@ -20,8 +20,8 @@
 #include <linux/mmc/tmio.h>
 #include <linux/mutex.h>
 #include <linux/pagemap.h>
-#include <linux/spinlock.h>
 #include <linux/scatterlist.h>
+#include <linux/spinlock.h>
 
 /* Definitions for values the CTRL_SDIO_STATUS register can take. */
 #define TMIO_SDIO_STAT_IOIRQ   0x0001
@@ -120,6 +120,7 @@ void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
 void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable);
 void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
 void tmio_mmc_release_dma(struct tmio_mmc_host *host);
+void tmio_mmc_abort_dma(struct tmio_mmc_host *host);
 #else
 static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
                               struct mmc_data *data)
@@ -140,6 +141,10 @@ static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
 static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
 {
 }
+
+static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
+{
+}
 #endif
 
 #ifdef CONFIG_PM
index 7a6e6cc8f8b842ddb065208aea07d093809bc79d..8253ec12003ed3c9001cdd7b8fed889179350d9b 100644 (file)
@@ -34,6 +34,18 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
 #endif
 }
 
+void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
+{
+       tmio_mmc_enable_dma(host, false);
+
+       if (host->chan_rx)
+               dmaengine_terminate_all(host->chan_rx);
+       if (host->chan_tx)
+               dmaengine_terminate_all(host->chan_tx);
+
+       tmio_mmc_enable_dma(host, true);
+}
+
 static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
 {
        struct scatterlist *sg = host->sg_ptr, *sg_tmp;
index abad01b37cfbbab50761cafda285d40e67346b3b..5f9ad74fbf80b3a4a3556c5c5919c9ba525c610d 100644 (file)
@@ -41,8 +41,8 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/scatterlist.h>
-#include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/workqueue.h>
 
 #include "tmio_mmc.h"
 
@@ -246,6 +246,7 @@ static void tmio_mmc_reset_work(struct work_struct *work)
        /* Ready for new calls */
        host->mrq = NULL;
 
+       tmio_mmc_abort_dma(host);
        mmc_request_done(host->mmc, mrq);
 }
 
@@ -272,6 +273,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
        host->mrq = NULL;
        spin_unlock_irqrestore(&host->lock, flags);
 
+       if (mrq->cmd->error || (mrq->data && mrq->data->error))
+               tmio_mmc_abort_dma(host);
+
        mmc_request_done(host->mmc, mrq);
 }