mmc: card: abort the suspend if the card is busy
mmc_blk_suspend() is triggered when system is going into suspend which
then waits for the mmcqd thread (which processes active MMC transfer
requests) to complete all queued transfer requests but if mmcqd has
multiple requests to be processed at this point, mmc_blk_suspend() may
very well sleep for duration longer than DPM (Device Power Management)
timeout (currently 12 sec) causing the DPM timeout bug.
To fix this issue, mmc_blk_suspend() checks if there are any more pending
MMC requests in progress or not and if there are any, it returns error
which should abort the ongoing system suspend.
CRs-Fixed: 439192
Change-Id: Ic7ba2f013d10a1952c30ea2ed93f74b831fcc27d
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9ee19ab..5531c05 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2879,14 +2879,27 @@
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
+ int rc = 0;
if (md) {
- mmc_queue_suspend(&md->queue);
+ rc = mmc_queue_suspend(&md->queue);
+ if (rc)
+ goto out;
list_for_each_entry(part_md, &md->part, part) {
- mmc_queue_suspend(&part_md->queue);
+ rc = mmc_queue_suspend(&part_md->queue);
+ if (rc)
+ goto out_resume;
}
}
- return 0;
+ goto out;
+
+ out_resume:
+ mmc_queue_resume(&md->queue);
+ list_for_each_entry(part_md, &md->part, part) {
+ mmc_queue_resume(&part_md->queue);
+ }
+ out:
+ return rc;
}
static int mmc_blk_resume(struct mmc_card *card)
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index c4b2d16..f0aca77 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -387,10 +387,11 @@
* complete any outstanding requests. This ensures that we
* won't suspend while a request is being processed.
*/
-void mmc_queue_suspend(struct mmc_queue *mq)
+int mmc_queue_suspend(struct mmc_queue *mq)
{
struct request_queue *q = mq->queue;
unsigned long flags;
+ int rc = 0;
if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
mq->flags |= MMC_QUEUE_SUSPENDED;
@@ -399,8 +400,20 @@
blk_stop_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
- down(&mq->thread_sem);
+ rc = down_trylock(&mq->thread_sem);
+ if (rc) {
+ /*
+ * Failed to take the lock so better to abort the
+ * suspend because mmcqd thread is processing requests.
+ */
+ mq->flags &= ~MMC_QUEUE_SUSPENDED;
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_start_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ rc = -EBUSY;
+ }
}
+ return rc;
}
/**
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 119b0c7..df1e872 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -59,7 +59,7 @@
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
const char *);
extern void mmc_cleanup_queue(struct mmc_queue *);
-extern void mmc_queue_suspend(struct mmc_queue *);
+extern int mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);
extern unsigned int mmc_queue_map_sg(struct mmc_queue *,