From 5ca694dfd981a371e9b18cdd4a89c002ffaccbc5 Mon Sep 17 00:00:00 2001
From: San Mehat <san@android.com>
Date: Wed, 3 Dec 2008 10:22:59 -0800
Subject: [PATCH 099/134] mmc: mmcblk: Add new feature 'CONFIG_MMC_BLOCK_PARANOID_RESUME'

  With this feature enabled, mmcblk will check the card-status before issuing
a transaction *only* after being resumed. This protectes us from issuing
transactions before the sdcard is ready (which can occur if the host driver
deferrs mmc_resume_host() to reduce resume latency)

Signed-off-by: San Mehat <san@android.com>
---
 drivers/mmc/card/Kconfig |    7 +++++++
 drivers/mmc/card/block.c |    3 +++
 drivers/mmc/card/queue.c |   28 ++++++++++++++++++++++++++++
 drivers/mmc/card/queue.h |    3 +++
 4 files changed, 41 insertions(+), 0 deletions(-)

--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -32,6 +32,13 @@ config MMC_BLOCK_BOUNCE
 
 	  If unsure, say Y here.
 
+config MMC_BLOCK_PARANOID_RESUME
+	bool "Check card status on resume"
+        depends on MMC_BLOCK
+        default y
+        help
+          Nohelp
+
 config SDIO_UART
 	tristate "SDIO UART/GPS class support"
 	help
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -643,6 +643,9 @@ static int mmc_blk_resume(struct mmc_car
 
 	if (md) {
 		mmc_blk_set_blksize(md, card);
+#ifdef CONFIG_MMC_BLOCK_PARANOID_RESUME
+		md->queue.check_status = 1;
+#endif
 		mmc_queue_resume(&md->queue);
 	}
 	return 0;
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -14,7 +14,9 @@
 #include <linux/freezer.h>
 #include <linux/kthread.h>
 #include <linux/scatterlist.h>
+#include <linux/delay.h>
 
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include "queue.h"
@@ -70,7 +72,33 @@ static int mmc_queue_thread(void *d)
 			continue;
 		}
 		set_current_state(TASK_RUNNING);
+#ifdef CONFIG_MMC_BLOCK_PARANOID_RESUME
+		if (mq->check_status) {
+			struct mmc_command cmd;
 
+			do {
+				int err;
+
+				cmd.opcode = MMC_SEND_STATUS;
+				cmd.arg = mq->card->rca << 16;
+				cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+				mmc_claim_host(mq->card->host);
+				err = mmc_wait_for_cmd(mq->card->host, &cmd, 5);
+				mmc_release_host(mq->card->host);
+
+				if (err) {
+					printk(KERN_ERR "%s: failed to get status (%d)\n",
+					       __func__, err);
+					msleep(5);
+					continue;
+				}
+				printk(KERN_DEBUG "%s: status 0x%.8x\n", __func__, cmd.resp[0]);
+			} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
+				(R1_CURRENT_STATE(cmd.resp[0]) == 7));
+			mq->check_status = 0;
+                }
+#endif
 		mq->issue_fn(mq, req);
 	} while (1);
 	up(&mq->thread_sem);
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -17,6 +17,9 @@ struct mmc_queue {
 	char			*bounce_buf;
 	struct scatterlist	*bounce_sg;
 	unsigned int		bounce_sg_len;
+#ifdef CONFIG_MMC_BLOCK_PARANOID_RESUME
+	int			check_status;
+#endif
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
