Skip to content

Commit 83ce20c

Browse files
committed
[ot] hw/opentitan: ot_uart: model watermark/empty as status interrupts
tx_watermark, rx_watermark and tx_empty are declared as status-type interrupts in the UART HWIP (uart.hjson / prim_intr_hw IntrT="Status"): their INTR_STATE bits track the live FIFO condition every cycle rather than latching, and a RW1C write has no lasting effect while the condition holds. The model treated them as event-type, latching the bit on a receive batch and clearing it only via RW1C. As a result, once software drained the RX FIFO the latched rx_watermark bit stayed asserted, so the next received byte produced no fresh interrupt edge and interrupt-driven RX (e.g. a software-loopback test on ot-earlgrey) would hang. Compute the status-type bits live from the FIFO levels and OR them with the latched event-type bits when reading INTR_STATE and when driving the IRQ lines, so they assert and de-assert with the hardware condition: - rx_watermark: rx_fifo_depth >= threshold - tx_watermark: tx_fifo_depth < threshold - tx_empty: tx_fifo_depth == 0 Re-evaluate the lines after an RDATA pop and on FIFO_CTRL writes, and drop the now-unused tx_watermark edge-tracking state. Also align the FIFO depths (TxFifoDepth=32, RxFifoDepth=64) and the watermark threshold mappings (TX saturates at TxFifoDepth/2; RX saturates at RxFifoDepth-2, with rxilvl=7 disabling the interrupt) with uart_core.sv, and only push as many received bytes as the RX FIFO can hold. Signed-off-by: Miguel Osorio <miguelosorio@google.com>
1 parent b28bb56 commit 83ce20c

1 file changed

Lines changed: 103 additions & 41 deletions

File tree

hw/opentitan/ot_uart.c

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ REG32(TIMEOUT_CTRL, 0x30u)
106106
INTR_RX_OVERFLOW_MASK | INTR_RX_FRAME_ERR_MASK | INTR_RX_BREAK_ERR_MASK | \
107107
INTR_RX_TIMEOUT_MASK | INTR_RX_PARITY_ERR_MASK | INTR_TX_EMPTY_MASK)
108108

109+
/*
110+
* Status-type interrupts (tx_watermark, rx_watermark, tx_empty per uart.hjson).
111+
* Unlike event-type interrupts, their INTR_STATE bits are not latched: the
112+
* hardware drives them every cycle from the live FIFO condition, so a RW1C write
113+
* has no lasting effect while the condition holds and they de-assert
114+
* automatically once the condition clears. See prim_intr_hw.sv (IntrT="Status").
115+
*/
116+
#define INTR_STATUS_MASK \
117+
(INTR_TX_WATERMARK_MASK | INTR_RX_WATERMARK_MASK | INTR_TX_EMPTY_MASK)
118+
109119
#define CTRL_MASK \
110120
(R_CTRL_TX_MASK | R_CTRL_RX_MASK | R_CTRL_NF_MASK | R_CTRL_SLPBK_MASK | \
111121
R_CTRL_LLPBK_MASK | R_CTRL_PARITY_EN_MASK | R_CTRL_PARITY_ODD_MASK | \
@@ -115,8 +125,9 @@ REG32(TIMEOUT_CTRL, 0x30u)
115125
(R_CTRL_RX_MASK | R_CTRL_TX_MASK | R_CTRL_SLPBK_MASK | R_CTRL_NCO_MASK)
116126

117127
#define OT_UART_NCO_BITS 16u
118-
#define OT_UART_TX_FIFO_SIZE 128u
119-
#define OT_UART_RX_FIFO_SIZE 128u
128+
/* FIFO depths match uart_reg_pkg.sv (TxFifoDepth=32, RxFifoDepth=64). */
129+
#define OT_UART_TX_FIFO_SIZE 32u
130+
#define OT_UART_RX_FIFO_SIZE 64u
120131
#define OT_UART_IRQ_NUM 9u
121132

122133
#define R32_OFF(_r_) ((_r_) / sizeof(uint32_t))
@@ -157,7 +168,6 @@ struct OtUARTState {
157168

158169
Fifo8 tx_fifo;
159170
Fifo8 rx_fifo;
160-
uint32_t tx_watermark_level;
161171
bool in_break;
162172
guint watch_tag;
163173
unsigned pclk; /* Current input clock */
@@ -181,23 +191,81 @@ static uint32_t ot_uart_get_tx_watermark_level(const OtUARTState *s)
181191
uint32_t tx_ilvl = (s->regs[R_FIFO_CTRL] & R_FIFO_CTRL_TXILVL_MASK) >>
182192
R_FIFO_CTRL_TXILVL_SHIFT;
183193

184-
return tx_ilvl < 7u ? (1u << tx_ilvl) : 64u;
194+
/*
195+
* Power-of-two thresholds, matching uart_core.sv. TxFifoDepthW == 6 for a
196+
* 32-entry FIFO, so the threshold saturates at half the FIFO depth (16)
197+
* once txilvl >= TxFifoDepthW - 2 == 4.
198+
*/
199+
if (tx_ilvl >= 4u) {
200+
return OT_UART_TX_FIFO_SIZE / 2u;
201+
}
202+
return 1u << tx_ilvl;
185203
}
186204

187205
static uint32_t ot_uart_get_rx_watermark_level(const OtUARTState *s)
188206
{
189207
uint32_t rx_ilvl = (s->regs[R_FIFO_CTRL] & R_FIFO_CTRL_RXILVL_MASK) >>
190208
R_FIFO_CTRL_RXILVL_SHIFT;
191209

192-
return rx_ilvl < 7u ? (1u << rx_ilvl) : 126u;
210+
/*
211+
* Power-of-two thresholds, matching uart_core.sv. RxFifoDepthW == 7 for a
212+
* 64-entry FIFO: rxilvl 6 saturates at RxFifoDepth - 2 (62), and rxilvl 7
213+
* selects a threshold the FIFO can never reach (2*RxFifoDepth - 1), which
214+
* disables the interrupt.
215+
*/
216+
if (rx_ilvl > 6u) {
217+
return OT_UART_RX_FIFO_SIZE * 2u - 1u;
218+
}
219+
if (rx_ilvl == 6u) {
220+
return OT_UART_RX_FIFO_SIZE - 2u;
221+
}
222+
return 1u << rx_ilvl;
223+
}
224+
225+
/*
226+
* Compute the live values of the status-type interrupt conditions from the
227+
* current FIFO state. These bits are not stored in regs[R_INTR_STATE]; they are
228+
* recomputed on every INTR_STATE read and IRQ update so that the interrupt
229+
* tracks the hardware condition (matching prim_intr_hw IntrT="Status").
230+
*/
231+
static uint32_t ot_uart_status_intr_bits(OtUARTState *s)
232+
{
233+
uint32_t bits = 0;
234+
235+
/* rx_watermark: asserted while RX FIFO fill level >= threshold. */
236+
if ((uint32_t)fifo8_num_used(&s->rx_fifo) >=
237+
ot_uart_get_rx_watermark_level(s)) {
238+
bits |= INTR_RX_WATERMARK_MASK;
239+
}
240+
/* tx_watermark: asserted while TX FIFO has drained below the threshold. */
241+
if ((uint32_t)fifo8_num_used(&s->tx_fifo) <
242+
ot_uart_get_tx_watermark_level(s)) {
243+
bits |= INTR_TX_WATERMARK_MASK;
244+
}
245+
/* tx_empty: asserted while the TX FIFO is empty. */
246+
if (fifo8_is_empty(&s->tx_fifo)) {
247+
bits |= INTR_TX_EMPTY_MASK;
248+
}
249+
250+
return bits;
251+
}
252+
253+
/*
254+
* The architectural INTR_STATE value: latched event-type bits (held in
255+
* regs[R_INTR_STATE]) combined with the live status-type bits.
256+
*/
257+
static uint32_t ot_uart_intr_state(OtUARTState *s)
258+
{
259+
return (s->regs[R_INTR_STATE] & ~INTR_STATUS_MASK) |
260+
ot_uart_status_intr_bits(s);
193261
}
194262

195263
static void ot_uart_update_irqs(OtUARTState *s)
196264
{
197-
uint32_t state_masked = s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE];
265+
uint32_t state = ot_uart_intr_state(s);
266+
uint32_t state_masked = state & s->regs[R_INTR_ENABLE];
198267

199-
trace_ot_uart_irqs(s->ot_id, s->regs[R_INTR_STATE], s->regs[R_INTR_ENABLE],
200-
state_masked);
268+
trace_ot_uart_irqs(s->ot_id, state, s->regs[R_INTR_ENABLE], state_masked);
201269

202270
for (int index = 0; index < OT_UART_IRQ_NUM; index++) {
203271
bool level = (state_masked & (1U << index)) != 0;
@@ -256,27 +324,23 @@ static int ot_uart_can_receive(void *opaque)
256324
static void ot_uart_receive(void *opaque, const uint8_t *buf, int size)
257325
{
258326
OtUARTState *s = opaque;
259-
uint32_t rx_watermark_level;
260327
size_t count = MIN(fifo8_num_free(&s->rx_fifo), (size_t)size);
261328

262329
if (size && !s->toggle_break) {
263330
/* no longer breaking, so emulate idle in oversampled VAL register */
264331
s->in_break = false;
265332
}
266333

267-
for (int index = 0; index < size; index++) {
334+
for (size_t index = 0; index < count; index++) {
268335
fifo8_push(&s->rx_fifo, buf[index]);
269336
}
270337

271-
/* update INTR_STATE */
272-
if (count != size) {
338+
/* rx_overflow is event-type: latch it when the FIFO could not absorb all. */
339+
if (count != (size_t)size) {
273340
s->regs[R_INTR_STATE] |= INTR_RX_OVERFLOW_MASK;
274341
}
275-
rx_watermark_level = ot_uart_get_rx_watermark_level(s);
276-
if (rx_watermark_level && size >= rx_watermark_level) {
277-
s->regs[R_INTR_STATE] |= INTR_RX_WATERMARK_MASK;
278-
}
279342

343+
/* rx_watermark is status-type: computed live in ot_uart_update_irqs(). */
280344
ot_uart_update_irqs(s);
281345
}
282346

@@ -312,6 +376,12 @@ static uint8_t ot_uart_read_rx_fifo(OtUARTState *s)
312376

313377
val = fifo8_pop(&s->rx_fifo);
314378

379+
/*
380+
* rx_watermark is status-type: draining the FIFO may drop it below the
381+
* threshold, which must de-assert the interrupt line immediately.
382+
*/
383+
ot_uart_update_irqs(s);
384+
315385
if (ot_uart_is_rx_enabled(s) && !ot_uart_is_sys_loopack_enabled(s)) {
316386
qemu_chr_fe_accept_input(&s->chr);
317387
}
@@ -322,12 +392,11 @@ static uint8_t ot_uart_read_rx_fifo(OtUARTState *s)
322392
static void ot_uart_reset_tx_fifo(OtUARTState *s)
323393
{
324394
fifo8_reset(&s->tx_fifo);
325-
s->regs[R_INTR_STATE] |= INTR_TX_EMPTY_MASK;
395+
/*
396+
* tx_done is event-type and latched here; tx_empty and tx_watermark are
397+
* status-type and follow the (now empty) FIFO live via ot_uart_update_irqs.
398+
*/
326399
s->regs[R_INTR_STATE] |= INTR_TX_DONE_MASK;
327-
if (s->tx_watermark_level) {
328-
s->regs[R_INTR_STATE] |= INTR_TX_WATERMARK_MASK;
329-
s->tx_watermark_level = 0;
330-
}
331400
}
332401

333402
static void ot_uart_xmit(OtUARTState *s)
@@ -373,16 +442,11 @@ static void ot_uart_xmit(OtUARTState *s)
373442
}
374443
}
375444

376-
/* update INTR_STATE */
445+
/* update INTR_STATE: tx_done is event-type and latched on drain.
446+
* tx_empty/tx_watermark are status-type and tracked live in update_irqs. */
377447
if (fifo8_is_empty(&s->tx_fifo)) {
378-
s->regs[R_INTR_STATE] |= INTR_TX_EMPTY_MASK;
379448
s->regs[R_INTR_STATE] |= INTR_TX_DONE_MASK;
380449
}
381-
if (s->tx_watermark_level &&
382-
fifo8_num_used(&s->tx_fifo) < s->tx_watermark_level) {
383-
s->regs[R_INTR_STATE] |= INTR_TX_WATERMARK_MASK;
384-
s->tx_watermark_level = 0;
385-
}
386450

387451
ot_uart_update_irqs(s);
388452
}
@@ -409,18 +473,11 @@ static void uart_write_tx_fifo(OtUARTState *s, uint8_t val)
409473

410474
fifo8_push(&s->tx_fifo, val);
411475

412-
s->tx_watermark_level = ot_uart_get_tx_watermark_level(s);
413-
if (fifo8_num_used(&s->tx_fifo) < s->tx_watermark_level) {
414-
/*
415-
* TX watermark interrupt is raised when FIFO depth goes from above
416-
* watermark to below. If we haven't reached watermark, reset cached
417-
* watermark level
418-
*/
419-
s->tx_watermark_level = 0;
420-
}
421-
422476
if (ot_uart_is_tx_enabled(s)) {
423477
ot_uart_xmit(s);
478+
} else {
479+
/* tx_watermark/tx_empty are status-type: refresh from the new level. */
480+
ot_uart_update_irqs(s);
424481
}
425482
}
426483

@@ -445,6 +502,9 @@ static uint64_t ot_uart_read(void *opaque, hwaddr addr, unsigned size)
445502
hwaddr reg = R32_OFF(addr);
446503
switch (reg) {
447504
case R_INTR_STATE:
505+
/* Status-type bits reflect the live FIFO condition, not a latch. */
506+
val32 = ot_uart_intr_state(s);
507+
break;
448508
case R_INTR_ENABLE:
449509
case R_CTRL:
450510
case R_FIFO_CTRL:
@@ -601,12 +661,15 @@ static void ot_uart_write(void *opaque, hwaddr addr, uint64_t val64,
601661
val32 & (R_FIFO_CTRL_RXILVL_MASK | R_FIFO_CTRL_TXILVL_MASK);
602662
if (val32 & R_FIFO_CTRL_RXRST_MASK) {
603663
ot_uart_reset_rx_fifo(s);
604-
ot_uart_update_irqs(s);
605664
}
606665
if (val32 & R_FIFO_CTRL_TXRST_MASK) {
607666
ot_uart_reset_tx_fifo(s);
608-
ot_uart_update_irqs(s);
609667
}
668+
/*
669+
* Changing RXILVL/TXILVL moves the status-type watermark thresholds, so
670+
* re-evaluate the interrupt lines unconditionally.
671+
*/
672+
ot_uart_update_irqs(s);
610673
break;
611674
case R_OVRD:
612675
if (val32 & R_OVRD_TXEN_MASK) {
@@ -680,7 +743,6 @@ static void ot_uart_reset_enter(Object *obj, ResetType type)
680743

681744
memset(&s->regs[0], 0, sizeof(s->regs));
682745

683-
s->tx_watermark_level = 0;
684746
for (unsigned index = 0; index < ARRAY_SIZE(s->irqs); index++) {
685747
ibex_irq_set(&s->irqs[index], 0);
686748
}

0 commit comments

Comments
 (0)