drivers: serial: nrfx_uarte: Fix misbehavior due to preemption

UART_RX_RDY event can be generated from UARTE interrupt or k_timer
handler. When ENDRX event occurs then k_timer is stopped (it can
be restarted if there is another buffer provided). However, if UARTE
interrupt priority is higher than k_timer priority (RTC is used
underneath) then k_timer handler may still be executed later.
K_timer notifies new bytes based on RXDRDY HW event which is
counter by the TIMER (using PPI). It may happen that RXDRDY
event arrives due to byte received into RX FIFO but since there is
not buffer provided it stays in that FIFO. Given all this, it
was possible that RX_RDY event was reported from ENDRX UARTE event,
timer was stopped but because UARTE interrupt had higher priority
timer handler is executed after UARTE interrupt is handled. In
timer handler TIMER counter reports more bytes and calls
UART_RX_RDY event with null buffer and non-zero amount of bytes.

Fixed by generating UART_RX_RDY event only if RX buffer is not
null.

Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruściński 2024-02-06 13:15:34 +01:00 committed by Henrik Brix Andersen
parent 24b9b60025
commit 5db338c035

View file

@ -1047,9 +1047,11 @@ static void rx_timeout(struct k_timer *timer)
(data->async->rx_timeout_left
< data->async->rx_timeout_slab)) {
/* rx_timeout us elapsed since last receiving */
notify_uart_rx_rdy(dev, len);
data->async->rx_offset += len;
data->async->rx_total_user_byte_cnt += len;
if (data->async->rx_buf != NULL) {
notify_uart_rx_rdy(dev, len);
data->async->rx_offset += len;
data->async->rx_total_user_byte_cnt += len;
}
} else {
data->async->rx_timeout_left -=
data->async->rx_timeout_slab;