diff options
| author | Asutosh Das <asutoshd@codeaurora.org> | 2015-04-23 16:01:57 +0530 |
|---|---|---|
| committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-31 15:26:34 -0700 |
| commit | 5bec5e8420699f14d23f0e9589ff10f916dc213b (patch) | |
| tree | 307b6409b7aba4b83f00a4b933629b7bfe6232f1 | |
| parent | d10ca4a6adbf5ad663f565a7f7fe0356647beab0 (diff) | |
mmc: core: fix shutdown in cmdq mode
During the shutdown process,
- Stop the queue
- Flush all the pending requests
- Halt the Controller
- Put the card in legacy mode
Change-Id: I5fe4e998bc04bfd8f50de63f3beae3cb25f1c8ba
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
| -rw-r--r-- | drivers/mmc/card/block.c | 32 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.c | 29 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.h | 2 |
3 files changed, 63 insertions, 0 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index daccedcb7f58..4a0dba010cfd 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2735,6 +2735,34 @@ reset: clear_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state); } +static void mmc_blk_cmdq_shutdown(struct mmc_queue *mq) +{ + int err; + struct mmc_card *card = mq->card; + struct mmc_host *host = card->host; + + err = mmc_cmdq_halt(host, true); + if (err) { + pr_err("%s: halt: failed: %d\n", __func__, err); + return; + } + + mmc_claim_host(card->host); + /* disable CQ mode in card */ + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_CMDQ, 0, + card->ext_csd.generic_cmd6_time); + if (err) { + pr_err("%s: failed to switch card to legacy mode: %d\n", + __func__, err); + goto out; + } else { + host->card->cmdq_init = false; + } +out: + mmc_release_host(card->host); +} + static enum blk_eh_timer_return mmc_blk_cmdq_req_timed_out(struct request *req) { struct mmc_queue *mq = req->q->queuedata; @@ -2880,6 +2908,9 @@ out: test_and_clear_bit(0, &ctx_info->req_starved)) blk_run_queue(mq->queue); mmc_release_host(host); + + if (blk_queue_stopped(mq->queue) && !ctx_info->active_reqs) + complete(&mq->cmdq_shutdown_complete); return; } @@ -3340,6 +3371,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, 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; + md->queue.cmdq_shutdown = mmc_blk_cmdq_shutdown; } if (mmc_card_mmc(card) && !card->cmdq_init && diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index be417461f44b..d47b18c20e71 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -628,6 +628,7 @@ 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); + init_completion(&mq->cmdq_shutdown_complete); blk_queue_rq_timed_out(mq->queue, mmc_cmdq_rq_timed_out); blk_queue_rq_timeout(mq->queue, 120 * HZ); @@ -659,6 +660,12 @@ void mmc_cmdq_clean(struct mmc_queue *mq, struct mmc_card *card) mq->mqrq_cmdq = NULL; } +static void mmc_wait_for_pending_reqs(struct mmc_queue *mq) +{ + wait_for_completion(&mq->cmdq_shutdown_complete); + mq->cmdq_shutdown(mq); +} + /** * mmc_queue_suspend - suspend a MMC request queue * @mq: MMC queue to suspend @@ -673,6 +680,27 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) struct request_queue *q = mq->queue; unsigned long flags; int rc = 0; + struct mmc_card *card = mq->card; + + if (card->cmdq_init) { + struct mmc_host *host = card->host; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + blk_stop_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + + if (host->cmdq_ctx.active_reqs) { + if (!wait) + rc = -EBUSY; + else + mmc_wait_for_pending_reqs(mq); + } else { + mq->cmdq_shutdown(mq); + } + + goto out; + } if (!(test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags))) { spin_lock_irqsave(q->queue_lock, flags); @@ -695,6 +723,7 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) rc = 0; } } +out: return rc; } diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 388f099a06f5..ab89102a4baa 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -70,9 +70,11 @@ struct mmc_queue { int num_wr_reqs_to_start_packing; bool no_pack_for_random; struct work_struct cmdq_err_work; + struct completion cmdq_shutdown_complete; int (*err_check_fn) (struct mmc_card *, struct mmc_async_req *); void (*packed_test_fn) (struct request_queue *, struct mmc_queue_req *); + void (*cmdq_shutdown)(struct mmc_queue *); }; extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *, |
