summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsutosh Das <asutoshd@codeaurora.org>2015-03-02 23:14:05 +0530
committerSubhash Jadavani <subhashj@codeaurora.org>2016-05-31 15:26:33 -0700
commiteb2587ce536bffd12bc2cd2a59e3331ba34d4d68 (patch)
treee0db4b2a9007a76a4aedd1681df25665e9591431
parentf446730be194afa78404fd8d1e474305218a000c (diff)
mmc: queue: add timeout capability to requests
Individual requests can have timeouts defined. The default timeout is set to 120 seconds. On a timeout, the block layer notifies the driver and error can be handled thereafter. Change-Id: Ifcd690411770ab266c12a01bb0993f92b0f18bc6 Signed-off-by: Asutosh Das <asutoshd@codeaurora.org> Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
-rw-r--r--drivers/mmc/card/block.c21
-rw-r--r--drivers/mmc/card/queue.c12
-rw-r--r--drivers/mmc/card/queue.h1
-rw-r--r--drivers/mmc/host/cmdq_hci.c8
-rw-r--r--include/linux/mmc/host.h1
5 files changed, 43 insertions, 0 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index fc98eea77fe7..daccedcb7f58 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2735,6 +2735,26 @@ reset:
clear_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
}
+static enum blk_eh_timer_return mmc_blk_cmdq_req_timed_out(struct request *req)
+{
+ struct mmc_queue *mq = req->q->queuedata;
+ struct mmc_host *host = mq->card->host;
+ struct mmc_queue_req *mq_rq = req->special;
+ struct mmc_request *mrq = &mq_rq->cmdq_req.mrq;
+ struct mmc_cmdq_req *cmdq_req = &mq_rq->cmdq_req;
+
+ host->cmdq_ops->dumpstate(host);
+ if (cmdq_req->cmdq_req_flags & DCMD)
+ mrq->cmd->error = -ETIMEDOUT;
+ else
+ mrq->data->error = -ETIMEDOUT;
+
+ host->err_mrq = mrq;
+ mrq->done(mrq);
+
+ return BLK_EH_NOT_HANDLED;
+}
+
static void mmc_blk_cmdq_err(struct mmc_queue *mq)
{
int err;
@@ -3319,6 +3339,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
md->queue.cmdq_complete_fn = mmc_blk_cmdq_complete_rq;
md->queue.cmdq_issue_fn = mmc_blk_cmdq_issue_rq;
md->queue.cmdq_error_fn = mmc_blk_cmdq_err;
+ md->queue.cmdq_req_timed_out = mmc_blk_cmdq_req_timed_out;
}
if (mmc_card_mmc(card) && !card->cmdq_init &&
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 676e080550f8..be417461f44b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -577,6 +577,16 @@ static void mmc_cmdq_error_work(struct work_struct *work)
mq->cmdq_error_fn(mq);
}
+enum blk_eh_timer_return mmc_cmdq_rq_timed_out(struct request *req)
+{
+ struct mmc_queue *mq = req->q->queuedata;
+
+ pr_err("%s: request with tag: %d flags: 0x%llx timed out\n",
+ mmc_hostname(mq->card->host), req->tag, req->cmd_flags);
+
+ return mq->cmdq_req_timed_out(req);
+}
+
int mmc_cmdq_init(struct mmc_queue *mq, struct mmc_card *card)
{
int i, ret = 0;
@@ -619,6 +629,8 @@ int mmc_cmdq_init(struct mmc_queue *mq, struct mmc_card *card)
blk_queue_softirq_done(mq->queue, mmc_cmdq_softirq_done);
INIT_WORK(&mq->cmdq_err_work, mmc_cmdq_error_work);
+ blk_queue_rq_timed_out(mq->queue, mmc_cmdq_rq_timed_out);
+ blk_queue_rq_timeout(mq->queue, 120 * HZ);
card->cmdq_init = true;
goto out;
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index c4acab9bff27..388f099a06f5 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -58,6 +58,7 @@ struct mmc_queue {
struct request *);
void (*cmdq_complete_fn)(struct request *);
void (*cmdq_error_fn)(struct mmc_queue *);
+ enum blk_eh_timer_return (*cmdq_req_timed_out)(struct request *);
void *data;
struct request_queue *queue;
struct mmc_queue_req mqrq[2];
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index affc92756c0b..08ba2546cf37 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -715,6 +715,13 @@ static void cmdq_post_req(struct mmc_host *host, struct mmc_request *mrq,
}
}
+static void cmdq_dumpstate(struct mmc_host *mmc)
+{
+ struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
+
+ cmdq_dumpregs(cq_host);
+}
+
static const struct mmc_cmdq_host_ops cmdq_host_ops = {
.enable = cmdq_enable,
.disable = cmdq_disable,
@@ -722,6 +729,7 @@ static const struct mmc_cmdq_host_ops cmdq_host_ops = {
.post_req = cmdq_post_req,
.halt = cmdq_halt,
.reset = cmdq_reset,
+ .dumpstate = cmdq_dumpstate,
};
struct cmdq_host *cmdq_pltfm_init(struct platform_device *pdev)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 18d041f85f95..6c6a699abea9 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -96,6 +96,7 @@ struct mmc_cmdq_host_ops {
int err);
int (*halt)(struct mmc_host *host, bool halt);
void (*reset)(struct mmc_host *host, bool soft);
+ void (*dumpstate)(struct mmc_host *host);
};
struct mmc_host_ops {