Support for Virtual CPU Hotplug requires a sequence of ACPI handshakes between QEMU and the guest kernel when a vCPU is plugged or unplugged. Most of the AML code to support these handshakes already exists. This AML needs to be built during VM initialization for the ARM architecture as well, if GED support exists.
TODO (Peculiar Problem with AML): Encountering the following ACPI namespace error when the GED AML is placed after the CPU AML. Error excerpt: [ 75.795774] ACPI BIOS Error (bug): Could not resolve symbol [\_SB.GED.CSCN], [ 75.797237] ACPI Error: Aborting method \_SB.GED._EVT due to previous error [ 75.798530] acpi-ged ACPI0013:00: IRQ method execution failed Preliminary analysis: The error is definitely not related to a `forward declaration` issue but rather to associating the `CSCN` (CPU Scan event handler) method with the `GED` scope before the `\\_SB.GED` scope is created. Therefore, it appears that the GED AML should be initialized prior to the CPU AML. As a result, I had to move the GED AML before the CPU AML to resolve the issue. Everything about the two AML sections seems identical, except for their location. Any insights? ============================== Summary comparison of DSDT.dsl ============================== [1] Both working and not working DSDT.dsl Files are placed at below path: https://drive.google.com/drive/folders/1bbEvS18CtBn3vYFnGIVdgcSD_hggyODV?usp=drive_link [2] Configuration: -smp cpu 4, maxcpus 6 DSDT.dsl (Not Working) DSDT.dsl (Working) --------------------- ------------------ DefinitionBlock ("", "DSDT", 2, "BOCHS ", "BXPC ", 0x00000001) DefinitionBlock ("", "DSDT", 2, "BOCHS ", "BXPC ", 0x00000001) { { Scope (\_SB) Scope (\_SB) { { Scope (_SB) Device (\_SB.GED) { { Device (\_SB.PRES) Name (_HID, "ACPI0013" { Name (_UID, "GED") [...] Name (_CRS, ResourceTemplate () Device (\_SB.CPUS) [...] { Method (_EVT, 1, Serialized) Name (_HID, "ACPI0010") { Name (_CID, EisaId ("PNP0A05")) Local0 = ESEL /* \_SB_.GED_.ESEL */ Method (CTFY, 2, NotSerialized) If (((Local0 & 0x02) == 0x02)) { { [...] Notify (PWRB, 0x80) Method (CSTA, 1, Serialized) } { [...] If (((Local0 & 0x08) == 0x08)) Method (CEJ0, 1, Serialized) { { \_SB.GED.CSCN () [...] } Method (CSCN, 0, Serialized) } { } [...] Method (COST, 4, Serialized) Scope (_SB) { { [...] Device (\_SB.PRES) Device (C000) { { [...] [...] Device (\_SB.CPUS) Device (C001) { { Name (_HID, "ACPI0010") [...] Name (_CID, EisaId ("PNP0A05")) Device (C002) Method (CTFY, 2, NotSerialized) { { [...] [...] Device (C003) Method (CSTA, 1, Serialized) { { [...] [...] Device (C004) Method (CEJ0, 1, Serialized) { { [...] [...] Device (C005) Method (CSCN, 0, Serialized) { { } [...] } Method (COST, 4, Serialized) { Method (\_SB.GED.CSCN, 0, NotSerialized) [...] { Device (C000) \_SB.CPUS.CSCN () { } [...] Device (C001) Device (COM0) { { [...] [...] Device (C002) { Device (\_SB.GED) [...] { Device (C003) Name (_HID, "ACPI0013") { Name (_UID, "GED") [...] Name (_CRS, ResourceTemplate () Device (C004) { { [...] [...] OperationRegion (EREG, SystemMemory, 0x09080000, 0x04) Device (C005) Field (EREG, DWordAcc, NoLock, WriteAsZeros) { { } [...] } Method (_EVT, 1, Serialized) Method (\_SB.GED.CSCN, 0, NotSerialized) { { Local0 = ESEL \_SB.CPUS.CSCN () If (((Local0 & 0x02) == 0x02)) } { Notify (PWRB, 0x80) Device (COM0) } { [...] If (((Local0 & 0x08) == 0x08)) } { } \_SB.GED.CSCN () } } } Device (PWRB) { [...] } } Signed-off-by: Salil Mehta <salil.me...@huawei.com> --- hw/arm/virt-acpi-build.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index f76fb117ad..32238170ab 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -805,6 +805,7 @@ static void build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); + MachineClass *mc = MACHINE_GET_CLASS(vms); Aml *scope, *dsdt; MachineState *ms = MACHINE(vms); const MemMapEntry *memmap = vms->memmap; @@ -821,7 +822,28 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); - acpi_dsdt_add_cpus(scope, vms); + if (vms->acpi_dev) { + build_ged_aml(scope, "\\_SB."GED_DEVICE, + HOTPLUG_HANDLER(vms->acpi_dev), + irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY, + memmap[VIRT_ACPI_GED].base); + } else { + acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], + (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); + } + + /* if GED is enabled then cpus AML shall be added as part build_cpus_aml */ + if (vms->acpi_dev && mc->has_hotpluggable_cpus) { + CPUHotplugFeatures opts = { + .acpi_1_compatible = false, + .has_legacy_cphp = false + }; + + build_cpus_aml(scope, ms, opts, NULL, memmap[VIRT_CPUHP_ACPI].base, + "\\_SB", AML_GED_EVT_CPU_SCAN_METHOD, AML_SYSTEM_MEMORY); + } else { + acpi_dsdt_add_cpus(scope, vms); + } acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], (irqmap[VIRT_UART0] + ARM_SPI_BASE), 0); if (vms->second_ns_uart_present) { @@ -836,15 +858,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) (irqmap[VIRT_MMIO] + ARM_SPI_BASE), 0, NUM_VIRTIO_TRANSPORTS); acpi_dsdt_add_pci(scope, memmap, irqmap[VIRT_PCIE] + ARM_SPI_BASE, vms); - if (vms->acpi_dev) { - build_ged_aml(scope, "\\_SB."GED_DEVICE, - HOTPLUG_HANDLER(vms->acpi_dev), - irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY, - memmap[VIRT_ACPI_GED].base); - } else { - acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], - (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); - } if (vms->acpi_dev) { uint32_t event = object_property_get_uint(OBJECT(vms->acpi_dev), -- 2.34.1