Commit 3b45d638 authored by Andrea Paterniani's avatar Andrea Paterniani Committed by Linus Torvalds

spi_imx: full duplex dma corruption bugfix

Fix unsafe order in dma mapping operation: always flush data from the
cache *BEFORE* invalidating it, to allow full duplex transfers where the
same buffer may be used for both writes and reads.
Signed-off-by: default avatarAndrea Paterniani <a.paterniani@swapp-eng.it>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b3b4dc88
...@@ -506,20 +506,6 @@ static int map_dma_buffers(struct driver_data *drv_data) ...@@ -506,20 +506,6 @@ static int map_dma_buffers(struct driver_data *drv_data)
if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx)) if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
return -1; return -1;
/* NULL rx means write-only transfer and no map needed
since rx DMA will not be used */
if (drv_data->rx) {
buf = drv_data->rx;
drv_data->rx_dma = dma_map_single(
dev,
buf,
drv_data->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, drv_data->rx_dma))
return -1;
drv_data->rx_dma_needs_unmap = 1;
}
if (drv_data->tx == NULL) { if (drv_data->tx == NULL) {
/* Read only message --> use drv_data->dummy_dma_buf for dummy /* Read only message --> use drv_data->dummy_dma_buf for dummy
writes to achive reads */ writes to achive reads */
...@@ -533,18 +519,31 @@ static int map_dma_buffers(struct driver_data *drv_data) ...@@ -533,18 +519,31 @@ static int map_dma_buffers(struct driver_data *drv_data)
buf, buf,
drv_data->tx_map_len, drv_data->tx_map_len,
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (dma_mapping_error(dev, drv_data->tx_dma)) { if (dma_mapping_error(dev, drv_data->tx_dma))
if (drv_data->rx_dma) {
dma_unmap_single(dev,
drv_data->rx_dma,
drv_data->len,
DMA_FROM_DEVICE);
drv_data->rx_dma_needs_unmap = 0;
}
return -1; return -1;
}
drv_data->tx_dma_needs_unmap = 1; drv_data->tx_dma_needs_unmap = 1;
/* NULL rx means write-only transfer and no map needed
* since rx DMA will not be used */
if (drv_data->rx) {
buf = drv_data->rx;
drv_data->rx_dma = dma_map_single(dev,
buf,
drv_data->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, drv_data->rx_dma)) {
if (drv_data->tx_dma) {
dma_unmap_single(dev,
drv_data->tx_dma,
drv_data->tx_map_len,
DMA_TO_DEVICE);
drv_data->tx_dma_needs_unmap = 0;
}
return -1;
}
drv_data->rx_dma_needs_unmap = 1;
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment