Skip to content

Commit

Permalink
spi: pl022: Fix race in giveback() leading to driver lock-up
Browse files Browse the repository at this point in the history
Commit fd31694 ("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: fd31694 (spi/pl022: disable port when unused)
Signed-off-by: Alexander Sverdlin <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
Cc: [email protected]
  • Loading branch information
asverdlin authored and broonie committed Mar 6, 2015
1 parent c517d83 commit cd6fa8d
Showing 1 changed file with 1 addition and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/spi/spi-pl022.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,12 +534,12 @@ static void giveback(struct pl022 *pl022)
pl022->cur_msg = NULL;
pl022->cur_transfer = NULL;
pl022->cur_chip = NULL;
spi_finalize_current_message(pl022->master);

/* disable the SPI/SSP operation */
writew((readw(SSP_CR1(pl022->virtbase)) &
(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));

spi_finalize_current_message(pl022->master);
}

/**
Expand Down

0 comments on commit cd6fa8d

Please sign in to comment.