0415-bcm2835-sdhost-Improvements-to-error-recovery.patch 11 KB

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