From: Salil Mehta <salil.me...@huawei.com> This change emits AML in DSDT to support vCPU deferred online-capability on arm/virt. It wires the CPU OSPM coordination paths so that CPUs which are administratively disabled at boot can be brought online later under policy, providing hotplug-like functionality without claiming full hotplug support.
The AML connects the CPUS scan method to a GED handler so QEMU and the guest OSPM can coordinate CPU add/remove while the VM is running (e.g. device-check, eject-request, _EJ0, CPU scan, _OST status reporting). It also fixes an ACPI namespace load error: AE_NOT_FOUND resolving \_SB.GED.PSCN Error excerpt: [ 0.070518] ACPI BIOS Error (bug): Object does not exist: GED_ [ 0.071457] ACPI BIOS Error (bug): Could not resolve symbol [\_SB.GED.PSCN], [ 0.073084] ACPI Error: AE_NOT_FOUND, During name lookup/catalog Root cause was build order and naming: the PSCN handler must be created under \_SB.GED using a short ACPI 'NameSeg', and referenced elsewhere by its fully qualified path. The GED device (and PSCN) are now defined before the CPUS AML, preventing the early lookup failure. Notes: * CPU enumeration remains from MADT (GICC). CPU0 is Enabled; other CPUs may be Disabled but Online-Capable. * Policy (which CPUs start disabled, later enabled) is administrative and not decided by OSPM. Tested: boot with EDK2/ACPI; no AE_NOT_FOUND for \_SB.GED.PSCN; generic CPU devices register; sysfs topology group warnings do not occur. 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.CPUR) 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.PSCN () [...] } Method (CSCN, 0, Serialized) } { } [...] Method (COST, 4, Serialized) Scope (_SB) { { [...] Device (\_SB.CPUR) 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.PSCN, 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.PSCN, 0, NotSerialized) { { Local0 = ESEL \_SB.CPUS.CSCN () If (((Local0 & 0x02) == 0x02)) } { Notify (PWRB, 0x80) Device (COM0) } { [...] If (((Local0 & 0x08) == 0x08)) } { } \_SB.GED.PSCN () } } } Device (PWRB) { [...] } } Signed-off-by: Salil Mehta <salil.me...@huawei.com> --- hw/arm/virt-acpi-build.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 7c24dd6369..5e5acb3026 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -931,6 +931,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); Aml *scope, *dsdt; MachineState *ms = MACHINE(vms); + MachineClass *mc = MACHINE_GET_CLASS(ms); const MemMapEntry *memmap = vms->memmap; const int *irqmap = vms->irqmap; AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = vms->oem_id, @@ -946,7 +947,30 @@ 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 the machine supports bringing administratively disabled vCPUs + * deferred-online under policy, build AML to coordinate the addition and + * removal of CPUs gracefully with the OSPM while the VM is running. This + * includes events such as device-check, eject-request, ejection (_EJ0), + * CPU scan, _OST status reporting, etc. + */ + if (vms->acpi_dev && mc->has_online_capable_cpus) { + acpi_build_cpus_aml(scope, memmap[VIRT_ACPI_CPUPS].base, "\\_SB", + AML_GED_EVT_CPUPS_SCAN_METHOD); + } 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) { @@ -961,15 +985,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