mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
loongarch queue
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQNhkKjomWfgLCz0aQfewwSUazn0QUCZ8ezJgAKCRAfewwSUazn 0T9pAQCKb+C69kbf9cEVg7PU/z5I0ALFtCNWCKxSkWZPDPik4gEA3IYwdrJ+csuX 8nWL0fzyk+8+LDzEwEgCYoNcMnttRQw= =P8mi -----END PGP SIGNATURE----- Merge tag 'pull-loongarch-20250305' of https://gitlab.com/bibo-mao/qemu into staging loongarch queue # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQQNhkKjomWfgLCz0aQfewwSUazn0QUCZ8ezJgAKCRAfewwSUazn # 0T9pAQCKb+C69kbf9cEVg7PU/z5I0ALFtCNWCKxSkWZPDPik4gEA3IYwdrJ+csuX # 8nWL0fzyk+8+LDzEwEgCYoNcMnttRQw= # =P8mi # -----END PGP SIGNATURE----- # gpg: Signature made Wed 05 Mar 2025 10:12:54 HKT # gpg: using EDDSA key 0D8642A3A2659F80B0B3D1A41F7B0C1251ACE7D1 # gpg: Good signature from "bibo mao <maobibo@loongson.cn>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 7044 3A00 19C0 E97A 31C7 13C4 8E86 8FB7 A176 9D4C # Subkey fingerprint: 0D86 42A3 A265 9F80 B0B3 D1A4 1F7B 0C12 51AC E7D1 * tag 'pull-loongarch-20250305' of https://gitlab.com/bibo-mao/qemu: target/loongarch: Adjust the cpu reset action to a proper position hw/loongarch/virt: Enable cpu hotplug feature on virt machine hw/loongarch/virt: Update the ACPI table for hotplug cpu hw/loongarch/virt: Implement cpu plug interface hw/loongarch/virt: Implement cpu unplug interface hw/loongarch/virt: Add basic cpu plug interface framework hw/loongarch/virt: Add topo properties on CPU object hw/loongarch/virt: Add CPU topology support hw/intc/loongarch_extioi: Use cpu plug notification hw/intc/loongarch_extioi: Implment cpu hotplug interface hw/intc/loongarch_extioi: Add basic hotplug framework hw/intc/loongarch_extioi: Move gpio irq initial to common code hw/intc/loongarch_ipi: Notify ipi object when cpu is plugged hw/intc/loongarch_ipi: Implment cpu hotplug interface hw/intc/loongarch_ipi: Add basic hotplug framework Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
cf2f8cf3b7
9 changed files with 493 additions and 44 deletions
|
@ -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)
|
||||
|
|
|
@ -4,11 +4,82 @@
|
|||
* 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 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)
|
||||
{
|
||||
|
@ -16,7 +87,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 +101,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,11 +178,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[] = {
|
||||
|
@ -117,6 +195,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,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
@ -48,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);
|
||||
|
@ -76,9 +93,57 @@ 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)
|
||||
{
|
||||
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 +151,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 +162,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 },
|
||||
{ }
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ config LOONGARCH_VIRT
|
|||
select LOONGARCH_EXTIOI
|
||||
select LS7A_RTC
|
||||
select SMBIOS
|
||||
select ACPI_CPU_HOTPLUG
|
||||
select ACPI_PCI
|
||||
select ACPI_HW_REDUCED
|
||||
select FW_CFG_DMA
|
||||
|
|
|
@ -47,6 +47,22 @@
|
|||
#define ACPI_BUILD_DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
static void virt_madt_cpu_entry(int uid,
|
||||
const CPUArchIdList *apic_ids,
|
||||
GArray *entry, bool force_enabled)
|
||||
{
|
||||
uint32_t flags, apic_id = apic_ids->cpus[uid].arch_id;
|
||||
|
||||
flags = apic_ids->cpus[uid].cpu || force_enabled ? 1 /* Enabled */ : 0;
|
||||
|
||||
/* Rev 1.0b, Table 5-13 Processor Local APIC Structure */
|
||||
build_append_int_noprefix(entry, 0, 1); /* Type */
|
||||
build_append_int_noprefix(entry, 8, 1); /* Length */
|
||||
build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */
|
||||
build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */
|
||||
build_append_int_noprefix(entry, flags, 4); /* Flags */
|
||||
}
|
||||
|
||||
/* build FADT */
|
||||
static void init_common_fadt_data(AcpiFadtData *data)
|
||||
{
|
||||
|
@ -112,7 +128,7 @@ build_madt(GArray *table_data, BIOSLinker *linker,
|
|||
MachineState *ms = MACHINE(lvms);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
|
||||
int i, arch_id;
|
||||
int i, arch_id, flags;
|
||||
AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id,
|
||||
.oem_table_id = lvms->oem_table_id };
|
||||
|
||||
|
@ -125,13 +141,13 @@ build_madt(GArray *table_data, BIOSLinker *linker,
|
|||
for (i = 0; i < arch_ids->len; i++) {
|
||||
/* Processor Core Interrupt Controller Structure */
|
||||
arch_id = arch_ids->cpus[i].arch_id;
|
||||
|
||||
flags = arch_ids->cpus[i].cpu ? 1 : 0;
|
||||
build_append_int_noprefix(table_data, 17, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 15, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Version */
|
||||
build_append_int_noprefix(table_data, i, 4); /* ACPI Processor ID */
|
||||
build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */
|
||||
build_append_int_noprefix(table_data, 1, 4); /* Flags */
|
||||
build_append_int_noprefix(table_data, flags, 4); /* Flags */
|
||||
}
|
||||
|
||||
/* Extend I/O Interrupt Controller Structure */
|
||||
|
@ -338,6 +354,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
|
|||
{
|
||||
uint32_t event;
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
CPUHotplugFeatures opts;
|
||||
|
||||
build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
|
||||
HOTPLUG_HANDLER(lvms->acpi_ged),
|
||||
|
@ -350,6 +367,18 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
|
|||
AML_SYSTEM_MEMORY,
|
||||
VIRT_GED_MEM_ADDR);
|
||||
}
|
||||
|
||||
if (event & ACPI_GED_CPU_HOTPLUG_EVT) {
|
||||
opts.acpi_1_compatible = false;
|
||||
opts.has_legacy_cphp = false;
|
||||
opts.fw_unplugs_cpu = false;
|
||||
opts.smi_path = NULL;
|
||||
|
||||
build_cpus_aml(dsdt, machine, opts, virt_madt_cpu_entry,
|
||||
VIRT_GED_CPUHP_ADDR, "\\_SB",
|
||||
AML_GED_EVT_CPU_SCAN_METHOD, AML_SYSTEM_MEMORY);
|
||||
}
|
||||
|
||||
acpi_dsdt_add_power_button(dsdt);
|
||||
}
|
||||
|
||||
|
|
|
@ -187,11 +187,17 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic,
|
|||
{
|
||||
DeviceState *dev;
|
||||
MachineState *ms = MACHINE(lvms);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(lvms);
|
||||
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
|
||||
|
||||
if (ms->ram_slots) {
|
||||
event |= ACPI_GED_MEM_HOTPLUG_EVT;
|
||||
}
|
||||
|
||||
if (mc->has_hotpluggable_cpus) {
|
||||
event |= ACPI_GED_CPU_HOTPLUG_EVT;
|
||||
}
|
||||
|
||||
dev = qdev_new(TYPE_ACPI_GED);
|
||||
qdev_prop_set_uint32(dev, "ged-event", event);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
@ -203,6 +209,10 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic,
|
|||
/* ged regs used for reset and power down */
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_GED_REG_ADDR);
|
||||
|
||||
if (mc->has_hotpluggable_cpus) {
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 3, VIRT_GED_CPUHP_ADDR);
|
||||
}
|
||||
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||
qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - VIRT_GSI_BASE));
|
||||
return dev;
|
||||
|
@ -312,11 +322,12 @@ static void virt_devices_init(DeviceState *pch_pic,
|
|||
|
||||
static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
|
||||
{
|
||||
int num, pin;
|
||||
int num;
|
||||
MachineState *ms = MACHINE(lvms);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
const CPUArchIdList *possible_cpus;
|
||||
CPUState *cs;
|
||||
Error *err = NULL;
|
||||
|
||||
/* cpu nodes */
|
||||
possible_cpus = mc->possible_cpu_arch_ids(ms);
|
||||
|
@ -326,18 +337,8 @@ static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* connect ipi irq to cpu irq */
|
||||
qdev_connect_gpio_out(lvms->ipi, num,
|
||||
qdev_get_gpio_in(DEVICE(cs), IRQ_IPI));
|
||||
|
||||
/*
|
||||
* connect ext irq to the cpu irq
|
||||
* cpu_pin[9:2] <= intc_pin[7:0]
|
||||
*/
|
||||
for (pin = 0; pin < LS3A_INTC_IP; pin++) {
|
||||
qdev_connect_gpio_out(lvms->extioi, (num * LS3A_INTC_IP + pin),
|
||||
qdev_get_gpio_in(DEVICE(cs), pin + 2));
|
||||
}
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), DEVICE(cs), &err);
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), DEVICE(cs), &err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,15 +657,13 @@ static void fw_cfg_add_memory(MachineState *ms)
|
|||
|
||||
static void virt_init(MachineState *machine)
|
||||
{
|
||||
LoongArchCPU *lacpu;
|
||||
const char *cpu_model = machine->cpu_type;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
||||
int i;
|
||||
hwaddr base, size, ram_size = machine->ram_size;
|
||||
const CPUArchIdList *possible_cpus;
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
CPUState *cpu;
|
||||
Object *cpuobj;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
|
||||
|
@ -680,14 +679,15 @@ static void virt_init(MachineState *machine)
|
|||
memory_region_add_subregion(&lvms->system_iocsr, 0, &lvms->iocsr_mem);
|
||||
|
||||
/* Init CPUs */
|
||||
possible_cpus = mc->possible_cpu_arch_ids(machine);
|
||||
for (i = 0; i < possible_cpus->len; i++) {
|
||||
cpu = cpu_create(machine->cpu_type);
|
||||
cpu->cpu_index = i;
|
||||
machine->possible_cpus->cpus[i].cpu = cpu;
|
||||
lacpu = LOONGARCH_CPU(cpu);
|
||||
lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
|
||||
lacpu->env.address_space_iocsr = &lvms->as_iocsr;
|
||||
mc->possible_cpu_arch_ids(machine);
|
||||
for (i = 0; i < machine->smp.cpus; i++) {
|
||||
cpuobj = object_new(machine->cpu_type);
|
||||
if (cpuobj == NULL) {
|
||||
error_report("Fail to create object with type %s ",
|
||||
machine->cpu_type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
qdev_realize_and_unref(DEVICE(cpuobj), NULL, &error_fatal);
|
||||
}
|
||||
fw_cfg_add_memory(machine);
|
||||
|
||||
|
@ -783,6 +783,232 @@ static void virt_initfn(Object *obj)
|
|||
virt_flash_create(lvms);
|
||||
}
|
||||
|
||||
static void virt_get_topo_from_index(MachineState *ms,
|
||||
LoongArchCPUTopo *topo, int index)
|
||||
{
|
||||
topo->socket_id = index / (ms->smp.cores * ms->smp.threads);
|
||||
topo->core_id = index / ms->smp.threads % ms->smp.cores;
|
||||
topo->thread_id = index % ms->smp.threads;
|
||||
}
|
||||
|
||||
static unsigned int topo_align_up(unsigned int count)
|
||||
{
|
||||
g_assert(count >= 1);
|
||||
count -= 1;
|
||||
return BIT(count ? 32 - clz32(count) : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* LoongArch Reference Manual Vol1, Chapter 7.4.12 CPU Identity
|
||||
* For CPU architecture, bit0 .. bit8 is valid for CPU id, max cpuid is 512
|
||||
* However for IPI/Eiointc interrupt controller, max supported cpu id for
|
||||
* irq routingis 256
|
||||
*
|
||||
* Here max cpu id is 256 for virt machine
|
||||
*/
|
||||
static int virt_get_arch_id_from_topo(MachineState *ms, LoongArchCPUTopo *topo)
|
||||
{
|
||||
int arch_id, threads, cores, sockets;
|
||||
|
||||
threads = topo_align_up(ms->smp.threads);
|
||||
cores = topo_align_up(ms->smp.cores);
|
||||
sockets = topo_align_up(ms->smp.sockets);
|
||||
if ((threads * cores * sockets) > 256) {
|
||||
error_report("Exceeding max cpuid 256 with sockets[%d] cores[%d]"
|
||||
" threads[%d]", ms->smp.sockets, ms->smp.cores,
|
||||
ms->smp.threads);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
arch_id = topo->thread_id + topo->core_id * threads;
|
||||
arch_id += topo->socket_id * threads * cores;
|
||||
return arch_id;
|
||||
}
|
||||
|
||||
/* Find cpu slot in machine->possible_cpus by arch_id */
|
||||
static CPUArchId *virt_find_cpu_slot(MachineState *ms, int arch_id)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < ms->possible_cpus->len; n++) {
|
||||
if (ms->possible_cpus->cpus[n].arch_id == arch_id) {
|
||||
return &ms->possible_cpus->cpus[n];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find cpu slot for cold-plut CPU object where cpu is NULL */
|
||||
static CPUArchId *virt_find_empty_cpu_slot(MachineState *ms)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < ms->possible_cpus->len; n++) {
|
||||
if (ms->possible_cpus->cpus[n].cpu == NULL) {
|
||||
return &ms->possible_cpus->cpus[n];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
||||
MachineState *ms = MACHINE(OBJECT(hotplug_dev));
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(dev);
|
||||
CPUState *cs = CPU(dev);
|
||||
CPUArchId *cpu_slot;
|
||||
Error *err = NULL;
|
||||
LoongArchCPUTopo topo;
|
||||
int arch_id;
|
||||
|
||||
if (lvms->acpi_ged) {
|
||||
if ((cpu->thread_id < 0) || (cpu->thread_id >= ms->smp.threads)) {
|
||||
error_setg(&err,
|
||||
"Invalid thread-id %u specified, must be in range 1:%u",
|
||||
cpu->thread_id, ms->smp.threads - 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((cpu->core_id < 0) || (cpu->core_id >= ms->smp.cores)) {
|
||||
error_setg(&err,
|
||||
"Invalid core-id %u specified, must be in range 1:%u",
|
||||
cpu->core_id, ms->smp.cores - 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((cpu->socket_id < 0) || (cpu->socket_id >= ms->smp.sockets)) {
|
||||
error_setg(&err,
|
||||
"Invalid socket-id %u specified, must be in range 1:%u",
|
||||
cpu->socket_id, ms->smp.sockets - 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
topo.socket_id = cpu->socket_id;
|
||||
topo.core_id = cpu->core_id;
|
||||
topo.thread_id = cpu->thread_id;
|
||||
arch_id = virt_get_arch_id_from_topo(ms, &topo);
|
||||
cpu_slot = virt_find_cpu_slot(ms, arch_id);
|
||||
if (CPU(cpu_slot->cpu)) {
|
||||
error_setg(&err,
|
||||
"cpu(id%d=%d:%d:%d) with arch-id %" PRIu64 " exists",
|
||||
cs->cpu_index, cpu->socket_id, cpu->core_id,
|
||||
cpu->thread_id, cpu_slot->arch_id);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* For cold-add cpu, find empty cpu slot */
|
||||
cpu_slot = virt_find_empty_cpu_slot(ms);
|
||||
topo.socket_id = cpu_slot->props.socket_id;
|
||||
topo.core_id = cpu_slot->props.core_id;
|
||||
topo.thread_id = cpu_slot->props.thread_id;
|
||||
object_property_set_int(OBJECT(dev), "socket-id", topo.socket_id, NULL);
|
||||
object_property_set_int(OBJECT(dev), "core-id", topo.core_id, NULL);
|
||||
object_property_set_int(OBJECT(dev), "thread-id", topo.thread_id, NULL);
|
||||
}
|
||||
|
||||
cpu->env.address_space_iocsr = &lvms->as_iocsr;
|
||||
cpu->phy_id = cpu_slot->arch_id;
|
||||
cs->cpu_index = cpu_slot - ms->possible_cpus->cpus;
|
||||
numa_cpu_pre_plug(cpu_slot, dev, &err);
|
||||
out:
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
||||
Error *err = NULL;
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(dev);
|
||||
CPUState *cs = CPU(dev);
|
||||
|
||||
if (cs->cpu_index == 0) {
|
||||
error_setg(&err, "hot-unplug of boot cpu(id%d=%d:%d:%d) not supported",
|
||||
cs->cpu_index, cpu->socket_id,
|
||||
cpu->core_id, cpu->thread_id);
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_cpu_unplug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUArchId *cpu_slot;
|
||||
Error *err = NULL;
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(dev);
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
||||
|
||||
/* Notify ipi and extioi irqchip to remove interrupt routing to CPU */
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->ipi), dev, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->extioi), dev, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Notify acpi ged CPU removed */
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id);
|
||||
cpu_slot->cpu = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
static void virt_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUArchId *cpu_slot;
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(dev);
|
||||
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
||||
Error *err = NULL;
|
||||
|
||||
cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id);
|
||||
cpu_slot->cpu = CPU(dev);
|
||||
if (lvms->ipi) {
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), dev, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (lvms->extioi) {
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), dev, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (lvms->acpi_ged) {
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static bool memhp_type_supported(DeviceState *dev)
|
||||
{
|
||||
/* we only support pc dimm now */
|
||||
|
@ -801,6 +1027,8 @@ static void virt_device_pre_plug(HotplugHandler *hotplug_dev,
|
|||
{
|
||||
if (memhp_type_supported(dev)) {
|
||||
virt_mem_pre_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
|
||||
virt_cpu_pre_plug(hotplug_dev, dev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -819,6 +1047,8 @@ static void virt_device_unplug_request(HotplugHandler *hotplug_dev,
|
|||
{
|
||||
if (memhp_type_supported(dev)) {
|
||||
virt_mem_unplug_request(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
|
||||
virt_cpu_unplug_request(hotplug_dev, dev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -837,6 +1067,8 @@ static void virt_device_unplug(HotplugHandler *hotplug_dev,
|
|||
{
|
||||
if (memhp_type_supported(dev)) {
|
||||
virt_mem_unplug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
|
||||
virt_cpu_unplug(hotplug_dev, dev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -864,6 +1096,8 @@ static void virt_device_plug_cb(HotplugHandler *hotplug_dev,
|
|||
}
|
||||
} else if (memhp_type_supported(dev)) {
|
||||
virt_mem_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
|
||||
virt_cpu_plug(hotplug_dev, dev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -873,6 +1107,7 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine,
|
|||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
|
||||
if (device_is_dynamic_sysbus(mc, dev) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
|
||||
memhp_type_supported(dev)) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
|
@ -882,8 +1117,9 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine,
|
|||
|
||||
static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
|
||||
{
|
||||
int n;
|
||||
int n, arch_id;
|
||||
unsigned int max_cpus = ms->smp.max_cpus;
|
||||
LoongArchCPUTopo topo;
|
||||
|
||||
if (ms->possible_cpus) {
|
||||
assert(ms->possible_cpus->len == max_cpus);
|
||||
|
@ -894,17 +1130,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
|
|||
sizeof(CPUArchId) * max_cpus);
|
||||
ms->possible_cpus->len = max_cpus;
|
||||
for (n = 0; n < ms->possible_cpus->len; n++) {
|
||||
virt_get_topo_from_index(ms, &topo, n);
|
||||
arch_id = virt_get_arch_id_from_topo(ms, &topo);
|
||||
ms->possible_cpus->cpus[n].type = ms->cpu_type;
|
||||
ms->possible_cpus->cpus[n].arch_id = n;
|
||||
|
||||
ms->possible_cpus->cpus[n].arch_id = arch_id;
|
||||
ms->possible_cpus->cpus[n].vcpus_count = 1;
|
||||
ms->possible_cpus->cpus[n].props.has_socket_id = true;
|
||||
ms->possible_cpus->cpus[n].props.socket_id =
|
||||
n / (ms->smp.cores * ms->smp.threads);
|
||||
ms->possible_cpus->cpus[n].props.socket_id = topo.socket_id;
|
||||
ms->possible_cpus->cpus[n].props.has_core_id = true;
|
||||
ms->possible_cpus->cpus[n].props.core_id =
|
||||
n / ms->smp.threads % ms->smp.cores;
|
||||
ms->possible_cpus->cpus[n].props.core_id = topo.core_id;
|
||||
ms->possible_cpus->cpus[n].props.has_thread_id = true;
|
||||
ms->possible_cpus->cpus[n].props.thread_id = n % ms->smp.threads;
|
||||
ms->possible_cpus->cpus[n].props.thread_id = topo.thread_id;
|
||||
}
|
||||
return ms->possible_cpus;
|
||||
}
|
||||
|
@ -952,6 +1188,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
|
|||
mc->numa_mem_supported = true;
|
||||
mc->auto_enable_numa_with_memhp = true;
|
||||
mc->auto_enable_numa_with_memdev = true;
|
||||
mc->has_hotpluggable_cpus = true;
|
||||
mc->get_hotplug_handler = virt_get_hotplug_handler;
|
||||
mc->default_nic = "virtio-net-pci";
|
||||
hc->plug = virt_device_plug_cb;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#define VIRT_GED_EVT_ADDR 0x100e0000
|
||||
#define VIRT_GED_MEM_ADDR (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN)
|
||||
#define VIRT_GED_REG_ADDR (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN)
|
||||
#define VIRT_GED_CPUHP_ADDR (VIRT_GED_REG_ADDR + ACPI_GED_REG_COUNT)
|
||||
|
||||
#define COMMAND_LINE_SIZE 512
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "system/tcg.h"
|
||||
#include "system/kvm.h"
|
||||
#include "kvm/kvm_loongarch.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/translation-block.h"
|
||||
#include "cpu.h"
|
||||
|
@ -640,12 +641,23 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
|
||||
loongarch_cpu_register_gdb_regs_for_features(cs);
|
||||
|
||||
cpu_reset(cs);
|
||||
qemu_init_vcpu(cs);
|
||||
cpu_reset(cs);
|
||||
|
||||
lacc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void loongarch_cpu_unrealizefn(DeviceState *dev)
|
||||
{
|
||||
LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cpu_remove_sync(CPU(dev));
|
||||
#endif
|
||||
|
||||
lacc->parent_unrealize(dev);
|
||||
}
|
||||
|
||||
static bool loongarch_get_lsx(Object *obj, Error **errp)
|
||||
{
|
||||
return LOONGARCH_CPU(obj)->lsx != ON_OFF_AUTO_OFF;
|
||||
|
@ -879,6 +891,13 @@ static int64_t loongarch_cpu_get_arch_id(CPUState *cs)
|
|||
}
|
||||
#endif
|
||||
|
||||
static const Property loongarch_cpu_properties[] = {
|
||||
DEFINE_PROP_INT32("socket-id", LoongArchCPU, socket_id, 0),
|
||||
DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, 0),
|
||||
DEFINE_PROP_INT32("thread-id", LoongArchCPU, thread_id, 0),
|
||||
DEFINE_PROP_INT32("node-id", LoongArchCPU, node_id, CPU_UNSET_NUMA_NODE_ID),
|
||||
};
|
||||
|
||||
static void loongarch_cpu_class_init(ObjectClass *c, void *data)
|
||||
{
|
||||
LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
|
||||
|
@ -886,8 +905,11 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
|
|||
DeviceClass *dc = DEVICE_CLASS(c);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(c);
|
||||
|
||||
device_class_set_props(dc, loongarch_cpu_properties);
|
||||
device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
|
||||
&lacc->parent_realize);
|
||||
device_class_set_parent_unrealize(dc, loongarch_cpu_unrealizefn,
|
||||
&lacc->parent_unrealize);
|
||||
resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL,
|
||||
&lacc->parent_phases);
|
||||
|
||||
|
@ -910,6 +932,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
|
|||
#ifdef CONFIG_TCG
|
||||
cc->tcg_ops = &loongarch_tcg_ops;
|
||||
#endif
|
||||
dc->user_creatable = true;
|
||||
}
|
||||
|
||||
static const gchar *loongarch32_gdb_arch_name(CPUState *cs)
|
||||
|
|
|
@ -393,6 +393,12 @@ typedef struct CPUArchState {
|
|||
#endif
|
||||
} CPULoongArchState;
|
||||
|
||||
typedef struct LoongArchCPUTopo {
|
||||
int32_t socket_id; /* socket-id of this VCPU */
|
||||
int32_t core_id; /* core-id of this VCPU */
|
||||
int32_t thread_id; /* thread-id of this VCPU */
|
||||
} LoongArchCPUTopo;
|
||||
|
||||
/**
|
||||
* LoongArchCPU:
|
||||
* @env: #CPULoongArchState
|
||||
|
@ -411,6 +417,10 @@ struct ArchCPU {
|
|||
OnOffAuto lasx;
|
||||
OnOffAuto kvm_pv_ipi;
|
||||
OnOffAuto kvm_steal_time;
|
||||
int32_t socket_id; /* socket-id of this CPU */
|
||||
int32_t core_id; /* core-id of this CPU */
|
||||
int32_t thread_id; /* thread-id of this CPU */
|
||||
int32_t node_id; /* NUMA node of this CPU */
|
||||
|
||||
/* 'compatible' string for this CPU for Linux device trees */
|
||||
const char *dtb_compatible;
|
||||
|
@ -429,6 +439,7 @@ struct LoongArchCPUClass {
|
|||
CPUClass parent_class;
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
DeviceUnrealize parent_unrealize;
|
||||
ResettablePhases parent_phases;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue