aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2008-07-04 18:25:15 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-07-15 08:14:39 -0400
commitee53ab5d73998e502801c024a08de2c39a92c52a (patch)
treebbee55e0cfffa4837918b7ada2f031f7dab3fcbb
parent22606405894a3ca5796eb4454a4b83af611fd201 (diff)
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.c2
-rw-r--r--drivers/mmc/host/sdhci.c50
-rw-r--r--drivers/mmc/host/sdhci.h4
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 = {
98 98
99static const struct sdhci_pci_fixes sdhci_cafe = { 99static const struct sdhci_pci_fixes sdhci_cafe = {
100 .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | 100 .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
101 SDHCI_QUIRK_INCR_TIMEOUT_CONTROL, 101 SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
102}; 102};
103 103
104static const struct sdhci_pci_fixes sdhci_jmicron = { 104static 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)
314 DBG("PIO transfer complete.\n"); 314 DBG("PIO transfer complete.\n");
315} 315}
316 316
317static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) 317static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
318{ 318{
319 u8 count; 319 u8 count;
320 unsigned target_timeout, current_timeout; 320 unsigned target_timeout, current_timeout;
321 321
322 WARN_ON(host->data); 322 /*
323 323 * If the host controller provides us with an incorrect timeout
324 if (data == NULL) 324 * value, just skip the check and use 0xE. The hardware may take
325 return; 325 * longer to time out, but that's much better than having a too-short
326 326 * timeout value.
327 /* Sanity checks */ 327 */
328 BUG_ON(data->blksz * data->blocks > 524288); 328 if ((host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL))
329 BUG_ON(data->blksz > host->mmc->max_blk_size); 329 return 0xE;
330 BUG_ON(data->blocks > 65535);
331
332 host->data = data;
333 host->data_early = 0;
334 330
335 /* timeout in us */ 331 /* timeout in us */
336 target_timeout = data->timeout_ns / 1000 + 332 target_timeout = data->timeout_ns / 1000 +
@@ -355,19 +351,33 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
355 break; 351 break;
356 } 352 }
357 353
358 /*
359 * Compensate for an off-by-one error in the CaFe hardware; otherwise,
360 * a too-small count gives us interrupt timeouts.
361 */
362 if ((host->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
363 count++;
364
365 if (count >= 0xF) { 354 if (count >= 0xF) {
366 printk(KERN_WARNING "%s: Too large timeout requested!\n", 355 printk(KERN_WARNING "%s: Too large timeout requested!\n",
367 mmc_hostname(host->mmc)); 356 mmc_hostname(host->mmc));
368 count = 0xE; 357 count = 0xE;
369 } 358 }
370 359
360 return count;
361}
362
363static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
364{
365 u8 count;
366
367 WARN_ON(host->data);
368
369 if (data == NULL)
370 return;
371
372 /* Sanity checks */
373 BUG_ON(data->blksz * data->blocks > 524288);
374 BUG_ON(data->blksz > host->mmc->max_blk_size);
375 BUG_ON(data->blocks > 65535);
376
377 host->data = data;
378 host->data_early = 0;
379
380 count = sdhci_calc_timeout(host, data);
371 writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); 381 writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
372 382
373 if (host->flags & SDHCI_USE_DMA) 383 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 {
178#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) 178#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8)
179/* Controller needs voltage and power writes to happen separately */ 179/* Controller needs voltage and power writes to happen separately */
180#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9) 180#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9)
181/* Controller has an off-by-one issue with timeout value */ 181/* Controller provides an incorrect timeout value for transfers */
182#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<10) 182#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<10)
183 183
184 int irq; /* Device IRQ */ 184 int irq; /* Device IRQ */
185 void __iomem * ioaddr; /* Mapped address */ 185 void __iomem * ioaddr; /* Mapped address */