[PATCH qemu v2 7/7] ot_uart: add tracing

~lexbaileylowrisc posted 7 patches 3 days, 7 hours ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, Alistair Francis <Alistair.Francis@wdc.com>, Palmer Dabbelt <palmer@dabbelt.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>, Chao Liu <chao.liu.zevorn@gmail.com>
[PATCH qemu v2 7/7] ot_uart: add tracing
Posted by ~lexbaileylowrisc 4 days, 4 hours ago
From: Lex Bailey <lex.bailey@lowrisc.org>

Added some tracing to the OpenTitan UART for transparency when debugging

Signed-off-by: Lex Bailey <lex.bailey@lowrisc.org>
---
 hw/char/ot_uart.c         | 30 ++++++++++++++++++++++++++++++
 hw/char/trace-events      |  8 ++++++++
 hw/riscv/opentitan.c      |  1 +
 include/hw/char/ot_uart.h |  1 +
 4 files changed, 40 insertions(+)

diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c
index 1dda771724..6f7b8946e8 100644
--- a/hw/char/ot_uart.c
+++ b/hw/char/ot_uart.c
@@ -30,6 +30,7 @@
 #include "migration/vmstate.h"
 #include "qemu/log.h"
 #include "qemu/module.h"
+#include "trace.h"
 
 /* clang-format off */
 REG32(INTR_STATE, 0x00)
@@ -135,6 +136,9 @@ static void ot_uart_update_irqs(OtUARTState *s)
 {
     uint32_t state_masked = s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE];
 
+    trace_ot_uart_irqs(s->ot_id, s->regs[R_INTR_STATE], s->regs[R_INTR_ENABLE],
+                       state_masked);
+
     for (int index = 0; index < OT_UART_IRQ_NUM; index++) {
         bool level = (state_masked & (1U << index)) != 0;
         qemu_set_irq(s->irqs[index], level);
@@ -156,6 +160,18 @@ static bool ot_uart_is_rx_enabled(const OtUARTState *s)
     return FIELD_EX32(s->regs[R_CTRL], CTRL, RX);
 }
 
+static void ot_uart_check_baudrate(const OtUARTState *s)
+{
+    uint32_t nco = FIELD_EX32(s->regs[R_CTRL], CTRL, NCO);
+
+    unsigned baudrate = (unsigned)(((uint64_t)nco * (uint64_t)s->pclk) >>
+                                   (R_CTRL_NCO_LENGTH + 4));
+
+    if (baudrate) {
+        trace_ot_uart_check_baudrate(s->ot_id, s->pclk, baudrate);
+    }
+}
+
 static int ot_uart_can_receive(void *opaque)
 {
     OtUARTState *s = opaque;
@@ -403,6 +419,7 @@ static void ot_uart_clock_input(void *opaque, int irq, int level)
     s->pclk = (unsigned)level;
 
     /* TODO: disable UART transfer when PCLK is 0 */
+    ot_uart_check_baudrate(s);
 }
 
 static uint64_t ot_uart_read(void *opaque, hwaddr addr, unsigned int size)
@@ -500,6 +517,10 @@ static uint64_t ot_uart_read(void *opaque, hwaddr addr, unsigned int size)
         break;
     }
 
+    uint32_t pc = current_cpu->cc->get_pc(current_cpu);
+    trace_ot_uart_io_read_out(s->ot_id, (uint32_t)addr, REG_NAME(reg), val32,
+                              pc);
+
     return (uint64_t)val32;
 }
 
@@ -511,6 +532,9 @@ static void ot_uart_write(void *opaque, hwaddr addr, uint64_t val64,
 
     hwaddr reg = R32_OFF(addr);
 
+    uint32_t pc = current_cpu->cc->get_pc(current_cpu);
+    trace_ot_uart_io_write(s->ot_id, (uint32_t)addr, REG_NAME(reg), val32, pc);
+
     switch (reg) {
     case R_INTR_STATE:
         val32 &= INTR_MASK;
@@ -541,6 +565,9 @@ static void ot_uart_write(void *opaque, hwaddr addr, uint64_t val64,
         uint32_t prev = s->regs[R_CTRL];
         s->regs[R_CTRL] = val32 & CTRL_MASK;
         uint32_t change = prev ^ s->regs[R_CTRL];
+        if (change & R_CTRL_NCO_MASK) {
+            ot_uart_check_baudrate(s);
+        }
         if ((change & R_CTRL_RX_MASK) && ot_uart_is_rx_enabled(s) &&
             !ot_uart_is_sys_loopack_enabled(s)) {
             qemu_chr_fe_accept_input(&s->chr);
@@ -621,6 +648,7 @@ static const VMStateDescription vmstate_ot_uart = {
 };
 
 static const Property ot_uart_properties[] = {
+    DEFINE_PROP_STRING("ot-id", OtUARTState, ot_id),
     DEFINE_PROP_CHR("chardev", OtUARTState, chr),
     DEFINE_PROP_BOOL("oversample-break", OtUARTState, oversample_break, false),
     DEFINE_PROP_BOOL("toggle-break", OtUARTState, toggle_break, false),
@@ -669,6 +697,8 @@ static void ot_uart_realize(DeviceState *dev, Error **errp)
 {
     OtUARTState *s = OT_UART(dev);
 
+    g_assert(s->ot_id);
+
     qdev_init_gpio_in_named(DEVICE(s), &ot_uart_clock_input, "clock-in", 1);
 
     fifo8_create(&s->tx_fifo, OT_UART_TX_FIFO_SIZE);
diff --git a/hw/char/trace-events b/hw/char/trace-events
index a3fcc77287..c859d8af4e 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -141,3 +141,11 @@ stm32f2xx_usart_receive(char *id, uint8_t chr) " %s receiving '%c'"
 # riscv_htif.c
 htif_uart_write_to_host(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
 htif_uart_unknown_device_command(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
+
+# ot_uart.c
+ot_uart_check_baudrate(const char *id, unsigned pclk, unsigned baud) "%s: @ %u Hz: %u bps"
+ot_uart_connect_input_clock(const char *id, const char * srcname) "%s: %s"
+ot_uart_debug(const char *id, const char *msg) "%s: %s"
+ot_uart_io_read_out(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x"
+ot_uart_io_write(const char *id, uint32_t addr, const char *regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x"
+ot_uart_irqs(const char *id, uint32_t active, uint32_t mask, uint32_t eff) "%s: act:0x%08x msk:0x%08x eff:0x%08x"
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 97c33d1b53..163d3ac3d3 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -133,6 +133,7 @@ static void lowrisc_ibex_soc_init(Object *obj)
     object_initialize_child(obj, "plic", &s->plic, TYPE_SIFIVE_PLIC);
 
     object_initialize_child(obj, "uart", &s->uart, TYPE_OT_UART);
+    object_property_set_str(OBJECT(&s->uart), "ot-id", "uart0", &error_fatal);
 
     object_initialize_child(obj, "timer", &s->timer, TYPE_IBEX_TIMER);
 
diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h
index 221c581e52..7c2b5f3457 100644
--- a/include/hw/char/ot_uart.h
+++ b/include/hw/char/ot_uart.h
@@ -46,6 +46,7 @@ struct OtUARTState {
     unsigned pclk; /* Current input clock */
     const char *clock_src_name; /* IRQ name once connected */
 
+    char *ot_id;
     DeviceState *clock_src;
     CharFrontend chr;
     bool oversample_break; /* Should mock break in the oversampled VAL reg? */
-- 
2.49.1