sdhci: make workaround for timeout bug more general
authorPierre Ossman <drzeus@drzeus.cx>
Fri, 4 Jul 2008 22:25:15 +0000 (00:25 +0200)
committerPierre Ossman <drzeus@drzeus.cx>
Tue, 15 Jul 2008 12:14:39 +0000 (14:14 +0200)
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>
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h

index 5094fe8..856bb2b 100644 (file)
@@ -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 = {
index 8ce01d4..95b081a 100644 (file)
@@ -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)
index 22fc258..7ce12f3 100644 (file)
@@ -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 */