diff --git a/drivers/firmware/samsung/exynos-acpm.c b/drivers/firmware/samsung/exynos-acpm.c index 620880d8820a..3fa9fe283be4 100644 --- a/drivers/firmware/samsung/exynos-acpm.c +++ b/drivers/firmware/samsung/exynos-acpm.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include @@ -340,7 +340,7 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan, acpm_get_saved_rx(achan, xfer, seqnum); /* Relinquish ownership of the sequence slot */ - clear_bit(seqnum - 1, achan->bitmap_seqnum); + clear_bit_unlock(seqnum - 1, achan->bitmap_seqnum); return 0; } @@ -397,11 +397,18 @@ static void acpm_prepare_xfer(struct acpm_chan *achan, struct acpm_rx_data *rx_data; u32 *txd = (u32 *)xfer->txd; - /* Prevent chan->seqnum from being re-used */ + /* + * Prevent chan->seqnum from being re-used. + * test_and_set_bit_lock() provides formal LKMM Acquire semantics. + * It pairs with the RX thread's clear_bit_unlock() to ensure the CPU + * does not speculatively execute the rx_data buffer wipe (memset) + * before the sequence number is safely claimed. + */ do { if (++achan->seqnum == ACPM_SEQNUM_MAX) achan->seqnum = 1; - } while (test_bit(achan->seqnum - 1, achan->bitmap_seqnum)); + /* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */ + } while (test_and_set_bit_lock(achan->seqnum - 1, achan->bitmap_seqnum)); txd[0] |= FIELD_PREP(ACPM_PROTOCOL_SEQNUM, achan->seqnum); @@ -411,9 +418,6 @@ static void acpm_prepare_xfer(struct acpm_chan *achan, memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd); /* zero means no response expected */ rx_data->rxcnt = xfer->rxcnt; - - /* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */ - set_bit(achan->seqnum - 1, achan->bitmap_seqnum); } /**