Commit 970657e490 for qemu.org

commit 970657e490c05b0d2dd8ffbd68466d22685083d1
Author: Bibo Mao <maobibo@loongson.cn>
Date:   Thu Aug 27 15:53:10 2026 +0800

    hw/intc/loongarch_extioi: Add extioi interrupt status display

    When irqchip in kernel is enabled, the register status of extioi irqchip
    is in KVM kernel. Here add interrupt status display in user side in order
    to debug extioi irqchip driver.

    Signed-off-by: Bibo Mao <maobibo@loongson.cn>
    Reviewed-by: Xianglai Li <lixianglai@loongson.cn>

diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 2999740269..06f2aa7b14 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -10,6 +10,7 @@
 #include "qemu/log.h"
 #include "qapi/error.h"
 #include "hw/core/irq.h"
+#include "hw/intc/intc.h"
 #include "hw/loongarch/virt.h"
 #include "system/address-spaces.h"
 #include "system/kvm.h"
@@ -420,11 +421,63 @@ static int vmstate_extioi_post_load(void *opaque, int version_id)
     return 0;
 }

+static void loongarch_extioi_print_info(InterruptStatsProvider *obj,
+                                        GString *buf)
+{
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(obj);
+    uint64_t *val;
+    unsigned long irq;
+    ExtIOICore *core;
+    int i;
+
+    vmstate_extioi_pre_save(s);
+    g_string_append_printf(buf, "%s:\n", object_get_typename(OBJECT(obj)));
+
+    val = (uint64_t *)s->isr;
+    g_string_append_printf(buf, "  ISR     0x%016"PRIx64" 0x%016"PRIx64
+                                " 0x%016"PRIx64" 0x%016"PRIx64"\n",
+                                *val, *(val + 1), *(val + 2), *(val + 3));
+    val = (uint64_t *)s->enable;
+    g_string_append_printf(buf, "  ENABLE  0x%016"PRIx64" 0x%016"PRIx64
+                                " 0x%016"PRIx64" 0x%016"PRIx64"\n",
+                                *val, *(val + 1), *(val + 2), *(val + 3));
+    val = (uint64_t *)s->ipmap;
+    g_string_append_printf(buf, "  IPMAP   0x%016"PRIx64"\n", *val);
+
+    val = (uint64_t *)s->coremap;
+    for (i = 0; i < EXTIOI_IRQS; i += 32) {
+        g_string_append_printf(buf, "  COREMAP 0x%016"PRIx64" 0x%016"PRIx64
+                                    " 0x%016"PRIx64" 0x%016"PRIx64"\n",
+                                    *val, *(val + 1), *(val + 2), *(val + 3));
+        val += 4;
+    }
+
+    core = s->cpu;
+    for (i = 0; i < s->num_cpu; i++, core++) {
+        if (!core->cpu) {
+            continue;
+        }
+
+        irq = find_first_bit((unsigned long *)core->coreisr, EXTIOI_IRQS);
+        /* No pending IRQ */
+        if (irq == EXTIOI_IRQS) {
+            continue;
+        }
+
+        val = (uint64_t *)core->coreisr;
+        g_string_append_printf(buf, "  CPU[%d] ISR 0x%016"PRIx64" 0x%016"PRIx64
+                                    " 0x%016"PRIx64" 0x%016"PRIx64"\n",
+                                    i, *val, *(val + 1), *(val + 2),
+                                    *(val + 3));
+    }
+}
+
 static void loongarch_extioi_class_init(ObjectClass *klass, const void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_CLASS(klass);
     LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
+    InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
     ResettableClass *rc = RESETTABLE_CLASS(klass);

     device_class_set_parent_realize(dc, loongarch_extioi_realize,
@@ -433,6 +486,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, const void *data)
                                        NULL, &lec->parent_phases);
     lecc->pre_save  = vmstate_extioi_pre_save;
     lecc->post_load = vmstate_extioi_post_load;
+    ic->print_info = loongarch_extioi_print_info;
 }

 static const TypeInfo loongarch_extioi_types[] = {
@@ -442,6 +496,10 @@ static const TypeInfo loongarch_extioi_types[] = {
         .instance_size = sizeof(LoongArchExtIOIState),
         .class_size    = sizeof(LoongArchExtIOIClass),
         .class_init    = loongarch_extioi_class_init,
+        .interfaces         = (const InterfaceInfo[]) {
+            { TYPE_INTERRUPT_STATS_PROVIDER },
+            { }
+        },
     }
 };