diff options
author | Andres Salomon <dilinger@queued.net> | 2008-07-04 13:00:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-04 13:40:09 -0400 |
commit | 603ded16a308d0a7a17738c973e3c8cbcd5db7dd (patch) | |
tree | 580c111f2d8dceb6d97a261302f48521ff140254 /drivers/mmc/host/sdhci.c | |
parent | e08c1694d9e2138204f2b79b73f0f159074ce2f5 (diff) |
olpc: sdhci: add quirk for the Marvell CaFe's interrupt timeout
The CaFe chip has a hardware bug that ends up with us getting a timeout
value that's too small, causing the following sorts of problems:
[ 60.525138] mmcblk0: error -110 transferring data
[ 60.531477] end_request: I/O error, dev mmcblk0, sector 1484353
[ 60.533371] Buffer I/O error on device mmcblk0p2, logical block 181632
[ 60.533371] lost page write due to I/O error on mmcblk0p2
Presumably this is an off-by-one error in the hardware. Incrementing
the timeout count value that we stuff into the TIMEOUT_CONTROL register
gets us a value that works. This bug was originally discovered by
Pierre Ossman, I believe.
[thanks to Robert Millan for proving that this was still a problem]
Signed-off-by: Andres Salomon <dilinger@debian.org>
Cc: Pierre Ossman <drzeus-list@drzeus.cx>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5b74c8cf4409..2b3f06a024f2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -57,6 +57,8 @@ static unsigned int debug_quirks = 0; | |||
57 | #define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) | 57 | #define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) |
58 | /* Controller needs voltage and power writes to happen separately */ | 58 | /* Controller needs voltage and power writes to happen separately */ |
59 | #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9) | 59 | #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9) |
60 | /* Controller has an off-by-one issue with timeout value */ | ||
61 | #define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<10) | ||
60 | 62 | ||
61 | static const struct pci_device_id pci_ids[] __devinitdata = { | 63 | static const struct pci_device_id pci_ids[] __devinitdata = { |
62 | { | 64 | { |
@@ -134,7 +136,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = { | |||
134 | .device = PCI_DEVICE_ID_MARVELL_CAFE_SD, | 136 | .device = PCI_DEVICE_ID_MARVELL_CAFE_SD, |
135 | .subvendor = PCI_ANY_ID, | 137 | .subvendor = PCI_ANY_ID, |
136 | .subdevice = PCI_ANY_ID, | 138 | .subdevice = PCI_ANY_ID, |
137 | .driver_data = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER, | 139 | .driver_data = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | |
140 | SDHCI_QUIRK_INCR_TIMEOUT_CONTROL, | ||
138 | }, | 141 | }, |
139 | 142 | ||
140 | { | 143 | { |
@@ -479,6 +482,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) | |||
479 | break; | 482 | break; |
480 | } | 483 | } |
481 | 484 | ||
485 | /* | ||
486 | * Compensate for an off-by-one error in the CaFe hardware; otherwise, | ||
487 | * a too-small count gives us interrupt timeouts. | ||
488 | */ | ||
489 | if ((host->chip->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL)) | ||
490 | count++; | ||
491 | |||
482 | if (count >= 0xF) { | 492 | if (count >= 0xF) { |
483 | printk(KERN_WARNING "%s: Too large timeout requested!\n", | 493 | printk(KERN_WARNING "%s: Too large timeout requested!\n", |
484 | mmc_hostname(host->mmc)); | 494 | mmc_hostname(host->mmc)); |