lkml.org 
[lkml]   [2019]   [Jan]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 115/170] spi: bcm2835: Fix race on DMA termination
    Date
    4.19-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Lukas Wunner <lukas@wunner.de>

    commit e82b0b3828451c1cd331d9f304c6078fcd43b62e upstream.

    If a DMA transfer finishes orderly right when spi_transfer_one_message()
    determines that it has timed out, the callbacks bcm2835_spi_dma_done()
    and bcm2835_spi_handle_err() race to call dmaengine_terminate_all(),
    potentially leading to double termination.

    Prevent by atomically changing the dma_pending flag before calling
    dmaengine_terminate_all().

    Signed-off-by: Lukas Wunner <lukas@wunner.de>
    Fixes: 3ecd37edaa2a ("spi: bcm2835: enable dma modes for transfers meeting certain conditions")
    Cc: stable@vger.kernel.org # v4.2+
    Cc: Mathias Duckeck <m.duckeck@kunbus.de>
    Cc: Frank Pavlic <f.pavlic@kunbus.de>
    Cc: Martin Sperl <kernel@martin.sperl.org>
    Cc: Noralf Trønnes <noralf@tronnes.org>
    Signed-off-by: Mark Brown <broonie@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/spi/spi-bcm2835.c | 10 ++++------
    1 file changed, 4 insertions(+), 6 deletions(-)

    --- a/drivers/spi/spi-bcm2835.c
    +++ b/drivers/spi/spi-bcm2835.c
    @@ -233,10 +233,9 @@ static void bcm2835_spi_dma_done(void *d
    * is called the tx-dma must have finished - can't get to this
    * situation otherwise...
    */
    - dmaengine_terminate_all(master->dma_tx);
    -
    - /* mark as no longer pending */
    - bs->dma_pending = 0;
    + if (cmpxchg(&bs->dma_pending, true, false)) {
    + dmaengine_terminate_all(master->dma_tx);
    + }

    /* and mark as completed */;
    complete(&master->xfer_completion);
    @@ -617,10 +616,9 @@ static void bcm2835_spi_handle_err(struc
    struct bcm2835_spi *bs = spi_master_get_devdata(master);

    /* if an error occurred and we have an active dma, then terminate */
    - if (bs->dma_pending) {
    + if (cmpxchg(&bs->dma_pending, true, false)) {
    dmaengine_terminate_all(master->dma_tx);
    dmaengine_terminate_all(master->dma_rx);
    - bs->dma_pending = 0;
    }
    /* and reset */
    bcm2835_spi_reset_hw(master);

    \
     
     \ /
      Last update: 2019-01-07 18:24    [W:3.135 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site