]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/mmc/host/tmio_mmc_dma.c
mmc: tmio: ensure end of DMA and SD access are in sync
[karo-tx-linux.git] / drivers / mmc / host / tmio_mmc_dma.c
index fa8a936a3d9ba1d0f0e33a2bbe26aac899cd77dc..c7684fa91f1f9c46a2cc043ad9f7df9a4b052723 100644 (file)
@@ -43,6 +43,31 @@ void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
        tmio_mmc_enable_dma(host, true);
 }
 
+static void tmio_mmc_dma_callback(void *arg)
+{
+       struct tmio_mmc_host *host = arg;
+
+       wait_for_completion(&host->dma_dataend);
+
+       spin_lock_irq(&host->lock);
+
+       if (!host->data)
+               goto out;
+
+       if (host->data->flags & MMC_DATA_READ)
+               dma_unmap_sg(host->chan_rx->device->dev,
+                            host->sg_ptr, host->sg_len,
+                            DMA_FROM_DEVICE);
+       else
+               dma_unmap_sg(host->chan_tx->device->dev,
+                            host->sg_ptr, host->sg_len,
+                            DMA_TO_DEVICE);
+
+       tmio_mmc_do_data_irq(host);
+out:
+       spin_unlock_irq(&host->lock);
+}
+
 static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
 {
        struct scatterlist *sg = host->sg_ptr, *sg_tmp;
@@ -88,6 +113,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
                        DMA_DEV_TO_MEM, DMA_CTRL_ACK);
 
        if (desc) {
+               reinit_completion(&host->dma_dataend);
+               desc->callback = tmio_mmc_dma_callback;
+               desc->callback_param = host;
+
                cookie = dmaengine_submit(desc);
                if (cookie < 0) {
                        desc = NULL;
@@ -162,6 +191,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
                        DMA_MEM_TO_DEV, DMA_CTRL_ACK);
 
        if (desc) {
+               reinit_completion(&host->dma_dataend);
+               desc->callback = tmio_mmc_dma_callback;
+               desc->callback_param = host;
+
                cookie = dmaengine_submit(desc);
                if (cookie < 0) {
                        desc = NULL;
@@ -221,29 +254,6 @@ static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
                dma_async_issue_pending(chan);
 }
 
-static void tmio_mmc_tasklet_fn(unsigned long arg)
-{
-       struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
-
-       spin_lock_irq(&host->lock);
-
-       if (!host->data)
-               goto out;
-
-       if (host->data->flags & MMC_DATA_READ)
-               dma_unmap_sg(host->chan_rx->device->dev,
-                            host->sg_ptr, host->sg_len,
-                            DMA_FROM_DEVICE);
-       else
-               dma_unmap_sg(host->chan_tx->device->dev,
-                            host->sg_ptr, host->sg_len,
-                            DMA_TO_DEVICE);
-
-       tmio_mmc_do_data_irq(host);
-out:
-       spin_unlock_irq(&host->lock);
-}
-
 void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
 {
        /* We can only either use DMA for both Tx and Rx or not use it at all */
@@ -306,7 +316,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
                if (!host->bounce_buf)
                        goto ebouncebuf;
 
-               tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
+               init_completion(&host->dma_dataend);
                tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
        }