summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVenkat Gopalakrishnan <venkatg@codeaurora.org>2015-08-28 17:18:54 -0700
committerSubhash Jadavani <subhashj@codeaurora.org>2016-05-31 15:27:25 -0700
commitcedee495d8ea2a70fbbd928f1dbbaf4d2a2db82c (patch)
treef3bb322aac9365c64fd7bfdbf8207e287606a1bd
parent5175b0f4f57ed86136a89aac8e45ae56f68d9b92 (diff)
mmc: card: fix null pointer deference in cmdq timeout handler
The mmc_queue_req will be present only if the request is issued to the LLD. The request could be fetched from block layer queue but could be waiting to be issued (for e.g. clock scaling is waiting for an empty cmdq queue). Evaluate such cases and reset the timer to give LLD more time. Change-Id: Ic5818f5c2b8356bda9b1612d78b65e07dad011d7 Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
-rw-r--r--drivers/mmc/card/block.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index ed868929b164..7224f4c57421 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2989,18 +2989,38 @@ 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;
+ struct mmc_request *mrq;
+ struct mmc_cmdq_req *cmdq_req;
+
+ BUG_ON(!host);
+
+ /*
+ * The mmc_queue_req will be present only if the request
+ * is issued to the LLD. The request could be fetched from
+ * block layer queue but could be waiting to be issued
+ * (for e.g. clock scaling is waiting for an empty cmdq queue)
+ * Reset the timer in such cases to give LLD more time
+ */
+ if (!mq_rq) {
+ pr_warn("%s: restart timer for tag: %d\n", __func__, req->tag);
+ return BLK_EH_RESET_TIMER;
+ }
+
+ mrq = &mq_rq->cmdq_req.mrq;
+ cmdq_req = &mq_rq->cmdq_req;
+
+ BUG_ON(!mrq || !cmdq_req);
if (cmdq_req->cmdq_req_flags & DCMD)
mrq->cmd->error = -ETIMEDOUT;
else
mrq->data->error = -ETIMEDOUT;
+ BUG_ON(host->err_mrq != NULL);
host->err_mrq = mrq;
- mrq->done(mrq);
- return BLK_EH_NOT_HANDLED;
+ mmc_host_clk_release(mrq->host);
+ return BLK_EH_HANDLED;
}
static void mmc_blk_cmdq_err(struct mmc_queue *mq)
@@ -3081,6 +3101,7 @@ unhalt:
mmc_cmdq_halt(host, false);
out:
+ host->err_mrq = NULL;
pm_runtime_mark_last_busy(&card->dev);
__mmc_put_card(card);