diff options
author | Tony Lin <tony.lin@freescale.com> | 2012-02-27 15:53:02 +0800 |
---|---|---|
committer | Tony Lin <tony.lin@freescale.com> | 2012-03-07 14:26:20 +0800 |
commit | ba81de88099550576886d3bc242bc843fe387ed3 (patch) | |
tree | 02e5dfd6be476fd0f6fc0188019237ead88cf266 | |
parent | 8a039e5df30dbb88bda7f5f2eb3a35f6d2a07b84 (diff) |
ENGR00175864 [MMC]pipeline mmc requests
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>
-rwxr-xr-x | drivers/mmc/host/sdhci.c | 71 | ||||
-rw-r--r-- | include/linux/mmc/sdhci.h | 6 |
2 files changed, 77 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6137f9de67c6..82afe0522ecc 100755 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1865,8 +1865,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, diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index d73ed4622881..d9dca2739cb5 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -17,6 +17,11 @@ #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 */ |