summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2012-08-31 16:07:59 +0000
committerStefano Babic <sbabic@denx.de>2012-09-06 14:17:55 +0200
commit88d155596879035532f8be05172d605965c733ed (patch)
tree03312a62ce08fe8179250e939e54017a48e44385
parent697191d57fb2fae7b31cec9581fb7749f965d877 (diff)
downloadu-boot-imx-88d155596879035532f8be05172d605965c733ed.zip
u-boot-imx-88d155596879035532f8be05172d605965c733ed.tar.gz
u-boot-imx-88d155596879035532f8be05172d605965c733ed.tar.bz2
MX28: SPI: Fix the DMA DCache race condition
This patch fixes dcache-related problem. The problem manifested when dcache was enabled and the following command issued twice: mw 0x42000000 0 0x4000 ; sf probe ; sf read 0x42000000 0x0 0x10000 ; sha1sum 0x42000000 0x10000 The SHA1 checksum was correct during the first call. Yet with every subsequent call of the above command, it differed and was wrong. It turns out this was because of a race condition. On the first time the command was called, no cacheline contained any data from the destination memory location. The DMA transfered data into the location and the cache above the location was invalidated. Then the checksum was computed, but that meant the data were loaded into data cache. On any subsequent call, the DMA again transfered data into the same destination. Yet during the transfer, some of the DCache lines were evicted and written back into the main memory. Once the DMA transfer completed, the data cache was invalidated over the memory location as usual. But the data that were to be loaded back into the data cache by subsequent SHA1 checksuming were corrupted. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Fabio Estevam <festevam@gmail.com> Cc: Otavio Salvador <otavio@ossystems.com.br> Cc: Stefano Babic <sbabic@denx.de>
-rw-r--r--drivers/spi/mxs_spi.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index 168dbe4..c399707 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -224,6 +224,7 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
struct mxs_dma_desc *dp;
uint32_t ctrl0;
uint32_t cache_data_count;
+ const uint32_t dstart = (uint32_t)data;
int dmach;
int tl;
@@ -246,10 +247,12 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
else
cache_data_count = length;
+ /* Flush data to DRAM so DMA can pick them up */
if (write)
- /* Flush data to DRAM so DMA can pick them up */
- flush_dcache_range((uint32_t)data,
- (uint32_t)(data + cache_data_count));
+ flush_dcache_range(dstart, dstart + cache_data_count);
+
+ /* Invalidate the area, so no writeback into the RAM races with DMA */
+ invalidate_dcache_range(dstart, dstart + cache_data_count);
dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + slave->slave.bus;
@@ -310,10 +313,8 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
return -EINVAL;
/* The data arrived into DRAM, invalidate cache over them */
- if (!write) {
- invalidate_dcache_range((uint32_t)data,
- (uint32_t)(data + cache_data_count));
- }
+ if (!write)
+ invalidate_dcache_range(dstart, dstart + cache_data_count);
return 0;
}