diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2008-07-05 00:25:15 +0200 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2008-07-15 14:14:39 +0200 |
commit | ee53ab5d73998e502801c024a08de2c39a92c52a (patch) | |
tree | bbee55e0cfffa4837918b7ada2f031f7dab3fcbb | |
parent | sdhci: more complex quirks handling (diff) | |
download | linux-ee53ab5d73998e502801c024a08de2c39a92c52a.tar.xz linux-ee53ab5d73998e502801c024a08de2c39a92c52a.zip |
sdhci: make workaround for timeout bug more general
Give the quirk for broken timeout handling a better chance of handling
more controllers by simply classifying the system as broken and setting
a fixed value.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 50 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 4 |
3 files changed, 33 insertions, 23 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 5094fe805764..856bb2b2837e 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -98,7 +98,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = { static const struct sdhci_pci_fixes sdhci_cafe = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | - SDHCI_QUIRK_INCR_TIMEOUT_CONTROL, + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, }; static const struct sdhci_pci_fixes sdhci_jmicron = { diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8ce01d434ea8..95b081a9967b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -314,23 +314,19 @@ static void sdhci_transfer_pio(struct sdhci_host *host) DBG("PIO transfer complete.\n"); } -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) +static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data) { u8 count; unsigned target_timeout, current_timeout; - WARN_ON(host->data); - - if (data == NULL) - return; - - /* Sanity checks */ - BUG_ON(data->blksz * data->blocks > 524288); - BUG_ON(data->blksz > host->mmc->max_blk_size); - BUG_ON(data->blocks > 65535); - - host->data = data; - host->data_early = 0; + /* + * If the host controller provides us with an incorrect timeout + * value, just skip the check and use 0xE. The hardware may take + * longer to time out, but that's much better than having a too-short + * timeout value. + */ + if ((host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)) + return 0xE; /* timeout in us */ target_timeout = data->timeout_ns / 1000 + @@ -355,19 +351,33 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) break; } - /* - * Compensate for an off-by-one error in the CaFe hardware; otherwise, - * a too-small count gives us interrupt timeouts. - */ - if ((host->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL)) - count++; - if (count >= 0xF) { printk(KERN_WARNING "%s: Too large timeout requested!\n", mmc_hostname(host->mmc)); count = 0xE; } + return count; +} + +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) +{ + u8 count; + + WARN_ON(host->data); + + if (data == NULL) + return; + + /* Sanity checks */ + BUG_ON(data->blksz * data->blocks > 524288); + BUG_ON(data->blksz > host->mmc->max_blk_size); + BUG_ON(data->blocks > 65535); + + host->data = data; + host->data_early = 0; + + count = sdhci_calc_timeout(host, data); writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); if (host->flags & SDHCI_USE_DMA) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 22fc258b12aa..7ce12f3e7452 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -178,8 +178,8 @@ struct sdhci_host { #define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) /* Controller needs voltage and power writes to happen separately */ #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9) -/* Controller has an off-by-one issue with timeout value */ -#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<10) +/* Controller provides an incorrect timeout value for transfers */ +#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<10) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ |