forked from luck/tmp_suning_uos_patched
spi: bcm2835: Drop dma_pending flag
The BCM2835 SPI driver uses a flag to keep track of whether a DMA
transfer is in progress.
The flag is used to avoid terminating DMA channels multiple times if a
transfer finishes orderly while simultaneously the SPI core invokes the
->handle_err() callback because the transfer took too long. However
terminating DMA channels multiple times is perfectly fine, so the flag
is unnecessary for this particular purpose.
The flag is also used to avoid invoking bcm2835_spi_undo_prologue()
multiple times under this race condition. However multiple *concurrent*
invocations can no longer happen since commit 2527704d84
("spi:
bcm2835: Synchronize with callback on DMA termination") because the
->handle_err() callback now uses the _sync() variant when terminating
DMA channels.
The only raison d'être of the flag is therefore that
bcm2835_spi_undo_prologue() cannot cope with multiple *sequential*
invocations. Achieve that by setting tx_prologue to 0 at the end of
the function. Subsequent invocations thus become no-ops.
With that, the dma_pending flag becomes unnecessary, so drop it.
Tested-by: Nuno Sá <nuno.sa@analog.com>
Tested-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Acked-by: Stefan Wahren <wahrenst@gmx.net>
Acked-by: Martin Sperl <kernel@martin.sperl.org>
Link: https://lore.kernel.org/r/062b03b7f86af77a13ce0ec3b22e0bdbfcfba10d.1568187525.git.lukas@wunner.de
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
8995673e6f
commit
1513ceee70
|
@ -94,7 +94,6 @@ MODULE_PARM_DESC(polling_limit_us,
|
||||||
* @rx_prologue: bytes received without DMA if first RX sglist entry's
|
* @rx_prologue: bytes received without DMA if first RX sglist entry's
|
||||||
* length is not a multiple of 4 (to overcome hardware limitation)
|
* length is not a multiple of 4 (to overcome hardware limitation)
|
||||||
* @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
|
* @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
|
||||||
* @dma_pending: whether a DMA transfer is in progress
|
|
||||||
* @debugfs_dir: the debugfs directory - neede to remove debugfs when
|
* @debugfs_dir: the debugfs directory - neede to remove debugfs when
|
||||||
* unloading the module
|
* unloading the module
|
||||||
* @count_transfer_polling: count of how often polling mode is used
|
* @count_transfer_polling: count of how often polling mode is used
|
||||||
|
@ -117,7 +116,6 @@ struct bcm2835_spi {
|
||||||
int tx_prologue;
|
int tx_prologue;
|
||||||
int rx_prologue;
|
int rx_prologue;
|
||||||
unsigned int tx_spillover;
|
unsigned int tx_spillover;
|
||||||
unsigned int dma_pending;
|
|
||||||
|
|
||||||
struct dentry *debugfs_dir;
|
struct dentry *debugfs_dir;
|
||||||
u64 count_transfer_polling;
|
u64 count_transfer_polling;
|
||||||
|
@ -541,6 +539,8 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
|
||||||
sg_dma_address(&tfr->tx_sg.sgl[1]) -= 4;
|
sg_dma_address(&tfr->tx_sg.sgl[1]) -= 4;
|
||||||
sg_dma_len(&tfr->tx_sg.sgl[1]) += 4;
|
sg_dma_len(&tfr->tx_sg.sgl[1]) += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bs->tx_prologue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm2835_spi_dma_done(void *data)
|
static void bcm2835_spi_dma_done(void *data)
|
||||||
|
@ -556,10 +556,8 @@ static void bcm2835_spi_dma_done(void *data)
|
||||||
* is called the tx-dma must have finished - can't get to this
|
* is called the tx-dma must have finished - can't get to this
|
||||||
* situation otherwise...
|
* situation otherwise...
|
||||||
*/
|
*/
|
||||||
if (cmpxchg(&bs->dma_pending, true, false)) {
|
dmaengine_terminate_async(ctlr->dma_tx);
|
||||||
dmaengine_terminate_async(ctlr->dma_tx);
|
bcm2835_spi_undo_prologue(bs);
|
||||||
bcm2835_spi_undo_prologue(bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* and mark as completed */;
|
/* and mark as completed */;
|
||||||
complete(&ctlr->xfer_completion);
|
complete(&ctlr->xfer_completion);
|
||||||
|
@ -634,9 +632,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
|
||||||
/* start TX early */
|
/* start TX early */
|
||||||
dma_async_issue_pending(ctlr->dma_tx);
|
dma_async_issue_pending(ctlr->dma_tx);
|
||||||
|
|
||||||
/* mark as dma pending */
|
|
||||||
bs->dma_pending = 1;
|
|
||||||
|
|
||||||
/* set the DMA length */
|
/* set the DMA length */
|
||||||
bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len);
|
bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len);
|
||||||
|
|
||||||
|
@ -652,7 +647,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* need to reset on errors */
|
/* need to reset on errors */
|
||||||
dmaengine_terminate_sync(ctlr->dma_tx);
|
dmaengine_terminate_sync(ctlr->dma_tx);
|
||||||
bs->dma_pending = false;
|
|
||||||
goto err_reset_hw;
|
goto err_reset_hw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,11 +911,10 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
|
||||||
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
|
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
|
||||||
|
|
||||||
/* if an error occurred and we have an active dma, then terminate */
|
/* if an error occurred and we have an active dma, then terminate */
|
||||||
if (cmpxchg(&bs->dma_pending, true, false)) {
|
dmaengine_terminate_sync(ctlr->dma_tx);
|
||||||
dmaengine_terminate_sync(ctlr->dma_tx);
|
dmaengine_terminate_sync(ctlr->dma_rx);
|
||||||
dmaengine_terminate_sync(ctlr->dma_rx);
|
bcm2835_spi_undo_prologue(bs);
|
||||||
bcm2835_spi_undo_prologue(bs);
|
|
||||||
}
|
|
||||||
/* and reset */
|
/* and reset */
|
||||||
bcm2835_spi_reset_hw(ctlr);
|
bcm2835_spi_reset_hw(ctlr);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user