summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-3.10/0038-Lazy-CRC-quirk-Implemented-retrying-mechanisms-for-S.patch
blob: b21e62bcba1c2d9ab491428339f4db3a3177293e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
From d6442f505a7bf1bebe9bd4689d021f007a269cd6 Mon Sep 17 00:00:00 2001
From: dero <de@ro>
Date: Mon, 19 Nov 2012 12:46:06 +0100
Subject: [PATCH 038/174] 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(-)

--- 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_car
 }
 
 /*
- * 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
 	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 *h
 
 	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.
--- 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_
         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_op
 	.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 pl
 		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
 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");