
This involves introduction of bounce buffers since the block layer doesn't align buffers. We'll need to eventually start hunting down all of the places where the buffers aren't aligned in the block layer, but for now, the small amount of cases where the access is unaligned/obscure can be handled by bounce buffer.
The slowdown due to the bounce buffer is not noticable, measured with sustained reads.
Signed-off-by: Marek Vasut marex@denx.de Cc: Stefano Babic sbabic@denx.de Cc: Andy Fleming afleming@gmail.com Cc: Fabio Estevam festevam@gmail.com --- drivers/mmc/mxsmmc.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index fcd39a1..3ff4b2b 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -66,8 +66,10 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) struct mx28_ssp_regs *ssp_regs = priv->regs; uint32_t reg; int timeout; - uint32_t data_count; + uint32_t data_count, bb_data_count = 0; uint32_t ctrl0; + uint8_t *bounce = NULL; + int bb = 0;
debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx);
@@ -186,12 +188,41 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
data_count = data->blocksize * data->blocks;
+ if (data_count % MXS_DMA_ALIGNMENT) { + bb_data_count = roundup(data_count, MXS_DMA_ALIGNMENT); + bb = 1; + } + if (data->flags & MMC_DATA_READ) { priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; - priv->desc->cmd.address = (dma_addr_t)data->dest; + /* Alignment fault, bounce */ + if ((uint32_t)(data->dest) & (MXS_DMA_ALIGNMENT - 1)) + bb = 1; + + if (bb) { + bounce = memalign(bb_data_count, MXS_DMA_ALIGNMENT); + priv->desc->cmd.address = (dma_addr_t)bounce; + } else { + priv->desc->cmd.address = (dma_addr_t)data->dest; + bb_data_count = data_count; + } } else { priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; - priv->desc->cmd.address = (dma_addr_t)data->src; + if ((uint32_t)(data->src) & (MXS_DMA_ALIGNMENT - 1)) + bb = 1; + + if (bb) { + bounce = memalign(bb_data_count, MXS_DMA_ALIGNMENT); + priv->desc->cmd.address = (dma_addr_t)bounce; + memcpy(bounce, data->src, data_count); + } else { + priv->desc->cmd.address = (dma_addr_t)data->src; + bb_data_count = data_count; + } + + /* Flush data to DRAM so DMA can pick them up */ + flush_dcache_range((uint32_t)priv->desc->cmd.address, + (uint32_t)(priv->desc->cmd.address + bb_data_count)); }
priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | @@ -203,6 +234,19 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) return COMM_ERR; }
+ /* The data arrived into DRAM, invalidate cache over them */ + if (data->flags & MMC_DATA_READ) { + invalidate_dcache_range((uint32_t)priv->desc->cmd.address, + (uint32_t)(priv->desc->cmd.address + bb_data_count)); + if (bb) { + memcpy(data->dest, bounce, data_count); + free(bounce); + } + } else { + if (bb) + free(bounce); + } + /* Check data errors */ reg = readl(&ssp_regs->hw_ssp_status); if (reg &