diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-12-02 13:52:11 -0500 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-12-12 14:01:00 -0500 |
commit | c9fddbc4f844f5a16b5957c61fe2cfcb5c12f990 (patch) | |
tree | 0bc8f857acfb7c47ab4c7231ffab5c8628b714c3 /drivers/mmc/host | |
parent | c6573c94670882079174e2ea0da4abf1a0da51fe (diff) |
sdhci: use PIO when DMA can't satisfy the request
Some controllers have been designed on the assumption that all transfers
will be 32-bit aligned, both in start address and in size. This is not a
guarantee the SDHCI specification provides and not one we can provide.
Revert back to PIO for individual requests in order to work around the
hardware bug.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 32 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 3 |
2 files changed, 31 insertions, 4 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 758a7417eb50..a5300f238d98 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -43,6 +43,10 @@ static unsigned int debug_quirks = 0; | |||
43 | #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) | 43 | #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) |
44 | /* Controller has an unusable DMA engine */ | 44 | /* Controller has an unusable DMA engine */ |
45 | #define SDHCI_QUIRK_BROKEN_DMA (1<<5) | 45 | #define SDHCI_QUIRK_BROKEN_DMA (1<<5) |
46 | /* Controller can only DMA from 32-bit aligned addresses */ | ||
47 | #define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<6) | ||
48 | /* Controller can only DMA chunk sizes that are a multiple of 32 bits */ | ||
49 | #define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<7) | ||
46 | 50 | ||
47 | static const struct pci_device_id pci_ids[] __devinitdata = { | 51 | static const struct pci_device_id pci_ids[] __devinitdata = { |
48 | { | 52 | { |
@@ -429,7 +433,29 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) | |||
429 | 433 | ||
430 | writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); | 434 | writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); |
431 | 435 | ||
432 | if (host->flags & SDHCI_USE_DMA) { | 436 | if (host->flags & SDHCI_USE_DMA) |
437 | host->flags |= SDHCI_REQ_USE_DMA; | ||
438 | |||
439 | if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && | ||
440 | (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && | ||
441 | ((data->blksz * data->blocks) & 0x3))) { | ||
442 | DBG("Reverting to PIO because of transfer size (%d)\n", | ||
443 | data->blksz * data->blocks); | ||
444 | host->flags &= ~SDHCI_REQ_USE_DMA; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * The assumption here being that alignment is the same after | ||
449 | * translation to device address space. | ||
450 | */ | ||
451 | if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && | ||
452 | (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && | ||
453 | (data->sg->offset & 0x3))) { | ||
454 | DBG("Reverting to PIO because of bad alignment\n"); | ||
455 | host->flags &= ~SDHCI_REQ_USE_DMA; | ||
456 | } | ||
457 | |||
458 | if (host->flags & SDHCI_REQ_USE_DMA) { | ||
433 | int count; | 459 | int count; |
434 | 460 | ||
435 | count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len, | 461 | count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len, |
@@ -466,7 +492,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, | |||
466 | mode |= SDHCI_TRNS_MULTI; | 492 | mode |= SDHCI_TRNS_MULTI; |
467 | if (data->flags & MMC_DATA_READ) | 493 | if (data->flags & MMC_DATA_READ) |
468 | mode |= SDHCI_TRNS_READ; | 494 | mode |= SDHCI_TRNS_READ; |
469 | if (host->flags & SDHCI_USE_DMA) | 495 | if (host->flags & SDHCI_REQ_USE_DMA) |
470 | mode |= SDHCI_TRNS_DMA; | 496 | mode |= SDHCI_TRNS_DMA; |
471 | 497 | ||
472 | writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); | 498 | writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); |
@@ -482,7 +508,7 @@ static void sdhci_finish_data(struct sdhci_host *host) | |||
482 | data = host->data; | 508 | data = host->data; |
483 | host->data = NULL; | 509 | host->data = NULL; |
484 | 510 | ||
485 | if (host->flags & SDHCI_USE_DMA) { | 511 | if (host->flags & SDHCI_REQ_USE_DMA) { |
486 | pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, | 512 | pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, |
487 | (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); | 513 | (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); |
488 | } | 514 | } |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 05195ea900f4..e4d77b038bfa 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
@@ -171,7 +171,8 @@ struct sdhci_host { | |||
171 | spinlock_t lock; /* Mutex */ | 171 | spinlock_t lock; /* Mutex */ |
172 | 172 | ||
173 | int flags; /* Host attributes */ | 173 | int flags; /* Host attributes */ |
174 | #define SDHCI_USE_DMA (1<<0) | 174 | #define SDHCI_USE_DMA (1<<0) /* Host is DMA capable */ |
175 | #define SDHCI_REQ_USE_DMA (1<<1) /* Use DMA for this req. */ | ||
175 | 176 | ||
176 | unsigned int max_clk; /* Max possible freq (MHz) */ | 177 | unsigned int max_clk; /* Max possible freq (MHz) */ |
177 | unsigned int timeout_clk; /* Timeout freq (KHz) */ | 178 | unsigned int timeout_clk; /* Timeout freq (KHz) */ |