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>
This commit is contained in:
Konstantin Dorfman 2015-07-23 10:16:57 +03:00 committed by Subhash Jadavani
parent 42dd0264d1
commit 2cfffa3bbe

View file

@ -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;
}