mmc: sdhci: avoid unnecessary mapping/unmapping of align buffer
[cascardo/linux.git] / drivers / mmc / host / sdhci.c
index 5c90941..78359ba 100644 (file)
@@ -465,8 +465,6 @@ static void sdhci_adma_mark_end(void *desc)
 static int sdhci_adma_table_pre(struct sdhci_host *host,
        struct mmc_data *data)
 {
-       int direction;
-
        void *desc;
        void *align;
        dma_addr_t addr;
@@ -483,20 +481,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
         * We currently guess that it is LE.
         */
 
-       if (data->flags & MMC_DATA_READ)
-               direction = DMA_FROM_DEVICE;
-       else
-               direction = DMA_TO_DEVICE;
-
-       host->align_addr = dma_map_single(mmc_dev(host->mmc),
-               host->align_buffer, host->align_buffer_sz, direction);
-       if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
-               goto fail;
-       BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
-
        host->sg_count = sdhci_pre_dma_transfer(host, data);
        if (host->sg_count < 0)
-               goto unmap_align;
+               return -EINVAL;
 
        desc = host->adma_table;
        align = host->align_buffer;
@@ -570,22 +557,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                /* nop, end, valid */
                sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID);
        }
-
-       /*
-        * Resync align buffer as we might have changed it.
-        */
-       if (data->flags & MMC_DATA_WRITE) {
-               dma_sync_single_for_device(mmc_dev(host->mmc),
-                       host->align_addr, host->align_buffer_sz, direction);
-       }
-
        return 0;
-
-unmap_align:
-       dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
-               host->align_buffer_sz, direction);
-fail:
-       return -EINVAL;
 }
 
 static void sdhci_adma_table_post(struct sdhci_host *host,
@@ -605,9 +577,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
        else
                direction = DMA_TO_DEVICE;
 
-       dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
-               host->align_buffer_sz, direction);
-
        /* Do a quick scan of the SG list for any unaligned mappings */
        has_unaligned = false;
        for_each_sg(data->sg, sg, host->sg_count, i)
@@ -2985,14 +2954,21 @@ int sdhci_add_host(struct sdhci_host *host)
                                                      &host->adma_addr,
                                                      GFP_KERNEL);
                host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
-               host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
+               host->align_buffer = dma_alloc_coherent(mmc_dev(mmc),
+                                                       host->align_buffer_sz,
+                                                       &host->align_addr,
+                                                       GFP_KERNEL);
                if (!host->adma_table || !host->align_buffer) {
                        if (host->adma_table)
                                dma_free_coherent(mmc_dev(mmc),
                                                  host->adma_table_sz,
                                                  host->adma_table,
                                                  host->adma_addr);
-                       kfree(host->align_buffer);
+                       if (host->align_buffer)
+                               dma_free_coherent(mmc_dev(mmc),
+                                                 host->align_buffer_sz,
+                                                 host->align_buffer,
+                                                 host->align_addr);
                        pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
                                mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
@@ -3004,10 +2980,14 @@ int sdhci_add_host(struct sdhci_host *host)
                        host->flags &= ~SDHCI_USE_ADMA;
                        dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
                                          host->adma_table, host->adma_addr);
-                       kfree(host->align_buffer);
+                       dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz,
+                                         host->align_buffer, host->align_addr);
                        host->adma_table = NULL;
                        host->align_buffer = NULL;
                }
+
+               /* dma_alloc_coherent returns page aligned and sized buffers */
+               BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
        }
 
        /*
@@ -3470,7 +3450,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        if (host->adma_table)
                dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
                                  host->adma_table, host->adma_addr);
-       kfree(host->align_buffer);
+       if (host->align_buffer)
+               dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz,
+                                 host->align_buffer, host->align_addr);
 
        host->adma_table = NULL;
        host->align_buffer = NULL;