More than 1kb of data is taken by the 32 copies of the PCI hotplug SSDT methods. We can build them from a single template like we do for CPUs (wrapped in a Scope(_SB.PCI0) block).
Three items differ for each slot: the device name, bits 16-23 of _ADR, the _SUN value. On top of this we have to rename the eject method for non-removable slots, like we already do in build_pcihp.
There is a small change in the ASL: instead of including the number of the slot in the implementation of _EJ0, we just call _SUN. This is also similar to what we do for CPU hotplug.
Once we do this, there is no need to keep a separate SSDT for PCI hotplug. Everything can reside in the same table.
Signed-off-by: Paolo Bonzini pbonzini@redhat.com --- On top of this: do we actually need the S01/S02 devices? Their address is a duplicate of _SB.PCI0.ISA and _SB.PCI0.VGA's; and they are never removable so _EJ0 is always patched out. The only addition is the _SUN, which can be added in the DSDT.
src/acpi.c | 97 +++++++++++++++++++++++++++------------------------- src/ssdt-pcihp.dsl | 51 +++++++-------------------- 2 files changed, 63 insertions(+), 85 deletions(-)
diff --git a/src/acpi.c b/src/acpi.c index 906237c..2d4513b 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -405,11 +405,42 @@ encodeLen(u8 *ssdt_ptr, int length, int bytes) #define PROC_SIZEOF (*ssdt_proc_end - *ssdt_proc_start) #define PROC_AML (ssdp_proc_aml + *ssdt_proc_start)
+/* 0x5B 0x82 DeviceOp PkgLength NameString */ +#define PCIHP_OFFSET_HEX (*ssdt_pcihp_name - *ssdt_pcihp_start + 1) +#define PCIHP_OFFSET_ID (*ssdt_pcihp_id - *ssdt_pcihp_start) +#define PCIHP_OFFSET_ADR (*ssdt_pcihp_adr - *ssdt_pcihp_start) +#define PCIHP_OFFSET_EJ0 (*ssdt_pcihp_ej0 - *ssdt_pcihp_start) +#define PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start) +#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start) +#define PCI_SLOTS 32 + #define SSDT_SIGNATURE 0x54445353 // SSDT #define SSDT_HEADER_LENGTH 36
#include "ssdt-susp.hex"
+#include "ssdt-pcihp.hex" + +#define PCI_RMV_BASE 0xae0c + +static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject) +{ + ssdt_ptr[PCIHP_OFFSET_HEX] = getHex(slot >> 4); + ssdt_ptr[PCIHP_OFFSET_HEX+1] = getHex(slot); + ssdt_ptr[PCIHP_OFFSET_ID] = slot; + ssdt_ptr[PCIHP_OFFSET_ADR + 2] = slot; + + /* Runtime patching of EJ0: to disable hotplug for a slot, + * replace the method name: _EJ0 by EJ0_. */ + /* Sanity check */ + if (memcmp(ssdp_pcihp_aml + PCIHP_OFFSET_EJ0, "_EJ0", 4)) { + warn_internalerror(); + } + if (!eject) { + memcpy(ssdt_ptr + PCIHP_OFFSET_EJ0, "EJ0_", 4); + } +} + static void* build_ssdt(void) { @@ -420,7 +451,9 @@ build_ssdt(void) + (acpi_cpus * PROC_SIZEOF) + (1+2+5+(12*acpi_cpus)) + (6+2+1+(1*acpi_cpus)) - + 17); + + 17 + + (1+3+4) + + (PCI_SLOTS * PCIHP_SIZEOF)); u8 *ssdt = malloc_high(length); if (! ssdt) { warn_noalloc(); @@ -522,6 +555,23 @@ build_ssdt(void) *(u32*)ssdt_ptr = sizeof(struct bfld); ssdt_ptr += 4;
+ // build Scope(PCI0) opcode + *(ssdt_ptr++) = 0x10; // ScopeOp + ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3); + *(ssdt_ptr++) = 'P'; + *(ssdt_ptr++) = 'C'; + *(ssdt_ptr++) = 'I'; + *(ssdt_ptr++) = '0'; + + // build Device object for each slot + u32 rmvc_pcrm = inl(PCI_RMV_BASE); + for (i=1; i<PCI_SLOTS; i++) { + u32 eject = rmvc_pcrm & (0x1 << i); + memcpy(ssdt_ptr, PCIHP_AML, PCIHP_SIZEOF); + patch_pcihp(i, ssdt_ptr, eject != 0); + ssdt_ptr += PCIHP_SIZEOF; + } + build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
//hexdump(ssdt, ssdt_ptr - ssdt); @@ -529,50 +579,6 @@ build_ssdt(void) return ssdt; }
-#include "ssdt-pcihp.hex" - -#define PCI_RMV_BASE 0xae0c - -extern void link_time_assertion(void); - -static void* build_pcihp(void) -{ - u32 rmvc_pcrm; - int i; - - u8 *ssdt = malloc_high(sizeof ssdp_pcihp_aml); - if (!ssdt) { - warn_noalloc(); - return NULL; - } - memcpy(ssdt, ssdp_pcihp_aml, sizeof ssdp_pcihp_aml); - - /* Runtime patching of EJ0: to disable hotplug for a slot, - * replace the method name: _EJ0 by EJ0_. */ - if (ARRAY_SIZE(aml_ej0_name) != ARRAY_SIZE(aml_adr_dword)) { - link_time_assertion(); - } - - rmvc_pcrm = inl(PCI_RMV_BASE); - for (i = 0; i < ARRAY_SIZE(aml_ej0_name); ++i) { - /* Slot is in byte 2 in _ADR */ - u8 slot = ssdp_pcihp_aml[aml_adr_dword[i] + 2] & 0x1F; - /* Sanity check */ - if (memcmp(ssdp_pcihp_aml + aml_ej0_name[i], "_EJ0", 4)) { - warn_internalerror(); - free(ssdt); - return NULL; - } - if (!(rmvc_pcrm & (0x1 << slot))) { - memcpy(ssdt + aml_ej0_name[i], "EJ0_", 4); - } - } - - ((struct acpi_table_header*)ssdt)->checksum = 0; - ((struct acpi_table_header*)ssdt)->checksum -= checksum(ssdt, sizeof(ssdp_pcihp_aml)); - return ssdt; -} - #define HPET_SIGNATURE 0x54455048 // HPET static void* build_hpet(void) @@ -754,7 +760,6 @@ acpi_bios_init(void) ACPI_INIT_TABLE(build_madt()); ACPI_INIT_TABLE(build_hpet()); ACPI_INIT_TABLE(build_srat()); - ACPI_INIT_TABLE(build_pcihp());
u16 i, external_tables = qemu_cfg_acpi_additional_tables();
diff --git a/src/ssdt-pcihp.dsl b/src/ssdt-pcihp.dsl index fd9c0bb..cd66b83 100644 --- a/src/ssdt-pcihp.dsl +++ b/src/ssdt-pcihp.dsl @@ -12,50 +12,23 @@ DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 0x1) External (_SB.PCI0.PCEJ, MethodObj)
Scope(_SB.PCI0) { + /* Bulk generated PCI hotplug devices */ + ACPI_EXTRACT_DEVICE_START ssdt_pcihp_start + ACPI_EXTRACT_DEVICE_END ssdt_pcihp_end + ACPI_EXTRACT_DEVICE_STRING ssdt_pcihp_name + // Method _EJ0 can be patched by BIOS to EJ0_ // at runtime, if the slot is detected to not support hotplug. // Extract the offset of the address dword and the // _EJ0 name to allow this patching. -#define hotplug_slot(slot) \ - Device (S##slot) { \ - ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword \ - Name (_ADR, 0x##slot##0000) \ - ACPI_EXTRACT_METHOD_STRING aml_ej0_name \ - Method (_EJ0, 1) { Return(PCEJ(0x##slot)) } \ - Name (_SUN, 0x##slot) \ + Device (SAA) { + ACPI_EXTRACT_NAME_BYTE_CONST ssdt_pcihp_id + Name (_SUN, 0xAA) + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcihp_adr + Name (_ADR, 0xAA0000) + ACPI_EXTRACT_METHOD_STRING ssdt_pcihp_ej0 + Method (_EJ0, 1) { Return(PCEJ(_SUN)) } } - - hotplug_slot(01) - hotplug_slot(02) - hotplug_slot(03) - hotplug_slot(04) - hotplug_slot(05) - hotplug_slot(06) - hotplug_slot(07) - hotplug_slot(08) - hotplug_slot(09) - hotplug_slot(0a) - hotplug_slot(0b) - hotplug_slot(0c) - hotplug_slot(0d) - hotplug_slot(0e) - hotplug_slot(0f) - hotplug_slot(10) - hotplug_slot(11) - hotplug_slot(12) - hotplug_slot(13) - hotplug_slot(14) - hotplug_slot(15) - hotplug_slot(16) - hotplug_slot(17) - hotplug_slot(18) - hotplug_slot(19) - hotplug_slot(1a) - hotplug_slot(1b) - hotplug_slot(1c) - hotplug_slot(1d) - hotplug_slot(1e) - hotplug_slot(1f) } }