[PATCH v3 1/3] hw/intc/loongarch_extioi: Add extioi virt extension definition

Song Gao posted 3 patches 6 months, 1 week ago
There is a newer version of this series
[PATCH v3 1/3] hw/intc/loongarch_extioi: Add extioi virt extension definition
Posted by Song Gao 6 months, 1 week ago
On LoongArch, IRQs can be routed to four vcpus with hardware extioi.
This patch adds the extioi virt extension definition so that the IRQ can
route to 256 vcpus.

Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 include/hw/intc/loongarch_extioi.h | 21 +++++++
 hw/intc/loongarch_extioi.c         | 88 ++++++++++++++++++++++++++++--
 2 files changed, 105 insertions(+), 4 deletions(-)

diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
index 410c6e1121..eccc2e0d18 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -41,6 +41,24 @@
 #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_INT_ENCODE)    \
+                                      | 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)
+
 typedef struct ExtIOICore {
     uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
     DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
@@ -52,6 +70,8 @@ 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];
@@ -65,5 +85,6 @@ struct LoongArchExtIOI {
     qemu_irq irq[EXTIOI_IRQS];
     ExtIOICore *cpu;
     MemoryRegion extioi_system_mem;
+    MemoryRegion virt_extend;
 };
 #endif /* LOONGARCH_EXTIOI_H */
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 0b358548eb..e605ca64d5 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -143,10 +143,13 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
 
     for (i = 0; i < 4; i++) {
         cpu = val & 0xff;
-        cpu = ctz32(cpu);
-        cpu = (cpu >= 4) ? 0 : cpu;
         val = val >> 8;
 
+        if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) {
+            cpu = ctz32(cpu);
+            cpu = (cpu >= 4) ? 0 : cpu;
+        }
+
         if (s->sw_coremap[irq + i] == cpu) {
             continue;
         }
@@ -265,6 +268,61 @@ static const MemoryRegionOps extioi_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data,
+                                     unsigned size, MemTxAttrs attrs)
+{
+    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+
+    switch (addr) {
+    case EXTIOI_VIRT_FEATURES:
+        *data = s->features;
+        break;
+    case EXTIOI_VIRT_CONFIG:
+        *data = s->status;
+        break;
+    default:
+        break;
+    }
+
+    return MEMTX_OK;
+}
+
+static MemTxResult extioi_virt_writew(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned size,
+                          MemTxAttrs attrs)
+{
+    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+
+    switch (addr) {
+    case EXTIOI_VIRT_FEATURES:
+        return MEMTX_ACCESS_ERROR;
+
+    case EXTIOI_VIRT_CONFIG:
+        /*
+         * extioi features can only be set at disabled status
+         */
+        if ((s->status & BIT(EXTIOI_ENABLE)) && val) {
+            return MEMTX_ACCESS_ERROR;
+        }
+
+        s->status = val & s->features;
+        break;
+    default:
+        break;
+    }
+    return MEMTX_OK;
+}
+
+static const MemoryRegionOps extioi_virt_ops = {
+    .read_with_attrs = extioi_virt_readw,
+    .write_with_attrs = extioi_virt_writew,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 8,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
 {
     LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
@@ -284,6 +342,16 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
     memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
                           s, "extioi_system_mem", 0x900);
     sysbus_init_mmio(sbd, &s->extioi_system_mem);
+
+    if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
+        memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
+                              s, "extioi_virt", EXTIOI_VIRT_SIZE);
+        sysbus_init_mmio(sbd, &s->virt_extend);
+        s->features |= EXTIOI_VIRT_HAS_FEATURES;
+    } else {
+        s->status |= BIT(EXTIOI_ENABLE);
+    }
+
     s->cpu = g_new0(ExtIOICore, s->num_cpu);
     if (s->cpu == NULL) {
         error_setg(errp, "Memory allocation for ExtIOICore faile");
@@ -304,6 +372,13 @@ static void loongarch_extioi_finalize(Object *obj)
     g_free(s->cpu);
 }
 
+static void loongarch_extioi_reset(DeviceState *d)
+{
+    LoongArchExtIOI *s = LOONGARCH_EXTIOI(d);
+
+    s->status = 0;
+}
+
 static int vmstate_extioi_post_load(void *opaque, int version_id)
 {
     LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
@@ -333,8 +408,8 @@ static const VMStateDescription vmstate_extioi_core = {
 
 static const VMStateDescription vmstate_loongarch_extioi = {
     .name = TYPE_LOONGARCH_EXTIOI,
-    .version_id = 2,
-    .minimum_version_id = 2,
+    .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),
@@ -347,12 +422,16 @@ static const VMStateDescription vmstate_loongarch_extioi = {
 
         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 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(),
 };
 
@@ -361,6 +440,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = loongarch_extioi_realize;
+    dc->reset   = loongarch_extioi_reset;
     device_class_set_props(dc, extioi_properties);
     dc->vmsd = &vmstate_loongarch_extioi;
 }
-- 
2.34.1
Re: [PATCH v3 1/3] hw/intc/loongarch_extioi: Add extioi virt extension definition
Posted by maobibo 6 months ago
On 2024/5/21 下午8:32, Song Gao wrote:
> On LoongArch, IRQs can be routed to four vcpus with hardware extioi.
> This patch adds the extioi virt extension definition so that the IRQ can
> route to 256 vcpus.
> 
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   include/hw/intc/loongarch_extioi.h | 21 +++++++
>   hw/intc/loongarch_extioi.c         | 88 ++++++++++++++++++++++++++++--
>   2 files changed, 105 insertions(+), 4 deletions(-)
> 
> diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
> index 410c6e1121..eccc2e0d18 100644
> --- a/include/hw/intc/loongarch_extioi.h
> +++ b/include/hw/intc/loongarch_extioi.h
> @@ -41,6 +41,24 @@
>   #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_INT_ENCODE)    \
> +                                      | 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)
> +
>   typedef struct ExtIOICore {
>       uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
>       DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
> @@ -52,6 +70,8 @@ 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];
> @@ -65,5 +85,6 @@ struct LoongArchExtIOI {
>       qemu_irq irq[EXTIOI_IRQS];
>       ExtIOICore *cpu;
>       MemoryRegion extioi_system_mem;
> +    MemoryRegion virt_extend;
>   };
>   #endif /* LOONGARCH_EXTIOI_H */
> diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
> index 0b358548eb..e605ca64d5 100644
> --- a/hw/intc/loongarch_extioi.c
> +++ b/hw/intc/loongarch_extioi.c
> @@ -143,10 +143,13 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
>   
>       for (i = 0; i < 4; i++) {
>           cpu = val & 0xff;
> -        cpu = ctz32(cpu);
> -        cpu = (cpu >= 4) ? 0 : cpu;
>           val = val >> 8;
>   
> +        if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) {
> +            cpu = ctz32(cpu);
> +            cpu = (cpu >= 4) ? 0 : cpu;
> +        }
> +
>           if (s->sw_coremap[irq + i] == cpu) {
>               continue;
>           }
> @@ -265,6 +268,61 @@ static const MemoryRegionOps extioi_ops = {
>       .endianness = DEVICE_LITTLE_ENDIAN,
>   };
>   
> +static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data,
> +                                     unsigned size, MemTxAttrs attrs)
> +{
> +    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> +
> +    switch (addr) {
> +    case EXTIOI_VIRT_FEATURES:
> +        *data = s->features;
> +        break;
> +    case EXTIOI_VIRT_CONFIG:
> +        *data = s->status;
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult extioi_virt_writew(void *opaque, hwaddr addr,
> +                          uint64_t val, unsigned size,
> +                          MemTxAttrs attrs)
> +{
> +    LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> +
> +    switch (addr) {
> +    case EXTIOI_VIRT_FEATURES:
> +        return MEMTX_ACCESS_ERROR;
> +
> +    case EXTIOI_VIRT_CONFIG:
> +        /*
> +         * extioi features can only be set at disabled status
> +         */
> +        if ((s->status & BIT(EXTIOI_ENABLE)) && val) {
> +            return MEMTX_ACCESS_ERROR;
> +        }
> +
> +        s->status = val & s->features;
> +        break;
> +    default:
> +        break;
> +    }
> +    return MEMTX_OK;
> +}
> +
> +static const MemoryRegionOps extioi_virt_ops = {
> +    .read_with_attrs = extioi_virt_readw,
> +    .write_with_attrs = extioi_virt_writew,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +    .valid.min_access_size = 4,
> +    .valid.max_access_size = 8,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
>   static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
>   {
>       LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
> @@ -284,6 +342,16 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
>       memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
>                             s, "extioi_system_mem", 0x900);
>       sysbus_init_mmio(sbd, &s->extioi_system_mem);
> +
> +    if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
> +        memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
> +                              s, "extioi_virt", EXTIOI_VIRT_SIZE);
> +        sysbus_init_mmio(sbd, &s->virt_extend);
> +        s->features |= EXTIOI_VIRT_HAS_FEATURES;
> +    } else {
> +        s->status |= BIT(EXTIOI_ENABLE);
> +    }
> +
>       s->cpu = g_new0(ExtIOICore, s->num_cpu);
>       if (s->cpu == NULL) {
>           error_setg(errp, "Memory allocation for ExtIOICore faile");
> @@ -304,6 +372,13 @@ static void loongarch_extioi_finalize(Object *obj)
>       g_free(s->cpu);
>   }
>   
> +static void loongarch_extioi_reset(DeviceState *d)
> +{
> +    LoongArchExtIOI *s = LOONGARCH_EXTIOI(d);
> +
> +    s->status = 0;
> +}
> +
>   static int vmstate_extioi_post_load(void *opaque, int version_id)
>   {
>       LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> @@ -333,8 +408,8 @@ static const VMStateDescription vmstate_extioi_core = {
>   
>   static const VMStateDescription vmstate_loongarch_extioi = {
>       .name = TYPE_LOONGARCH_EXTIOI,
> -    .version_id = 2,
> -    .minimum_version_id = 2,
> +    .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),
> @@ -347,12 +422,16 @@ static const VMStateDescription vmstate_loongarch_extioi = {
>   
>           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 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(),
>   };
>   
> @@ -361,6 +440,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
>       DeviceClass *dc = DEVICE_CLASS(klass);
>   
>       dc->realize = loongarch_extioi_realize;
> +    dc->reset   = loongarch_extioi_reset;
>       device_class_set_props(dc, extioi_properties);
>       dc->vmsd = &vmstate_loongarch_extioi;
>   }
> 
Reviewed-by: Bibo Mao <maobibo@loongson.cn>