From: Pierre Ossman Date: Fri, 4 Jul 2008 22:25:15 +0000 (+0200) Subject: sdhci: make workaround for timeout bug more general X-Git-Tag: v2.6.27-rc1~1047^2~63 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee53ab5d73998e502801c024a08de2c39a92c52a;p=linux-2.6 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 --- diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 5094fe8057..856bb2b283 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 8ce01d434e..95b081a996 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 22fc258b12..7ce12f3e74 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 */