summaryrefslogtreecommitdiff
path: root/drivers/mmc/card/queue.c
diff options
context:
space:
mode:
authorKonstantin Dorfman <kdorfman@codeaurora.org>2015-07-23 10:16:57 +0300
committerSubhash Jadavani <subhashj@codeaurora.org>2016-05-31 15:27:06 -0700
commit2cfffa3bbe271f834b8b4d28332430eb809f7fc9 (patch)
treeb7d73930f17b275dbd44f598c8b051524f2c2071 /drivers/mmc/card/queue.c
parent42dd0264d115e4b70a4a044679dd121689e422f0 (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.c40
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;
}