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 /drivers | |
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>
Diffstat (limited to 'drivers')
-rwxr-xr-x | drivers/mmc/host/sdhci.c | 71 |
1 files changed, 71 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, |