summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);