Message ID | 1302116833-24540-2-git-send-email-per.forlin@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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
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
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 --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",
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(-)