drivers: serial: nrfx_uarte: Fix race condition in async isr

When DMA switches from one buffer to another ENDRX followed by
RXSTARTED is generated. Code flow assumes that ENDRX will be
handled before RXSTARTED but this may not be the case if there
is a short between ENDRX and RXSTARTED and event occurs after
ENDRX event check but before RXSTARTED event check. In that case,
RXSTARTED event is handled first. Such case may happen if there
is a higher priority interrupt that may preempt UARTE interrupt
handler.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2021-07-19 15:16:54 +02:00 committed by Carles Cufí
commit c44a46f1f5

View file

@ -1329,7 +1329,15 @@ static void uarte_nrfx_isr_async(const struct device *dev)
endrx_isr(dev);
}
if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXSTARTED)) {
/* RXSTARTED must be handled after ENDRX because it starts the RX timeout
* and if order is swapped then ENDRX will stop this timeout.
* Skip if ENDRX is set when RXSTARTED is set. It means that
* ENDRX occurred after check for ENDRX in isr which may happen when
* UARTE interrupt got preempted. Events are not cleared
* and isr will be called again. ENDRX will be handled first.
*/
if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXSTARTED) &&
!nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDRX)) {
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED);
rxstarted_isr(dev);
}