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>
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index a36783d..9d3dcd1 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3280,18 +3280,38 @@
 	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)
@@ -3372,6 +3392,7 @@
 	mmc_cmdq_halt(host, false);
 
 out:
+	host->err_mrq = NULL;
 	pm_runtime_mark_last_busy(&card->dev);
 	__mmc_put_card(card);