1 From cf43a49e4ace4cbf98e135db16d47b4ee1378273 Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.org>
3 Date: Thu, 25 Jun 2015 08:47:09 +0100
4 Subject: [PATCH 092/148] bcm2835-sdhost: Further improve overclock back-off
7 drivers/mmc/host/bcm2835-sdhost.c | 144 +++++++++++++++++++++-----------------
8 1 file changed, 78 insertions(+), 66 deletions(-)
10 --- a/drivers/mmc/host/bcm2835-sdhost.c
11 +++ b/drivers/mmc/host/bcm2835-sdhost.c
12 @@ -161,8 +161,6 @@ struct bcm2835_host {
14 unsigned int use_busy:1; /* Wait for busy interrupt */
16 - unsigned int reduce_overclock:1; /* ...at the next opportunity */
18 unsigned int debug:1; /* Enable debug output */
21 @@ -466,36 +464,25 @@ static void bcm2835_sdhost_dma_complete(
22 spin_unlock_irqrestore(&host->lock, flags);
25 -static bool data_transfer_wait(struct bcm2835_host *host, const char *caller)
26 +static bool data_transfer_wait(struct bcm2835_host *host)
28 unsigned long timeout = 1000000;
32 - hsts = bcm2835_sdhost_read(host, SDHSTS);
33 - if (hsts & (SDHSTS_TRANSFER_ERROR_MASK |
34 - SDHSTS_DATA_FLAG)) {
35 - bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK,
37 + u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
38 + if (sdhsts & SDHSTS_DATA_FLAG) {
39 + bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
45 - if (hsts & (SDHSTS_CRC16_ERROR |
47 - SDHSTS_FIFO_ERROR)) {
48 - pr_err("%s: data error in %s - HSTS %x\n",
49 - mmc_hostname(host->mmc), caller, hsts);
50 - host->data->error = -EILSEQ;
52 - } else if ((timeout == 0) ||
53 - (hsts & (SDHSTS_CMD_TIME_OUT |
54 - SDHSTS_REW_TIME_OUT))) {
55 - pr_err("%s: timeout in %s - HSTS %x\n",
56 - mmc_hostname(host->mmc), caller, hsts);
57 - host->data->error = -ETIMEDOUT;
60 + pr_err("%s: Data %s timeout\n",
61 + mmc_hostname(host->mmc),
62 + (host->data->flags & MMC_DATA_READ) ? "read" : "write");
63 + bcm2835_sdhost_dumpregs(host);
64 + host->data->error = -ETIMEDOUT;
69 @@ -523,7 +510,7 @@ static void bcm2835_sdhost_read_block_pi
70 buf = (u32 *)host->sg_miter.addr;
73 - if (!data_transfer_wait(host, "read_block_pio"))
74 + if (!data_transfer_wait(host))
77 *(buf++) = bcm2835_sdhost_read(host, SDDATA);
78 @@ -562,7 +549,7 @@ static void bcm2835_sdhost_write_block_p
79 buf = host->sg_miter.addr;
82 - if (!data_transfer_wait(host, "write_block_pio"))
83 + if (!data_transfer_wait(host))
86 bcm2835_sdhost_write(host, *(buf++), SDDATA);
87 @@ -581,13 +568,33 @@ static void bcm2835_sdhost_write_block_p
89 static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
95 - if (host->data->flags & MMC_DATA_READ) {
96 + is_read = (host->data->flags & MMC_DATA_READ) != 0;
98 bcm2835_sdhost_read_block_pio(host);
101 bcm2835_sdhost_write_block_pio(host);
103 + sdhsts = bcm2835_sdhost_read(host, SDHSTS);
104 + if (sdhsts & (SDHSTS_CRC16_ERROR |
105 + SDHSTS_CRC7_ERROR |
106 + SDHSTS_FIFO_ERROR)) {
107 + pr_err("%s: %s transfer error - HSTS %x\n",
108 + mmc_hostname(host->mmc),
109 + is_read ? "read" : "write",
111 + host->data->error = -EILSEQ;
112 + } else if ((sdhsts & (SDHSTS_CMD_TIME_OUT |
113 + SDHSTS_REW_TIME_OUT))) {
114 + pr_err("%s: %s timeout error - HSTS %x\n",
115 + mmc_hostname(host->mmc),
116 + is_read ? "read" : "write",
118 + host->data->error = -ETIMEDOUT;
119 + } else if (!is_read && !host->data->error) {
120 /* Start a timer in case a transfer error occurs because
121 there is no error interrupt */
122 mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
123 @@ -701,8 +708,9 @@ static void bcm2835_sdhost_prepare_data(
125 void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
129 unsigned long timeout;
134 @@ -719,8 +727,8 @@ void bcm2835_sdhost_send_command(struct
135 mmc_hostname(host->mmc),
136 cmd->opcode, cmd->arg, cmd->flags);
138 - /* Wait max 10 ms */
140 + /* Wait max 100 ms */
143 while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
145 @@ -735,8 +743,9 @@ void bcm2835_sdhost_send_command(struct
149 - if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) {
150 - host->max_delay = (1000-timeout)/100;
151 + delay = (10000 - timeout)/100;
152 + if (delay > host->max_delay) {
153 + host->max_delay = delay;
154 pr_warning("%s: controller hung for %d ms\n",
155 mmc_hostname(host->mmc),
157 @@ -751,6 +760,11 @@ void bcm2835_sdhost_send_command(struct
161 + /* Clear any error flags */
162 + sdhsts = bcm2835_sdhost_read(host, SDHSTS);
163 + if (sdhsts & SDHSTS_ERROR_MASK)
164 + bcm2835_sdhost_write(host, sdhsts, SDHSTS);
166 bcm2835_sdhost_prepare_data(host, cmd);
168 bcm2835_sdhost_write(host, cmd->arg, SDARG);
169 @@ -876,7 +890,7 @@ static void bcm2835_sdhost_transfer_comp
170 static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
173 - int timeout = 1000;
174 + unsigned long timeout;
176 struct timeval before, after;
178 @@ -889,6 +903,8 @@ static void bcm2835_sdhost_finish_comman
180 do_gettimeofday(&before);
182 + /* Wait max 100 ms */
184 for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
185 (sdcmd & SDCMD_NEW_FLAG) && timeout;
187 @@ -1049,9 +1065,9 @@ static void bcm2835_sdhost_pio_timeout(u
188 spin_lock_irqsave(&host->lock, flags);
191 - u32 hsts = bcm2835_sdhost_read(host, SDHSTS);
192 + u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
194 - if (hsts & SDHSTS_REW_TIME_OUT) {
195 + if (sdhsts & SDHSTS_REW_TIME_OUT) {
196 pr_err("%s: transfer timeout\n",
197 mmc_hostname(host->mmc));
199 @@ -1380,19 +1396,10 @@ void bcm2835_sdhost_set_clock(struct bcm
201 pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
203 - if ((clock == 0) && host->reduce_overclock) {
204 - /* This is a reset following data corruption - reduce any
206 - host->reduce_overclock = 0;
207 - if (host->overclock_50 > 50) {
208 - pr_warn("%s: reducing overclock due to errors\n",
209 - mmc_hostname(host->mmc));
210 - host->overclock_50--;
214 - if (host->overclock_50 && (clock == 50*MHZ))
215 + if ((host->overclock_50 > 50) &&
216 + (clock == 50*MHZ)) {
217 clock = host->overclock_50 * MHZ + (MHZ - 1);
220 /* The SDCDIV register has 11 bits, and holds (div - 2).
221 But in data mode the max is 50MHz wihout a minimum, and only the
222 @@ -1450,11 +1457,12 @@ void bcm2835_sdhost_set_clock(struct bcm
223 host->overclock = clock;
226 - else if ((clock == 50 * MHZ) && host->overclock)
227 + else if (host->overclock)
229 - pr_warn("%s: cancelling overclock\n",
230 - mmc_hostname(host->mmc));
232 + if (clock == 50 * MHZ)
233 + pr_warn("%s: cancelling overclock\n",
234 + mmc_hostname(host->mmc));
238 @@ -1492,6 +1500,14 @@ static void bcm2835_sdhost_request(struc
239 cmd->opcode, cmd->arg, cmd->flags);
242 + /* Reset the error statuses in case this is a retry */
244 + mrq->cmd->error = 0;
246 + mrq->data->error = 0;
248 + mrq->stop->error = 0;
250 if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
251 pr_err("%s: unsupported block size (%d bytes)\n",
252 mmc_hostname(mmc), mrq->data->blksz);
253 @@ -1613,21 +1629,16 @@ static void bcm2835_sdhost_tasklet_finis
255 /* Drop the overclock after any data corruption, or after any
257 - if (mrq->data && (mrq->data->error == -EILSEQ))
258 - host->reduce_overclock = 1;
259 - else if (host->overclock) {
260 - /* Convert timeout errors while overclocked to data errors,
261 - because the system recovers better. */
262 - if (mrq->cmd && mrq->cmd->error) {
263 - host->reduce_overclock = 1;
264 - if (mrq->cmd->error == -ETIMEDOUT)
265 - mrq->cmd->error = -EILSEQ;
268 - if (mrq->data && mrq->data->error) {
269 - host->reduce_overclock = 1;
270 - if (mrq->data->error == -ETIMEDOUT)
271 - mrq->data->error = -EILSEQ;
272 + if (host->overclock) {
273 + if ((mrq->cmd && mrq->cmd->error) ||
274 + (mrq->data && mrq->data->error) ||
275 + (mrq->stop && mrq->stop->error)) {
276 + host->overclock_50--;
277 + pr_warn("%s: reducing overclock due to errors\n",
278 + mmc_hostname(host->mmc));
279 + bcm2835_sdhost_set_clock(host,50*MHZ);
280 + mrq->cmd->error = -EILSEQ;
281 + mrq->cmd->retries = 1;
285 @@ -1769,6 +1780,7 @@ static int bcm2835_sdhost_probe(struct p
286 host = mmc_priv(mmc);
288 host->pio_timeout = msecs_to_jiffies(500);
289 + host->max_delay = 1; /* Warn if over 1ms */
290 spin_lock_init(&host->lock);
292 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);