On LoongArch virt machine, ACPI GED hardware is used for cpu
hotplug, here cpu hotplug support feature is added on GED device,
also cpu scan and reject method is added about CPU device in
DSDT table.
Co-developed-by: Xianglai Li <lixianglai@loongson.cn>
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
hw/loongarch/Kconfig | 1 +
hw/loongarch/acpi-build.c | 35 +++++++++++++++++++++++++++++++++--
hw/loongarch/virt.c | 10 ++++++++++
include/hw/loongarch/virt.h | 1 +
4 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index fe1c6feac1..bb2838b7b5 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -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
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 50709bda0f..c220edec68 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -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)
{
@@ -123,15 +139,17 @@ build_madt(GArray *table_data, BIOSLinker *linker,
build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
for (i = 0; i < arch_ids->len; i++) {
+ uint32_t flags;
+
/* 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 */
@@ -334,6 +352,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),
@@ -346,6 +365,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);
}
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 28a46bf195..655312b0fe 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -652,11 +652,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);
@@ -668,6 +674,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;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 9ba47793ef..861034d614 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -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
--
2.39.3
© 2016 - 2024 Red Hat, Inc.