From 9d71149a64f0ab051575a3f534e80918a3ca8610 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 20 Jan 2025 10:49:19 +0800 Subject: hw/intc/loongarch_ipi: Add basic hotplug framework LoongArch ipi can send interrupt to multiple CPUs, interrupt routing to CPU comes from destination physical cpu id. Here hotplug interface is added for IPI object, so that parent irq line can be connected, and routing table can be added for new created cpu. Here only basic hotplug framework is added, it is stub function. Signed-off-by: Bibo Mao --- hw/intc/loongarch_ipi.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'hw/intc') diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index 5376f1e..90bbb7a 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -6,6 +6,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "hw/boards.h" #include "qapi/error.h" #include "hw/intc/loongarch_ipi.h" @@ -76,9 +77,34 @@ static void loongarch_ipi_realize(DeviceState *dev, Error **errp) } } +static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + + if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { + warn_report("LoongArch extioi: Invalid %s device type", + object_get_typename(obj)); + return; + } +} + +static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + + if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { + warn_report("LoongArch extioi: Invalid %s device type", + object_get_typename(obj)); + return; + } +} + static void loongarch_ipi_class_init(ObjectClass *klass, void *data) { LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); LoongarchIPIClass *lic = LOONGARCH_IPI_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -86,6 +112,8 @@ static void loongarch_ipi_class_init(ObjectClass *klass, void *data) &lic->parent_realize); licc->get_iocsr_as = get_iocsr_as; licc->cpu_by_arch_id = loongarch_cpu_by_arch_id; + hc->plug = loongarch_ipi_cpu_plug; + hc->unplug = loongarch_ipi_cpu_unplug; } static const TypeInfo loongarch_ipi_types[] = { @@ -95,6 +123,10 @@ static const TypeInfo loongarch_ipi_types[] = { .instance_size = sizeof(LoongarchIPIState), .class_size = sizeof(LoongarchIPIClass), .class_init = loongarch_ipi_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, } }; -- cgit v1.1 From 54492213e6a2be203afff03098a188a0a2413fc9 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 20 Jan 2025 12:02:30 +0800 Subject: hw/intc/loongarch_ipi: Implment cpu hotplug interface Add logic cpu allocation and cpu mapping with cpu hotplug interface. When cpu is added, connect ipi gpio irq to CPU IRQ_IPI irq pin. Signed-off-by: Bibo Mao --- hw/intc/loongarch_ipi.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'hw/intc') diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index 90bbb7a..b10641d 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -49,6 +49,22 @@ static int loongarch_cpu_by_arch_id(LoongsonIPICommonState *lics, return MEMTX_ERROR; } +static IPICore *loongarch_ipi_get_cpu(LoongsonIPICommonState *lics, + DeviceState *dev) +{ + CPUClass *k = CPU_GET_CLASS(dev); + uint64_t arch_id = k->get_arch_id(CPU(dev)); + int i; + + for (i = 0; i < lics->num_cpu; i++) { + if (lics->cpu[i].arch_id == arch_id) { + return &lics->cpu[i]; + } + } + + return NULL; +} + static void loongarch_ipi_realize(DeviceState *dev, Error **errp) { LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(dev); @@ -80,25 +96,48 @@ static void loongarch_ipi_realize(DeviceState *dev, Error **errp) static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev); Object *obj = OBJECT(dev); + IPICore *core; + int index; if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { warn_report("LoongArch extioi: Invalid %s device type", object_get_typename(obj)); return; } + + core = loongarch_ipi_get_cpu(lics, dev); + if (!core) { + return; + } + + core->cpu = CPU(dev); + index = core - lics->cpu; + + /* connect ipi irq to cpu irq */ + qdev_connect_gpio_out(DEVICE(lics), index, qdev_get_gpio_in(dev, IRQ_IPI)); } static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev); Object *obj = OBJECT(dev); + IPICore *core; if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { warn_report("LoongArch extioi: Invalid %s device type", object_get_typename(obj)); return; } + + core = loongarch_ipi_get_cpu(lics, dev); + if (!core) { + return; + } + + core->cpu = NULL; } static void loongarch_ipi_class_init(ObjectClass *klass, void *data) -- cgit v1.1 From 8b4b668f6a3661885fcabcedcf812930d5577f7e Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 10 Jan 2025 16:29:47 +0800 Subject: hw/intc/loongarch_extioi: Move gpio irq initial to common code When cpu is added, it will connect gpio irq line to cpu irq. And cpu hot-add is put in common code, move gpio irq initial part into common code. Signed-off-by: Bibo Mao --- hw/intc/loongarch_extioi.c | 8 +------- hw/intc/loongarch_extioi_common.c | 6 +++++- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index f3055ec..a51a215 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -343,7 +343,7 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp) LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_GET_CLASS(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); Error *local_err = NULL; - int i, pin; + int i; lec->parent_realize(dev, &local_err); if (local_err) { @@ -368,12 +368,6 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp) } else { s->status |= BIT(EXTIOI_ENABLE); } - - for (i = 0; i < s->num_cpu; i++) { - for (pin = 0; pin < LS3A_INTC_IP; pin++) { - qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1); - } - } } static void loongarch_extioi_unrealize(DeviceState *dev) diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c index fd56253..e3a38b3 100644 --- a/hw/intc/loongarch_extioi_common.c +++ b/hw/intc/loongarch_extioi_common.c @@ -16,7 +16,7 @@ static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp) MachineState *machine = MACHINE(qdev_get_machine()); MachineClass *mc = MACHINE_GET_CLASS(machine); const CPUArchIdList *id_list; - int i; + int i, pin; assert(mc->possible_cpu_arch_ids); id_list = mc->possible_cpu_arch_ids(machine); @@ -30,6 +30,10 @@ static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_cpu; i++) { s->cpu[i].arch_id = id_list->cpus[i].arch_id; s->cpu[i].cpu = CPU(id_list->cpus[i].cpu); + + for (pin = 0; pin < LS3A_INTC_IP; pin++) { + qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1); + } } } -- cgit v1.1 From e45c96b7d62513327324e801c325b5b6530f8e4a Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 10 Jan 2025 15:35:24 +0800 Subject: hw/intc/loongarch_extioi: Add basic hotplug framework LoongArch extioi interrupt controller routes peripheral interrupt to multiple CPUs, physical cpu id is used in interrupt routing table. Here hotplug interface is added for extioi object, so that parent irq line can be connected, and routing table can be added for new created cpu. Here only basic hotplug framework is added, it is stub function. Signed-off-by: Bibo Mao --- hw/intc/loongarch_extioi_common.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'hw/intc') diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c index e3a38b3..19e19a9 100644 --- a/hw/intc/loongarch_extioi_common.c +++ b/hw/intc/loongarch_extioi_common.c @@ -4,11 +4,37 @@ * Copyright (C) 2024 Loongson Technology Corporation Limited */ #include "qemu/osdep.h" +#include "qemu/error-report.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" +#include "target/loongarch/cpu.h" + +static void loongarch_extioi_cpu_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + + if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { + warn_report("LoongArch extioi: Invalid %s device type", + object_get_typename(obj)); + return; + } +} + +static void loongarch_extioi_cpu_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + + if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { + warn_report("LoongArch extioi: Invalid %s device type", + object_get_typename(obj)); + return; + } +} static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp) { @@ -107,11 +133,14 @@ static void loongarch_extioi_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_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; + hc->plug = loongarch_extioi_cpu_plug; + hc->unplug = loongarch_extioi_cpu_unplug; } static const TypeInfo loongarch_extioi_common_types[] = { @@ -121,6 +150,10 @@ static const TypeInfo loongarch_extioi_common_types[] = { .instance_size = sizeof(LoongArchExtIOICommonState), .class_size = sizeof(LoongArchExtIOICommonClass), .class_init = loongarch_extioi_common_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, .abstract = true, } }; -- cgit v1.1 From 8e63a7a7c2227ed014d55717c3a4de90bff426a8 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 10 Jan 2025 16:38:42 +0800 Subject: hw/intc/loongarch_extioi: Implment cpu hotplug interface When cpu is added, connect extioi gpio irq to CPU irq pin. Signed-off-by: Bibo Mao --- hw/intc/loongarch_extioi_common.c | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'hw/intc') diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c index 19e19a9..ff3974f 100644 --- a/hw/intc/loongarch_extioi_common.c +++ b/hw/intc/loongarch_extioi_common.c @@ -12,28 +12,73 @@ #include "migration/vmstate.h" #include "target/loongarch/cpu.h" +static ExtIOICore *loongarch_extioi_get_cpu(LoongArchExtIOICommonState *s, + DeviceState *dev) +{ + CPUClass *k = CPU_GET_CLASS(dev); + uint64_t arch_id = k->get_arch_id(CPU(dev)); + int i; + + for (i = 0; i < s->num_cpu; i++) { + if (s->cpu[i].arch_id == arch_id) { + return &s->cpu[i]; + } + } + + return NULL; +} + static void loongarch_extioi_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev); Object *obj = OBJECT(dev); + ExtIOICore *core; + int pin, index; if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { warn_report("LoongArch extioi: Invalid %s device type", object_get_typename(obj)); return; } + + core = loongarch_extioi_get_cpu(s, dev); + if (!core) { + return; + } + + core->cpu = CPU(dev); + index = core - s->cpu; + + /* + * connect extioi irq to the cpu irq + * cpu_pin[LS3A_INTC_IP + 2 : 2] <= intc_pin[LS3A_INTC_IP : 0] + */ + for (pin = 0; pin < LS3A_INTC_IP; pin++) { + qdev_connect_gpio_out(DEVICE(s), index * LS3A_INTC_IP + pin, + qdev_get_gpio_in(dev, pin + 2)); + } } static void loongarch_extioi_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev); Object *obj = OBJECT(dev); + ExtIOICore *core; if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { warn_report("LoongArch extioi: Invalid %s device type", object_get_typename(obj)); return; } + + core = loongarch_extioi_get_cpu(s, dev); + if (!core) { + return; + } + + core->cpu = NULL; } static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp) -- cgit v1.1