• Serge Semin's avatar
    spi: dw: Locally wait for the DMA transfers completion · bdbdf0f0
    Serge Semin authored
    In general each DMA-based SPI transfer can be split up into two stages:
    DMA data transmission/reception and SPI-bus transmission/reception. DMA
    asynchronous transactions completion can be tracked by means of the
    DMA async Tx-descriptor completion callback. But that callback being
    called indicates that the DMA transfer has been finished, it doesn't
    mean that SPI data transmission is also done. Moreover in fact it isn't
    for at least Tx-only SPI transfers. Upon DMA transfer completion some
    data is left in the Tx FIFO and being pushed out by the SPI controller.
    So in order to make sure that an SPI transfer is completely pushed to the
    SPI-bus, the driver has to wait for both DMA transaction and the SPI-bus
    transmission/reception are finished. Note if there is a way to
    asynchronously track the former event by means of the DMA async Tx
    callback, there isn't easy one for the later (IRQ-based solution won't
    work since SPI controller doesn't notify about Rx FIFO being empty).
    
    The DMA transfer completion callback isn't suitable to wait for the
    SPI controller activity finish either. The callback might (in case of DW
    DMAC it will) be called in the tasklet context. Waiting for the SPI
    controller to complete the transfer might take a considerable amount of
    time since SPI-bus might be pretty slow. In this case delaying the
    execution in the tasklet atomic context might cause significant system
    performance drop.
    
    So to speak the best option we've got to solve the problem is to
    consequently wait for both stages being finished in the locally
    implemented SPI transfer execution procedure even if it costs us of the
    local wait-function re-implementation. In this case we don't need to use
    the SPI-core transfer-wait functionality, but we'll make sure that
    all DMA and SPI-bus transactions are completely finished before the
    SPI-core transfer_one callback returns. In this commit we provide an
    implementation of the DMA-transfers completion wait functionality.
    The DW APB SSI DMA-specific SPI transfer_one function waits for both
    Tx and Rx DMA transfers being finished, and only then exits with zero
    returned signalling to the SPI core that the SPI transfer is finished.
    This implementation is fully equivalent to the currently used
    DMA-execution-SPI-core-wait algorithm. The SPI-bus transmission/reception
    wait methods will be added in the follow-up commits.
    Signed-off-by: default avatarSerge Semin <Sergey.Semin@baikalelectronics.ru>
    Cc: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
    Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
    Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
    Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
    Cc: Arnd Bergmann <arnd@arndb.de>
    Cc: Feng Tang <feng.tang@intel.com>
    Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    Cc: Rob Herring <robh+dt@kernel.org>
    Cc: linux-mips@vger.kernel.org
    Cc: devicetree@vger.kernel.org
    Link: https://lore.kernel.org/r/20200529131205.31838-4-Sergey.Semin@baikalelectronics.ruSigned-off-by: default avatarMark Brown <broonie@kernel.org>
    bdbdf0f0
spi-dw-mid.c 9.41 KB