acpi: EJ0 method name patching
authorMichael S. Tsirkin <mst@redhat.com>
Sun, 20 Nov 2011 17:57:05 +0000 (19:57 +0200)
committerKevin O'Connor <kevin@koconnor.net>
Wed, 23 Nov 2011 02:53:11 +0000 (21:53 -0500)
Modify ACPI to only supply _EJ0 methods for PCI slots that support hotplug.

This is done by runtime patching:
- Instrument SSDT ASL code with ACPI_EXTRACT directives
  tagging _EJ0 and _ADR fields.
- At compile time, tools/acpi_extract.py looks for these methods
  in ASL source finds the matching AML, and stores the offsets
  of these methods in tables named aml_ej0_name and aml_adr_dword.
- At run time, go over aml_ej0_name, use aml_adr_dword
  to get slot information and check which slots support hotplug.

  If hotplug is disabled, we patch the _EJ0 NameString in ACPI table,
  replacing _EJ0 with EJ0_.

  Note that this has the same checksum, but is ignored by OSPM.

Note: the method used is robust in that we don't need
to change any offsets manually in case of ASL code changes.
As all parsing is done at compile time, any unexpected input causes
build failure, not a runtime failure.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
src/acpi.c
src/ssdt-pcihp.dsl
src/ssdt-pcihp.hex

index c5147d9c780cde7ecae360db0cfee40ebefde5b1..107469f2d3ff1be104a190da0d5b0a3928da55f2 100644 (file)
@@ -484,12 +484,42 @@ build_ssdt(void)
     return ssdt;
 }
 
-static void*
-copy_table(void *table, int size)
+#include "ssdt-pcihp.hex"
+
+#define PCI_RMV_BASE 0xae0c
+
+extern void link_time_assertion(void);
+
+static void* build_pcihp(void)
 {
-    u8 *copy = malloc_high(size);
-    memcpy(copy, table, size);
-    return copy;
+    u32 rmvc_pcrm;
+    int i;
+
+    u8 *ssdt = malloc_high(sizeof ssdp_pcihp_aml);
+    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);
+        }
+    }
+
+    return ssdt;
 }
 
 #define HPET_SIGNATURE 0x54455048 // HPET
@@ -642,8 +672,6 @@ static const struct pci_device_id acpi_find_tbl[] = {
 
 struct rsdp_descriptor *RsdpAddr;
 
-#include "ssdt-pcihp.hex"
-
 #define MAX_ACPI_TABLES 20
 void
 acpi_bios_init(void)
@@ -675,7 +703,7 @@ acpi_bios_init(void)
     ACPI_INIT_TABLE(build_madt());
     ACPI_INIT_TABLE(build_hpet());
     ACPI_INIT_TABLE(build_srat());
-    ACPI_INIT_TABLE(copy_table(ssdp_pcihp_aml, sizeof ssdp_pcihp_aml));
+    ACPI_INIT_TABLE(build_pcihp());
 
     u16 i, external_tables = qemu_cfg_acpi_additional_tables();
 
index 72d1bb72d8c772016445b5c9e0571d7187d50c10..cc96ffc741dbf9d15e95d5701df66b883b39fdf0 100644 (file)
@@ -53,9 +53,15 @@ DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 0x1)
         gen_pci_device(1f)
 
         /* Bulk generated PCI hotplug devices */
+        // 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)                        \
         }
index a103c0814941d3428e80cef07e656e7ff7baf76d..a410a799cbc612a6fa5707f799f12a2e766d55b6 100644 (file)
@@ -1,3 +1,69 @@
+static unsigned short aml_adr_dword[] = {
+0x48c,
+0x4b0,
+0x4d6,
+0x4fc,
+0x522,
+0x548,
+0x56e,
+0x594,
+0x5ba,
+0x5e0,
+0x606,
+0x62c,
+0x652,
+0x678,
+0x69e,
+0x6c4,
+0x6ea,
+0x710,
+0x736,
+0x75c,
+0x782,
+0x7a8,
+0x7ce,
+0x7f4,
+0x81a,
+0x840,
+0x866,
+0x88c,
+0x8b2,
+0x8d8,
+0x8fe
+};
+static unsigned short aml_ej0_name[] = {
+0x492,
+0x4b6,
+0x4dc,
+0x502,
+0x528,
+0x54e,
+0x574,
+0x59a,
+0x5c0,
+0x5e6,
+0x60c,
+0x632,
+0x658,
+0x67e,
+0x6a4,
+0x6ca,
+0x6f0,
+0x716,
+0x73c,
+0x762,
+0x788,
+0x7ae,
+0x7d4,
+0x7fa,
+0x820,
+0x846,
+0x86c,
+0x892,
+0x8b8,
+0x8de,
+0x904
+};
 static unsigned char ssdp_pcihp_aml[] = {
 0x53,
 0x53,