diff options
author | Konstantin Dorfman <kdorfman@codeaurora.org> | 2015-07-23 10:16:57 +0300 |
---|---|---|
committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-31 15:27:06 -0700 |
commit | 2cfffa3bbe271f834b8b4d28332430eb809f7fc9 (patch) | |
tree | b7d73930f17b275dbd44f598c8b051524f2c2071 /drivers/mmc/card/queue.c | |
parent | 42dd0264d115e4b70a4a044679dd121689e422f0 (diff) |
mmc: queue: fix for system suspend flow for eMMC command queue (cmdq)
System suspend executed on kernel PM core context. When there are active
requests system suspend is rejected. Semaphore used to resolve race
between mmc_cmdq_thread() and mmc_queue_suspend().
Change-Id: I88f668d7a6dd6403407ac8208265e4439b35173c
Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org>
Diffstat (limited to 'drivers/mmc/card/queue.c')
-rw-r--r-- | drivers/mmc/card/queue.c | 40 |
1 files changed, 24 insertions, 16 deletions
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index ba3949adbe48..3fcd18353eca 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -686,12 +686,6 @@ 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 @@ -708,22 +702,36 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) int rc = 0; struct mmc_card *card = mq->card; - if (card->cmdq_init && blk_queue_tagged(q) && wait) { + if (card->cmdq_init && blk_queue_tagged(q)) { struct mmc_host *host = card->host; spin_lock_irqsave(q->queue_lock, flags); blk_stop_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); - /* - * Wait for already queued requests to be issued by - * mmc_cmdqd. - */ - down(&mq->thread_sem); - /* Wait for already issued requests to complete */ - if (host->cmdq_ctx.active_reqs) - mmc_wait_for_pending_reqs(mq); - mq->cmdq_shutdown(mq); + if (wait) { + /* + * Wait for already queued requests to be issued by + * mmc_cmdqd. + */ + down(&mq->thread_sem); + /* Wait for already issued requests to complete */ + if (host->cmdq_ctx.active_reqs) + wait_for_completion( + &mq->cmdq_shutdown_complete); + + mq->cmdq_shutdown(mq); + } else if (!test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags)) { + rc = down_trylock(&mq->thread_sem); + if (rc || host->cmdq_ctx.active_reqs) { + clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags); + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + rc = -EBUSY; + } + } + goto out; } |