spi_imx: full duplex dma corruption bugfix
Subsystems (2)
PATCH 1/1 spi_imx: full duplex dma corruption bugfix
From: Andrea Paterniani <a.paterniani-03BXCEkGbFHYGGNLXY5/[email protected]>
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.
--- drivers/spi/spi_imx.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-)
drivers/spi/spi_imx.c +22 -23
@@ -506,20 +506,6 @@ static int map_dma_buffers(struct driverif (!IS_DMA_ALIGNED (drv_data->rx) || !IS_DMA_ALIGNED (drv_data->tx))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 ) {/* Read only message --> use drv_data->dummy_dma_buf for dummy writes to achive reads */
@@ -533,18 +519,31 @@ static int map_dma_buffers(struct driver buf, drv_data->tx_map_len, DMA_TO_DEVICE); -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 ; - } +if (dma_mapping_error (dev, drv_data->tx_dma))return -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 ; }
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
A message that is not in the archive (sent off-list or not yet received): 200811181406.25041.david-b-yBeKhBN/[email protected]
au1550-spi: full duplex dma data 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. Tested with mmc-spi.
--- drivers/spi/au1550_spi.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/spi/au1550_spi.c +16 -10
@@ -369,10 +369,23 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) dma_rx_addr = t->rx_dma;/* -* check if buffers are already dma mapped, map them otherwise +* check if buffers are already dma mapped, map them otherwise: +* - first map the TX buffer, so cache data gets written to memory +* - then map the RX buffer, so that cache entries (with +* soon-to-be-stale data) get removed * use rx buffer in place of tx if tx buffer was not provided * use temp rx buffer (preallocated or realloc to fit) for rx dma */ +if (t->tx_buf) { +if (t->tx_dma ==0 ) {/* if DMA_ADDR_INVALID, map it */ + dma_tx_addr =dma_map_single (hw->dev, + (void *)t->tx_buf, + t->len,DMA_TO_DEVICE ); +if (dma_mapping_error (hw->dev, dma_tx_addr)) +dev_err (hw->dev,"tx dma map error\n" ); + } + } +if (t->rx_buf) {if (t->rx_dma ==0 ) {/* if DMA_ADDR_INVALID, map it */ dma_rx_addr = dma_map_single(hw->dev,
@@ -396,15 +409,8 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)dma_sync_single_for_device (hw->dev, dma_rx_addr, t->len,DMA_FROM_DEVICE ); } -if (t->tx_buf) { -if (t->tx_dma ==0 ) {/* if DMA_ADDR_INVALID, map it */ - dma_tx_addr =dma_map_single (hw->dev, - (void *)t->tx_buf, - t->len,DMA_TO_DEVICE ); -if (dma_mapping_error (hw->dev, dma_tx_addr)) -dev_err (hw->dev,"tx dma map error\n" ); - } - }else { + +if (!t->tx_buf) {dma_sync_single_for_device (hw->dev, dma_rx_addr, t->len,DMA_BIDIRECTIONAL ); hw->tx = hw->rx;
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/