hw/loongarch/virt: Add reset support for kernel irqchip

When system reboot, interrupt controller is restored to initial
state. However if interrupt controller extioi/ipi/pch_pic is
emulated in kernel, it should notify kvm to do so. Here suspend
and restore API is used for reset, set initial state in qemu user
space and restore API is used to notify kvm to reload register
state.

Reviewed-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Message-ID: <20250606063033.2557365-11-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 7be0685..8b8ac6b 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -391,6 +391,10 @@
     if (lec->parent_phases.hold) {
         lec->parent_phases.hold(obj, type);
     }
+
+    if (kvm_irqchip_in_kernel()) {
+        kvm_extioi_put(obj, 0);
+    }
 }
 
 static int vmstate_extioi_pre_save(void *opaque)
diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c
index f4c618c..0133540 100644
--- a/hw/intc/loongarch_extioi_kvm.c
+++ b/hw/intc/loongarch_extioi_kvm.c
@@ -94,6 +94,10 @@
     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
     int fd = les->dev_fd;
 
+    if (fd == 0) {
+        return 0;
+    }
+
     kvm_extioi_access_regs(opaque, true);
     kvm_extioi_access_sw_status(opaque, true);
     kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index 0ea91ea..fc8005c 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -122,6 +122,10 @@
         core->clear = 0;
         memset(core->buf, 0, sizeof(core->buf));
     }
+
+    if (kvm_irqchip_in_kernel()) {
+        kvm_ipi_put(obj, 0);
+    }
 }
 
 static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c
index b615060..4cb3acc 100644
--- a/hw/intc/loongarch_ipi_kvm.c
+++ b/hw/intc/loongarch_ipi_kvm.c
@@ -25,6 +25,10 @@
     uint64_t attr;
     int cpu, fd = lis->dev_fd;
 
+    if (fd == 0) {
+        return;
+    }
+
     for (cpu = 0; cpu < ipi->num_cpu; cpu++) {
         core = &ipi->cpu[cpu];
         attr = (cpu << 16) | CORE_STATUS_OFF;
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
index 1adef98..c4b242d 100644
--- a/hw/intc/loongarch_pch_pic.c
+++ b/hw/intc/loongarch_pch_pic.c
@@ -264,6 +264,10 @@
     if (lpc->parent_phases.hold) {
         lpc->parent_phases.hold(obj, type);
     }
+
+    if (kvm_irqchip_in_kernel()) {
+        kvm_pic_put(obj, 0);
+    }
 }
 
 static void loongarch_pic_realize(DeviceState *dev, Error **errp)
diff --git a/hw/intc/loongarch_pic_kvm.c b/hw/intc/loongarch_pic_kvm.c
index 3eef81a..dd504ec 100644
--- a/hw/intc/loongarch_pic_kvm.c
+++ b/hw/intc/loongarch_pic_kvm.c
@@ -26,6 +26,10 @@
     int fd = lps->dev_fd;
     int addr, offset;
 
+    if (fd == 0) {
+        return;
+    }
+
     kvm_pch_pic_access_reg(fd, PCH_PIC_INT_MASK, &s->int_mask, write);
     kvm_pch_pic_access_reg(fd, PCH_PIC_HTMSI_EN, &s->htmsi_en, write);
     kvm_pch_pic_access_reg(fd, PCH_PIC_INT_EDGE, &s->intedge, write);