1 From d90c379ffd993c72371252fe7840c14e4428410b Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.org>
3 Date: Wed, 15 Jun 2016 17:13:55 +0100
4 Subject: [PATCH] bcm2835-sdhost: Improvements to error recovery
6 1) Try to avoid reducing overclock when a card is removed.
8 2) Reset overclock on card insertion.
10 3) Reduce logging when errors occur, lowering the severity of
11 some messages and making others conditional on the debug
14 4) Attempt to identify a disconnected SD bus earlier, treating a
15 zero returned OCR (voltage support) as an error condition.
17 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
19 drivers/mmc/host/bcm2835-sdhost.c | 117 ++++++++++++++++++++++++--------------
20 1 file changed, 74 insertions(+), 43 deletions(-)
22 --- a/drivers/mmc/host/bcm2835-sdhost.c
23 +++ b/drivers/mmc/host/bcm2835-sdhost.c
25 #include <linux/mmc/mmc.h>
26 #include <linux/mmc/host.h>
27 #include <linux/mmc/sd.h>
28 +#include <linux/mmc/sdio.h>
29 #include <linux/scatterlist.h>
30 #include <linux/of_address.h>
31 #include <linux/of_irq.h>
32 @@ -206,6 +207,7 @@ struct bcm2835_host {
33 struct timeval stop_time; /* when the last stop was issued */
34 u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
35 u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
36 + u32 user_overclock_50; /* User's preferred frequency to use when 50MHz is requested (in MHz) */
37 u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
38 u32 overclock; /* Current frequency if overclocked, else zero */
39 u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
40 @@ -282,7 +284,7 @@ static void log_dump(void)
42 entry = sdhost_log_buf + idx;
43 if (entry->event[0] != '\0')
44 - pr_err("[%08x] %.4s %x %x\n",
45 + pr_info("[%08x] %.4s %x %x\n",
49 @@ -324,7 +326,7 @@ static void bcm2835_sdhost_dumpcmd(struc
53 - pr_err("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
54 + pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n",
55 mmc_hostname(host->mmc),
56 (cmd == host->cmd) ? '>' : ' ',
57 label, cmd->opcode, cmd->arg, cmd->flags,
58 @@ -339,7 +341,7 @@ static void bcm2835_sdhost_dumpregs(stru
59 bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc");
60 bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd");
62 - pr_err("%s: data blocks %x blksz %x - err %d\n",
63 + pr_info("%s: data blocks %x blksz %x - err %d\n",
64 mmc_hostname(host->mmc),
65 host->mrq->data->blocks,
66 host->mrq->data->blksz,
67 @@ -347,53 +349,53 @@ static void bcm2835_sdhost_dumpregs(stru
68 bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop");
71 - pr_err("%s: =========== REGISTER DUMP ===========\n",
72 + pr_info("%s: =========== REGISTER DUMP ===========\n",
73 mmc_hostname(host->mmc));
75 - pr_err("%s: SDCMD 0x%08x\n",
76 + pr_info("%s: SDCMD 0x%08x\n",
77 mmc_hostname(host->mmc),
78 bcm2835_sdhost_read(host, SDCMD));
79 - pr_err("%s: SDARG 0x%08x\n",
80 + pr_info("%s: SDARG 0x%08x\n",
81 mmc_hostname(host->mmc),
82 bcm2835_sdhost_read(host, SDARG));
83 - pr_err("%s: SDTOUT 0x%08x\n",
84 + pr_info("%s: SDTOUT 0x%08x\n",
85 mmc_hostname(host->mmc),
86 bcm2835_sdhost_read(host, SDTOUT));
87 - pr_err("%s: SDCDIV 0x%08x\n",
88 + pr_info("%s: SDCDIV 0x%08x\n",
89 mmc_hostname(host->mmc),
90 bcm2835_sdhost_read(host, SDCDIV));
91 - pr_err("%s: SDRSP0 0x%08x\n",
92 + pr_info("%s: SDRSP0 0x%08x\n",
93 mmc_hostname(host->mmc),
94 bcm2835_sdhost_read(host, SDRSP0));
95 - pr_err("%s: SDRSP1 0x%08x\n",
96 + pr_info("%s: SDRSP1 0x%08x\n",
97 mmc_hostname(host->mmc),
98 bcm2835_sdhost_read(host, SDRSP1));
99 - pr_err("%s: SDRSP2 0x%08x\n",
100 + pr_info("%s: SDRSP2 0x%08x\n",
101 mmc_hostname(host->mmc),
102 bcm2835_sdhost_read(host, SDRSP2));
103 pr_err("%s: SDRSP3 0x%08x\n",
104 mmc_hostname(host->mmc),
105 bcm2835_sdhost_read(host, SDRSP3));
106 - pr_err("%s: SDHSTS 0x%08x\n",
107 + pr_info("%s: SDHSTS 0x%08x\n",
108 mmc_hostname(host->mmc),
109 bcm2835_sdhost_read(host, SDHSTS));
110 - pr_err("%s: SDVDD 0x%08x\n",
111 + pr_info("%s: SDVDD 0x%08x\n",
112 mmc_hostname(host->mmc),
113 bcm2835_sdhost_read(host, SDVDD));
114 - pr_err("%s: SDEDM 0x%08x\n",
115 + pr_info("%s: SDEDM 0x%08x\n",
116 mmc_hostname(host->mmc),
117 bcm2835_sdhost_read(host, SDEDM));
118 - pr_err("%s: SDHCFG 0x%08x\n",
119 + pr_info("%s: SDHCFG 0x%08x\n",
120 mmc_hostname(host->mmc),
121 bcm2835_sdhost_read(host, SDHCFG));
122 - pr_err("%s: SDHBCT 0x%08x\n",
123 + pr_info("%s: SDHBCT 0x%08x\n",
124 mmc_hostname(host->mmc),
125 bcm2835_sdhost_read(host, SDHBCT));
126 - pr_err("%s: SDHBLC 0x%08x\n",
127 + pr_info("%s: SDHBLC 0x%08x\n",
128 mmc_hostname(host->mmc),
129 bcm2835_sdhost_read(host, SDHBLC));
131 - pr_err("%s: ===========================================\n",
132 + pr_info("%s: ===========================================\n",
133 mmc_hostname(host->mmc));
136 @@ -608,7 +610,7 @@ static void bcm2835_sdhost_read_block_pi
137 (fsm_state != SDEDM_FSM_READCRC)) {
138 hsts = bcm2835_sdhost_read(host,
140 - pr_err("%s: fsm %x, hsts %x\n",
141 + pr_info("%s: fsm %x, hsts %x\n",
142 mmc_hostname(host->mmc),
144 if (hsts & SDHSTS_ERROR_MASK)
145 @@ -698,7 +700,7 @@ static void bcm2835_sdhost_write_block_p
146 (fsm_state != SDEDM_FSM_WRITESTART2)) {
147 hsts = bcm2835_sdhost_read(host,
149 - pr_err("%s: fsm %x, hsts %x\n",
150 + pr_info("%s: fsm %x, hsts %x\n",
151 mmc_hostname(host->mmc),
153 if (hsts & SDHSTS_ERROR_MASK)
154 @@ -953,9 +955,10 @@ bool bcm2835_sdhost_send_command(struct
156 while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
158 - pr_err("%s: previous command never completed.\n",
159 + pr_warn("%s: previous command never completed.\n",
160 mmc_hostname(host->mmc));
161 - bcm2835_sdhost_dumpregs(host);
163 + bcm2835_sdhost_dumpregs(host);
164 cmd->error = -EILSEQ;
165 tasklet_schedule(&host->finish_tasklet);
167 @@ -1213,10 +1216,12 @@ static void bcm2835_sdhost_finish_comman
169 /* Check for errors */
170 if (sdcmd & SDCMD_NEW_FLAG) {
171 - pr_err("%s: command never completed.\n",
172 - mmc_hostname(host->mmc));
173 - bcm2835_sdhost_dumpregs(host);
174 - host->cmd->error = -EIO;
176 + pr_err("%s: command %d never completed.\n",
177 + mmc_hostname(host->mmc), host->cmd->opcode);
178 + bcm2835_sdhost_dumpregs(host);
180 + host->cmd->error = -EILSEQ;
181 tasklet_schedule(&host->finish_tasklet);
183 } else if (sdcmd & SDCMD_FAIL_FLAG) {
184 @@ -1238,15 +1243,14 @@ static void bcm2835_sdhost_finish_comman
186 if (sdhsts & SDHSTS_CMD_TIME_OUT) {
188 - pr_err("%s: command %d timeout\n",
189 + pr_warn("%s: command %d timeout\n",
190 mmc_hostname(host->mmc),
192 host->cmd->error = -ETIMEDOUT;
194 - pr_err("%s: unexpected command %d error\n",
195 + pr_warn("%s: unexpected command %d error\n",
196 mmc_hostname(host->mmc),
198 - bcm2835_sdhost_dumpregs(host);
199 host->cmd->error = -EILSEQ;
201 tasklet_schedule(&host->finish_tasklet);
202 @@ -1370,8 +1374,10 @@ static void bcm2835_sdhost_busy_irq(stru
203 } else if (intmask & SDHSTS_CMD_TIME_OUT)
204 host->cmd->error = -ETIMEDOUT;
207 - bcm2835_sdhost_dumpregs(host);
210 + bcm2835_sdhost_dumpregs(host);
214 bcm2835_sdhost_finish_command(host, NULL);
215 @@ -1595,7 +1601,7 @@ void bcm2835_sdhost_set_clock(struct bcm
216 host->overclock_50 = (clock/MHZ);
218 if (clock != host->overclock) {
219 - pr_warn("%s: overclocking to %dHz\n",
220 + pr_info("%s: overclocking to %dHz\n",
221 mmc_hostname(host->mmc), clock);
222 host->overclock = clock;
224 @@ -1605,6 +1611,11 @@ void bcm2835_sdhost_set_clock(struct bcm
225 pr_warn("%s: cancelling overclock\n",
226 mmc_hostname(host->mmc));
228 + } else if (input_clock == 0) {
229 + /* Reset the preferred overclock when the clock is stopped.
230 + * This always happens during initialisation. */
231 + host->overclock_50 = host->user_overclock_50;
232 + host->overclock = 0;
235 /* Set the timeout to 500ms */
236 @@ -1678,13 +1689,15 @@ static void bcm2835_sdhost_request(struc
237 log_event("REQ<", (u32)mrq, edm);
238 if ((fsm != SDEDM_FSM_IDENTMODE) &&
239 (fsm != SDEDM_FSM_DATAMODE)) {
240 - pr_err("%s: previous command (%d) not complete (EDM %x)\n",
241 - mmc_hostname(host->mmc),
242 - bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK,
244 log_event("REQ!", (u32)mrq, edm);
246 - bcm2835_sdhost_dumpregs(host);
248 + pr_warn("%s: previous command (%d) not complete (EDM %x)\n",
249 + mmc_hostname(host->mmc),
250 + bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK,
253 + bcm2835_sdhost_dumpregs(host);
255 mrq->cmd->error = -EILSEQ;
256 tasklet_schedule(&host->finish_tasklet);
258 @@ -1814,16 +1827,19 @@ static void bcm2835_sdhost_tasklet_finis
261 /* Drop the overclock after any data corruption, or after any
262 - error overclocked */
263 + * error while overclocked. Ignore errors for status commands,
264 + * as they are likely when a card is ejected. */
265 if (host->overclock) {
266 - if ((mrq->cmd && mrq->cmd->error) ||
267 + if ((mrq->cmd && mrq->cmd->error &&
268 + (mrq->cmd->opcode != MMC_SEND_STATUS)) ||
269 (mrq->data && mrq->data->error) ||
270 - (mrq->stop && mrq->stop->error)) {
271 + (mrq->stop && mrq->stop->error) ||
272 + (mrq->sbc && mrq->sbc->error)) {
273 host->overclock_50--;
274 pr_warn("%s: reducing overclock due to errors\n",
275 mmc_hostname(host->mmc));
276 host->reset_clock = 1;
277 - mrq->cmd->error = -EILSEQ;
278 + mrq->cmd->error = -ETIMEDOUT;
279 mrq->cmd->retries = 1;
282 @@ -1848,6 +1864,21 @@ static void bcm2835_sdhost_tasklet_finis
283 mmc_hostname(host->mmc), err);
286 + /* The SDHOST block doesn't report any errors for a disconnected
287 + interface. All cards and SDIO devices should report some supported
288 + voltage range, so a zero response to SEND_OP_COND, IO_SEND_OP_COND
289 + or APP_SEND_OP_COND can be treated as an error. */
290 + if (((mrq->cmd->opcode == MMC_SEND_OP_COND) ||
291 + (mrq->cmd->opcode == SD_IO_SEND_OP_COND) ||
292 + (mrq->cmd->opcode == SD_APP_OP_COND)) &&
293 + (mrq->cmd->error == 0) &&
294 + (mrq->cmd->resp[0] == 0)) {
295 + mrq->cmd->error = -ETIMEDOUT;
297 + pr_info("%s: faking timeout due to zero OCR\n",
298 + mmc_hostname(host->mmc));
301 mmc_request_done(host->mmc, mrq);
302 log_event("TSK>", (u32)mrq, 0);
304 @@ -2023,7 +2054,7 @@ static int bcm2835_sdhost_probe(struct p
305 &host->delay_after_stop);
306 of_property_read_u32(node,
308 - &host->overclock_50);
309 + &host->user_overclock_50);
310 of_property_read_u32(node,