Skip to content

Commit

Permalink
spi: bcm2835: Drop dma_pending flag
Browse files Browse the repository at this point in the history
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 2527704 ("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>
  • Loading branch information
Lukas Wunner authored and Mark Brown committed Sep 11, 2019
1 parent 8995673 commit 1513cee
Showing 1 changed file with 8 additions and 15 deletions.
23 changes: 8 additions & 15 deletions drivers/spi/spi-bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ MODULE_PARM_DESC(polling_limit_us,
* @rx_prologue: bytes received without DMA if first RX sglist entry's
* length is not a multiple of 4 (to overcome hardware limitation)
* @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
* unloading the module
* @count_transfer_polling: count of how often polling mode is used
Expand All @@ -117,7 +116,6 @@ struct bcm2835_spi {
int tx_prologue;
int rx_prologue;
unsigned int tx_spillover;
unsigned int dma_pending;

struct dentry *debugfs_dir;
u64 count_transfer_polling;
Expand Down Expand Up @@ -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_len(&tfr->tx_sg.sgl[1]) += 4;
}

bs->tx_prologue = 0;
}

static void bcm2835_spi_dma_done(void *data)
Expand All @@ -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
* situation otherwise...
*/
if (cmpxchg(&bs->dma_pending, true, false)) {
dmaengine_terminate_async(ctlr->dma_tx);
bcm2835_spi_undo_prologue(bs);
}
dmaengine_terminate_async(ctlr->dma_tx);
bcm2835_spi_undo_prologue(bs);

/* and mark as completed */;
complete(&ctlr->xfer_completion);
Expand Down Expand Up @@ -634,9 +632,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
/* start TX early */
dma_async_issue_pending(ctlr->dma_tx);

/* mark as dma pending */
bs->dma_pending = 1;

/* set the DMA length */
bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len);

Expand All @@ -652,7 +647,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
if (ret) {
/* need to reset on errors */
dmaengine_terminate_sync(ctlr->dma_tx);
bs->dma_pending = false;
goto err_reset_hw;
}

Expand Down Expand Up @@ -917,11 +911,10 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);

/* 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_rx);
bcm2835_spi_undo_prologue(bs);
}
dmaengine_terminate_sync(ctlr->dma_tx);
dmaengine_terminate_sync(ctlr->dma_rx);
bcm2835_spi_undo_prologue(bs);

/* and reset */
bcm2835_spi_reset_hw(ctlr);
}
Expand Down

0 comments on commit 1513cee

Please sign in to comment.