aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikko Vinni <mmvinni@yahoo.com>2011-04-12 09:36:18 -0400
committerChris Ball <cjb@laptop.org>2011-05-24 21:01:29 -0400
commitf6a03cbf43e586211f8ea088148c8ecd3fc4b5be (patch)
tree6b3c34b585d7412cf1c82d0eb33b389ea0fa8e0f
parent6f60c22252af05df94352240f30f9fc84090d88d (diff)
mmc: sdhci: work around broken dma boundary behavior
Some SD host controllers (noticed on an integrated JMicron SD reader on an HP Pavilion dv5-1250eo laptop) don't update the dma address register before signaling a dma interrupt due to a dma boundary. Update the register manually to the next boundary (by default 512KiB), at which the transfer stopped. As long as each transfer is at most 512KiB in size (guaranteed by a BUG_ON in sdhci_prepare_data()) and the boundary is kept at the default value, this fix is needed at most once per transfer. Smaller boundaries are taken care of by counting the transferred bytes. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=28462 Signed-off-by: Mikko Vinni <mmvinni@yahoo.com> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/host/sdhci.c30
-rw-r--r--drivers/mmc/host/sdhci.h6
2 files changed, 31 insertions, 5 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ab17344fc7b..2ac0b6887ef 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -679,6 +679,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
679 679
680 host->data = data; 680 host->data = data;
681 host->data_early = 0; 681 host->data_early = 0;
682 host->data->bytes_xfered = 0;
682 683
683 if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) 684 if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
684 host->flags |= SDHCI_REQ_USE_DMA; 685 host->flags |= SDHCI_REQ_USE_DMA;
@@ -814,8 +815,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
814 815
815 sdhci_set_transfer_irqs(host); 816 sdhci_set_transfer_irqs(host);
816 817
817 /* We do not handle DMA boundaries, so set it to max (512 KiB) */ 818 /* Set the DMA boundary value and block size */
818 sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE); 819 sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
820 data->blksz), SDHCI_BLOCK_SIZE);
819 sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); 821 sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
820} 822}
821 823
@@ -1558,10 +1560,28 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
1558 * We currently don't do anything fancy with DMA 1560 * We currently don't do anything fancy with DMA
1559 * boundaries, but as we can't disable the feature 1561 * boundaries, but as we can't disable the feature
1560 * we need to at least restart the transfer. 1562 * we need to at least restart the transfer.
1563 *
1564 * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
1565 * should return a valid address to continue from, but as
1566 * some controllers are faulty, don't trust them.
1561 */ 1567 */
1562 if (intmask & SDHCI_INT_DMA_END) 1568 if (intmask & SDHCI_INT_DMA_END) {
1563 sdhci_writel(host, sdhci_readl(host, SDHCI_DMA_ADDRESS), 1569 u32 dmastart, dmanow;
1564 SDHCI_DMA_ADDRESS); 1570 dmastart = sg_dma_address(host->data->sg);
1571 dmanow = dmastart + host->data->bytes_xfered;
1572 /*
1573 * Force update to the next DMA block boundary.
1574 */
1575 dmanow = (dmanow &
1576 ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
1577 SDHCI_DEFAULT_BOUNDARY_SIZE;
1578 host->data->bytes_xfered = dmanow - dmastart;
1579 DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
1580 " next 0x%08x\n",
1581 mmc_hostname(host->mmc), dmastart,
1582 host->data->bytes_xfered, dmanow);
1583 sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
1584 }
1565 1585
1566 if (intmask & SDHCI_INT_DATA_END) { 1586 if (intmask & SDHCI_INT_DATA_END) {
1567 if (host->cmd) { 1587 if (host->cmd) {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 25e8bde600d..85750a94c61 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -202,6 +202,12 @@
202#define SDHCI_MAX_DIV_SPEC_200 256 202#define SDHCI_MAX_DIV_SPEC_200 256
203#define SDHCI_MAX_DIV_SPEC_300 2046 203#define SDHCI_MAX_DIV_SPEC_300 2046
204 204
205/*
206 * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
207 */
208#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
209#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
210
205struct sdhci_ops { 211struct sdhci_ops {
206#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS 212#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
207 u32 (*read_l)(struct sdhci_host *host, int reg); 213 u32 (*read_l)(struct sdhci_host *host, int reg);