Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 180a0da4 authored by Konstantin Dorfman's avatar Konstantin Dorfman
Browse files

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: default avatarKonstantin Dorfman <kdorfman@codeaurora.org>
parent 260b1b32
Loading
Loading
Loading
Loading
+24 −16
Original line number Diff line number Diff line
@@ -680,12 +680,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
@@ -702,13 +696,14 @@ 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);

		if (wait) {
			/*
			 * Wait for already queued requests to be issued by
			 * mmc_cmdqd.
@@ -716,8 +711,21 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait)
			down(&mq->thread_sem);
			/* Wait for already issued requests to complete */
			if (host->cmdq_ctx.active_reqs)
			mmc_wait_for_pending_reqs(mq);
				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;
	}