From d94e2bd60b27f2ff7d6e9ff7ee43848bb2090c06 Mon Sep 17 00:00:00 2001
From: dero <de@ro>
Date: Mon, 19 Nov 2012 12:46:06 +0100
Subject: [PATCH 038/196] Lazy CRC quirk: Implemented retrying mechanisms for
 SD SSR and SCR, disabled missing_status and spurious CRC ACMD51 quirks by
 default (should be fixed by the retrying-mechanishm)

---
 drivers/mmc/core/sd.c            | 115 +++++++++++++++++++++++++++++++++------
 drivers/mmc/host/sdhci-bcm2708.c |  11 +++-
 2 files changed, 108 insertions(+), 18 deletions(-)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 9e645e1..1ee6cf3 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -13,6 +13,8 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
+#include <linux/jiffies.h>
+#include <linux/nmi.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -58,6 +60,15 @@ static const unsigned int tacc_mant[] = {
 		__res & __mask;						\
 	})
 
+// timeout for tries
+static const unsigned long retry_timeout_ms= 10*1000;
+
+// try at least 10 times, even if timeout is reached
+static const int retry_min_tries= 10;
+
+// delay between tries
+static const unsigned long retry_delay_ms= 10;
+
 /*
  * Given the decoded CSD structure, decode the raw CID to our CID structure.
  */
@@ -210,12 +221,62 @@ static int mmc_decode_scr(struct mmc_card *card)
 }
 
 /*
- * Fetch and process SD Status register.
+ * Fetch and process SD Configuration Register.
+ */
+static int mmc_read_scr(struct mmc_card *card)
+{
+	unsigned long timeout_at;
+	int err, tries;
+
+	timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms );
+	tries= 		0;
+
+	while( tries < retry_min_tries || time_before( jiffies, timeout_at ) )
+	{
+		unsigned long delay_at;
+		tries++;
+
+		err = mmc_app_send_scr(card, card->raw_scr);
+		if( !err )
+			break; // sucess!!!
+
+		touch_nmi_watchdog();	  // we are still alive!
+
+		// delay
+		delay_at= jiffies + msecs_to_jiffies( retry_delay_ms );
+		while( time_before( jiffies, delay_at ) )
+		{
+			mdelay( 1 );
+			touch_nmi_watchdog();	  // we are still alive!
+		}
+	}
+	
+	if( err)
+	{
+		pr_err("%s: failed to read SD Configuration register (SCR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err );
+		return err;
+	}
+
+	if( tries > 1 )
+	{
+		pr_info("%s: could read SD Configuration register (SCR) at the %dth attempt\n", mmc_hostname(card->host), tries );
+	}
+
+	err = mmc_decode_scr(card);
+	if (err)
+		return err;
+	
+	return err;
+}
+
+/*
+ * Fetch and process SD Status Register.
  */
 static int mmc_read_ssr(struct mmc_card *card)
 {
+	unsigned long timeout_at;
 	unsigned int au, es, et, eo;
-	int err, i;
+	int err, i, tries;
 	u32 *ssr;
 
 	if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
@@ -227,15 +288,41 @@ static int mmc_read_ssr(struct mmc_card *card)
 	ssr = kmalloc(64, GFP_KERNEL);
 	if (!ssr)
 		return -ENOMEM;
-
-	err = mmc_app_sd_status(card, ssr);
-	if (err) {
-		pr_warning("%s: problem reading SD Status "
-			"register.\n", mmc_hostname(card->host));
-		err = 0;
+	
+	timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms );
+	tries= 		0;
+	
+	while( tries < retry_min_tries || time_before( jiffies, timeout_at ) )
+	{
+		unsigned long delay_at;
+		tries++;
+		
+		err= mmc_app_sd_status(card, ssr);
+		if( !err )
+			break; // sucess!!!
+	
+		touch_nmi_watchdog();	  // we are still alive!
+	
+		// delay
+		delay_at= jiffies + msecs_to_jiffies( retry_delay_ms );
+		while( time_before( jiffies, delay_at ) )
+		{
+			mdelay( 1 );
+			touch_nmi_watchdog();	  // we are still alive!
+		}			
+	}
+	
+	if( err) 
+	{
+		pr_err("%s: failed to read SD Status register (SSR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err );
 		goto out;
 	}
 
+	if( tries > 1 )
+	{
+		pr_info("%s: could read SD Status register (SSR) at the %dth attempt\n", mmc_hostname(card->host), tries );
+	}
+
 	for (i = 0; i < 16; i++)
 		ssr[i] = be32_to_cpu(ssr[i]);
 
@@ -808,15 +895,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 
 	if (!reinit) {
 		/*
-		 * Fetch SCR from card.
+		 * Fetch and decode SD Configuration register.
 		 */
-		err = mmc_app_send_scr(card, card->raw_scr);
-		if (err)
-			return err;
-
-		err = mmc_decode_scr(card);
-		if (err)
-			return err;
+	  	err = mmc_read_scr(card);
+	  	if( err )
+	  		return err;
 
 		/*
 		 * Fetch and process SD Status register.
diff --git a/drivers/mmc/host/sdhci-bcm2708.c b/drivers/mmc/host/sdhci-bcm2708.c
index ffd7310..3556ed3 100644
--- a/drivers/mmc/host/sdhci-bcm2708.c
+++ b/drivers/mmc/host/sdhci-bcm2708.c
@@ -137,6 +137,7 @@ static bool allow_highspeed = 1;
 static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ;
 static bool sync_after_dma = 1;
 static bool missing_status = 1;
+static bool spurious_crc_acmd51 = 0;
 bool enable_llm = 1;
 
 #if 0
@@ -1103,7 +1104,7 @@ static unsigned int sdhci_bcm2708_quirk_extra_ints(struct sdhci_host *host)
         return 1;
 }
 
-static unsigned int sdhci_bcm2708_quirk_spurious_crc(struct sdhci_host *host)
+static unsigned int sdhci_bcm2708_quirk_spurious_crc_acmd51(struct sdhci_host *host)
 {
         return 1;
 }
@@ -1149,7 +1150,6 @@ static struct sdhci_ops sdhci_bcm2708_ops = {
 	.pdma_reset = sdhci_bcm2708_platdma_reset,
 #endif
 	.extra_ints = sdhci_bcm2708_quirk_extra_ints,
-	.spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc,
 	.voltage_broken = sdhci_bcm2708_quirk_voltage_broken,
 	.uhs_broken = sdhci_bcm2708_uhs_broken,
 };
@@ -1194,6 +1194,11 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev)
 		sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status;
 	}
 
+	if( spurious_crc_acmd51 ) {
+		sdhci_bcm2708_ops.spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc_acmd51;
+	}
+
+
 	printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable");
 
 	host->hw_name = "BCM2708_Arasan";
@@ -1389,6 +1394,7 @@ module_param(allow_highspeed, bool, 0444);
 module_param(emmc_clock_freq, int, 0444);
 module_param(sync_after_dma, bool, 0444);
 module_param(missing_status, bool, 0444);
+module_param(spurious_crc_acmd51, bool, 0444);
 module_param(enable_llm, bool, 0444);
 module_param(cycle_delay, int, 0444);
 
@@ -1401,6 +1407,7 @@ MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes");
 MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock");
 MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete");
 MODULE_PARM_DESC(missing_status, "Use the missing status quirk");
+MODULE_PARM_DESC(spurious_crc_acmd51, "Use the spurious crc quirk for reading SCR (ACMD51)");
 MODULE_PARM_DESC(enable_llm, "Enable low-latency mode");
 
 
-- 
1.9.1

