spi: atmel: enhance the DMA handling
Subsystems (3)
cover spi: atmel: enhance the DMA handling
Use the dummy buffer handling and DMA mapping core infrastructure to simplify spi-atmel driver.
By using these frameworks we also fix the use of any kind of memory with dmaengine. This work was triggered by issues encountered while using UBI/UBIFS on a serial flash.
Some good ideas of this series have been inspired by spi-rspi.c and commits by Geert Uytterhoeven.
I have a side question still: is the is_dma_mapped tag still used and considered into the core spi routines or is it always the driver itself that have to deal with it (so how to do with the can_dma() routine)?
Cyrille Pitchen (1):
spi: atmel: Use SPI core DMA mapping framework
Nicolas Ferre (4):
spi: atmel: trivial: move info banner to latest probe action
spi: atmel: Use core SPI_MASTER_MUST_[RT]X handling
spi: atmel: trivial: remove unused fields in DMA structure
spi: atmel: remove the use of private channel fields
drivers/spi/spi-atmel.c | 268 ++++++++++++++++++------------------------------ 1 file changed, 98 insertions(+), 170 deletions(-)
Signature · 1 line
2.9.0
PATCH 1/5 spi: atmel: trivial: move info banner to latest probe action
The info banner is here to tell that everything went well, so place it at the very end of the probe function.
--- drivers/spi/spi-atmel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/spi/spi-atmel.c +4 -4
@@ -1658,10 +1658,6 @@ static int atmel_spi_probe(struct platform_device *pdev)spi_writel (as,CR ,SPI_BIT (FIFOEN )); } -/* go! */ -dev_info (&pdev->dev,"Atmel SPI Controller at 0x%08lx (irq %d)\n" , - (unsigned long )regs->start, irq); -pm_runtime_set_autosuspend_delay (&pdev->dev,AUTOSUSPEND_TIMEOUT );pm_runtime_use_autosuspend (&pdev->dev);pm_runtime_set_active (&pdev->dev);
@@ -1671,6 +1667,10 @@ static int atmel_spi_probe(struct platform_device *pdev)if (ret) goto out_free_dma; +/* go! */ +dev_info (&pdev->dev,"Atmel SPI Controller at 0x%08lx (irq %d)\n" , + (unsigned long )regs->start, irq); +return 0 ; out_free_dma:
Signature · 1 line
2.9.0
Mark Brown
maintainerRe: [PATCH 1/5] spi: atmel: trivial: move info banner to latest probe action
Quoted 2 lines · Nicolas Ferre
The info banner is here to tell that everything went well, so place it at the very end of the probe function.
Really we should just drop this, the banner is only telling us things
enumerated from DT so it's adding noise to the boot.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161125/7ef8494d/attachment.sig>
Mark Brown
maintainerApplied "spi: atmel: trivial: move info banner to latest probe action" to the spi tree
In reply to Nicolas FerreThe patch
spi: atmel: trivial: move info banner to latest probe action
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks,
Mark
Quoted 1 line
From
ce24a513fb142e855b4aa77f91334c2f203c0d99Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <[email protected]>
Date: Thu, 24 Nov 2016 12:24:57 +0100
Subject: [PATCH] spi: atmel: trivial: move info banner to latest probe action
The info banner is here to tell that everything went well, so place it at the very end of the probe function.
--- drivers/spi/spi-atmel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/spi/spi-atmel.c +4 -4
@@ -1654,10 +1654,6 @@ static int atmel_spi_probe(struct platform_device *pdev)spi_writel (as,CR ,SPI_BIT (FIFOEN )); } -/* go! */ -dev_info (&pdev->dev,"Atmel SPI Controller at 0x%08lx (irq %d)\n" , - (unsigned long )regs->start, irq); -pm_runtime_set_autosuspend_delay (&pdev->dev,AUTOSUSPEND_TIMEOUT );pm_runtime_use_autosuspend (&pdev->dev);pm_runtime_set_active (&pdev->dev);
@@ -1667,6 +1663,10 @@ static int atmel_spi_probe(struct platform_device *pdev)if (ret) goto out_free_dma; +/* go! */ +dev_info (&pdev->dev,"Atmel SPI Controller at 0x%08lx (irq %d)\n" , + (unsigned long )regs->start, irq); +return 0 ; out_free_dma:
Signature · 1 line
2.10.2
PATCH 2/5 spi: atmel: Use core SPI_MASTER_MUST_[RT]X handling
In reply to Nicolas FerreWe need both RX and TX data for each transfer in any case (PIO, PDC, DMA). So convert the driver to the core dummy buffer handling with the SPI_MASTER_MUST_RX/SPI_MASTER_MUST_TX infrastructure.
This move changes the maximum PDC/DMA buffer handling to 65535 bytes instead of a single page and sets master->max_dma_len to this value.
All dummy buffer management is removed from the driver.
--- drivers/spi/spi-atmel.c | 131 +++++++++++++----------------------------------- 1 file changed, 35 insertions(+), 96 deletions(-)
drivers/spi/spi-atmel.c +35 -96
@@ -304,10 +304,6 @@ struct atmel_spi {struct completion xfer_completion; -/* scratch buffer */ -void *buffer; -dma_addr_t buffer_dma; -struct atmel_spi_caps caps;bool use_dma;
@@ -328,7 +324,7 @@ struct atmel_spi_device {u32 csr; }; -#define BUFFER_SIZE PAGE_SIZE +#define SPI_MAX_DMA_XFER 65535/* true for both PDC and DMA */ #define INVALID_DMA_ADDRESS 0xffffffff/*
@@ -613,14 +609,10 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,cpu_relax (); } -if (xfer->tx_buf) { -if (xfer->bits_per_word >8 ) -spi_writel (as,TDR , *(u16 *)(xfer->tx_buf + xfer_pos)); -else -spi_writel (as,TDR , *(u8 *)(xfer->tx_buf + xfer_pos)); - }else { -spi_writel (as,TDR ,0 ); - } +if (xfer->bits_per_word >8 ) +spi_writel (as,TDR , *(u16 *)(xfer->tx_buf + xfer_pos)); +else +spi_writel (as,TDR , *(u8 *)(xfer->tx_buf + xfer_pos)); dev_dbg(master->dev.parent, " start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
@@ -667,17 +659,12 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,/* Fill TX FIFO */ while (num_data >=2 ) { -if (xfer->tx_buf) { -if (xfer->bits_per_word >8 ) { - td0 = *words++; - td1 = *words++; - }else { - td0 = *bytes++; - td1 = *bytes++; - } +if (xfer->bits_per_word >8 ) { + td0 = *words++; + td1 = *words++; }else { - td0 =0 ; - td1 =0 ; + td0 = *bytes++; + td1 = *bytes++; }spi_writel (as,TDR , (td1 <<16 ) | td0);
@@ -685,14 +672,10 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master, }if (num_data) { -if (xfer->tx_buf) { -if (xfer->bits_per_word >8 ) - td0 = *words++; -else - td0 = *bytes++; - }else { - td0 =0 ; - } +if (xfer->bits_per_word >8 ) + td0 = *words++; +else + td0 = *bytes++;spi_writew (as,TDR , td0); num_data--;
@@ -751,24 +734,14 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,/* prepare the RX dma transfer */ sg_init_table (&as->dma.sgrx,1 ); -if (xfer->rx_buf) { - as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen; - }else { - as->dma.sgrx.dma_address = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; - } + as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen;/* prepare the TX dma transfer */ sg_init_table (&as->dma.sgtx,1 ); -if (xfer->tx_buf) { - as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen; - }else { - as->dma.sgtx.dma_address = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; -memset (as->buffer,0 , len); - } + as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen; + +if (len > master->max_dma_len) + len = master->max_dma_len;sg_dma_len (&as->dma.sgtx) = len;sg_dma_len (&as->dma.sgrx) = len;
@@ -835,25 +808,10 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,struct atmel_spi *as =spi_master_get_devdata (master);u32 len = *plen; -/* use scratch buffer only when rx or tx data is unspecified */ -if (xfer->rx_buf) - *rx_dma = xfer->rx_dma + xfer->len - *plen; -else { - *rx_dma = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; - } - -if (xfer->tx_buf) - *tx_dma = xfer->tx_dma + xfer->len - *plen; -else { - *tx_dma = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; -memset (as->buffer,0 , len); -dma_sync_single_for_device (&as->pdev->dev, - as->buffer_dma, len,DMA_TO_DEVICE ); - } + *rx_dma = xfer->rx_dma + xfer->len - *plen; + *tx_dma = xfer->tx_dma + xfer->len - *plen; +if (len > master->max_dma_len) + len = master->max_dma_len; *plen = len; }
@@ -1027,16 +985,12 @@ atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer)u16 *rxp16;unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; -if (xfer->rx_buf) { -if (xfer->bits_per_word >8 ) { - rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos); - *rxp16 =spi_readl (as,RDR ); - }else { - rxp = ((u8 *)xfer->rx_buf) + xfer_pos; - *rxp =spi_readl (as,RDR ); - } +if (xfer->bits_per_word >8 ) { + rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos); + *rxp16 =spi_readl (as,RDR ); }else { -spi_readl (as,RDR ); + rxp = ((u8 *)xfer->rx_buf) + xfer_pos; + *rxp =spi_readl (as,RDR ); }if (xfer->bits_per_word >8 ) {if (as->current_remaining_bytes >2 )
@@ -1075,12 +1029,10 @@ atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer)/* Read data */ while (num_data) { rd =spi_readl (as,RDR ); -if (xfer->rx_buf) { -if (xfer->bits_per_word >8 ) - *words++ = rd; -else - *bytes++ = rd; - } +if (xfer->bits_per_word >8 ) + *words++ = rd; +else + *bytes++ = rd; num_data--; } }
@@ -1562,29 +1514,22 @@ static int atmel_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = master->dev.of_node ?0 :4 ; master->setup = atmel_spi_setup; + master->flags = (SPI_MASTER_MUST_RX |SPI_MASTER_MUST_TX ); master->transfer_one_message = atmel_spi_transfer_one_message; master->cleanup = atmel_spi_cleanup; master->auto_runtime_pm = true; + master->max_dma_len =SPI_MAX_DMA_XFER ;platform_set_drvdata (pdev, master); as =spi_master_get_devdata (master); -/* -* Scratch buffer is used for throwaway rx and tx data. -* It's coherent to minimize dcache pollution. -*/ - as->buffer =dma_alloc_coherent (&pdev->dev,BUFFER_SIZE , - &as->buffer_dma,GFP_KERNEL ); -if (!as->buffer) - goto out_free; -spin_lock_init (&as->lock); as->pdev = pdev; as->regs =devm_ioremap_resource (&pdev->dev, regs);if (IS_ERR (as->regs)) { ret =PTR_ERR (as->regs); - goto out_free_buffer; + goto out_unmap_regs; } as->phybase = regs->start; as->irq = irq;
@@ -1685,9 +1630,6 @@ static int atmel_spi_probe(struct platform_device *pdev)clk_disable_unprepare (clk); out_free_irq: out_unmap_regs: -out_free_buffer: -dma_free_coherent (&pdev->dev,BUFFER_SIZE , as->buffer, - as->buffer_dma); out_free:spi_master_put (master);return ret;
@@ -1712,9 +1654,6 @@ static int atmel_spi_remove(struct platform_device *pdev)spi_readl (as,SR );spin_unlock_irq (&as->lock); -dma_free_coherent (&pdev->dev,BUFFER_SIZE , as->buffer, - as->buffer_dma); -clk_disable_unprepare (as->clk);pm_runtime_put_noidle (&pdev->dev);
Signature · 1 line
2.9.0
Mark Brown
maintainerApplied "spi: atmel: Use core SPI_MASTER_MUST_[RT]X handling" to the spi tree
The patch
spi: atmel: Use core SPI_MASTER_MUST_[RT]X handling
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks,
Mark
Quoted 1 line
From
7910d9af000acc155745e44be55a5d0dc9e26ce7Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <[email protected]>
Date: Thu, 24 Nov 2016 12:24:58 +0100
Subject: [PATCH] spi: atmel: Use core SPI_MASTER_MUST_[RT]X handling
We need both RX and TX data for each transfer in any case (PIO, PDC, DMA). So convert the driver to the core dummy buffer handling with the SPI_MASTER_MUST_RX/SPI_MASTER_MUST_TX infrastructure.
This move changes the maximum PDC/DMA buffer handling to 65535 bytes instead of a single page and sets master->max_dma_len to this value.
All dummy buffer management is removed from the driver.
--- drivers/spi/spi-atmel.c | 131 +++++++++++++----------------------------------- 1 file changed, 35 insertions(+), 96 deletions(-)
drivers/spi/spi-atmel.c +35 -96
@@ -303,10 +303,6 @@ struct atmel_spi {struct completion xfer_completion; -/* scratch buffer */ -void *buffer; -dma_addr_t buffer_dma; -struct atmel_spi_caps caps;bool use_dma;
@@ -327,7 +323,7 @@ struct atmel_spi_device {u32 csr; }; -#define BUFFER_SIZE PAGE_SIZE +#define SPI_MAX_DMA_XFER 65535/* true for both PDC and DMA */ #define INVALID_DMA_ADDRESS 0xffffffff/*
@@ -612,14 +608,10 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,cpu_relax (); } -if (xfer->tx_buf) { -if (xfer->bits_per_word >8 ) -spi_writel (as,TDR , *(u16 *)(xfer->tx_buf + xfer_pos)); -else -spi_writel (as,TDR , *(u8 *)(xfer->tx_buf + xfer_pos)); - }else { -spi_writel (as,TDR ,0 ); - } +if (xfer->bits_per_word >8 ) +spi_writel (as,TDR , *(u16 *)(xfer->tx_buf + xfer_pos)); +else +spi_writel (as,TDR , *(u8 *)(xfer->tx_buf + xfer_pos)); dev_dbg(master->dev.parent, " start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
@@ -666,17 +658,12 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,/* Fill TX FIFO */ while (num_data >=2 ) { -if (xfer->tx_buf) { -if (xfer->bits_per_word >8 ) { - td0 = *words++; - td1 = *words++; - }else { - td0 = *bytes++; - td1 = *bytes++; - } +if (xfer->bits_per_word >8 ) { + td0 = *words++; + td1 = *words++; }else { - td0 =0 ; - td1 =0 ; + td0 = *bytes++; + td1 = *bytes++; }spi_writel (as,TDR , (td1 <<16 ) | td0);
@@ -684,14 +671,10 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master, }if (num_data) { -if (xfer->tx_buf) { -if (xfer->bits_per_word >8 ) - td0 = *words++; -else - td0 = *bytes++; - }else { - td0 =0 ; - } +if (xfer->bits_per_word >8 ) + td0 = *words++; +else + td0 = *bytes++;spi_writew (as,TDR , td0); num_data--;
@@ -750,24 +733,14 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,/* prepare the RX dma transfer */ sg_init_table (&as->dma.sgrx,1 ); -if (xfer->rx_buf) { - as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen; - }else { - as->dma.sgrx.dma_address = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; - } + as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen;/* prepare the TX dma transfer */ sg_init_table (&as->dma.sgtx,1 ); -if (xfer->tx_buf) { - as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen; - }else { - as->dma.sgtx.dma_address = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; -memset (as->buffer,0 , len); - } + as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen; + +if (len > master->max_dma_len) + len = master->max_dma_len;sg_dma_len (&as->dma.sgtx) = len;sg_dma_len (&as->dma.sgrx) = len;
@@ -834,25 +807,10 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,struct atmel_spi *as =spi_master_get_devdata (master);u32 len = *plen; -/* use scratch buffer only when rx or tx data is unspecified */ -if (xfer->rx_buf) - *rx_dma = xfer->rx_dma + xfer->len - *plen; -else { - *rx_dma = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; - } - -if (xfer->tx_buf) - *tx_dma = xfer->tx_dma + xfer->len - *plen; -else { - *tx_dma = as->buffer_dma; -if (len >BUFFER_SIZE ) - len =BUFFER_SIZE ; -memset (as->buffer,0 , len); -dma_sync_single_for_device (&as->pdev->dev, - as->buffer_dma, len,DMA_TO_DEVICE ); - } + *rx_dma = xfer->rx_dma + xfer->len - *plen; + *tx_dma = xfer->tx_dma + xfer->len - *plen; +if (len > master->max_dma_len) + len = master->max_dma_len; *plen = len; }
@@ -1026,16 +984,12 @@ atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer)u16 *rxp16;unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; -if (xfer->rx_buf) { -if (xfer->bits_per_word >8 ) { - rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos); - *rxp16 =spi_readl (as,RDR ); - }else { - rxp = ((u8 *)xfer->rx_buf) + xfer_pos; - *rxp =spi_readl (as,RDR ); - } +if (xfer->bits_per_word >8 ) { + rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos); + *rxp16 =spi_readl (as,RDR ); }else { -spi_readl (as,RDR ); + rxp = ((u8 *)xfer->rx_buf) + xfer_pos; + *rxp =spi_readl (as,RDR ); }if (xfer->bits_per_word >8 ) {if (as->current_remaining_bytes >2 )
@@ -1074,12 +1028,10 @@ atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer)/* Read data */ while (num_data) { rd =spi_readl (as,RDR ); -if (xfer->rx_buf) { -if (xfer->bits_per_word >8 ) - *words++ = rd; -else - *bytes++ = rd; - } +if (xfer->bits_per_word >8 ) + *words++ = rd; +else + *bytes++ = rd; num_data--; } }
@@ -1561,29 +1513,22 @@ static int atmel_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = master->dev.of_node ?0 :4 ; master->setup = atmel_spi_setup; + master->flags = (SPI_MASTER_MUST_RX |SPI_MASTER_MUST_TX ); master->transfer_one_message = atmel_spi_transfer_one_message; master->cleanup = atmel_spi_cleanup; master->auto_runtime_pm = true; + master->max_dma_len =SPI_MAX_DMA_XFER ;platform_set_drvdata (pdev, master); as =spi_master_get_devdata (master); -/* -* Scratch buffer is used for throwaway rx and tx data. -* It's coherent to minimize dcache pollution. -*/ - as->buffer =dma_alloc_coherent (&pdev->dev,BUFFER_SIZE , - &as->buffer_dma,GFP_KERNEL ); -if (!as->buffer) - goto out_free; -spin_lock_init (&as->lock); as->pdev = pdev; as->regs =devm_ioremap_resource (&pdev->dev, regs);if (IS_ERR (as->regs)) { ret =PTR_ERR (as->regs); - goto out_free_buffer; + goto out_unmap_regs; } as->phybase = regs->start; as->irq = irq;
@@ -1681,9 +1626,6 @@ static int atmel_spi_probe(struct platform_device *pdev)clk_disable_unprepare (clk); out_free_irq: out_unmap_regs: -out_free_buffer: -dma_free_coherent (&pdev->dev,BUFFER_SIZE , as->buffer, - as->buffer_dma); out_free:spi_master_put (master);return ret;
@@ -1708,9 +1650,6 @@ static int atmel_spi_remove(struct platform_device *pdev)spi_readl (as,SR );spin_unlock_irq (&as->lock); -dma_free_coherent (&pdev->dev,BUFFER_SIZE , as->buffer, - as->buffer_dma); -clk_disable_unprepare (as->clk);pm_runtime_put_noidle (&pdev->dev);
Signature · 1 line
2.10.2
PATCH 3/5 spi: atmel: Use SPI core DMA mapping framework
In reply to Nicolas FerreFrom: Cyrille Pitchen <[email protected]>
Use the SPI core DMA mapping framework instead of our own in case of DMA support. PDC support is not converted to this framework.
The driver is now able to transfer a complete sg list through DMA. This eventually fix an issue with vmalloc'ed DMA memory that is provided for example by UBI/UBIFS layers.
--- drivers/spi/spi-atmel.c | 57 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-)
drivers/spi/spi-atmel.c +25 -32
@@ -268,8 +268,6 @@struct atmel_spi_dma {struct dma_chan *chan_rx;struct dma_chan *chan_tx; -struct scatterlist sgrx; -struct scatterlist sgtx;struct dma_async_tx_descriptor *data_desc_rx;struct dma_async_tx_descriptor *data_desc_tx;
@@ -454,6 +452,15 @@ static inline bool atmel_spi_use_dma(struct atmel_spi *as,return as->use_dma && xfer->len >=DMA_MIN_BYTES ; } +static bool atmel_spi_can_dma (struct spi_master *master, +struct spi_device *spi, +struct spi_transfer *xfer) +{ +struct atmel_spi *as =spi_master_get_devdata (master); + +return atmel_spi_use_dma (as, xfer); +} +static int atmel_spi_dma_slave_config (struct atmel_spi *as,struct dma_slave_config *slave_config,u8 bits_per_word)
@@ -721,7 +728,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,struct dma_async_tx_descriptor *txdesc;struct dma_slave_config slave_config;dma_cookie_t cookie; -u32 len = *plen;dev_vdbg (master->dev.parent,"atmel_spi_next_xfer_dma_submit\n" );
@@ -732,34 +738,22 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,/* release lock for DMA operations */ atmel_spi_unlock (as); -/* prepare the RX dma transfer */ -sg_init_table (&as->dma.sgrx,1 ); - as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen; - -/* prepare the TX dma transfer */ -sg_init_table (&as->dma.sgtx,1 ); - as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen; - -if (len > master->max_dma_len) - len = master->max_dma_len; - -sg_dma_len (&as->dma.sgtx) = len; -sg_dma_len (&as->dma.sgrx) = len; - - *plen = len; + *plen = xfer->len;if (atmel_spi_dma_slave_config (as, &slave_config, xfer->bits_per_word)) goto err_exit;/* Send both scatterlists */ - rxdesc =dmaengine_prep_slave_sg (rxchan, &as->dma.sgrx,1 , + rxdesc =dmaengine_prep_slave_sg (rxchan, + xfer->rx_sg.sgl, xfer->rx_sg.nents,DMA_FROM_DEVICE ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK );if (!rxdesc) goto err_dma; - txdesc =dmaengine_prep_slave_sg (txchan, &as->dma.sgtx,1 , + txdesc =dmaengine_prep_slave_sg (txchan, + xfer->tx_sg.sgl, xfer->tx_sg.nents,DMA_TO_DEVICE ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK );if (!txdesc)
@@ -805,15 +799,10 @@ static void atmel_spi_next_xfer_data(struct spi_master *master, dma_addr_t *rx_dma, u32 *plen) { -struct atmel_spi *as =spi_master_get_devdata (master); -u32 len = *plen; - *rx_dma = xfer->rx_dma + xfer->len - *plen; *tx_dma = xfer->tx_dma + xfer->len - *plen; -if (len > master->max_dma_len) - len = master->max_dma_len; - - *plen = len; +if (*plen > master->max_dma_len) + *plen = master->max_dma_len; } static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
@@ -1253,7 +1242,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,* better fault reporting. */ if ((!msg->is_dma_mapped) - && (atmel_spi_use_dma (as, xfer) || as->use_pdc)) { + && as->use_pdc) {if (atmel_spi_dma_map_xfer (as, xfer) <0 )return -ENOMEM ; }
@@ -1330,7 +1319,7 @@ static int atmel_spi_one_transfer(struct spi_master *master, }if (!msg->is_dma_mapped - && (atmel_spi_use_dma (as, xfer) || as->use_pdc)) + && as->use_pdc)atmel_spi_dma_unmap_xfer (master, xfer);return 0 ;
@@ -1341,7 +1330,7 @@ static int atmel_spi_one_transfer(struct spi_master *master, }if (!msg->is_dma_mapped - && (atmel_spi_use_dma (as, xfer) || as->use_pdc)) + && as->use_pdc)atmel_spi_dma_unmap_xfer (master, xfer);if (xfer->delay_usecs)
@@ -1519,6 +1508,7 @@ static int atmel_spi_probe(struct platform_device *pdev) master->cleanup = atmel_spi_cleanup; master->auto_runtime_pm = true; master->max_dma_len =SPI_MAX_DMA_XFER ; + master->can_dma = atmel_spi_can_dma;platform_set_drvdata (pdev, master); as =spi_master_get_devdata (master);
@@ -1555,10 +1545,13 @@ static int atmel_spi_probe(struct platform_device *pdev) as->use_pdc = false;if (as->caps.has_dma_support) { ret =atmel_spi_configure_dma (as); -if (ret ==0 ) +if (ret ==0 ) { + master->dma_tx = as->dma.chan_tx; + master->dma_rx = as->dma.chan_rx; as->use_dma = true; -else if (ret == -EPROBE_DEFER ) + }else if (ret == -EPROBE_DEFER ) {return ret; + } }else { as->use_pdc = true; }
Signature · 1 line
2.9.0
Mark Brown
maintainerApplied "spi: atmel: Use SPI core DMA mapping framework" to the spi tree
The patch
spi: atmel: Use SPI core DMA mapping framework
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks,
Mark
Quoted 1 line
From
04242ca4e8917999ac2bbc3d2b10409661f60272Mon Sep 17 00:00:00 2001
From: Cyrille Pitchen <[email protected]>
Date: Thu, 24 Nov 2016 12:24:59 +0100
Subject: [PATCH] spi: atmel: Use SPI core DMA mapping framework
Use the SPI core DMA mapping framework instead of our own in case of DMA support. PDC support is not converted to this framework.
The driver is now able to transfer a complete sg list through DMA. This eventually fix an issue with vmalloc'ed DMA memory that is provided for example by UBI/UBIFS layers.
--- drivers/spi/spi-atmel.c | 57 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-)
drivers/spi/spi-atmel.c +25 -32
@@ -268,8 +268,6 @@struct atmel_spi_dma {struct dma_chan *chan_rx;struct dma_chan *chan_tx; -struct scatterlist sgrx; -struct scatterlist sgtx;struct dma_async_tx_descriptor *data_desc_rx;struct dma_async_tx_descriptor *data_desc_tx;
@@ -453,6 +451,15 @@ static inline bool atmel_spi_use_dma(struct atmel_spi *as,return as->use_dma && xfer->len >=DMA_MIN_BYTES ; } +static bool atmel_spi_can_dma (struct spi_master *master, +struct spi_device *spi, +struct spi_transfer *xfer) +{ +struct atmel_spi *as =spi_master_get_devdata (master); + +return atmel_spi_use_dma (as, xfer); +} +static int atmel_spi_dma_slave_config (struct atmel_spi *as,struct dma_slave_config *slave_config,u8 bits_per_word)
@@ -720,7 +727,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,struct dma_async_tx_descriptor *txdesc;struct dma_slave_config slave_config;dma_cookie_t cookie; -u32 len = *plen;dev_vdbg (master->dev.parent,"atmel_spi_next_xfer_dma_submit\n" );
@@ -731,34 +737,22 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,/* release lock for DMA operations */ atmel_spi_unlock (as); -/* prepare the RX dma transfer */ -sg_init_table (&as->dma.sgrx,1 ); - as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen; - -/* prepare the TX dma transfer */ -sg_init_table (&as->dma.sgtx,1 ); - as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen; - -if (len > master->max_dma_len) - len = master->max_dma_len; - -sg_dma_len (&as->dma.sgtx) = len; -sg_dma_len (&as->dma.sgrx) = len; - - *plen = len; + *plen = xfer->len;if (atmel_spi_dma_slave_config (as, &slave_config, xfer->bits_per_word)) goto err_exit;/* Send both scatterlists */ - rxdesc =dmaengine_prep_slave_sg (rxchan, &as->dma.sgrx,1 , + rxdesc =dmaengine_prep_slave_sg (rxchan, + xfer->rx_sg.sgl, xfer->rx_sg.nents,DMA_FROM_DEVICE ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK );if (!rxdesc) goto err_dma; - txdesc =dmaengine_prep_slave_sg (txchan, &as->dma.sgtx,1 , + txdesc =dmaengine_prep_slave_sg (txchan, + xfer->tx_sg.sgl, xfer->tx_sg.nents,DMA_TO_DEVICE ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK );if (!txdesc)
@@ -804,15 +798,10 @@ static void atmel_spi_next_xfer_data(struct spi_master *master, dma_addr_t *rx_dma, u32 *plen) { -struct atmel_spi *as =spi_master_get_devdata (master); -u32 len = *plen; - *rx_dma = xfer->rx_dma + xfer->len - *plen; *tx_dma = xfer->tx_dma + xfer->len - *plen; -if (len > master->max_dma_len) - len = master->max_dma_len; - - *plen = len; +if (*plen > master->max_dma_len) + *plen = master->max_dma_len; } static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
@@ -1252,7 +1241,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,* better fault reporting. */ if ((!msg->is_dma_mapped) - && (atmel_spi_use_dma (as, xfer) || as->use_pdc)) { + && as->use_pdc) {if (atmel_spi_dma_map_xfer (as, xfer) <0 )return -ENOMEM ; }
@@ -1329,7 +1318,7 @@ static int atmel_spi_one_transfer(struct spi_master *master, }if (!msg->is_dma_mapped - && (atmel_spi_use_dma (as, xfer) || as->use_pdc)) + && as->use_pdc)atmel_spi_dma_unmap_xfer (master, xfer);return 0 ;
@@ -1340,7 +1329,7 @@ static int atmel_spi_one_transfer(struct spi_master *master, }if (!msg->is_dma_mapped - && (atmel_spi_use_dma (as, xfer) || as->use_pdc)) + && as->use_pdc)atmel_spi_dma_unmap_xfer (master, xfer);if (xfer->delay_usecs)
@@ -1518,6 +1507,7 @@ static int atmel_spi_probe(struct platform_device *pdev) master->cleanup = atmel_spi_cleanup; master->auto_runtime_pm = true; master->max_dma_len =SPI_MAX_DMA_XFER ; + master->can_dma = atmel_spi_can_dma;platform_set_drvdata (pdev, master); as =spi_master_get_devdata (master);
@@ -1554,10 +1544,13 @@ static int atmel_spi_probe(struct platform_device *pdev) as->use_pdc = false;if (as->caps.has_dma_support) { ret =atmel_spi_configure_dma (as); -if (ret ==0 ) +if (ret ==0 ) { + master->dma_tx = as->dma.chan_tx; + master->dma_rx = as->dma.chan_rx; as->use_dma = true; -else if (ret == -EPROBE_DEFER ) + }else if (ret == -EPROBE_DEFER ) {return ret; + } }else { as->use_pdc = true; }
Signature · 1 line
2.10.2
PATCH 4/5 spi: atmel: trivial: remove unused fields in DMA structure
In reply to Nicolas FerreThe atmel_spi_dma structure was cluttered with unused fields relative to older DMA channel selection API. Remove them.
--- drivers/spi/spi-atmel.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/spi/spi-atmel.c +0 -4
@@ -268,10 +268,6 @@struct atmel_spi_dma {struct dma_chan *chan_rx;struct dma_chan *chan_tx; -struct dma_async_tx_descriptor *data_desc_rx; -struct dma_async_tx_descriptor *data_desc_tx; - -struct at_dma_slave dma_slave; };struct atmel_spi_caps {
Signature · 1 line
2.9.0
Mark Brown
maintainerApplied "spi: atmel: trivial: remove unused fields in DMA structure" to the spi tree
The patch
spi: atmel: trivial: remove unused fields in DMA structure
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks,
Mark
Quoted 1 line
From
d5fab59cab1875b42b93f53da248cac90046547dMon Sep 17 00:00:00 2001
From: Nicolas Ferre <[email protected]>
Date: Thu, 24 Nov 2016 12:25:00 +0100
Subject: [PATCH] spi: atmel: trivial: remove unused fields in DMA structure
The atmel_spi_dma structure was cluttered with unused fields relative to older DMA channel selection API. Remove them.
--- drivers/spi/spi-atmel.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/spi/spi-atmel.c +0 -4
@@ -268,10 +268,6 @@struct atmel_spi_dma {struct dma_chan *chan_rx;struct dma_chan *chan_tx; -struct dma_async_tx_descriptor *data_desc_rx; -struct dma_async_tx_descriptor *data_desc_tx; - -struct at_dma_slave dma_slave; };struct atmel_spi_caps {
Signature · 1 line
2.10.2
PATCH 5/5 spi: atmel: remove the use of private channel fields
In reply to Nicolas FerreFor DMA transfers, we now use the core DMA framework which provides channel fields in the spi_master structure. Remove the private channels from atmel_spi stucture which were located in a sub-structure. This last one (atmel_spi_dma) which is now empty is also removed.
--- drivers/spi/spi-atmel.c | 86 ++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 43 deletions(-)
drivers/spi/spi-atmel.c +43 -43
@@ -265,11 +265,6 @@#define AUTOSUSPEND_TIMEOUT 2000 -struct atmel_spi_dma { -struct dma_chan *chan_rx; -struct dma_chan *chan_tx; -}; -struct atmel_spi_caps {bool is_spi2;bool has_wdrbt;
@@ -303,8 +298,6 @@ struct atmel_spi {bool use_dma;bool use_pdc;bool use_cs_gpios; -/* dmaengine data */ -struct atmel_spi_dma dma;bool keep_cs;bool cs_active;
@@ -461,6 +454,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, struct dma_slave_config *slave_config, u8 bits_per_word) { +struct spi_master *master =platform_get_drvdata (as->pdev);int err =0 ;if (bits_per_word >8 ) {
@@ -492,7 +486,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,* path works the same whether FIFOs are available (and enabled) or not. */ slave_config->direction =DMA_MEM_TO_DEV ; -if (dmaengine_slave_config (as->dma.chan_tx, slave_config)) { +if (dmaengine_slave_config (master->dma_tx, slave_config)) {dev_err (&as->pdev->dev,"failed to configure tx dma channel\n" ); err = -EINVAL ;
@@ -507,7 +501,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,* enabled) or not. */ slave_config->direction =DMA_DEV_TO_MEM ; -if (dmaengine_slave_config (as->dma.chan_rx, slave_config)) { +if (dmaengine_slave_config (master->dma_rx, slave_config)) {dev_err (&as->pdev->dev,"failed to configure rx dma channel\n" ); err = -EINVAL ;
@@ -516,7 +510,8 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,return err; } -static int atmel_spi_configure_dma (struct atmel_spi *as) +static int atmel_spi_configure_dma (struct spi_master *master, +struct atmel_spi *as) {struct dma_slave_config slave_config;struct device *dev = &as->pdev->dev;
@@ -526,26 +521,26 @@ static int atmel_spi_configure_dma(struct atmel_spi *as)dma_cap_zero (mask);dma_cap_set (DMA_SLAVE , mask); - as->dma.chan_tx =dma_request_slave_channel_reason (dev,"tx" ); -if (IS_ERR (as->dma.chan_tx)) { - err =PTR_ERR (as->dma.chan_tx); + master->dma_tx =dma_request_slave_channel_reason (dev,"tx" ); +if (IS_ERR (master->dma_tx)) { + err =PTR_ERR (master->dma_tx);if (err == -EPROBE_DEFER ) {dev_warn (dev,"no DMA channel available at the moment\n" ); -return err; + goto error_clear; }dev_err (dev,"DMA TX channel not available, SPI unable to use DMA\n" ); err = -EBUSY ; - goto error; + goto error_clear; }/* * No reason to check EPROBE_DEFER here since we have already requested * tx channel. If it fails here, it's for another reason. */ - as->dma.chan_rx =dma_request_slave_channel (dev,"rx" ); + master->dma_rx =dma_request_slave_channel (dev,"rx" ); -if (!as->dma.chan_rx) { +if (!master->dma_rx) {dev_err (dev,"DMA RX channel not available, SPI unable to use DMA\n" ); err = -EBUSY ;
@@ -558,31 +553,38 @@ static int atmel_spi_configure_dma(struct atmel_spi *as)dev_info (&as->pdev->dev,"Using %s (tx) and %s (rx) for DMA transfers\n" , -dma_chan_name (as->dma.chan_tx), -dma_chan_name (as->dma.chan_rx)); +dma_chan_name (master->dma_tx), +dma_chan_name (master->dma_rx)); +return 0 ; error: -if (as->dma.chan_rx) -dma_release_channel (as->dma.chan_rx); -if (!IS_ERR (as->dma.chan_tx)) -dma_release_channel (as->dma.chan_tx); +if (master->dma_rx) +dma_release_channel (master->dma_rx); +if (!IS_ERR (master->dma_tx)) +dma_release_channel (master->dma_tx); +error_clear: + master->dma_tx = master->dma_rx =NULL ;return err; } -static void atmel_spi_stop_dma (struct atmel_spi *as) +static void atmel_spi_stop_dma (struct spi_master *master) { -if (as->dma.chan_rx) -dmaengine_terminate_all (as->dma.chan_rx); -if (as->dma.chan_tx) -dmaengine_terminate_all (as->dma.chan_tx); +if (master->dma_rx) +dmaengine_terminate_all (master->dma_rx); +if (master->dma_tx) +dmaengine_terminate_all (master->dma_tx); } -static void atmel_spi_release_dma (struct atmel_spi *as) +static void atmel_spi_release_dma (struct spi_master *master) { -if (as->dma.chan_rx) -dma_release_channel (as->dma.chan_rx); -if (as->dma.chan_tx) -dma_release_channel (as->dma.chan_tx); +if (master->dma_rx) { +dma_release_channel (master->dma_rx); + master->dma_rx =NULL ; + } +if (master->dma_tx) { +dma_release_channel (master->dma_tx); + master->dma_tx =NULL ; + } }/* This function is called by the DMA driver from tasklet context */
@@ -718,8 +720,8 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, u32 *plen) {struct atmel_spi *as =spi_master_get_devdata (master); -struct dma_chan *rxchan = as->dma.chan_rx; -struct dma_chan *txchan = as->dma.chan_tx; +struct dma_chan *rxchan = master->dma_rx; +struct dma_chan *txchan = master->dma_tx;struct dma_async_tx_descriptor *rxdesc;struct dma_async_tx_descriptor *txdesc;struct dma_slave_config slave_config;
@@ -783,7 +785,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, err_dma:spi_writel (as,IDR ,SPI_BIT (OVRES )); -atmel_spi_stop_dma (as); +atmel_spi_stop_dma (master); err_exit:atmel_spi_lock (as);return -ENOMEM ;
@@ -1311,7 +1313,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,spi_readl (as,SR ); }else if (atmel_spi_use_dma (as, xfer)) { -atmel_spi_stop_dma (as); +atmel_spi_stop_dma (master); } if (!msg->is_dma_mapped
@@ -1540,10 +1542,8 @@ static int atmel_spi_probe(struct platform_device *pdev) as->use_dma = false; as->use_pdc = false;if (as->caps.has_dma_support) { - ret =atmel_spi_configure_dma (as); + ret =atmel_spi_configure_dma (master, as);if (ret ==0 ) { - master->dma_tx = as->dma.chan_tx; - master->dma_rx = as->dma.chan_rx; as->use_dma = true; }else if (ret == -EPROBE_DEFER ) {return ret;
@@ -1612,7 +1612,7 @@ static int atmel_spi_probe(struct platform_device *pdev)pm_runtime_set_suspended (&pdev->dev);if (as->use_dma) -atmel_spi_release_dma (as); +atmel_spi_release_dma (master);spi_writel (as,CR ,SPI_BIT (SWRST ));spi_writel (as,CR ,SPI_BIT (SWRST ));/* AT91SAM9263 Rev B workaround */
@@ -1634,8 +1634,8 @@ static int atmel_spi_remove(struct platform_device *pdev)/* reset the hardware and block queue progress */ spin_lock_irq (&as->lock);if (as->use_dma) { -atmel_spi_stop_dma (as); -atmel_spi_release_dma (as); +atmel_spi_stop_dma (master); +atmel_spi_release_dma (master); }spi_writel (as,CR ,SPI_BIT (SWRST ));
Signature · 1 line
2.9.0
Mark Brown
maintainerApplied "spi: atmel: remove the use of private channel fields" to the spi tree
The patch
spi: atmel: remove the use of private channel fields
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks,
Mark
Quoted 1 line
From
768f3d9d80d28c0d2d3cb5774f220c04d4d3c6d8Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <[email protected]>
Date: Thu, 24 Nov 2016 12:25:01 +0100
Subject: [PATCH] spi: atmel: remove the use of private channel fields
For DMA transfers, we now use the core DMA framework which provides channel fields in the spi_master structure. Remove the private channels from atmel_spi stucture which were located in a sub-structure. This last one (atmel_spi_dma) which is now empty is also removed.
--- drivers/spi/spi-atmel.c | 86 ++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 43 deletions(-)
drivers/spi/spi-atmel.c +43 -43
@@ -265,11 +265,6 @@#define AUTOSUSPEND_TIMEOUT 2000 -struct atmel_spi_dma { -struct dma_chan *chan_rx; -struct dma_chan *chan_tx; -}; -struct atmel_spi_caps {bool is_spi2;bool has_wdrbt;
@@ -302,8 +297,6 @@ struct atmel_spi {bool use_dma;bool use_pdc;bool use_cs_gpios; -/* dmaengine data */ -struct atmel_spi_dma dma;bool keep_cs;bool cs_active;
@@ -460,6 +453,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, struct dma_slave_config *slave_config, u8 bits_per_word) { +struct spi_master *master =platform_get_drvdata (as->pdev);int err =0 ;if (bits_per_word >8 ) {
@@ -491,7 +485,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,* path works the same whether FIFOs are available (and enabled) or not. */ slave_config->direction =DMA_MEM_TO_DEV ; -if (dmaengine_slave_config (as->dma.chan_tx, slave_config)) { +if (dmaengine_slave_config (master->dma_tx, slave_config)) {dev_err (&as->pdev->dev,"failed to configure tx dma channel\n" ); err = -EINVAL ;
@@ -506,7 +500,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,* enabled) or not. */ slave_config->direction =DMA_DEV_TO_MEM ; -if (dmaengine_slave_config (as->dma.chan_rx, slave_config)) { +if (dmaengine_slave_config (master->dma_rx, slave_config)) {dev_err (&as->pdev->dev,"failed to configure rx dma channel\n" ); err = -EINVAL ;
@@ -515,7 +509,8 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,return err; } -static int atmel_spi_configure_dma (struct atmel_spi *as) +static int atmel_spi_configure_dma (struct spi_master *master, +struct atmel_spi *as) {struct dma_slave_config slave_config;struct device *dev = &as->pdev->dev;
@@ -525,26 +520,26 @@ static int atmel_spi_configure_dma(struct atmel_spi *as)dma_cap_zero (mask);dma_cap_set (DMA_SLAVE , mask); - as->dma.chan_tx =dma_request_slave_channel_reason (dev,"tx" ); -if (IS_ERR (as->dma.chan_tx)) { - err =PTR_ERR (as->dma.chan_tx); + master->dma_tx =dma_request_slave_channel_reason (dev,"tx" ); +if (IS_ERR (master->dma_tx)) { + err =PTR_ERR (master->dma_tx);if (err == -EPROBE_DEFER ) {dev_warn (dev,"no DMA channel available at the moment\n" ); -return err; + goto error_clear; }dev_err (dev,"DMA TX channel not available, SPI unable to use DMA\n" ); err = -EBUSY ; - goto error; + goto error_clear; }/* * No reason to check EPROBE_DEFER here since we have already requested * tx channel. If it fails here, it's for another reason. */ - as->dma.chan_rx =dma_request_slave_channel (dev,"rx" ); + master->dma_rx =dma_request_slave_channel (dev,"rx" ); -if (!as->dma.chan_rx) { +if (!master->dma_rx) {dev_err (dev,"DMA RX channel not available, SPI unable to use DMA\n" ); err = -EBUSY ;
@@ -557,31 +552,38 @@ static int atmel_spi_configure_dma(struct atmel_spi *as)dev_info (&as->pdev->dev,"Using %s (tx) and %s (rx) for DMA transfers\n" , -dma_chan_name (as->dma.chan_tx), -dma_chan_name (as->dma.chan_rx)); +dma_chan_name (master->dma_tx), +dma_chan_name (master->dma_rx)); +return 0 ; error: -if (as->dma.chan_rx) -dma_release_channel (as->dma.chan_rx); -if (!IS_ERR (as->dma.chan_tx)) -dma_release_channel (as->dma.chan_tx); +if (master->dma_rx) +dma_release_channel (master->dma_rx); +if (!IS_ERR (master->dma_tx)) +dma_release_channel (master->dma_tx); +error_clear: + master->dma_tx = master->dma_rx =NULL ;return err; } -static void atmel_spi_stop_dma (struct atmel_spi *as) +static void atmel_spi_stop_dma (struct spi_master *master) { -if (as->dma.chan_rx) -dmaengine_terminate_all (as->dma.chan_rx); -if (as->dma.chan_tx) -dmaengine_terminate_all (as->dma.chan_tx); +if (master->dma_rx) +dmaengine_terminate_all (master->dma_rx); +if (master->dma_tx) +dmaengine_terminate_all (master->dma_tx); } -static void atmel_spi_release_dma (struct atmel_spi *as) +static void atmel_spi_release_dma (struct spi_master *master) { -if (as->dma.chan_rx) -dma_release_channel (as->dma.chan_rx); -if (as->dma.chan_tx) -dma_release_channel (as->dma.chan_tx); +if (master->dma_rx) { +dma_release_channel (master->dma_rx); + master->dma_rx =NULL ; + } +if (master->dma_tx) { +dma_release_channel (master->dma_tx); + master->dma_tx =NULL ; + } }/* This function is called by the DMA driver from tasklet context */
@@ -717,8 +719,8 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, u32 *plen) {struct atmel_spi *as =spi_master_get_devdata (master); -struct dma_chan *rxchan = as->dma.chan_rx; -struct dma_chan *txchan = as->dma.chan_tx; +struct dma_chan *rxchan = master->dma_rx; +struct dma_chan *txchan = master->dma_tx;struct dma_async_tx_descriptor *rxdesc;struct dma_async_tx_descriptor *txdesc;struct dma_slave_config slave_config;
@@ -782,7 +784,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, err_dma:spi_writel (as,IDR ,SPI_BIT (OVRES )); -atmel_spi_stop_dma (as); +atmel_spi_stop_dma (master); err_exit:atmel_spi_lock (as);return -ENOMEM ;
@@ -1310,7 +1312,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,spi_readl (as,SR ); }else if (atmel_spi_use_dma (as, xfer)) { -atmel_spi_stop_dma (as); +atmel_spi_stop_dma (master); } if (!msg->is_dma_mapped
@@ -1539,10 +1541,8 @@ static int atmel_spi_probe(struct platform_device *pdev) as->use_dma = false; as->use_pdc = false;if (as->caps.has_dma_support) { - ret =atmel_spi_configure_dma (as); + ret =atmel_spi_configure_dma (master, as);if (ret ==0 ) { - master->dma_tx = as->dma.chan_tx; - master->dma_rx = as->dma.chan_rx; as->use_dma = true; }else if (ret == -EPROBE_DEFER ) {return ret;
@@ -1608,7 +1608,7 @@ static int atmel_spi_probe(struct platform_device *pdev)pm_runtime_set_suspended (&pdev->dev);if (as->use_dma) -atmel_spi_release_dma (as); +atmel_spi_release_dma (master);spi_writel (as,CR ,SPI_BIT (SWRST ));spi_writel (as,CR ,SPI_BIT (SWRST ));/* AT91SAM9263 Rev B workaround */
@@ -1630,8 +1630,8 @@ static int atmel_spi_remove(struct platform_device *pdev)/* reset the hardware and block queue progress */ spin_lock_irq (&as->lock);if (as->use_dma) { -atmel_spi_stop_dma (as); -atmel_spi_release_dma (as); +atmel_spi_stop_dma (master); +atmel_spi_release_dma (master); }spi_writel (as,CR ,SPI_BIT (SWRST ));
Signature · 1 line
2.10.2