]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00175864 [MMC]pipeline mmc requests
authorTony Lin <tony.lin@freescale.com>
Mon, 27 Feb 2012 07:53:02 +0000 (15:53 +0800)
committerOliver Wendt <ow@karo-electronics.de>
Mon, 30 Sep 2013 12:11:10 +0000 (14:11 +0200)
the patch is based on a series of patches by Per Forlin
the patch is sdhci host side implementation.

using a toshiba SDHC3.0 card, the performance increases
from 48.5MB/s to 52.4MB/s.

cmd: dd if=/dev/mmcblk0 of=/dev/null bs=1M count=500

the performance results running@1GHz, 200MHz CPU freq are:
52.4MB/s -> 20.7MB/s

Signed-off-by: Tony Lin <tony.lin@freescale.com>
drivers/mmc/host/sdhci.c
include/linux/mmc/sdhci.h

index 519f713ffa1855f82621276216b32e479536cde8..428f352dd569d14683ea1eafce3b518552de406d 100755 (executable)
@@ -1864,8 +1864,79 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+                               int err)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (host->flags & SDHCI_REQ_USE_DMA) {
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                            data->flags & MMC_DATA_WRITE ? \
+                            DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               data->host_cookie = 0;
+       }
+}
+
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+                                      struct mmc_data *data,
+                                      struct sdhci_host_next *next)
+{
+       int dma_len;
+
+       if (!next && data->host_cookie &&
+           data->host_cookie != host->next_data.cookie) {
+               printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d"
+                      " host->next_data.cookie %d\n",
+                      __func__, data->host_cookie, host->next_data.cookie);
+               data->host_cookie = 0;
+       }
+
+       /* Check if next job is already prepared */
+       if (next ||
+           (!next && data->host_cookie != host->next_data.cookie)) {
+               dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+                                    data->sg_len,
+                                    data->flags & MMC_DATA_WRITE ? \
+                                    DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+       } else {
+               dma_len = host->next_data.dma_len;
+               host->next_data.dma_len = 0;
+       }
+
+
+       if (dma_len == 0)
+               return -EINVAL;
+
+       if (next) {
+               next->dma_len = dma_len;
+               data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+       }
+
+       return 0;
+}
+
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+                              bool is_first_req)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (mrq->data->host_cookie) {
+               mrq->data->host_cookie = 0;
+               return ;
+       }
+
+       if (host->flags & SDHCI_REQ_USE_DMA)
+               if (sdhci_pre_dma_transfer(host, mrq->data,
+                                               &host->next_data))
+                       mrq->data->host_cookie = 0;
+}
+
 static const struct mmc_host_ops sdhci_ops = {
        .request        = sdhci_request,
+       .post_req       = sdhci_post_req,
+       .pre_req        = sdhci_pre_req,
        .set_ios        = sdhci_set_ios,
        .get_ro         = sdhci_get_ro,
        .enable_sdio_irq = sdhci_enable_sdio_irq,
index d73ed46228817075308e0cc7462bad146cee9a4c..d9dca2739cb50cdf78300233a1c94bede18a1b19 100644 (file)
 #include <linux/io.h>
 #include <linux/mmc/host.h>
 
+struct sdhci_host_next {
+       unsigned int    dma_len;
+       s32             cookie;
+};
+
 struct sdhci_host {
        /* Data set by hardware interface driver */
        const char *hw_name;    /* Hardware bus name */
@@ -166,6 +171,7 @@ struct sdhci_host {
        struct delayed_work     clk_worker;     /* Clock delayed worker */
        unsigned int            clk_mgr_en;
        unsigned int            clk_status;
+       struct sdhci_host_next  next_data;
        unsigned long private[0] ____cacheline_aligned;
 };
 #endif /* __SDHCI_H */