pre_req() runs dma_map_sg() post_req() runs dma_unmap_sg.
If not calling pre_req() before mxs_mmc_request(), request()
will prepare the cache just like it did it before.
It is optional to use pre_req() and post_req().

Signed-off-by: Shawn Guo <shawn....@linaro.org>
---
Changes since v1:
* Get dma_unmap_sg() call in mxs_mmc_request_done() non-blocking

 drivers/mmc/host/mxs-mmc.c |   81 +++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 76 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 99d39a6..235acfa 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -137,6 +137,10 @@
 
 #define SSP_PIO_NUM    3
 
+struct mxs_mmc_next {
+       s32 cookie;
+};
+
 struct mxs_mmc_host {
        struct mmc_host                 *mmc;
        struct mmc_request              *mrq;
@@ -154,6 +158,7 @@ struct mxs_mmc_host {
        struct mxs_dma_data             dma_data;
        unsigned int                    dma_dir;
        u32                             ssp_pio_words[SSP_PIO_NUM];
+       struct mxs_mmc_next             next_data;
 
        unsigned int                    version;
        unsigned char                   bus_width;
@@ -236,8 +241,10 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host)
        }
 
        if (data) {
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-                            data->sg_len, host->dma_dir);
+               if (!data->host_cookie)
+                       dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+                                    data->sg_len, host->dma_dir);
+
                /*
                 * If there was an error on any block, we mark all
                 * data blocks as being in error.
@@ -302,6 +309,31 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void 
*dev_id)
        return IRQ_HANDLED;
 }
 
+static int mxs_mmc_prep_dma_data(struct mxs_mmc_host *host,
+                               struct mmc_data *data,
+                               struct mxs_mmc_next *next)
+{
+       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))
+               if (dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                              (data->flags & MMC_DATA_WRITE) ?
+                              DMA_TO_DEVICE : DMA_FROM_DEVICE) == 0)
+                       return -EINVAL;
+
+       if (next)
+               data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+
+       return 0;
+}
+
 static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
        struct mxs_mmc_host *host, unsigned int append)
 {
@@ -312,8 +344,8 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
 
        if (data) {
                /* data */
-               dma_map_sg(mmc_dev(host->mmc), data->sg,
-                          data->sg_len, host->dma_dir);
+               if (mxs_mmc_prep_dma_data(host, data, NULL))
+                       return NULL;
                sgl = data->sg;
                sg_len = data->sg_len;
        } else {
@@ -328,9 +360,11 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
                desc->callback = mxs_mmc_dma_irq_callback;
                desc->callback_param = host;
        } else {
-               if (data)
+               if (data) {
                        dma_unmap_sg(mmc_dev(host->mmc), data->sg,
                                     data->sg_len, host->dma_dir);
+                       data->host_cookie = 0;
+               }
        }
 
        return desc;
@@ -553,6 +587,40 @@ static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
        }
 }
 
+static void mxs_mmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+                           bool is_first_req)
+{
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (!data)
+               return;
+
+       if (data->host_cookie) {
+               data->host_cookie = 0;
+               return;
+       }
+
+       if (mxs_mmc_prep_dma_data(host, data, &host->next_data))
+               data->host_cookie = 0;
+}
+
+static void mxs_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+                            int err)
+{
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (!data)
+               return;
+
+       if (data->host_cookie) {
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+                            data->sg_len, host->dma_dir);
+               data->host_cookie = 0;
+       }
+}
+
 static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct mxs_mmc_host *host = mmc_priv(mmc);
@@ -644,6 +712,8 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, 
int enable)
 }
 
 static const struct mmc_host_ops mxs_mmc_ops = {
+       .pre_req = mxs_mmc_pre_req,
+       .post_req = mxs_mmc_post_req,
        .request = mxs_mmc_request,
        .get_ro = mxs_mmc_get_ro,
        .get_cd = mxs_mmc_get_cd,
@@ -708,6 +778,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        host->dma_res = dmares;
        host->irq = irq_err;
        host->sdio_irq_en = 0;
+       host->next_data.cookie = 1;
 
        host->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk)) {
-- 
1.7.4.1


--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to