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 | 92 ++++++++++++++++++++++++++++--
2 files changed, 109 insertions(+), 4 deletions(-)
diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
index 410c6e1121..d4646fab9f 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..89afdb1c3c 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,16 @@ static void loongarch_extioi_finalize(Object *obj)
g_free(s->cpu);
}
+static void loongarch_extioi_reset(DeviceState *d)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(d);
+
+ /* use legacy interrupt routing method by default */
+ if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
+ s->status = 0;
+ }
+}
+
static int vmstate_extioi_post_load(void *opaque, int version_id)
{
LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
@@ -333,8 +411,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 +425,17 @@ 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 +444,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.25.1
On 2024/5/14 下午5:07, 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 | 92 ++++++++++++++++++++++++++++-- > 2 files changed, 109 insertions(+), 4 deletions(-) > > diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h > index 410c6e1121..d4646fab9f 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..89afdb1c3c 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,16 @@ static void loongarch_extioi_finalize(Object *obj) > g_free(s->cpu); > } > > +static void loongarch_extioi_reset(DeviceState *d) > +{ > + LoongArchExtIOI *s = LOONGARCH_EXTIOI(d); > + > + /* use legacy interrupt routing method by default */ > + if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) { > + s->status = 0; > + } How about clear status without checking with BIT(EXTIOI_HAS_VIRT_EXTENSION)? > +} > + > static int vmstate_extioi_post_load(void *opaque, int version_id) > { > LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque); > @@ -333,8 +411,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 +425,17 @@ static const VMStateDescription vmstate_loongarch_extioi = { > > VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOI, num_cpu, > vmstate_extioi_core, ExtIOICore), > + It seems that there is redundant empty line. Regards Bibo Mao > + 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 +444,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; > } >
© 2016 - 2024 Red Hat, Inc.