diff options
author | Per Forlin <per.forlin@stericsson.com> | 2011-09-24 12:14:56 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-06 17:30:22 +0100 |
commit | 1e0623a778270ce0e60e57a5fa53f0d2948d4601 (patch) | |
tree | 9a400a8d2842db97dc304cf30ae91684462e0911 | |
parent | b88d61c659d97860c449a69f952bef9699247128 (diff) |
ARM: mmci: DMA preparations in parellel with cmd
Do DMA preparations after start_command() instead of before.
DMA is being prepared while the controller process the read/write cmd.
This flow will decrease the start up latency which improves the
throughput, especially for small transfers.
ST-Ericsson Linux next: N/A
ST-Ericsson ID: 371812
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: I98db024658cac5fe6ee09e4250c31e53a643bead
Signed-off-by: Per Forlin <per.forlin@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/36180
Reviewed-by: QABUILD
Reviewed-by: Ulf HANSSON <ulf.hansson@stericsson.com>
-rw-r--r-- | drivers/mmc/host/mmci.c | 79 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 1 |
2 files changed, 55 insertions, 25 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 6d42941c600..8555965cdec 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -264,6 +264,7 @@ static void mmci_stop_data(struct mmci_host *host) writel(0, host->base + MMCIDATACTRL); mmci_set_mask1(host, 0); host->data = NULL; + host->datactrl_reg = 0; } static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) @@ -374,13 +375,13 @@ static inline void mmci_dma_release(struct mmci_host *host) host->dma_rx_channel = host->dma_tx_channel = NULL; } -static void mmci_dma_data_error(struct mmci_host *host) +static void mmci_dma_data_error(struct mmci_host *host, struct mmc_data *data) { dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); dmaengine_terminate_all(host->dma_current); host->dma_current = NULL; host->dma_desc_current = NULL; - host->data->host_cookie = 0; + data->host_cookie = 0; } static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) @@ -420,7 +421,7 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) */ if (status & MCI_RXDATAAVLBLMASK) { data->error = -EIO; - mmci_dma_data_error(host); + mmci_dma_data_error(host, data); } if (!data->host_cookie) @@ -521,7 +522,7 @@ static inline int mmci_dma_prep_next(struct mmci_host *host, return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc); } -static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +static int mmci_dma_start_data(struct mmci_host *host) { int ret; struct mmc_data *data = host->data; @@ -538,15 +539,15 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) dmaengine_submit(host->dma_desc_current); dma_async_issue_pending(host->dma_current); - datactrl |= MCI_DPSM_DMAENABLE; + host->datactrl_reg |= MCI_DPSM_DMAENABLE; /* Some hardware versions need special flags for SDIO DMA write */ if (variant->sdio && host->mmc->card && mmc_card_sdio(host->mmc->card) && (data->flags & MMC_DATA_WRITE)) - datactrl |= variant->dma_sdio_req_ctrl; + host->datactrl_reg |= variant->dma_sdio_req_ctrl; /* Trigger the DMA transfer */ - writel(datactrl, host->base + MMCIDATACTRL); + writel(host->datactrl_reg, host->base + MMCIDATACTRL); /* * Let the MMCI say when the data is ended and it's time @@ -640,11 +641,16 @@ static inline void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *da { } -static inline void mmci_dma_data_error(struct mmci_host *host) +static inline void mmci_dma_data_error(struct mmci_host *host, struct mmc_data *data) { } -static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +static inline int mmci_dma_start_data(struct mmci_host *host) +{ + return -ENOSYS; +} + +static inline int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data) { return -ENOSYS; } @@ -654,10 +660,10 @@ static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datac #endif -static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) +static void mmci_setup_datactrl(struct mmci_host *host, struct mmc_data *data) { struct variant_data *variant = host->variant; - unsigned int datactrl, timeout, irqmask; + unsigned int datactrl, timeout; unsigned long long clks; void __iomem *base; int blksz_bits; @@ -711,12 +717,21 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) */ datactrl |= MCI_ST_DPSM_SDIOEN; } + host->datactrl_reg = datactrl; + writel(datactrl, base + MMCIDATACTRL); +} + +static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) +{ + unsigned int irqmask; + struct variant_data *variant = host->variant; + void __iomem *base = host->base; /* * Attempt to use DMA operation mode, if this * should fail, fall back to PIO mode */ - if (!mmci_dma_start_data(host, datactrl)) + if (!mmci_dma_start_data(host)) return; /* IRQ mode, map the SG list for CPU reading/writing */ @@ -740,7 +755,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } - writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); mmci_set_mask1(host, irqmask); } @@ -784,7 +798,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, /* Terminate the DMA transfer */ if (dma_inprogress(host)) { - mmci_dma_data_error(host); + mmci_dma_data_error(host, data); mmci_dma_unmap(host, data); } @@ -860,16 +874,16 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, } if (!cmd->data || cmd->error) { - if (host->data) { - /* Terminate the DMA transfer */ - if (dma_inprogress(host)) { - mmci_dma_data_error(host); - mmci_dma_unmap(host, host->data); - } - mmci_stop_data(host); + /* Terminate the DMA transfer */ + if (dma_inprogress(host)) { + mmci_dma_data_error(host, host->mrq->data); + mmci_dma_unmap(host, host->mrq->data); } + if (host->data) + mmci_stop_data(host); mmci_request_end(host, cmd->mrq); } else if (!(cmd->data->flags & MMC_DATA_READ)) { + mmci_setup_datactrl(host, cmd->data); mmci_start_data(host, cmd->data); } } @@ -1088,6 +1102,7 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct mmci_host *host = mmc_priv(mmc); unsigned long flags; + bool dmaprep_after_cmd = false; WARN_ON(host->mrq != NULL); @@ -1103,14 +1118,28 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; - if (mrq->data) + if (mrq->data) { + dmaprep_after_cmd = + (host->variant->clkreg_enable && + (mrq->data->flags & MMC_DATA_READ)) || + !(mrq->data->flags & MMC_DATA_READ); mmci_get_next_data(host, mrq->data); - - if (mrq->data && mrq->data->flags & MMC_DATA_READ) - mmci_start_data(host, mrq->data); + if (mrq->data->flags & MMC_DATA_READ) { + mmci_setup_datactrl(host, mrq->data); + if (!dmaprep_after_cmd) + mmci_start_data(host, mrq->data); + } + } mmci_start_command(host, mrq->cmd, 0); + if (mrq->data && dmaprep_after_cmd) { + mmci_dma_prep_data(host, mrq->data); + + if (mrq->data->flags & MMC_DATA_READ) + mmci_start_data(host, mrq->data); + } + spin_unlock_irqrestore(&host->lock, flags); } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index c2b33326547..ba09a603787 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -188,6 +188,7 @@ struct mmci_host { unsigned int cclk; u32 pwr_reg; u32 clk_reg; + u32 datactrl_reg; struct mmci_platform_data *plat; struct variant_data *variant; |