Skip to content

Commit a8ca87b

Browse files
author
Radu Pirea
committed
spi: atmel: Implements transfers with bounce buffer
This patch enables SPI DMA transfers for Atmel SAM9 SoCs and implements a bounce buffer for transfers which have vmalloc allocated buffers. Those buffers are not cache coherent even if they have been transformed into sg lists. UBIFS is affected by this cache coherency issue. In this patch I also reverted "spi: atmel: fix corrupted data issue on SAM9 family SoCs"(7094576). Signed-off-by: Radu Pirea <radu.pirea@microchip.com> Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com> Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 56abc64 commit a8ca87b

1 file changed

Lines changed: 84 additions & 29 deletions

File tree

drivers/spi/spi-atmel.c

Lines changed: 84 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ struct atmel_spi {
291291
struct spi_transfer *current_transfer;
292292
int current_remaining_bytes;
293293
int done_status;
294+
dma_addr_t dma_addr_rx_bbuf;
295+
dma_addr_t dma_addr_tx_bbuf;
296+
void *addr_rx_bbuf;
297+
void *addr_tx_bbuf;
294298

295299
struct completion xfer_completion;
296300

@@ -436,6 +440,11 @@ static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock)
436440
spin_unlock_irqrestore(&as->lock, as->flags);
437441
}
438442

443+
static inline bool atmel_spi_is_vmalloc_xfer(struct spi_transfer *xfer)
444+
{
445+
return is_vmalloc_addr(xfer->tx_buf) || is_vmalloc_addr(xfer->rx_buf);
446+
}
447+
439448
static inline bool atmel_spi_use_dma(struct atmel_spi *as,
440449
struct spi_transfer *xfer)
441450
{
@@ -448,7 +457,12 @@ static bool atmel_spi_can_dma(struct spi_master *master,
448457
{
449458
struct atmel_spi *as = spi_master_get_devdata(master);
450459

451-
return atmel_spi_use_dma(as, xfer);
460+
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5))
461+
return atmel_spi_use_dma(as, xfer) &&
462+
!atmel_spi_is_vmalloc_xfer(xfer);
463+
else
464+
return atmel_spi_use_dma(as, xfer);
465+
452466
}
453467

454468
static int atmel_spi_dma_slave_config(struct atmel_spi *as,
@@ -594,6 +608,11 @@ static void dma_callback(void *data)
594608
struct spi_master *master = data;
595609
struct atmel_spi *as = spi_master_get_devdata(master);
596610

611+
if (is_vmalloc_addr(as->current_transfer->rx_buf) &&
612+
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
613+
memcpy(as->current_transfer->rx_buf, as->addr_rx_bbuf,
614+
as->current_transfer->len);
615+
}
597616
complete(&as->xfer_completion);
598617
}
599618

@@ -744,17 +763,41 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
744763
goto err_exit;
745764

746765
/* Send both scatterlists */
747-
rxdesc = dmaengine_prep_slave_sg(rxchan,
748-
xfer->rx_sg.sgl, xfer->rx_sg.nents,
749-
DMA_FROM_DEVICE,
750-
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
766+
if (atmel_spi_is_vmalloc_xfer(xfer) &&
767+
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
768+
rxdesc = dmaengine_prep_slave_single(rxchan,
769+
as->dma_addr_rx_bbuf,
770+
xfer->len,
771+
DMA_FROM_DEVICE,
772+
DMA_PREP_INTERRUPT |
773+
DMA_CTRL_ACK);
774+
} else {
775+
rxdesc = dmaengine_prep_slave_sg(rxchan,
776+
xfer->rx_sg.sgl,
777+
xfer->rx_sg.nents,
778+
DMA_FROM_DEVICE,
779+
DMA_PREP_INTERRUPT |
780+
DMA_CTRL_ACK);
781+
}
751782
if (!rxdesc)
752783
goto err_dma;
753784

754-
txdesc = dmaengine_prep_slave_sg(txchan,
755-
xfer->tx_sg.sgl, xfer->tx_sg.nents,
756-
DMA_TO_DEVICE,
757-
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
785+
if (atmel_spi_is_vmalloc_xfer(xfer) &&
786+
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
787+
memcpy(as->addr_tx_bbuf, xfer->tx_buf, xfer->len);
788+
txdesc = dmaengine_prep_slave_single(txchan,
789+
as->dma_addr_tx_bbuf,
790+
xfer->len, DMA_TO_DEVICE,
791+
DMA_PREP_INTERRUPT |
792+
DMA_CTRL_ACK);
793+
} else {
794+
txdesc = dmaengine_prep_slave_sg(txchan,
795+
xfer->tx_sg.sgl,
796+
xfer->tx_sg.nents,
797+
DMA_TO_DEVICE,
798+
DMA_PREP_INTERRUPT |
799+
DMA_CTRL_ACK);
800+
}
758801
if (!txdesc)
759802
goto err_dma;
760803

@@ -1426,27 +1469,7 @@ static void atmel_get_caps(struct atmel_spi *as)
14261469

14271470
as->caps.is_spi2 = version > 0x121;
14281471
as->caps.has_wdrbt = version >= 0x210;
1429-
#ifdef CONFIG_SOC_SAM_V4_V5
1430-
/*
1431-
* Atmel SoCs based on ARM9 (SAM9x) cores should not use spi_map_buf()
1432-
* since this later function tries to map buffers with dma_map_sg()
1433-
* even if they have not been allocated inside DMA-safe areas.
1434-
* On SoCs based on Cortex A5 (SAMA5Dx), it works anyway because for
1435-
* those ARM cores, the data cache follows the PIPT model.
1436-
* Also the L2 cache controller of SAMA5D2 uses the PIPT model too.
1437-
* In case of PIPT caches, there cannot be cache aliases.
1438-
* However on ARM9 cores, the data cache follows the VIVT model, hence
1439-
* the cache aliases issue can occur when buffers are allocated from
1440-
* DMA-unsafe areas, by vmalloc() for instance, where cache coherency is
1441-
* not taken into account or at least not handled completely (cache
1442-
* lines of aliases are not invalidated).
1443-
* This is not a theorical issue: it was reproduced when trying to mount
1444-
* a UBI file-system on a at91sam9g35ek board.
1445-
*/
1446-
as->caps.has_dma_support = false;
1447-
#else
14481472
as->caps.has_dma_support = version >= 0x212;
1449-
#endif
14501473
as->caps.has_pdc_support = version < 0x212;
14511474
}
14521475

@@ -1573,6 +1596,30 @@ static int atmel_spi_probe(struct platform_device *pdev)
15731596
as->use_pdc = true;
15741597
}
15751598

1599+
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
1600+
as->addr_rx_bbuf = dma_alloc_coherent(&pdev->dev,
1601+
SPI_MAX_DMA_XFER,
1602+
&as->dma_addr_rx_bbuf,
1603+
GFP_KERNEL | GFP_DMA);
1604+
if (!as->addr_rx_bbuf) {
1605+
as->use_dma = false;
1606+
} else {
1607+
as->addr_tx_bbuf = dma_alloc_coherent(&pdev->dev,
1608+
SPI_MAX_DMA_XFER,
1609+
&as->dma_addr_tx_bbuf,
1610+
GFP_KERNEL | GFP_DMA);
1611+
if (!as->addr_tx_bbuf) {
1612+
as->use_dma = false;
1613+
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
1614+
as->addr_rx_bbuf,
1615+
as->dma_addr_rx_bbuf);
1616+
}
1617+
}
1618+
if (!as->use_dma)
1619+
dev_info(master->dev.parent,
1620+
" can not allocate dma coherent memory\n");
1621+
}
1622+
15761623
if (as->caps.has_dma_support && !as->use_dma)
15771624
dev_info(&pdev->dev, "Atmel SPI Controller using PIO only\n");
15781625

@@ -1657,6 +1704,14 @@ static int atmel_spi_remove(struct platform_device *pdev)
16571704
if (as->use_dma) {
16581705
atmel_spi_stop_dma(master);
16591706
atmel_spi_release_dma(master);
1707+
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
1708+
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
1709+
as->addr_tx_bbuf,
1710+
as->dma_addr_tx_bbuf);
1711+
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
1712+
as->addr_rx_bbuf,
1713+
as->dma_addr_rx_bbuf);
1714+
}
16601715
}
16611716

16621717
spin_lock_irq(&as->lock);

0 commit comments

Comments
 (0)