brcm2708: update linux 4.4 patches to latest version
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0185-bcm2835-sdhost-Workaround-for-slow-sectors.patch
1 From 95ca033cb9ac492b060c0cc44093180871e8d63b Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.org>
3 Date: Tue, 15 Mar 2016 14:10:29 +0000
4 Subject: [PATCH] bcm2835-sdhost: Workaround for "slow" sectors
5
6 Some cards have been seen to cause timeouts after certain sectors are
7 read. This workaround enforces a minimum delay between the stop after
8 reading one of those sectors and a subsequent data command.
9
10 Using CMD23 (SET_BLOCK_COUNT) avoids this problem, so good cards will
11 not be penalised by this workaround.
12
13 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
14 ---
15 drivers/mmc/host/bcm2835-sdhost.c | 50 +++++++++++++++++++++++++++++++++++----
16 1 file changed, 46 insertions(+), 4 deletions(-)
17
18 --- a/drivers/mmc/host/bcm2835-sdhost.c
19 +++ b/drivers/mmc/host/bcm2835-sdhost.c
20 @@ -202,9 +202,12 @@ struct bcm2835_host {
21 int max_delay; /* maximum length of time spent waiting */
22 struct timeval stop_time; /* when the last stop was issued */
23 u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
24 + u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
25 u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
26 u32 overclock; /* Current frequency if overclocked, else zero */
27 u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
28 +
29 + u32 sectors; /* Cached card size in sectors */
30 };
31
32 #if ENABLE_LOG
33 @@ -425,6 +428,7 @@ static void bcm2835_sdhost_reset_interna
34 bcm2835_sdhost_set_power(host, true);
35 mdelay(10);
36 host->clock = 0;
37 + host->sectors = 0;
38 bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
39 bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
40 mmiowb();
41 @@ -880,6 +884,24 @@ static void bcm2835_sdhost_prepare_data(
42 host->flush_fifo = 0;
43 host->data->bytes_xfered = 0;
44
45 + if (!host->sectors && host->mmc->card) {
46 + struct mmc_card *card = host->mmc->card;
47 + if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
48 + /*
49 + * The EXT_CSD sector count is in number of 512 byte
50 + * sectors.
51 + */
52 + host->sectors = card->ext_csd.sectors;
53 + } else {
54 + /*
55 + * The CSD capacity field is in units of read_blkbits.
56 + * set_capacity takes units of 512 bytes.
57 + */
58 + host->sectors = card->csd.capacity <<
59 + (card->csd.read_blkbits - 9);
60 + }
61 + }
62 +
63 if (!host->dma_desc) {
64 /* Use PIO */
65 int flags = SG_MITER_ATOMIC;
66 @@ -989,7 +1011,7 @@ bool bcm2835_sdhost_send_command(struct
67
68 if (cmd->data) {
69 log_event("CMDD", cmd->data->blocks, cmd->data->blksz);
70 - if (host->delay_after_stop) {
71 + if (host->delay_after_this_stop) {
72 struct timeval now;
73 int time_since_stop;
74 do_gettimeofday(&now);
75 @@ -998,12 +1020,32 @@ bool bcm2835_sdhost_send_command(struct
76 /* Possibly less than one second */
77 time_since_stop = time_since_stop * 1000000 +
78 (now.tv_usec - host->stop_time.tv_usec);
79 - if (time_since_stop < host->delay_after_stop)
80 - udelay(host->delay_after_stop -
81 + if (time_since_stop <
82 + host->delay_after_this_stop)
83 + udelay(host->delay_after_this_stop -
84 time_since_stop);
85 }
86 }
87
88 + host->delay_after_this_stop = host->delay_after_stop;
89 + if ((cmd->data->flags & MMC_DATA_READ) && !host->use_sbc) {
90 + /* See if read crosses one of the hazardous sectors */
91 + u32 first_blk, last_blk;
92 +
93 + /* Intentionally include the following sector because
94 + without CMD23/SBC the read may run on. */
95 + first_blk = host->mrq->cmd->arg;
96 + last_blk = first_blk + cmd->data->blocks;
97 +
98 + if (((last_blk >= (host->sectors - 64)) &&
99 + (first_blk <= (host->sectors - 64))) ||
100 + ((last_blk >= (host->sectors - 32)) &&
101 + (first_blk <= (host->sectors - 32)))) {
102 + host->delay_after_this_stop =
103 + max(250u, host->delay_after_stop);
104 + }
105 + }
106 +
107 if (cmd->data->flags & MMC_DATA_WRITE)
108 sdcmd |= SDCMD_WRITE_CMD;
109 if (cmd->data->flags & MMC_DATA_READ)
110 @@ -1078,7 +1120,7 @@ static void bcm2835_sdhost_transfer_comp
111 if (!host->use_busy)
112 bcm2835_sdhost_finish_command(host, NULL);
113
114 - if (host->delay_after_stop)
115 + if (host->delay_after_this_stop)
116 do_gettimeofday(&host->stop_time);
117 }
118 } else {