The current handler for TXFIFO writes schedules an async callback to
pop characters from the queue. When software writes to TXFIFO faster
than the async callback delay (100ns), the timer may be pushed back
while the previous character has not be dequeued yet. This happens in
particular when using -icount with small shift values. This is
especially worrysome when software repetitively issues amoor.w
instructions (as suggested by SiFive specification) and the FIFO is
full, leading to the callback being infinitly pushed back.

This commit fixes the issue by never pushing back the timer, only
updating it if it is not already active.

Signed-off-by: Florian Lugou <florian.lu...@provenrun.com>
---
 hw/char/sifive_uart.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c
index 0fc89e76d1..9bc697a67b 100644
--- a/hw/char/sifive_uart.c
+++ b/hw/char/sifive_uart.c
@@ -128,8 +128,10 @@ static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, 
const uint8_t *buf,
         s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
     }
 
-    timer_mod(s->fifo_trigger_handle, current_time +
-                  TX_INTERRUPT_TRIGGER_DELAY_NS);
+    if (!timer_pending(s->fifo_trigger_handle)) {
+        timer_mod(s->fifo_trigger_handle, current_time +
+                      TX_INTERRUPT_TRIGGER_DELAY_NS);
+    }
 }
 
 static uint64_t
-- 
2.43.0


Reply via email to