Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 255212
b: refs/heads/master
c: aa8b683
h: refs/heads/master
v: v3
  • Loading branch information
Per Forlin authored and Chris Ball committed Jul 20, 2011
1 parent 23b1978 commit 27ca299
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0500f10cc2d624034f350edae2529975c0f1c1f8
refs/heads/master: aa8b683a7d392271ed349c6ab9f36b8c313794b7
113 changes: 103 additions & 10 deletions trunk/drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,109 @@ 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);
}

static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
mmc_start_request(host, mrq);
}

static void mmc_wait_for_req_done(struct mmc_host *host,
struct mmc_request *mrq)
{
wait_for_completion(&mrq->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.
*/
static 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);
}

/**
* 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 non 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.
*/
static 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);
}

/**
* mmc_start_req - start a non-blocking request
* @host: MMC host to start command
* @areq: async request to start
* @error: out parameter returns 0 for success, otherwise non zero
*
* Start a new MMC custom command request for a host.
* If there is on ongoing async request wait for completion
* of that request and start the new one and return.
* Does not wait for the new request to complete.
*
* Returns the completed request, NULL in case of none completed.
* Wait for the an ongoing request (previoulsy started) to complete and
* return the completed request. If there is no ongoing request, NULL
* is returned without waiting. NULL is not an error condition.
*/
struct mmc_async_req *mmc_start_req(struct mmc_host *host,
struct mmc_async_req *areq, int *error)
{
int err = 0;
struct mmc_async_req *data = host->areq;

/* Prepare a new request */
if (areq)
mmc_pre_req(host, areq->mrq, !host->areq);

if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
err = host->areq->err_check(host->card, host->areq);
if (err) {
mmc_post_req(host, host->areq->mrq, 0);
if (areq)
mmc_post_req(host, areq->mrq, -EINVAL);

host->areq = NULL;
goto out;
}
}

if (areq)
__mmc_start_req(host, areq->mrq);

if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);

host->areq = areq;
out:
if (error)
*error = err;
return data;
}
EXPORT_SYMBOL(mmc_start_req);

/**
* mmc_wait_for_req - start a request and wait for completion
* @host: MMC host to start command
Expand All @@ -212,16 +312,9 @@ static void mmc_wait_done(struct mmc_request *mrq)
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
DECLARE_COMPLETION_ONSTACK(complete);

mrq->done_data = &complete;
mrq->done = mmc_wait_done;

mmc_start_request(host, mrq);

wait_for_completion(&complete);
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
}

EXPORT_SYMBOL(mmc_wait_for_req);

/**
Expand Down
6 changes: 5 additions & 1 deletion trunk/include/linux/mmc/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -125,13 +126,16 @@ 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;
struct mmc_async_req;

extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
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_app_cmd(struct mmc_host *, struct mmc_card *);
Expand Down
21 changes: 21 additions & 0 deletions trunk/include/linux/mmc/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,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",
Expand Down Expand Up @@ -144,6 +153,16 @@ struct mmc_host_ops {
struct mmc_card;
struct device;

struct mmc_async_req {
/* active mmc request */
struct mmc_request *mrq;
/*
* Check error status of completed mmc request.
* Returns 0 if success otherwise non zero.
*/
int (*err_check) (struct mmc_card *, struct mmc_async_req *);
};

struct mmc_host {
struct device *parent;
struct device class_dev;
Expand Down Expand Up @@ -282,6 +301,8 @@ struct mmc_host {

struct dentry *debugfs_root;

struct mmc_async_req *areq; /* active async req */

unsigned long private[0] ____cacheline_aligned;
};

Expand Down

0 comments on commit 27ca299

Please sign in to comment.