aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2007-12-02 13:52:11 -0500
committerPierre Ossman <drzeus@drzeus.cx>2007-12-12 14:01:00 -0500
commitc9fddbc4f844f5a16b5957c61fe2cfcb5c12f990 (patch)
tree0bc8f857acfb7c47ab4c7231ffab5c8628b714c3 /drivers/mmc/host
parentc6573c94670882079174e2ea0da4abf1a0da51fe (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.c32
-rw-r--r--drivers/mmc/host/sdhci.h3
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
47static const struct pci_device_id pci_ids[] __devinitdata = { 51static 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) */