diff mbox

[v2,01/12] mmc: add none blocking mmc request function

Message ID 1302116833-24540-2-git-send-email-per.forlin@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Per Forlin April 6, 2011, 7:07 p.m. UTC
Previously there has only been one function mmc_wait_for_req
to start and wait for a request. This patch adds
 * mmc_start_req - starts a request wihtout waiting
 * mmc_wait_for_req_done - waits until request is done
 * mmc_pre_req - asks the host driver to prepare for the next job
 * mmc_post_req - asks the host driver to clean up after a completed job

The intention is to use pre_req() and post_req() to do cache maintenance
while a request is active. pre_req() can be called while a request is active
to minimize latency to start next job. post_req() can be used after the next
job is started to clean up the request. This will minimize the host driver
request end latency. post_req() is typically used before ending the block
request and handing over the buffer to the block layer.

Add a host-private member in mmc_data to be used by
pre_req to mark the data. The host driver will then
check this mark to see if the data is prepared or not.

Signed-off-by: Per Forlin <per.forlin@linaro.org>
---
 drivers/mmc/core/core.c  |   78 ++++++++++++++++++++++++++++++++++++++++------
 include/linux/mmc/core.h |    9 +++++-
 include/linux/mmc/host.h |    9 +++++
 3 files changed, 85 insertions(+), 11 deletions(-)

Comments

David Vrabel April 15, 2011, 10:34 a.m. UTC | #1
On 06/04/11 20:07, Per Forlin wrote:
> Previously there has only been one function mmc_wait_for_req
> to start and wait for a request. This patch adds
>  * mmc_start_req - starts a request wihtout waiting
>  * mmc_wait_for_req_done - waits until request is done
>  * mmc_pre_req - asks the host driver to prepare for the next job
>  * mmc_post_req - asks the host driver to clean up after a completed job

If MMC core had a queue of requests internally you wouldn't need to
provide mmc_pre_req() and mmc_post_req() functions outside of the core.
 i.e., the mmc block driver would just need to queue up two mmc requests
and the core would take care of calling pre_req and post_req at the
correct time.

Using a MMC request queue has other benefits -- it allows multiple users
without having to claim/release the host.  This would be useful for
(especially multi-function) SDIO.

David
David Vrabel April 26, 2011, 1:29 p.m. UTC | #2
On 20/04/11 08:17, Per Forlin wrote:
> 
>> Using a MMC request queue has other benefits -- it allows multiple users
>> without having to claim/release the host.  This would be useful for
>> (especially multi-function) SDIO.
>
> You mean claim and release would be done only within the mmc core. The
> timed saved here would equal the time it takes to release and claim
> the host.
> Claim and release can also be used for power management to indicate if
> any client is using the host, if not the power can be switched off.

Isn't there a separate runtime power management API that different from
claim/release?

> I just want to make sure I understand the multi-function SDIO case, I
> haven't done any work with SDIO.
> Can the SDIO functions compete over the same claim_host at the same time?
> Example: if function 1 claims the host, function 2 and function 3 also
> want to claim the host but have to wait for function 1 to release the
> host.

This is the case.   Each function driver has to claim exclusive access
to the host.

> What is the extra benefit of having the internal request queue for
> multi function SDIO?

It reduces the delays between commands if multiple drivers are sending
commands.  I estimated performance improvements with 2-3% from just
removing the need to claim/release in one particular SDIO function
driver.  Performance improvements for multi-function cards would be a
bit more (5% perhaps?).

The more important benefit is the simplification of the API.

David
Per Forlin April 26, 2011, 2:22 p.m. UTC | #3
On 26 April 2011 15:29, David Vrabel <david.vrabel@csr.com> wrote:
> On 20/04/11 08:17, Per Forlin wrote:
>>
>>> Using a MMC request queue has other benefits -- it allows multiple users
>>> without having to claim/release the host.  This would be useful for
>>> (especially multi-function) SDIO.
>>
>> You mean claim and release would be done only within the mmc core. The
>> timed saved here would equal the time it takes to release and claim
>> the host.
>> Claim and release can also be used for power management to indicate if
>> any client is using the host, if not the power can be switched off.
>
> Isn't there a separate runtime power management API that different from
> claim/release?
>
I misunderstood. I thought you meant that the claim() and release()
were not needed if having an internal request queue in core.c.
Please discard my comment.

>> I just want to make sure I understand the multi-function SDIO case, I
>> haven't done any work with SDIO.
>> Can the SDIO functions compete over the same claim_host at the same time?
>> Example: if function 1 claims the host, function 2 and function 3 also
>> want to claim the host but have to wait for function 1 to release the
>> host.
>
> This is the case.   Each function driver has to claim exclusive access
> to the host.
>
>> What is the extra benefit of having the internal request queue for
>> multi function SDIO?
>
> It reduces the delays between commands if multiple drivers are sending
> commands.  I estimated performance improvements with 2-3% from just
> removing the need to claim/release in one particular SDIO function
> driver.  Performance improvements for multi-function cards would be a
> bit more (5% perhaps?).
>
Your estimates are promising.

> The more important benefit is the simplification of the API.
I agree. I will make a prototype for this. I don't think I will be
able to find time for this until middle of May. I let know you when I
have patches.

>
> David
Thanks,
Per
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1f453ac..e88dd36 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -198,30 +198,88 @@  mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 
 static void mmc_wait_done(struct mmc_request *mrq)
 {
-	complete(mrq->done_data);
+	complete(&mrq->completion);
 }
 
 /**
- *	mmc_wait_for_req - start a request and wait for completion
+ *	mmc_pre_req - Prepare for a new request
+ *	@host: MMC host to prepare command
+ *	@mrq: MMC request to prepare for
+ *	@is_first_req: true if there is no previous started request
+ *                     that may run in parellel to this call, otherwise false
+ *
+ *	mmc_pre_req() is called in prior to mmc_start_req() to let
+ *	host prepare for the new request. Preparation of a request may be
+ *	performed while another request is running on the host.
+ */
+void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+		 bool is_first_req)
+{
+	if (host->ops->pre_req)
+		host->ops->pre_req(host, mrq, is_first_req);
+}
+EXPORT_SYMBOL(mmc_pre_req);
+
+/**
+ *	mmc_post_req - Post process a completed request
+ *	@host: MMC host to post process command
+ *	@mrq: MMC request to post process for
+ *	@err: Error, if none zero, clean up any resources made in pre_req
+ *
+ *	Let the host post process a completed request. Post processing of
+ *	a request may be performed while another reuqest is running.
+ */
+void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, int err)
+{
+	if (host->ops->post_req)
+		host->ops->post_req(host, mrq, err);
+}
+EXPORT_SYMBOL(mmc_post_req);
+
+/**
+ *	mmc_start_req - start a request
  *	@host: MMC host to start command
  *	@mrq: MMC request to start
  *
- *	Start a new MMC custom command request for a host, and wait
- *	for the command to complete. Does not attempt to parse the
- *	response.
+ *	Start a new MMC custom command request for a host.
+ *	Does not wait for the command to complete.
  */
-void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+void mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
-	DECLARE_COMPLETION_ONSTACK(complete);
-
-	mrq->done_data = &complete;
+	init_completion(&mrq->completion);
 	mrq->done = mmc_wait_done;
 
 	mmc_start_request(host, mrq);
+}
+EXPORT_SYMBOL(mmc_start_req);
 
-	wait_for_completion(&complete);
+/**
+ *	mmc_wait_for_req_done - wait for completion of request
+ *	@mrq: MMC request to wait for
+ *
+ *	Wait for the command to complete. Does not attempt to parse the
+ *	response.
+ */
+void mmc_wait_for_req_done(struct mmc_request *mrq)
+{
+	wait_for_completion(&mrq->completion);
 }
+EXPORT_SYMBOL(mmc_wait_for_req_done);
 
+/**
+ *	mmc_wait_for_req - start a request and wait for completion
+ *	@host: MMC host to start command
+ *	@mrq: MMC request to start
+ *
+ *	Start a new MMC custom command request for a host, and wait
+ *	for the command to complete. Does not attempt to parse the
+ *	response.
+ */
+void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+	mmc_start_req(host, mrq);
+	mmc_wait_for_req_done(mrq);
+}
 EXPORT_SYMBOL(mmc_wait_for_req);
 
 /**
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 07f27af..5bbfb71 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -117,6 +117,7 @@  struct mmc_data {
 
 	unsigned int		sg_len;		/* size of scatter list */
 	struct scatterlist	*sg;		/* I/O scatter list */
+	s32			host_cookie;	/* host private data */
 };
 
 struct mmc_request {
@@ -124,13 +125,19 @@  struct mmc_request {
 	struct mmc_data		*data;
 	struct mmc_command	*stop;
 
-	void			*done_data;	/* completion data */
+	struct completion	completion;
 	void			(*done)(struct mmc_request *);/* completion function */
 };
 
 struct mmc_host;
 struct mmc_card;
 
+extern void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+			bool is_first_req);
+extern void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+			 int err);
+extern void mmc_start_req(struct mmc_host *host, struct mmc_request *mrq);
+extern void mmc_wait_for_req_done(struct mmc_request *mrq);
 extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index bcb793e..c056a3d 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -88,6 +88,15 @@  struct mmc_host_ops {
 	 */
 	int (*enable)(struct mmc_host *host);
 	int (*disable)(struct mmc_host *host, int lazy);
+	/*
+	 * It is optional for the host to implement pre_req and post_req in
+	 * order to support double buffering of requests (prepare one
+	 * request while another request is active).
+	 */
+	void	(*post_req)(struct mmc_host *host, struct mmc_request *req,
+			    int err);
+	void	(*pre_req)(struct mmc_host *host, struct mmc_request *req,
+			   bool is_first_req);
 	void	(*request)(struct mmc_host *host, struct mmc_request *req);
 	/*
 	 * Avoid calling these three functions too often or in a "fast path",