summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--hw/intc/loongarch_extioi.c112
-rw-r--r--hw/intc/loongarch_extioi_common.c113
-rw-r--r--hw/intc/loongarch_pch_pic.c106
-rw-r--r--hw/intc/loongarch_pic_common.c97
-rw-r--r--hw/intc/meson.build4
-rw-r--r--hw/loongarch/virt.c2
-rw-r--r--include/hw/intc/loongarch_extioi.h84
-rw-r--r--include/hw/intc/loongarch_extioi_common.h98
-rw-r--r--include/hw/intc/loongarch_pch_pic.h70
-rw-r--r--include/hw/intc/loongarch_pic_common.h82
10 files changed, 490 insertions, 278 deletions
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index dd91f89361..4a1a7c357c 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -10,16 +10,13 @@
 #include "qemu/log.h"
 #include "qapi/error.h"
 #include "hw/irq.h"
-#include "hw/sysbus.h"
 #include "hw/loongarch/virt.h"
-#include "hw/qdev-properties.h"
 #include "exec/address-spaces.h"
 #include "hw/intc/loongarch_extioi.h"
-#include "migration/vmstate.h"
 #include "trace.h"
 
 
-static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level)
+static void extioi_update_irq(LoongArchExtIOICommonState *s, int irq, int level)
 {
     int ipnum, cpu, found, irq_index, irq_mask;
 
@@ -54,7 +51,7 @@ static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level)
 
 static void extioi_setirq(void *opaque, int irq, int level)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
     trace_loongarch_extioi_setirq(irq, level);
     if (level) {
         set_bit32(irq, s->isr);
@@ -67,7 +64,7 @@ static void extioi_setirq(void *opaque, int irq, int level)
 static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data,
                                 unsigned size, MemTxAttrs attrs)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
     unsigned long offset = addr & 0xffff;
     uint32_t index, cpu;
 
@@ -106,7 +103,7 @@ static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data,
     return MEMTX_OK;
 }
 
-static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
+static inline void extioi_enable_irq(LoongArchExtIOICommonState *s, int index,\
                                      uint32_t mask, int level)
 {
     uint32_t val;
@@ -125,8 +122,8 @@ static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
     }
 }
 
-static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
-                                            uint64_t val, bool notify)
+static inline void extioi_update_sw_coremap(LoongArchExtIOICommonState *s,
+                                            int irq, uint64_t val, bool notify)
 {
     int i, cpu;
 
@@ -162,8 +159,8 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
     }
 }
 
-static inline void extioi_update_sw_ipmap(LoongArchExtIOI *s, int index,
-                                          uint64_t val)
+static inline void extioi_update_sw_ipmap(LoongArchExtIOICommonState *s,
+                                          int index, uint64_t val)
 {
     int i;
     uint8_t ipnum;
@@ -186,7 +183,7 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
                           uint64_t val, unsigned size,
                           MemTxAttrs attrs)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
     int cpu, index, old_data, irq;
     uint32_t offset;
 
@@ -266,7 +263,7 @@ static const MemoryRegionOps extioi_ops = {
 static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data,
                                      unsigned size, MemTxAttrs attrs)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
 
     switch (addr) {
     case EXTIOI_VIRT_FEATURES:
@@ -286,7 +283,7 @@ static MemTxResult extioi_virt_writew(void *opaque, hwaddr addr,
                           uint64_t val, unsigned size,
                           MemTxAttrs attrs)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
 
     switch (addr) {
     case EXTIOI_VIRT_FEATURES:
@@ -320,12 +317,15 @@ static const MemoryRegionOps extioi_virt_ops = {
 
 static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(dev);
+    LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_GET_CLASS(dev);
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    Error *local_err = NULL;
     int i, pin;
 
-    if (s->num_cpu == 0) {
-        error_setg(errp, "num-cpu must be at least 1");
+    lec->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
         return;
     }
 
@@ -360,23 +360,23 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
     }
 }
 
-static void loongarch_extioi_finalize(Object *obj)
+static void loongarch_extioi_unrealize(DeviceState *dev)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(dev);
 
     g_free(s->cpu);
 }
 
 static void loongarch_extioi_reset(DeviceState *d)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(d);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(d);
 
     s->status = 0;
 }
 
 static int vmstate_extioi_post_load(void *opaque, int version_id)
 {
-    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+    LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
     int i, start_irq;
 
     for (i = 0; i < (EXTIOI_IRQS / 4); i++) {
@@ -391,66 +391,28 @@ static int vmstate_extioi_post_load(void *opaque, int version_id)
     return 0;
 }
 
-static const VMStateDescription vmstate_extioi_core = {
-    .name = "extioi-core",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (const VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_loongarch_extioi = {
-    .name = TYPE_LOONGARCH_EXTIOI,
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .post_load = vmstate_extioi_post_load,
-    .fields = (const VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
-        VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
-                             EXTIOI_IRQS_NODETYPE_COUNT / 2),
-        VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32),
-        VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32),
-        VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4),
-        VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4),
-
-        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOI, num_cpu,
-                         vmstate_extioi_core, ExtIOICore),
-        VMSTATE_UINT32(features, LoongArchExtIOI),
-        VMSTATE_UINT32(status, LoongArchExtIOI),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const Property extioi_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", LoongArchExtIOI, num_cpu, 1),
-    DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOI, features,
-                    EXTIOI_HAS_VIRT_EXTENSION, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_CLASS(klass);
+    LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
 
-    dc->realize = loongarch_extioi_realize;
+    device_class_set_parent_realize(dc, loongarch_extioi_realize,
+                                    &lec->parent_realize);
+    device_class_set_parent_unrealize(dc, loongarch_extioi_unrealize,
+                                      &lec->parent_unrealize);
     device_class_set_legacy_reset(dc, loongarch_extioi_reset);
-    device_class_set_props(dc, extioi_properties);
-    dc->vmsd = &vmstate_loongarch_extioi;
+    lecc->post_load = vmstate_extioi_post_load;
 }
 
-static const TypeInfo loongarch_extioi_info = {
-    .name          = TYPE_LOONGARCH_EXTIOI,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct LoongArchExtIOI),
-    .class_init    = loongarch_extioi_class_init,
-    .instance_finalize = loongarch_extioi_finalize,
+static const TypeInfo loongarch_extioi_types[] = {
+    {
+        .name          = TYPE_LOONGARCH_EXTIOI,
+        .parent        = TYPE_LOONGARCH_EXTIOI_COMMON,
+        .instance_size = sizeof(LoongArchExtIOIState),
+        .class_size    = sizeof(LoongArchExtIOIClass),
+        .class_init    = loongarch_extioi_class_init,
+    }
 };
 
-static void loongarch_extioi_register_types(void)
-{
-    type_register_static(&loongarch_extioi_info);
-}
-
-type_init(loongarch_extioi_register_types)
+DEFINE_TYPES(loongarch_extioi_types)
diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c
new file mode 100644
index 0000000000..e50431f124
--- /dev/null
+++ b/hw/intc/loongarch_extioi_common.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongson extioi interrupt controller emulation
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/intc/loongarch_extioi_common.h"
+#include "migration/vmstate.h"
+
+static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp)
+{
+    LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)dev;
+
+    if (s->num_cpu == 0) {
+        error_setg(errp, "num-cpu must be at least 1");
+        return;
+    }
+}
+
+static int loongarch_extioi_common_pre_save(void *opaque)
+{
+    LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
+    LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
+
+    if (lecc->pre_save) {
+        return lecc->pre_save(s);
+    }
+
+    return 0;
+}
+
+static int loongarch_extioi_common_post_load(void *opaque, int version_id)
+{
+    LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
+    LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
+
+    if (lecc->post_load) {
+        return lecc->post_load(s, version_id);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_extioi_core = {
+    .name = "extioi-core",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_loongarch_extioi = {
+    .name = "loongarch.extioi",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .pre_save  = loongarch_extioi_common_pre_save,
+    .post_load = loongarch_extioi_common_post_load,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOICommonState,
+                             EXTIOI_IRQS_GROUP_COUNT),
+        VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOICommonState,
+                             EXTIOI_IRQS_NODETYPE_COUNT / 2),
+        VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOICommonState,
+                             EXTIOI_IRQS / 32),
+        VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOICommonState,
+                             EXTIOI_IRQS / 32),
+        VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOICommonState,
+                             EXTIOI_IRQS_IPMAP_SIZE / 4),
+        VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOICommonState,
+                             EXTIOI_IRQS / 4),
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOICommonState,
+                             num_cpu, vmstate_extioi_core, ExtIOICore),
+        VMSTATE_UINT32(features, LoongArchExtIOICommonState),
+        VMSTATE_UINT32(status, LoongArchExtIOICommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const Property extioi_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", LoongArchExtIOICommonState, num_cpu, 1),
+    DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState,
+                    features, EXTIOI_HAS_VIRT_EXTENSION, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void loongarch_extioi_common_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
+
+    device_class_set_parent_realize(dc, loongarch_extioi_common_realize,
+                                    &lecc->parent_realize);
+    device_class_set_props(dc, extioi_properties);
+    dc->vmsd = &vmstate_loongarch_extioi;
+}
+
+static const TypeInfo loongarch_extioi_common_types[] = {
+    {
+        .name               = TYPE_LOONGARCH_EXTIOI_COMMON,
+        .parent             = TYPE_SYS_BUS_DEVICE,
+        .instance_size      = sizeof(LoongArchExtIOICommonState),
+        .class_size         = sizeof(LoongArchExtIOICommonClass),
+        .class_init         = loongarch_extioi_common_class_init,
+        .abstract           = true,
+    }
+};
+
+DEFINE_TYPES(loongarch_extioi_common_types)
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
index 6a87b1aab7..acd75ccb0c 100644
--- a/hw/intc/loongarch_pch_pic.c
+++ b/hw/intc/loongarch_pch_pic.c
@@ -7,17 +7,13 @@
 
 #include "qemu/osdep.h"
 #include "qemu/bitops.h"
-#include "hw/sysbus.h"
-#include "hw/loongarch/virt.h"
-#include "hw/pci-host/ls7a.h"
 #include "hw/irq.h"
 #include "hw/intc/loongarch_pch_pic.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
 #include "trace.h"
 #include "qapi/error.h"
 
-static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
+static void pch_pic_update_irq(LoongArchPICCommonState *s, uint64_t mask,
+                               int level)
 {
     uint64_t val;
     int irq;
@@ -45,7 +41,7 @@ static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
 
 static void pch_pic_irq_handler(void *opaque, int irq, int level)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
     uint64_t mask = 1ULL << irq;
 
     assert(irq < s->irq_num);
@@ -78,7 +74,7 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level)
 static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
                                             unsigned size)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
     uint64_t val = 0;
     uint32_t offset = addr & 0xfff;
 
@@ -136,7 +132,7 @@ static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi)
 static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
                                          uint64_t value, unsigned size)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
     uint32_t offset, old_valid, data = (uint32_t)value;
     uint64_t old, int_mask;
     offset = addr & 0xfff;
@@ -208,7 +204,7 @@ static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
 static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
                                         unsigned size)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
     uint64_t val = 0;
     uint32_t offset = addr & 0xfff;
 
@@ -236,7 +232,7 @@ static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
 static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
                                      uint64_t value, unsigned size)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
     uint32_t offset, data = (uint32_t)value;
     offset = addr & 0xfff;
 
@@ -263,7 +259,7 @@ static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
 static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
                                         unsigned size)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
     uint64_t val = 0;
     uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
     int64_t offset_tmp;
@@ -292,7 +288,7 @@ static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
 static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
                                      uint64_t data, unsigned size)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
     int32_t offset_tmp;
     uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
 
@@ -360,7 +356,7 @@ static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
 
 static void loongarch_pch_pic_reset(DeviceState *d)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(d);
     int i;
 
     s->int_mask = -1;
@@ -379,30 +375,27 @@ static void loongarch_pch_pic_reset(DeviceState *d)
     s->int_polarity = 0x0;
 }
 
-static void loongarch_pch_pic_realize(DeviceState *dev, Error **errp)
+static void loongarch_pic_realize(DeviceState *dev, Error **errp)
 {
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(dev);
-
-    if (!s->irq_num || s->irq_num  > VIRT_PCH_PIC_IRQ_NUM) {
-        error_setg(errp, "Invalid 'pic_irq_num'");
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(dev);
+    LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    Error *local_err = NULL;
+
+    lpc->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
         return;
     }
 
     qdev_init_gpio_out(dev, s->parent_irq, s->irq_num);
     qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num);
-}
-
-static void loongarch_pch_pic_init(Object *obj)
-{
-    LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
-    memory_region_init_io(&s->iomem32_low, obj,
+    memory_region_init_io(&s->iomem32_low, OBJECT(dev),
                           &loongarch_pch_pic_reg32_low_ops,
                           s, PCH_PIC_NAME(.reg32_part1), 0x100);
-    memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
+    memory_region_init_io(&s->iomem8, OBJECT(dev), &loongarch_pch_pic_reg8_ops,
                           s, PCH_PIC_NAME(.reg8), 0x2a0);
-    memory_region_init_io(&s->iomem32_high, obj,
+    memory_region_init_io(&s->iomem32_high, OBJECT(dev),
                           &loongarch_pch_pic_reg32_high_ops,
                           s, PCH_PIC_NAME(.reg32_part2), 0xc60);
     sysbus_init_mmio(sbd, &s->iomem32_low);
@@ -411,53 +404,24 @@ static void loongarch_pch_pic_init(Object *obj)
 
 }
 
-static const Property loongarch_pch_pic_properties[] = {
-    DEFINE_PROP_UINT32("pch_pic_irq_num",  LoongArchPCHPIC, irq_num, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_loongarch_pch_pic = {
-    .name = TYPE_LOONGARCH_PCH_PIC,
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (const VMStateField[]) {
-        VMSTATE_UINT64(int_mask, LoongArchPCHPIC),
-        VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC),
-        VMSTATE_UINT64(intedge, LoongArchPCHPIC),
-        VMSTATE_UINT64(intclr, LoongArchPCHPIC),
-        VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC),
-        VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC),
-        VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
-        VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
-        VMSTATE_UINT64(last_intirr, LoongArchPCHPIC),
-        VMSTATE_UINT64(intirr, LoongArchPCHPIC),
-        VMSTATE_UINT64(intisr, LoongArchPCHPIC),
-        VMSTATE_UINT64(int_polarity, LoongArchPCHPIC),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
+static void loongarch_pic_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass);
 
-    dc->realize = loongarch_pch_pic_realize;
     device_class_set_legacy_reset(dc, loongarch_pch_pic_reset);
-    dc->vmsd = &vmstate_loongarch_pch_pic;
-    device_class_set_props(dc, loongarch_pch_pic_properties);
+    device_class_set_parent_realize(dc, loongarch_pic_realize,
+                                    &lpc->parent_realize);
 }
 
-static const TypeInfo loongarch_pch_pic_info = {
-    .name          = TYPE_LOONGARCH_PCH_PIC,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(LoongArchPCHPIC),
-    .instance_init = loongarch_pch_pic_init,
-    .class_init    = loongarch_pch_pic_class_init,
+static const TypeInfo loongarch_pic_types[] = {
+   {
+        .name               = TYPE_LOONGARCH_PIC,
+        .parent             = TYPE_LOONGARCH_PIC_COMMON,
+        .instance_size      = sizeof(LoongarchPICState),
+        .class_size         = sizeof(LoongarchPICClass),
+        .class_init         = loongarch_pic_class_init,
+    }
 };
 
-static void loongarch_pch_pic_register_types(void)
-{
-    type_register_static(&loongarch_pch_pic_info);
-}
-
-type_init(loongarch_pch_pic_register_types)
+DEFINE_TYPES(loongarch_pic_types)
diff --git a/hw/intc/loongarch_pic_common.c b/hw/intc/loongarch_pic_common.c
new file mode 100644
index 0000000000..bcb6b7b3fc
--- /dev/null
+++ b/hw/intc/loongarch_pic_common.c
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Loongson 7A1000 I/O interrupt controller.
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/intc/loongarch_pic_common.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+static int loongarch_pic_pre_save(void *opaque)
+{
+    LoongArchPICCommonState *s = (LoongArchPICCommonState *)opaque;
+    LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_GET_CLASS(s);
+
+    if (lpcc->pre_save) {
+        return lpcc->pre_save(s);
+    }
+
+    return 0;
+}
+
+static int loongarch_pic_post_load(void *opaque, int version_id)
+{
+    LoongArchPICCommonState *s = (LoongArchPICCommonState *)opaque;
+    LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_GET_CLASS(s);
+
+    if (lpcc->post_load) {
+        return lpcc->post_load(s, version_id);
+    }
+
+    return 0;
+}
+
+static void loongarch_pic_common_realize(DeviceState *dev, Error **errp)
+{
+    LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(dev);
+
+    if (!s->irq_num || s->irq_num  > VIRT_PCH_PIC_IRQ_NUM) {
+        error_setg(errp, "Invalid 'pic_irq_num'");
+        return;
+    }
+}
+
+static const Property loongarch_pic_common_properties[] = {
+    DEFINE_PROP_UINT32("pch_pic_irq_num", LoongArchPICCommonState, irq_num, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_loongarch_pic_common = {
+    .name = "loongarch_pch_pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save  = loongarch_pic_pre_save,
+    .post_load = loongarch_pic_post_load,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT64(int_mask, LoongArchPICCommonState),
+        VMSTATE_UINT64(htmsi_en, LoongArchPICCommonState),
+        VMSTATE_UINT64(intedge, LoongArchPICCommonState),
+        VMSTATE_UINT64(intclr, LoongArchPICCommonState),
+        VMSTATE_UINT64(auto_crtl0, LoongArchPICCommonState),
+        VMSTATE_UINT64(auto_crtl1, LoongArchPICCommonState),
+        VMSTATE_UINT8_ARRAY(route_entry, LoongArchPICCommonState, 64),
+        VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPICCommonState, 64),
+        VMSTATE_UINT64(last_intirr, LoongArchPICCommonState),
+        VMSTATE_UINT64(intirr, LoongArchPICCommonState),
+        VMSTATE_UINT64(intisr, LoongArchPICCommonState),
+        VMSTATE_UINT64(int_polarity, LoongArchPICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void loongarch_pic_common_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass);
+
+    device_class_set_parent_realize(dc, loongarch_pic_common_realize,
+                                    &lpcc->parent_realize);
+    device_class_set_props(dc, loongarch_pic_common_properties);
+    dc->vmsd = &vmstate_loongarch_pic_common;
+}
+
+static const TypeInfo loongarch_pic_common_types[] = {
+    {
+        .name               = TYPE_LOONGARCH_PIC_COMMON,
+        .parent             = TYPE_SYS_BUS_DEVICE,
+        .instance_size      = sizeof(LoongArchPICCommonState),
+        .class_size         = sizeof(LoongArchPICCommonClass),
+        .class_init         = loongarch_pic_common_class_init,
+        .abstract           = true,
+    }
+};
+
+DEFINE_TYPES(loongarch_pic_common_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 6bfdc4eb33..510fdfb688 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -71,6 +71,6 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
 specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c'))
 specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
-specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c', 'loongarch_pic_common.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
-specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c', 'loongarch_extioi_common.c'))
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 9a635d1d3d..43a3e0d4d4 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -894,7 +894,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
     /* Add Extend I/O Interrupt Controller node */
     fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle);
 
-    pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
+    pch_pic = qdev_new(TYPE_LOONGARCH_PIC);
     num = VIRT_PCH_PIC_IRQ_NUM;
     qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
     d = SYS_BUS_DEVICE(pch_pic);
diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
index 626a37dfa1..351f18afcf 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -5,85 +5,23 @@
  * Copyright (C) 2021 Loongson Technology Corporation Limited
  */
 
-#include "hw/sysbus.h"
-#include "hw/loongarch/virt.h"
-
 #ifndef LOONGARCH_EXTIOI_H
 #define LOONGARCH_EXTIOI_H
 
-#define LS3A_INTC_IP               8
-#define EXTIOI_IRQS                (256)
-#define EXTIOI_IRQS_BITMAP_SIZE    (256 / 8)
-/* irq from EXTIOI is routed to no more than 4 cpus */
-#define EXTIOI_CPUS                (4)
-/* map to ipnum per 32 irqs */
-#define EXTIOI_IRQS_IPMAP_SIZE     (256 / 32)
-#define EXTIOI_IRQS_COREMAP_SIZE   256
-#define EXTIOI_IRQS_NODETYPE_COUNT  16
-#define EXTIOI_IRQS_GROUP_COUNT    8
-
-#define APIC_OFFSET                  0x400
-#define APIC_BASE                    (0x1000ULL + APIC_OFFSET)
+#include "hw/intc/loongarch_extioi_common.h"
 
-#define EXTIOI_NODETYPE_START        (0x4a0 - APIC_OFFSET)
-#define EXTIOI_NODETYPE_END          (0x4c0 - APIC_OFFSET)
-#define EXTIOI_IPMAP_START           (0x4c0 - APIC_OFFSET)
-#define EXTIOI_IPMAP_END             (0x4c8 - APIC_OFFSET)
-#define EXTIOI_ENABLE_START          (0x600 - APIC_OFFSET)
-#define EXTIOI_ENABLE_END            (0x620 - APIC_OFFSET)
-#define EXTIOI_BOUNCE_START          (0x680 - APIC_OFFSET)
-#define EXTIOI_BOUNCE_END            (0x6a0 - APIC_OFFSET)
-#define EXTIOI_ISR_START             (0x700 - APIC_OFFSET)
-#define EXTIOI_ISR_END               (0x720 - APIC_OFFSET)
-#define EXTIOI_COREISR_START         (0x800 - APIC_OFFSET)
-#define EXTIOI_COREISR_END           (0xB20 - APIC_OFFSET)
-#define EXTIOI_COREMAP_START         (0xC00 - APIC_OFFSET)
-#define EXTIOI_COREMAP_END           (0xD00 - APIC_OFFSET)
-#define EXTIOI_SIZE                  0x800
+#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
+OBJECT_DECLARE_TYPE(LoongArchExtIOIState, LoongArchExtIOIClass, LOONGARCH_EXTIOI)
 
-#define EXTIOI_VIRT_BASE             (0x40000000)
-#define EXTIOI_VIRT_SIZE             (0x1000)
-#define EXTIOI_VIRT_FEATURES         (0x0)
-#define  EXTIOI_HAS_VIRT_EXTENSION   (0)
-#define  EXTIOI_HAS_ENABLE_OPTION    (1)
-#define  EXTIOI_HAS_INT_ENCODE       (2)
-#define  EXTIOI_HAS_CPU_ENCODE       (3)
-#define  EXTIOI_VIRT_HAS_FEATURES    (BIT(EXTIOI_HAS_VIRT_EXTENSION)  \
-                                      | BIT(EXTIOI_HAS_ENABLE_OPTION) \
-                                      | BIT(EXTIOI_HAS_CPU_ENCODE))
-#define EXTIOI_VIRT_CONFIG           (0x4)
-#define  EXTIOI_ENABLE               (1)
-#define  EXTIOI_ENABLE_INT_ENCODE    (2)
-#define  EXTIOI_ENABLE_CPU_ENCODE    (3)
-#define EXTIOI_VIRT_COREMAP_START    (0x40)
-#define EXTIOI_VIRT_COREMAP_END      (0x240)
+struct LoongArchExtIOIState {
+    LoongArchExtIOICommonState parent_obj;
+};
 
-typedef struct ExtIOICore {
-    uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
-    DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
-    qemu_irq parent_irq[LS3A_INTC_IP];
-} ExtIOICore;
+struct LoongArchExtIOIClass {
+    LoongArchExtIOICommonClass parent_class;
 
-#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
-OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
-struct LoongArchExtIOI {
-    SysBusDevice parent_obj;
-    uint32_t num_cpu;
-    uint32_t features;
-    uint32_t status;
-    /* hardware state */
-    uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
-    uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
-    uint32_t isr[EXTIOI_IRQS / 32];
-    uint32_t enable[EXTIOI_IRQS / 32];
-    uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4];
-    uint32_t coremap[EXTIOI_IRQS / 4];
-    uint32_t sw_pending[EXTIOI_IRQS / 32];
-    uint8_t  sw_ipmap[EXTIOI_IRQS_IPMAP_SIZE];
-    uint8_t  sw_coremap[EXTIOI_IRQS];
-    qemu_irq irq[EXTIOI_IRQS];
-    ExtIOICore *cpu;
-    MemoryRegion extioi_system_mem;
-    MemoryRegion virt_extend;
+    DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
 };
+
 #endif /* LOONGARCH_EXTIOI_H */
diff --git a/include/hw/intc/loongarch_extioi_common.h b/include/hw/intc/loongarch_extioi_common.h
new file mode 100644
index 0000000000..f6bc778a85
--- /dev/null
+++ b/include/hw/intc/loongarch_extioi_common.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 3A5000 ext interrupt controller definitions
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#ifndef LOONGARCH_EXTIOI_COMMON_H
+#define LOONGARCH_EXTIOI_COMMON_H
+
+#include "qom/object.h"
+#include "hw/sysbus.h"
+#include "hw/loongarch/virt.h"
+
+#define LS3A_INTC_IP                 8
+#define EXTIOI_IRQS                  (256)
+#define EXTIOI_IRQS_BITMAP_SIZE      (256 / 8)
+/* irq from EXTIOI is routed to no more than 4 cpus */
+#define EXTIOI_CPUS                  (4)
+/* map to ipnum per 32 irqs */
+#define EXTIOI_IRQS_IPMAP_SIZE       (256 / 32)
+#define EXTIOI_IRQS_COREMAP_SIZE     256
+#define EXTIOI_IRQS_NODETYPE_COUNT   16
+#define EXTIOI_IRQS_GROUP_COUNT      8
+
+#define APIC_OFFSET                  0x400
+#define APIC_BASE                    (0x1000ULL + APIC_OFFSET)
+#define EXTIOI_NODETYPE_START        (0x4a0 - APIC_OFFSET)
+#define EXTIOI_NODETYPE_END          (0x4c0 - APIC_OFFSET)
+#define EXTIOI_IPMAP_START           (0x4c0 - APIC_OFFSET)
+#define EXTIOI_IPMAP_END             (0x4c8 - APIC_OFFSET)
+#define EXTIOI_ENABLE_START          (0x600 - APIC_OFFSET)
+#define EXTIOI_ENABLE_END            (0x620 - APIC_OFFSET)
+#define EXTIOI_BOUNCE_START          (0x680 - APIC_OFFSET)
+#define EXTIOI_BOUNCE_END            (0x6a0 - APIC_OFFSET)
+#define EXTIOI_ISR_START             (0x700 - APIC_OFFSET)
+#define EXTIOI_ISR_END               (0x720 - APIC_OFFSET)
+#define EXTIOI_COREISR_START         (0x800 - APIC_OFFSET)
+#define EXTIOI_COREISR_END           (0xB20 - APIC_OFFSET)
+#define EXTIOI_COREMAP_START         (0xC00 - APIC_OFFSET)
+#define EXTIOI_COREMAP_END           (0xD00 - APIC_OFFSET)
+#define EXTIOI_SIZE                  0x800
+
+#define EXTIOI_VIRT_BASE             (0x40000000)
+#define EXTIOI_VIRT_SIZE             (0x1000)
+#define EXTIOI_VIRT_FEATURES         (0x0)
+#define  EXTIOI_HAS_VIRT_EXTENSION   (0)
+#define  EXTIOI_HAS_ENABLE_OPTION    (1)
+#define  EXTIOI_HAS_INT_ENCODE       (2)
+#define  EXTIOI_HAS_CPU_ENCODE       (3)
+#define  EXTIOI_VIRT_HAS_FEATURES    (BIT(EXTIOI_HAS_VIRT_EXTENSION)  \
+                                      | BIT(EXTIOI_HAS_ENABLE_OPTION) \
+                                      | BIT(EXTIOI_HAS_CPU_ENCODE))
+#define EXTIOI_VIRT_CONFIG           (0x4)
+#define  EXTIOI_ENABLE               (1)
+#define  EXTIOI_ENABLE_INT_ENCODE    (2)
+#define  EXTIOI_ENABLE_CPU_ENCODE    (3)
+#define EXTIOI_VIRT_COREMAP_START    (0x40)
+#define EXTIOI_VIRT_COREMAP_END      (0x240)
+
+#define TYPE_LOONGARCH_EXTIOI_COMMON "loongarch_extioi_common"
+OBJECT_DECLARE_TYPE(LoongArchExtIOICommonState,
+                    LoongArchExtIOICommonClass, LOONGARCH_EXTIOI_COMMON)
+
+typedef struct ExtIOICore {
+    uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
+    DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
+    qemu_irq parent_irq[LS3A_INTC_IP];
+} ExtIOICore;
+
+struct LoongArchExtIOICommonState {
+    SysBusDevice parent_obj;
+    uint32_t num_cpu;
+    uint32_t features;
+    uint32_t status;
+    /* hardware state */
+    uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
+    uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
+    uint32_t isr[EXTIOI_IRQS / 32];
+    uint32_t enable[EXTIOI_IRQS / 32];
+    uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4];
+    uint32_t coremap[EXTIOI_IRQS / 4];
+    uint32_t sw_pending[EXTIOI_IRQS / 32];
+    uint8_t  sw_ipmap[EXTIOI_IRQS_IPMAP_SIZE];
+    uint8_t  sw_coremap[EXTIOI_IRQS];
+    qemu_irq irq[EXTIOI_IRQS];
+    ExtIOICore *cpu;
+    MemoryRegion extioi_system_mem;
+    MemoryRegion virt_extend;
+};
+
+struct LoongArchExtIOICommonClass {
+    SysBusDeviceClass parent_class;
+
+    DeviceRealize parent_realize;
+    int (*pre_save)(void *s);
+    int (*post_load)(void *s, int version_id);
+};
+#endif /* LOONGARCH_EXTIOI_H */
diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
index d5437e88f2..481cc58aed 100644
--- a/include/hw/intc/loongarch_pch_pic.h
+++ b/include/hw/intc/loongarch_pch_pic.h
@@ -5,65 +5,23 @@
  * Copyright (c) 2021 Loongson Technology Corporation Limited
  */
 
-#include "hw/sysbus.h"
+#ifndef HW_LOONGARCH_PCH_PIC_H
+#define HW_LOONGARCH_PCH_PIC_H
 
-#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
-#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
-OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
+#include "hw/intc/loongarch_pic_common.h"
 
-#define PCH_PIC_INT_ID_VAL              0x7000000UL
-#define PCH_PIC_INT_ID_VER              0x1UL
+#define TYPE_LOONGARCH_PIC  "loongarch_pic"
+#define PCH_PIC_NAME(name)  TYPE_LOONGARCH_PIC#name
+OBJECT_DECLARE_TYPE(LoongarchPICState, LoongarchPICClass, LOONGARCH_PIC)
 
-#define PCH_PIC_INT_ID_LO               0x00
-#define PCH_PIC_INT_ID_HI               0x04
-#define PCH_PIC_INT_MASK_LO             0x20
-#define PCH_PIC_INT_MASK_HI             0x24
-#define PCH_PIC_HTMSI_EN_LO             0x40
-#define PCH_PIC_HTMSI_EN_HI             0x44
-#define PCH_PIC_INT_EDGE_LO             0x60
-#define PCH_PIC_INT_EDGE_HI             0x64
-#define PCH_PIC_INT_CLEAR_LO            0x80
-#define PCH_PIC_INT_CLEAR_HI            0x84
-#define PCH_PIC_AUTO_CTRL0_LO           0xc0
-#define PCH_PIC_AUTO_CTRL0_HI           0xc4
-#define PCH_PIC_AUTO_CTRL1_LO           0xe0
-#define PCH_PIC_AUTO_CTRL1_HI           0xe4
-#define PCH_PIC_ROUTE_ENTRY_OFFSET      0x100
-#define PCH_PIC_ROUTE_ENTRY_END         0x13f
-#define PCH_PIC_HTMSI_VEC_OFFSET        0x200
-#define PCH_PIC_HTMSI_VEC_END           0x23f
-#define PCH_PIC_INT_STATUS_LO           0x3a0
-#define PCH_PIC_INT_STATUS_HI           0x3a4
-#define PCH_PIC_INT_POL_LO              0x3e0
-#define PCH_PIC_INT_POL_HI              0x3e4
-
-#define STATUS_LO_START                 0
-#define STATUS_HI_START                 0x4
-#define POL_LO_START                    0x40
-#define POL_HI_START                    0x44
-struct LoongArchPCHPIC {
-    SysBusDevice parent_obj;
-    qemu_irq parent_irq[64];
-    uint64_t int_mask; /*0x020 interrupt mask register*/
-    uint64_t htmsi_en; /*0x040 1=msi*/
-    uint64_t intedge; /*0x060 edge=1 level  =0*/
-    uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
-    uint64_t auto_crtl0; /*0x0c0*/
-    uint64_t auto_crtl1; /*0x0e0*/
-    uint64_t last_intirr;    /* edge detection */
-    uint64_t intirr; /* 0x380 interrupt request register */
-    uint64_t intisr; /* 0x3a0 interrupt service register */
-    /*
-     * 0x3e0 interrupt level polarity selection
-     * register 0 for high level trigger
-     */
-    uint64_t int_polarity;
+struct LoongarchPICState {
+    LoongArchPICCommonState parent_obj;
+};
 
-    uint8_t route_entry[64]; /*0x100 - 0x138*/
-    uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
+struct LoongarchPICClass {
+    LoongArchPICCommonClass parent_class;
 
-    MemoryRegion iomem32_low;
-    MemoryRegion iomem32_high;
-    MemoryRegion iomem8;
-    unsigned int irq_num;
+    DeviceRealize parent_realize;
 };
+
+#endif /* HW_LOONGARCH_PCH_PIC_H */
diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h
new file mode 100644
index 0000000000..43cce48978
--- /dev/null
+++ b/include/hw/intc/loongarch_pic_common.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 7A1000 I/O interrupt controller definitions
+ * Copyright (c) 2024 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_PIC_COMMON_H
+#define HW_LOONGARCH_PIC_COMMON_H
+
+#include "hw/pci-host/ls7a.h"
+#include "hw/sysbus.h"
+
+#define PCH_PIC_INT_ID_VAL              0x7000000UL
+#define PCH_PIC_INT_ID_VER              0x1UL
+#define PCH_PIC_INT_ID_LO               0x00
+#define PCH_PIC_INT_ID_HI               0x04
+#define PCH_PIC_INT_MASK_LO             0x20
+#define PCH_PIC_INT_MASK_HI             0x24
+#define PCH_PIC_HTMSI_EN_LO             0x40
+#define PCH_PIC_HTMSI_EN_HI             0x44
+#define PCH_PIC_INT_EDGE_LO             0x60
+#define PCH_PIC_INT_EDGE_HI             0x64
+#define PCH_PIC_INT_CLEAR_LO            0x80
+#define PCH_PIC_INT_CLEAR_HI            0x84
+#define PCH_PIC_AUTO_CTRL0_LO           0xc0
+#define PCH_PIC_AUTO_CTRL0_HI           0xc4
+#define PCH_PIC_AUTO_CTRL1_LO           0xe0
+#define PCH_PIC_AUTO_CTRL1_HI           0xe4
+#define PCH_PIC_ROUTE_ENTRY_OFFSET      0x100
+#define PCH_PIC_ROUTE_ENTRY_END         0x13f
+#define PCH_PIC_HTMSI_VEC_OFFSET        0x200
+#define PCH_PIC_HTMSI_VEC_END           0x23f
+#define PCH_PIC_INT_STATUS_LO           0x3a0
+#define PCH_PIC_INT_STATUS_HI           0x3a4
+#define PCH_PIC_INT_POL_LO              0x3e0
+#define PCH_PIC_INT_POL_HI              0x3e4
+
+#define STATUS_LO_START                 0
+#define STATUS_HI_START                 0x4
+#define POL_LO_START                    0x40
+#define POL_HI_START                    0x44
+
+#define TYPE_LOONGARCH_PIC_COMMON "loongarch_pic_common"
+OBJECT_DECLARE_TYPE(LoongArchPICCommonState,
+                    LoongArchPICCommonClass, LOONGARCH_PIC_COMMON)
+
+struct LoongArchPICCommonState {
+    SysBusDevice parent_obj;
+
+    qemu_irq parent_irq[64];
+    uint64_t int_mask;        /* 0x020 interrupt mask register */
+    uint64_t htmsi_en;        /* 0x040 1=msi */
+    uint64_t intedge;         /* 0x060 edge=1 level=0 */
+    uint64_t intclr;          /* 0x080 clean edge int, set 1 clean, 0 noused */
+    uint64_t auto_crtl0;      /* 0x0c0 */
+    uint64_t auto_crtl1;      /* 0x0e0 */
+    uint64_t last_intirr;     /* edge detection */
+    uint64_t intirr;          /* 0x380 interrupt request register */
+    uint64_t intisr;          /* 0x3a0 interrupt service register */
+    /*
+     * 0x3e0 interrupt level polarity selection
+     * register 0 for high level trigger
+     */
+    uint64_t int_polarity;
+
+    uint8_t route_entry[64];  /* 0x100 - 0x138 */
+    uint8_t htmsi_vector[64]; /* 0x200 - 0x238 */
+
+    MemoryRegion iomem32_low;
+    MemoryRegion iomem32_high;
+    MemoryRegion iomem8;
+    unsigned int irq_num;
+};
+
+struct LoongArchPICCommonClass {
+    SysBusDeviceClass parent_class;
+
+    DeviceRealize parent_realize;
+    int (*pre_save)(LoongArchPICCommonState *s);
+    int (*post_load)(LoongArchPICCommonState *s, int version_id);
+};
+#endif  /* HW_LOONGARCH_PIC_COMMON_H */