brcm2708: update linux 4.4 patches to latest version
[openwrt/staging/dedeckeh.git] / target / linux / brcm2708 / patches-4.4 / 0417-bcm2835-sdhost-Improvements-to-error-recovery.patch
1 From 336a4fae0a026365e58842b5df9e275858938f79 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 417/423] bcm2835-sdhost: Improvements to error recovery
5
6 1) Try to avoid reducing overclock when a card is removed.
7
8 2) Reset overclock on card insertion.
9
10 3) Reduce logging when errors occur, lowering the severity of
11 some messages and making others conditional on the debug
12 flag.
13
14 4) Attempt to identify a disconnected SD bus earlier, treating a
15 zero returned OCR (voltage support) as an error condition.
16
17 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
18 ---
19 drivers/mmc/host/bcm2835-sdhost.c | 117 ++++++++++++++++++++++++--------------
20 1 file changed, 74 insertions(+), 43 deletions(-)
21
22 --- a/drivers/mmc/host/bcm2835-sdhost.c
23 +++ b/drivers/mmc/host/bcm2835-sdhost.c
24 @@ -38,6 +38,7 @@
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)
41 do {
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",
46 entry->timestamp,
47 entry->event,
48 entry->param1,
49 @@ -324,7 +326,7 @@ static void bcm2835_sdhost_dumpcmd(struc
50 const char *label)
51 {
52 if (cmd)
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");
61 if (host->mrq->data)
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");
69 }
70
71 - pr_err("%s: =========== REGISTER DUMP ===========\n",
72 + pr_info("%s: =========== REGISTER DUMP ===========\n",
73 mmc_hostname(host->mmc));
74
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));
130
131 - pr_err("%s: ===========================================\n",
132 + pr_info("%s: ===========================================\n",
133 mmc_hostname(host->mmc));
134 }
135
136 @@ -608,7 +610,7 @@ static void bcm2835_sdhost_read_block_pi
137 (fsm_state != SDEDM_FSM_READCRC)) {
138 hsts = bcm2835_sdhost_read(host,
139 SDHSTS);
140 - pr_err("%s: fsm %x, hsts %x\n",
141 + pr_info("%s: fsm %x, hsts %x\n",
142 mmc_hostname(host->mmc),
143 fsm_state, hsts);
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,
148 SDHSTS);
149 - pr_err("%s: fsm %x, hsts %x\n",
150 + pr_info("%s: fsm %x, hsts %x\n",
151 mmc_hostname(host->mmc),
152 fsm_state, hsts);
153 if (hsts & SDHSTS_ERROR_MASK)
154 @@ -953,9 +955,10 @@ bool bcm2835_sdhost_send_command(struct
155
156 while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
157 if (timeout == 0) {
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);
162 + if (host->debug)
163 + bcm2835_sdhost_dumpregs(host);
164 cmd->error = -EILSEQ;
165 tasklet_schedule(&host->finish_tasklet);
166 return false;
167 @@ -1213,10 +1216,12 @@ static void bcm2835_sdhost_finish_comman
168
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;
175 + if (host->debug) {
176 + pr_err("%s: command %d never completed.\n",
177 + mmc_hostname(host->mmc), host->cmd->opcode);
178 + bcm2835_sdhost_dumpregs(host);
179 + }
180 + host->cmd->error = -EILSEQ;
181 tasklet_schedule(&host->finish_tasklet);
182 return;
183 } else if (sdcmd & SDCMD_FAIL_FLAG) {
184 @@ -1238,15 +1243,14 @@ static void bcm2835_sdhost_finish_comman
185 } else {
186 if (sdhsts & SDHSTS_CMD_TIME_OUT) {
187 if (host->debug)
188 - pr_err("%s: command %d timeout\n",
189 + pr_warn("%s: command %d timeout\n",
190 mmc_hostname(host->mmc),
191 host->cmd->opcode);
192 host->cmd->error = -ETIMEDOUT;
193 } else {
194 - pr_err("%s: unexpected command %d error\n",
195 + pr_warn("%s: unexpected command %d error\n",
196 mmc_hostname(host->mmc),
197 host->cmd->opcode);
198 - bcm2835_sdhost_dumpregs(host);
199 host->cmd->error = -EILSEQ;
200 }
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;
205
206 - log_dump();
207 - bcm2835_sdhost_dumpregs(host);
208 + if (host->debug) {
209 + log_dump();
210 + bcm2835_sdhost_dumpregs(host);
211 + }
212 }
213 else
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);
217
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;
223 }
224 @@ -1605,6 +1611,11 @@ void bcm2835_sdhost_set_clock(struct bcm
225 pr_warn("%s: cancelling overclock\n",
226 mmc_hostname(host->mmc));
227 }
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;
233 }
234
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,
243 - edm);
244 log_event("REQ!", (u32)mrq, edm);
245 - log_dump();
246 - bcm2835_sdhost_dumpregs(host);
247 + if (host->debug) {
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,
251 + edm);
252 + log_dump();
253 + bcm2835_sdhost_dumpregs(host);
254 + }
255 mrq->cmd->error = -EILSEQ;
256 tasklet_schedule(&host->finish_tasklet);
257 mmiowb();
258 @@ -1814,16 +1827,19 @@ static void bcm2835_sdhost_tasklet_finis
259 mrq = host->mrq;
260
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;
280 }
281 }
282 @@ -1848,6 +1864,21 @@ static void bcm2835_sdhost_tasklet_finis
283 mmc_hostname(host->mmc), err);
284 }
285
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;
296 + if (host->debug)
297 + pr_info("%s: faking timeout due to zero OCR\n",
298 + mmc_hostname(host->mmc));
299 + }
300 +
301 mmc_request_done(host->mmc, mrq);
302 log_event("TSK>", (u32)mrq, 0);
303 }
304 @@ -2023,7 +2054,7 @@ static int bcm2835_sdhost_probe(struct p
305 &host->delay_after_stop);
306 of_property_read_u32(node,
307 "brcm,overclock-50",
308 - &host->overclock_50);
309 + &host->user_overclock_50);
310 of_property_read_u32(node,
311 "brcm,pio-limit",
312 &host->pio_limit);