mirror of https://github.com/hak5/openwrt.git
119 lines
4.1 KiB
Diff
119 lines
4.1 KiB
Diff
|
From 8a55d01fb0245d518898960123c3cb1b96dd9080 Mon Sep 17 00:00:00 2001
|
||
|
From: Phil Elwell <phil@raspberrypi.org>
|
||
|
Date: Tue, 15 Mar 2016 14:10:29 +0000
|
||
|
Subject: [PATCH 185/304] bcm2835-sdhost: Workaround for "slow" sectors
|
||
|
|
||
|
Some cards have been seen to cause timeouts after certain sectors are
|
||
|
read. This workaround enforces a minimum delay between the stop after
|
||
|
reading one of those sectors and a subsequent data command.
|
||
|
|
||
|
Using CMD23 (SET_BLOCK_COUNT) avoids this problem, so good cards will
|
||
|
not be penalised by this workaround.
|
||
|
|
||
|
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||
|
---
|
||
|
drivers/mmc/host/bcm2835-sdhost.c | 50 +++++++++++++++++++++++++++++++++++----
|
||
|
1 file changed, 46 insertions(+), 4 deletions(-)
|
||
|
|
||
|
--- a/drivers/mmc/host/bcm2835-sdhost.c
|
||
|
+++ b/drivers/mmc/host/bcm2835-sdhost.c
|
||
|
@@ -202,9 +202,12 @@ struct bcm2835_host {
|
||
|
int max_delay; /* maximum length of time spent waiting */
|
||
|
struct timeval stop_time; /* when the last stop was issued */
|
||
|
u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
|
||
|
+ u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
|
||
|
u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
|
||
|
u32 overclock; /* Current frequency if overclocked, else zero */
|
||
|
u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
|
||
|
+
|
||
|
+ u32 sectors; /* Cached card size in sectors */
|
||
|
};
|
||
|
|
||
|
#if ENABLE_LOG
|
||
|
@@ -425,6 +428,7 @@ static void bcm2835_sdhost_reset_interna
|
||
|
bcm2835_sdhost_set_power(host, true);
|
||
|
mdelay(10);
|
||
|
host->clock = 0;
|
||
|
+ host->sectors = 0;
|
||
|
bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
|
||
|
bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
|
||
|
mmiowb();
|
||
|
@@ -880,6 +884,24 @@ static void bcm2835_sdhost_prepare_data(
|
||
|
host->flush_fifo = 0;
|
||
|
host->data->bytes_xfered = 0;
|
||
|
|
||
|
+ if (!host->sectors && host->mmc->card) {
|
||
|
+ struct mmc_card *card = host->mmc->card;
|
||
|
+ if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
|
||
|
+ /*
|
||
|
+ * The EXT_CSD sector count is in number of 512 byte
|
||
|
+ * sectors.
|
||
|
+ */
|
||
|
+ host->sectors = card->ext_csd.sectors;
|
||
|
+ } else {
|
||
|
+ /*
|
||
|
+ * The CSD capacity field is in units of read_blkbits.
|
||
|
+ * set_capacity takes units of 512 bytes.
|
||
|
+ */
|
||
|
+ host->sectors = card->csd.capacity <<
|
||
|
+ (card->csd.read_blkbits - 9);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
if (!host->dma_desc) {
|
||
|
/* Use PIO */
|
||
|
int flags = SG_MITER_ATOMIC;
|
||
|
@@ -989,7 +1011,7 @@ bool bcm2835_sdhost_send_command(struct
|
||
|
|
||
|
if (cmd->data) {
|
||
|
log_event("CMDD", cmd->data->blocks, cmd->data->blksz);
|
||
|
- if (host->delay_after_stop) {
|
||
|
+ if (host->delay_after_this_stop) {
|
||
|
struct timeval now;
|
||
|
int time_since_stop;
|
||
|
do_gettimeofday(&now);
|
||
|
@@ -998,12 +1020,32 @@ bool bcm2835_sdhost_send_command(struct
|
||
|
/* Possibly less than one second */
|
||
|
time_since_stop = time_since_stop * 1000000 +
|
||
|
(now.tv_usec - host->stop_time.tv_usec);
|
||
|
- if (time_since_stop < host->delay_after_stop)
|
||
|
- udelay(host->delay_after_stop -
|
||
|
+ if (time_since_stop <
|
||
|
+ host->delay_after_this_stop)
|
||
|
+ udelay(host->delay_after_this_stop -
|
||
|
time_since_stop);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ host->delay_after_this_stop = host->delay_after_stop;
|
||
|
+ if ((cmd->data->flags & MMC_DATA_READ) && !host->use_sbc) {
|
||
|
+ /* See if read crosses one of the hazardous sectors */
|
||
|
+ u32 first_blk, last_blk;
|
||
|
+
|
||
|
+ /* Intentionally include the following sector because
|
||
|
+ without CMD23/SBC the read may run on. */
|
||
|
+ first_blk = host->mrq->cmd->arg;
|
||
|
+ last_blk = first_blk + cmd->data->blocks;
|
||
|
+
|
||
|
+ if (((last_blk >= (host->sectors - 64)) &&
|
||
|
+ (first_blk <= (host->sectors - 64))) ||
|
||
|
+ ((last_blk >= (host->sectors - 32)) &&
|
||
|
+ (first_blk <= (host->sectors - 32)))) {
|
||
|
+ host->delay_after_this_stop =
|
||
|
+ max(250u, host->delay_after_stop);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
if (cmd->data->flags & MMC_DATA_WRITE)
|
||
|
sdcmd |= SDCMD_WRITE_CMD;
|
||
|
if (cmd->data->flags & MMC_DATA_READ)
|
||
|
@@ -1078,7 +1120,7 @@ static void bcm2835_sdhost_transfer_comp
|
||
|
if (!host->use_busy)
|
||
|
bcm2835_sdhost_finish_command(host, NULL);
|
||
|
|
||
|
- if (host->delay_after_stop)
|
||
|
+ if (host->delay_after_this_stop)
|
||
|
do_gettimeofday(&host->stop_time);
|
||
|
}
|
||
|
} else {
|