|
@@ -679,6 +679,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
|
|
|
|
|
host->data = data;
|
|
|
host->data_early = 0;
|
|
|
+ host->data->bytes_xfered = 0;
|
|
|
|
|
|
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
|
|
|
host->flags |= SDHCI_REQ_USE_DMA;
|
|
@@ -814,8 +815,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
|
|
|
|
|
sdhci_set_transfer_irqs(host);
|
|
|
|
|
|
- /* We do not handle DMA boundaries, so set it to max (512 KiB) */
|
|
|
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE);
|
|
|
+ /* Set the DMA boundary value and block size */
|
|
|
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
|
|
|
+ data->blksz), SDHCI_BLOCK_SIZE);
|
|
|
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
|
|
|
}
|
|
|
|
|
@@ -1558,10 +1560,28 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
|
|
|
* We currently don't do anything fancy with DMA
|
|
|
* boundaries, but as we can't disable the feature
|
|
|
* we need to at least restart the transfer.
|
|
|
+ *
|
|
|
+ * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
|
|
|
+ * should return a valid address to continue from, but as
|
|
|
+ * some controllers are faulty, don't trust them.
|
|
|
*/
|
|
|
- if (intmask & SDHCI_INT_DMA_END)
|
|
|
- sdhci_writel(host, sdhci_readl(host, SDHCI_DMA_ADDRESS),
|
|
|
- SDHCI_DMA_ADDRESS);
|
|
|
+ if (intmask & SDHCI_INT_DMA_END) {
|
|
|
+ u32 dmastart, dmanow;
|
|
|
+ dmastart = sg_dma_address(host->data->sg);
|
|
|
+ dmanow = dmastart + host->data->bytes_xfered;
|
|
|
+ /*
|
|
|
+ * Force update to the next DMA block boundary.
|
|
|
+ */
|
|
|
+ dmanow = (dmanow &
|
|
|
+ ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
|
|
|
+ SDHCI_DEFAULT_BOUNDARY_SIZE;
|
|
|
+ host->data->bytes_xfered = dmanow - dmastart;
|
|
|
+ DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
|
|
|
+ " next 0x%08x\n",
|
|
|
+ mmc_hostname(host->mmc), dmastart,
|
|
|
+ host->data->bytes_xfered, dmanow);
|
|
|
+ sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
|
|
|
+ }
|
|
|
|
|
|
if (intmask & SDHCI_INT_DATA_END) {
|
|
|
if (host->cmd) {
|