The old code checked for overflow only once before the loop, which
meant a multi-byte write could silently overflow the FIFO when there
was space for some but not all bytes. Check per-byte instead, storing
as many bytes as possible before flagging ROVR. Only arm the FIFO
trigger timer when bytes were actually stored.

Fixes: 35548b06cf55 ("cadence_uart: initial version of device model")
Reported-by: Pavee Hui <[email protected]>
Signed-off-by: Marc-André Lureau <[email protected]>
---
 hw/char/cadence_uart.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index eff6a3c4d17a..ae11caa11b82 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -284,14 +284,16 @@ static void uart_write_rx_fifo(void *opaque, const 
uint8_t *buf, int size)
         return;
     }
 
-    if (s->rx_count == CADENCE_UART_RX_FIFO_SIZE) {
-        s->r[R_CISR] |= UART_INTR_ROVR;
-    } else {
-        for (i = 0; i < size; i++) {
-            s->rx_fifo[s->rx_wpos] = buf[i];
-            s->rx_wpos = (s->rx_wpos + 1) % CADENCE_UART_RX_FIFO_SIZE;
-            s->rx_count++;
+    for (i = 0; i < size; i++) {
+        if (s->rx_count >= CADENCE_UART_RX_FIFO_SIZE) {
+            s->r[R_CISR] |= UART_INTR_ROVR;
+            break;
         }
+        s->rx_fifo[s->rx_wpos] = buf[i];
+        s->rx_wpos = (s->rx_wpos + 1) % CADENCE_UART_RX_FIFO_SIZE;
+        s->rx_count++;
+    }
+    if (i > 0) {
         timer_mod(s->fifo_trigger_handle, new_rx_time +
                                                 (s->char_tx_time * 4));
     }

-- 
2.56.0.rc0.29.g47ce80527c56


Reply via email to