diff options
author | Ramin Moussavi <lordrasmus@gmail.com> | 2025-07-22 20:27:09 +0200 |
---|---|---|
committer | Eugen Hristev <eugen.hristev@linaro.org> | 2025-08-13 12:59:02 +0300 |
commit | 709b5be0a48d4e5bb95ef0b107c56045a8fe67c6 (patch) | |
tree | 8a923a7cb29d832fa9eead2e417f648746550d7d /drivers/usb/cdns3 | |
parent | a8f20bb6650df56d2600cda2c66f9349df9e49c8 (diff) |
spi: atmel_qspi: fix race condition in transfer completion check
In atmel_qspi_transfer(), the status register is polled with:
imr = QSPI_SR_INSTRE | QSPI_SR_CSR;
return readl_poll_timeout(aq->regs + QSPI_SR, sr,
(sr & imr) == imr,
ATMEL_QSPI_TIMEOUT);
However, this is racy: QSPI_SR_INSTRE can be set before QSPI_SR_CSR,
and will then be cleared by the read. If that happens, the condition
"(sr & imr) == imr" can never be true, and the function times out.
This race condition is avoided in at91bootstrap by accumulating the
status bits across reads until both bits have been observed:
/* Poll INSTruction End and Chip Select Rise flags. */
imr = (QSPI_SR_INSTRE | QSPI_SR_CSR);
sr = 0;
do {
udelay(1);
sr |= qspi_readl(qspi, QSPI_SR) & imr;
} while ((--timeout) && (sr != imr));
Update U-Boot's atmel_qspi_transfer() to use the same pattern,
ensuring that both flags are observed even if they are not set
simultaneously.
Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
[eugen.hristev@linaro.org: remove 'sr' and fix commit msg]
Signed-off-by: Eugen Hristev <eugen.hristev@linaro.org>
Diffstat (limited to 'drivers/usb/cdns3')
0 files changed, 0 insertions, 0 deletions