If we terminate a command early, we fail to properly clean up the DMA
mappings for the data part of the request.  Move this clean up to the
tasklet, which is the common path for finishing a request so we always
clean up after ourselves.

Signed-off-by: Russell King <rmk+ker...@arm.linux.org.uk>
---
 drivers/mmc/host/sdhci.c | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6f23dba74cbc..4ead8b2f8f8f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -899,17 +899,9 @@ static void sdhci_finish_data(struct sdhci_host *host)
        data = host->data;
        host->data = NULL;
 
-       if (host->flags & SDHCI_REQ_USE_DMA) {
-               if (host->flags & SDHCI_USE_ADMA)
-                       sdhci_adma_table_post(host, data);
-
-               if (data->host_cookie == COOKIE_MAPPED) {
-                       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                                    (data->flags & MMC_DATA_READ) ?
-                                    DMA_FROM_DEVICE : DMA_TO_DEVICE);
-                       data->host_cookie = COOKIE_UNMAPPED;
-               }
-       }
+       if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
+           (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA))
+               sdhci_adma_table_post(host, data);
 
        /*
         * The specification states that the block count register must
@@ -2174,6 +2166,22 @@ static void sdhci_tasklet_finish(unsigned long param)
        mrq = host->mrq;
 
        /*
+        * Always unmap the data buffers if they were mapped by
+        * sdhci_prepare_data() whenever we finish with a request.
+        * This avoids leaking DMA mappings on error.
+        */
+       if (host->flags & SDHCI_REQ_USE_DMA) {
+               struct mmc_data *data = mrq->data;
+
+               if (data && data->host_cookie == COOKIE_MAPPED) {
+                       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                                    (data->flags & MMC_DATA_READ) ?
+                                    DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       data->host_cookie = COOKIE_UNMAPPED;
+               }
+       }
+
+       /*
         * The controller needs a reset of internal state machines
         * upon error conditions.
         */
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to