linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: per.forlin@linaro.org (Per Forlin)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 08/12] mmc: add handling for two parallel block requests in issue_rw_rq
Date: Wed,  6 Apr 2011 21:07:09 +0200	[thread overview]
Message-ID: <1302116833-24540-9-git-send-email-per.forlin@linaro.org> (raw)
In-Reply-To: <1302116833-24540-1-git-send-email-per.forlin@linaro.org>

Change mmc_blk_issue_rw_rq() to become asynchronous.
The execution flow looks like this:
The mmc-queue calls issue_rw_rq(), which sends the request
to the host and returns back to the mmc-queue. The mmc-queue calls
isuue_rw_rq() again with a new request. This new request is prepared,
in isuue_rw_rq(), then it waits for the active request to complete before
pushing it to the host. When to mmc-queue is empty it will call
isuue_rw_rq() with req=NULL to finish off the active request
without starting a new request.

Signed-off-by: Per Forlin <per.forlin@linaro.org>
---
 drivers/mmc/card/block.c |  157 +++++++++++++++++++++++++++++++++++++++-------
 drivers/mmc/card/queue.c |    2 +-
 2 files changed, 134 insertions(+), 25 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index f5db000..4b530ae 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -516,24 +516,75 @@ static enum mmc_blk_status mmc_blk_get_status(struct mmc_blk_request *brq,
 
 }
 
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 {
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
-	struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
-	int ret = 1, disable_multi = 0;
+	struct mmc_blk_request *brqc = &mq->mqrq_cur->brq;
+	struct mmc_blk_request *brqp = &mq->mqrq_prev->brq;
+	struct mmc_queue_req  *mqrqp = mq->mqrq_prev;
+	struct request *rqp = mqrqp->req;
+	int ret = 0;
+	int disable_multi = 0;
 	enum mmc_blk_status status;
 
-	mmc_claim_host(card->host);
+	if (!rqc && !rqp)
+		return 0;
 
-	do {
-		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, disable_multi, mq);
-		mmc_wait_for_req(card->host, &brq->mrq);
+	if (rqc) {
+		/* Claim host for the first request in a serie of requests */
+		if (!rqp)
+			mmc_claim_host(card->host);
 
-		mmc_queue_bounce_post(mq->mqrq_cur);
-		status = mmc_blk_get_status(brq, req, card, md);
+		/* Prepare a new request */
+		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+		mmc_pre_req(card->host, &brqc->mrq, !rqp);
+	}
+	do {
+		/*
+		 * If there is an ongoing request, indicated by rqp, wait for
+		 * it to finish before starting a new one.
+		 */
+		if (rqp)
+			mmc_wait_for_req_done(&brqp->mrq);
+		else {
+			/* start a new asynchronous request */
+			mmc_start_req(card->host, &brqc->mrq);
+			goto out;
+		}
+		status = mmc_blk_get_status(brqp, rqp, card, md);
+		if (status != MMC_BLK_SUCCESS) {
+			mmc_post_req(card->host, &brqp->mrq, -EINVAL);
+			mmc_queue_bounce_post(mqrqp);
+			if (rqc)
+				mmc_post_req(card->host, &brqc->mrq, -EINVAL);
+		}
 
 		switch (status) {
+		case MMC_BLK_SUCCESS:
+			/*
+			 * A block was successfully transferred.
+			 */
+
+			/*
+			 * All data is transferred without errors.
+			 * Defer mmc post processing and _blk_end_request
+			 * until after the new request is started.
+			 */
+			if (blk_rq_bytes(rqp) == brqp->data.bytes_xfered)
+				break;
+
+			mmc_post_req(card->host, &brqp->mrq, 0);
+			mmc_queue_bounce_post(mqrqp);
+
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(rqp, 0,
+						brqp->data.bytes_xfered);
+			spin_unlock_irq(&md->lock);
+
+			if (rqc)
+				mmc_post_req(card->host, &brqc->mrq, -EINVAL);
+			break;
 		case MMC_BLK_CMD_ERR:
 			goto cmd_err;
 			break;
@@ -548,27 +599,73 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 			 * read a single sector.
 			 */
 			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, -EIO,
-						brq->data.blksz);
+			ret = __blk_end_request(rqp, -EIO, brqp->data.blksz);
 			spin_unlock_irq(&md->lock);
-
+			if (rqc && !ret)
+				mmc_pre_req(card->host, &brqc->mrq, false);
 			break;
-		case MMC_BLK_SUCCESS:
+		}
+
+		if (ret) {
 			/*
-			 * A block was successfully transferred.
+			 * In case of a none complete request
+			 * prepare it again and resend.
 			 */
-			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
-			spin_unlock_irq(&md->lock);
-			break;
+			mmc_blk_rw_rq_prep(mqrqp, card, disable_multi, mq);
+			mmc_pre_req(card->host, &brqp->mrq, true);
+			mmc_start_req(card->host, &brqp->mrq);
+			if (rqc)
+				mmc_pre_req(card->host, &brqc->mrq, false);
 		}
 	} while (ret);
 
-	mmc_release_host(card->host);
+	/* Previous request is completed, start the new request if any */
+	if (rqc)
+		mmc_start_req(card->host, &brqc->mrq);
+
+	/*
+	 * Post process the previous request while the new request is active.
+	 * In case of error the reuqest is already ended.
+	 */
+	if (status == MMC_BLK_SUCCESS) {
+		mmc_post_req(card->host, &brqp->mrq, 0);
+		mmc_queue_bounce_post(mqrqp);
+
+		spin_lock_irq(&md->lock);
+		ret = __blk_end_request(rqp, 0, brqp->data.bytes_xfered);
+		spin_unlock_irq(&md->lock);
+
+		if (ret) {
+			/* If this happen it is a bug */
+			printk(KERN_ERR "[%s] BUG: rq_bytes %d xfered %d\n",
+			       __func__, blk_rq_bytes(rqp),
+			       brqp->data.bytes_xfered);
+			goto cmd_err;
+		}
+	}
+
+	/* 1 indicates one request has been completed */
+	ret = 1;
+ out:
+	/*
+	 * TODO: Find out if it is OK to only release host after the
+	 *       last request. For the last request the current request
+	 *        is NULL, which means no requests are pending.
+	 */
+	/* Release host for the last request in a serie of requests */
+	if (!rqc)
+		mmc_release_host(card->host);
 
-	return 1;
+	/* Current request becomes previous request and vice versa. */
+	mqrqp->brq.mrq.data = NULL;
+	mqrqp->req = NULL;
+	mq->mqrq_prev = mq->mqrq_cur;
+	mq->mqrq_cur = mqrqp;
+
+	return ret;
 
  cmd_err:
+
  	/*
  	 * If this is an SD card and we're writing, we can first
  	 * mark the known good sectors as ok.
@@ -583,12 +680,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		blocks = mmc_sd_num_wr_blocks(card);
 		if (blocks != (u32)-1) {
 			spin_lock_irq(&md->lock);
-			ret = __blk_end_request(req, 0, blocks << 9);
+			ret = __blk_end_request(rqp, 0, blocks << 9);
 			spin_unlock_irq(&md->lock);
 		}
 	} else {
 		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
+		ret = __blk_end_request(rqp, 0, brqp->data.bytes_xfered);
 		spin_unlock_irq(&md->lock);
 	}
 
@@ -596,15 +693,27 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 
 	spin_lock_irq(&md->lock);
 	while (ret)
-		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
+		ret = __blk_end_request(rqp, -EIO, blk_rq_cur_bytes(rqp));
 	spin_unlock_irq(&md->lock);
 
+	if (rqc) {
+		mmc_claim_host(card->host);
+		mmc_pre_req(card->host, &brqc->mrq, false);
+		mmc_start_req(card->host, &brqc->mrq);
+	}
+
+	/* Current request becomes previous request and vice versa. */
+	mqrqp->brq.mrq.data = NULL;
+	mqrqp->req = NULL;
+	mq->mqrq_prev = mq->mqrq_cur;
+	mq->mqrq_cur = mqrqp;
+
 	return 0;
 }
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
-	if (req->cmd_flags & REQ_DISCARD) {
+	if (req && req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
 			return mmc_blk_issue_secdiscard_rq(mq, req);
 		else
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index eef3510..2b14d1c 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -59,6 +59,7 @@ static int mmc_queue_thread(void *d)
 		mq->mqrq_cur->req = req;
 		spin_unlock_irq(q->queue_lock);
 
+		mq->issue_fn(mq, req);
 		if (!req) {
 			if (kthread_should_stop()) {
 				set_current_state(TASK_RUNNING);
@@ -71,7 +72,6 @@ static int mmc_queue_thread(void *d)
 		}
 		set_current_state(TASK_RUNNING);
 
-		mq->issue_fn(mq, req);
 	} while (1);
 	up(&mq->thread_sem);
 
-- 
1.7.4.1

  parent reply	other threads:[~2011-04-06 19:07 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-06 19:07 [PATCH v2 00/12] mmc: use nonblock mmc requests to minimize latency Per Forlin
2011-04-06 19:07 ` [PATCH v2 01/12] mmc: add none blocking mmc request function Per Forlin
2011-04-15 10:34   ` David Vrabel
2011-04-20  7:17     ` Per Forlin
2011-04-26 13:29       ` David Vrabel
2011-04-26 14:22         ` Per Forlin
2011-04-06 19:07 ` [PATCH v2 02/12] mmc: mmc_test: add debugfs file to list all tests Per Forlin
2011-04-06 19:07 ` [PATCH v2 03/12] mmc: mmc_test: add test for none blocking transfers Per Forlin
2011-04-17  7:09   ` Lin Tony-B19295
2011-04-20  7:30     ` Per Forlin
2011-04-17 15:46   ` Shawn Guo
2011-04-20  7:41     ` Per Forlin
2011-04-06 19:07 ` [PATCH v2 04/12] mmc: add member in mmc queue struct to hold request data Per Forlin
2011-04-06 19:07 ` [PATCH v2 05/12] mmc: add a block request prepare function Per Forlin
2011-04-06 19:07 ` [PATCH v2 06/12] mmc: move error code in mmc_block_issue_rw_rq to a separate function Per Forlin
2011-04-06 19:07 ` [PATCH v2 07/12] mmc: add a second mmc queue request member Per Forlin
2011-04-06 19:07 ` Per Forlin [this message]
2011-04-20 11:32   ` [PATCH v2 08/12] mmc: add handling for two parallel block requests in issue_rw_rq Per Forlin
2011-04-06 19:07 ` [PATCH v2 09/12] mmc: test: add random fault injection in core.c Per Forlin
2011-04-06 19:07 ` [PATCH v2 10/12] omap_hsmmc: use original sg_len for dma_unmap_sg Per Forlin
2011-04-06 19:07 ` [PATCH v2 11/12] omap_hsmmc: add support for pre_req and post_req Per Forlin
2011-04-06 19:07 ` [PATCH v2 12/12] mmci: implement pre_req() and post_req() Per Forlin
2011-04-08 16:49 ` [PATCH v2 00/12] mmc: use nonblock mmc requests to minimize latency Linus Walleij
2011-04-09 11:55   ` Jae hoon Chung
2011-04-10  3:33     ` anish singh
2011-04-11  9:03       ` Per Forlin
2011-04-11  9:07         ` Sachin Nikam
2011-04-11  9:08     ` Per Forlin
2011-04-19 14:30       ` Jae hoon Chung
2011-04-16 15:48 ` Shawn Guo
2011-04-20  8:19   ` Per Forlin
2011-04-16 16:48 ` [PATCH] mmc: sdhci: add support for pre_req and post_req Shawn Guo
2011-04-16 23:06   ` Andrei Warkentin
2011-04-22 11:01     ` Jaehoon Chung
2011-04-27  0:59       ` Andrei Warkentin
2011-04-26  1:26     ` Jaehoon Chung
2011-04-26  2:47       ` Shawn Guo
2011-04-26 10:21         ` Per Forlin
2011-04-17 16:33 ` [PATCH] mmc: mxs-mmc: " Shawn Guo
2011-04-17 16:48   ` Shawn Guo
2011-04-20  8:01     ` Per Forlin
2011-04-20 14:01       ` Shawn Guo
2011-04-20 15:22         ` Per Forlin
2011-04-21  6:25           ` Shawn Guo
2011-04-21  8:52             ` Per Forlin
2011-04-20 15:30         ` Per Forlin
2011-04-21  6:29           ` Shawn Guo
2011-04-21  8:46             ` Per Forlin
2011-04-21  9:11               ` Shawn Guo
2011-04-21  9:47                 ` Per Forlin
2011-04-21 10:15                   ` Per Forlin
2011-04-28  7:52                   ` Per Forlin
2011-04-28 10:10                     ` Russell King - ARM Linux
2011-04-20  7:58   ` Per Forlin
2011-04-20  8:17     ` Shawn Guo
2011-04-20 13:51   ` [PATCH v2] " Shawn Guo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1302116833-24540-9-git-send-email-per.forlin@linaro.org \
    --to=per.forlin@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).