• Alexander Sverdlin's avatar
    spi: pl022: Fix race in giveback() leading to driver lock-up · cd6fa8d2
    Alexander Sverdlin authored
    Commit fd316941 ("spi/pl022: disable port when unused") introduced a race,
    which leads to possible driver lock up (easily reproducible on SMP).
    
    The problem happens in giveback() function where the completion of the transfer
    is signalled to SPI subsystem and then the HW SPI controller is disabled. Another
    transfer might be setup in between, which brings driver in locked-up state.
    
    Exact event sequence on SMP:
    
    core0                                   core1
    
                                            => pump_transfers()
                                            /* message->state == STATE_DONE */
                                              => giveback()
                                                => spi_finalize_current_message()
    
    => pl022_unprepare_transfer_hardware()
    => pl022_transfer_one_message
      => flush()
      => do_interrupt_dma_transfer()
        => set_up_next_transfer()
        /* Enable SSP, turn on interrupts */
        writew((readw(SSP_CR1(pl022->virtbase)) |
               SSP_CR1_MASK_SSE), SSP_CR1(pl022->virtbase));
    
    ...
    
    => pl022_interrupt_handler()
      => readwriter()
    
                                            /* disable the SPI/SSP operation */
                                            => writew((readw(SSP_CR1(pl022->virtbase)) &
                                                      (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
    
    Lockup! SPI controller is disabled and the data will never be received. Whole
    SPI subsystem is waiting for transfer ACK and blocked.
    
    So, only signal transfer completion after disabling the controller.
    
    Fixes: fd316941 (spi/pl022: disable port when unused)
    Signed-off-by: default avatarAlexander Sverdlin <alexander.sverdlin@nokia.com>
    Signed-off-by: default avatarMark Brown <broonie@kernel.org>
    Cc: stable@vger.kernel.org
    cd6fa8d2
spi-pl022.c 68.2 KB