aboutsummaryrefslogtreecommitdiff
path: root/hw/i386/acpi-build.c
diff options
context:
space:
mode:
authorIgor Mammedov <imammedo@redhat.com>2015-02-20 18:22:18 +0000
committerMichael S. Tsirkin <mst@redhat.com>2015-03-01 12:33:23 +0100
commit62b52c266582d3241a468dc08dbaa81e337cb03f (patch)
treec73ac109a6ee438e7a733fc0bb46988a45058fee /hw/i386/acpi-build.c
parent752bba815ec5b67e2aa6d7c86fd2be80e45c203b (diff)
pc: acpi-build: drop template patching and create PCI bus tree dynamically
Replace AML template patching with direct composing of PCI device entries in C. It allows to simplify PCI tree generation further and saves us about 400LOC scattered through different files, confining tree generation to one C function which is much easier to deal with. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/i386/acpi-build.c')
-rw-r--r--hw/i386/acpi-build.c235
1 files changed, 80 insertions, 155 deletions
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index ba056f0c21..b94e47e734 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -294,26 +294,6 @@ build_header(GArray *linker, GArray *table_data,
table_data->data, h, len, &h->checksum);
}
-static GArray *build_alloc_method(const char *name, uint8_t arg_count)
-{
- GArray *method = build_alloc_array();
-
- build_append_namestring(method, "%s", name);
- build_append_byte(method, arg_count); /* MethodFlags: ArgCount */
-
- return method;
-}
-
-static void build_append_and_cleanup_method(GArray *device, GArray *method)
-{
- uint8_t op = 0x14; /* MethodOp */
-
- build_package(method, op);
-
- build_append_array(device, method);
- build_free_array(method);
-}
-
/* End here */
#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
@@ -494,71 +474,12 @@ static inline char acpi_get_hex(uint32_t val)
return (val <= 9) ? ('0' + val) : ('A' + val - 10);
}
-/* 0x5B 0x82 DeviceOp PkgLength NameString */
-#define ACPI_PCIHP_OFFSET_HEX (*ssdt_pcihp_name - *ssdt_pcihp_start + 1)
-#define ACPI_PCIHP_OFFSET_ID (*ssdt_pcihp_id - *ssdt_pcihp_start)
-#define ACPI_PCIHP_OFFSET_ADR (*ssdt_pcihp_adr - *ssdt_pcihp_start)
-#define ACPI_PCIHP_OFFSET_EJ0 (*ssdt_pcihp_ej0 - *ssdt_pcihp_start)
-#define ACPI_PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start)
-#define ACPI_PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
-
-#define ACPI_PCINOHP_OFFSET_HEX (*ssdt_pcinohp_name - *ssdt_pcinohp_start + 1)
-#define ACPI_PCINOHP_OFFSET_ADR (*ssdt_pcinohp_adr - *ssdt_pcinohp_start)
-#define ACPI_PCINOHP_SIZEOF (*ssdt_pcinohp_end - *ssdt_pcinohp_start)
-#define ACPI_PCINOHP_AML (ssdp_pcihp_aml + *ssdt_pcinohp_start)
-
-#define ACPI_PCIVGA_OFFSET_HEX (*ssdt_pcivga_name - *ssdt_pcivga_start + 1)
-#define ACPI_PCIVGA_OFFSET_ADR (*ssdt_pcivga_adr - *ssdt_pcivga_start)
-#define ACPI_PCIVGA_SIZEOF (*ssdt_pcivga_end - *ssdt_pcivga_start)
-#define ACPI_PCIVGA_AML (ssdp_pcihp_aml + *ssdt_pcivga_start)
-
-#define ACPI_PCIQXL_OFFSET_HEX (*ssdt_pciqxl_name - *ssdt_pciqxl_start + 1)
-#define ACPI_PCIQXL_OFFSET_ADR (*ssdt_pciqxl_adr - *ssdt_pciqxl_start)
-#define ACPI_PCIQXL_SIZEOF (*ssdt_pciqxl_end - *ssdt_pciqxl_start)
-#define ACPI_PCIQXL_AML (ssdp_pcihp_aml + *ssdt_pciqxl_start)
#define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */
#define ACPI_SSDT_HEADER_LENGTH 36
-#include "hw/i386/ssdt-pcihp.hex"
#include "hw/i386/ssdt-tpm.hex"
-static void patch_pcihp(int slot, uint8_t *ssdt_ptr)
-{
- unsigned devfn = PCI_DEVFN(slot, 0);
-
- ssdt_ptr[ACPI_PCIHP_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
- ssdt_ptr[ACPI_PCIHP_OFFSET_HEX + 1] = acpi_get_hex(devfn);
- ssdt_ptr[ACPI_PCIHP_OFFSET_ID] = slot;
- ssdt_ptr[ACPI_PCIHP_OFFSET_ADR + 2] = slot;
-}
-
-static void patch_pcinohp(int slot, uint8_t *ssdt_ptr)
-{
- unsigned devfn = PCI_DEVFN(slot, 0);
-
- ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
- ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX + 1] = acpi_get_hex(devfn);
- ssdt_ptr[ACPI_PCINOHP_OFFSET_ADR + 2] = slot;
-}
-
-static void patch_pcivga(int slot, uint8_t *ssdt_ptr)
-{
- unsigned devfn = PCI_DEVFN(slot, 0);
-
- ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
- ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX + 1] = acpi_get_hex(devfn);
- ssdt_ptr[ACPI_PCIVGA_OFFSET_ADR + 2] = slot;
-}
-
-static void patch_pciqxl(int slot, uint8_t *ssdt_ptr)
-{
- unsigned devfn = PCI_DEVFN(slot, 0);
-
- ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
- ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX + 1] = acpi_get_hex(devfn);
- ssdt_ptr[ACPI_PCIQXL_OFFSET_ADR + 2] = slot;
-}
/* Assign BSEL property to all buses. In the future, this can be changed
* to only assign to buses that support hotplug.
@@ -590,46 +511,30 @@ static void acpi_set_pci_info(void)
}
}
-static void build_append_pcihp_notify_entry(GArray *method, int slot)
+static void build_append_pcihp_notify_entry(Aml *method, int slot)
{
- GArray *ifctx;
-
- ifctx = build_alloc_array();
- build_append_byte(ifctx, 0x7B); /* AndOp */
- build_append_byte(ifctx, 0x68); /* Arg0Op */
- build_append_int(ifctx, 0x1U << slot);
- build_append_byte(ifctx, 0x00); /* NullName */
- build_append_byte(ifctx, 0x86); /* NotifyOp */
- build_append_namestring(ifctx, "S%.02X", PCI_DEVFN(slot, 0));
- build_append_byte(ifctx, 0x69); /* Arg1Op */
-
- /* Pack it up */
- build_package(ifctx, 0xA0 /* IfOp */);
- build_append_array(method, ifctx);
- build_free_array(ifctx);
+ Aml *if_ctx;
+ int32_t devfn = PCI_DEVFN(slot, 0);
+
+ if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot)));
+ aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1)));
+ aml_append(method, if_ctx);
}
-static void build_append_pci_bus_devices(GArray *parent_scope, PCIBus *bus,
+static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
bool pcihp_bridge_en)
{
- GArray *bus_table = build_alloc_array();
- GArray *method = NULL;
+ Aml *dev, *notify_method, *method;
QObject *bsel;
PCIBus *sec;
int i;
- if (bus->parent_dev) {
- build_append_namestring(bus_table, "S%.02X_", bus->parent_dev->devfn);
- } else {
- build_append_namestring(bus_table, "PCI0");
- }
-
bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
if (bsel) {
- build_append_byte(bus_table, 0x08); /* NameOp */
- build_append_namestring(bus_table, "BSEL");
- build_append_int(bus_table, qint_get_int(qobject_to_qint(bsel)));
- method = build_alloc_method("DVNT", 2);
+ int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
+
+ aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
+ notify_method = aml_method("DVNT", 2);
}
for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) {
@@ -642,11 +547,17 @@ static void build_append_pci_bus_devices(GArray *parent_scope, PCIBus *bus,
if (!pdev) {
if (bsel) { /* add hotplug slots for non present devices */
- void *pcihp = acpi_data_push(bus_table, ACPI_PCIHP_SIZEOF);
- memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF);
- patch_pcihp(slot, pcihp);
-
- build_append_pcihp_notify_entry(method, slot);
+ dev = aml_device("S%.02X", PCI_DEVFN(slot, 0));
+ aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
+ aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16)));
+ method = aml_method("_EJ0", 1);
+ aml_append(method,
+ aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
+ );
+ aml_append(dev, method);
+ aml_append(parent_scope, dev);
+
+ build_append_pcihp_notify_entry(notify_method, slot);
}
continue;
}
@@ -668,74 +579,87 @@ static void build_append_pci_bus_devices(GArray *parent_scope, PCIBus *bus,
continue;
}
+ /* start to compose PCI slot descriptor */
+ dev = aml_device("S%.02X", PCI_DEVFN(slot, 0));
+ aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16)));
+
if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
+ /* add VGA specific AML methods */
+ int s3d;
+
if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) {
- void *pcihp = acpi_data_push(bus_table,
- ACPI_PCIQXL_SIZEOF);
- memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF);
- patch_pciqxl(slot, pcihp);
+ s3d = 3;
} else {
- void *pcihp = acpi_data_push(bus_table,
- ACPI_PCIVGA_SIZEOF);
- memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF);
- patch_pcivga(slot, pcihp);
+ s3d = 0;
}
+
+ method = aml_method("_S1D", 0);
+ aml_append(method, aml_return(aml_int(0)));
+ aml_append(dev, method);
+
+ method = aml_method("_S2D", 0);
+ aml_append(method, aml_return(aml_int(0)));
+ aml_append(dev, method);
+
+ method = aml_method("_S3D", 0);
+ aml_append(method, aml_return(aml_int(s3d)));
+ aml_append(dev, method);
} else if (hotplug_enabled_dev) {
- void *pcihp = acpi_data_push(bus_table, ACPI_PCIHP_SIZEOF);
+ /* add _SUN/_EJ0 to make slot hotpluggable */
+ aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
- memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF);
- patch_pcihp(slot, pcihp);
- build_append_pcihp_notify_entry(method, slot);
+ method = aml_method("_EJ0", 1);
+ aml_append(method,
+ aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
+ );
+ aml_append(dev, method);
+
+ if (bsel) {
+ build_append_pcihp_notify_entry(notify_method, slot);
+ }
} else if (bridge_in_acpi) {
+ /*
+ * device is coldplugged bridge,
+ * add child device descriptions into its scope
+ */
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
- void *pcihp = acpi_data_push(bus_table, ACPI_PCINOHP_SIZEOF);
- memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF);
- patch_pcinohp(slot, pcihp);
- build_append_pci_bus_devices(bus_table, sec_bus, pcihp_bridge_en);
- } else { /* non hotpluggable present devices */
- void *pcihp = acpi_data_push(bus_table, ACPI_PCINOHP_SIZEOF);
-
- memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF);
- patch_pcinohp(slot, pcihp);
+ build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en);
}
+ /* slot descriptor has been composed, add it into parent context */
+ aml_append(parent_scope, dev);
}
if (bsel) {
- build_append_and_cleanup_method(bus_table, method);
+ aml_append(parent_scope, notify_method);
}
/* Append PCNT method to notify about events on local and child buses.
* Add unconditionally for root since DSDT expects it.
*/
- method = build_alloc_method("PCNT", 0);
+ method = aml_method("PCNT", 0);
/* If bus supports hotplug select it and notify about local events */
if (bsel) {
- build_append_byte(method, 0x70); /* StoreOp */
- build_append_int(method, qint_get_int(qobject_to_qint(bsel)));
- build_append_namestring(method, "BNUM");
- build_append_namestring(method, "DVNT");
- build_append_namestring(method, "PCIU");
- build_append_int(method, 1); /* Device Check */
- build_append_namestring(method, "DVNT");
- build_append_namestring(method, "PCID");
- build_append_int(method, 3); /* Eject Request */
+ int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
+ aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
+ aml_append(method,
+ aml_call2("DVNT", aml_name("PCIU"), aml_int(1) /* Device Check */)
+ );
+ aml_append(method,
+ aml_call2("DVNT", aml_name("PCID"), aml_int(3)/* Eject Request */)
+ );
}
/* Notify about child bus events in any case */
if (pcihp_bridge_en) {
QLIST_FOREACH(sec, &bus->child, sibling) {
- build_append_namestring(method, "^S%.02X.PCNT",
- sec->parent_dev->devfn);
+ int32_t devfn = sec->parent_dev->devfn;
+
+ aml_append(method, aml_name("^S%.02X.PCNT", devfn));
}
}
-
- build_append_and_cleanup_method(bus_table, method);
-
- build_package(bus_table, 0x10); /* ScopeOp */
- build_append_array(parent_scope, bus_table);
- build_free_array(bus_table);
+ aml_append(parent_scope, method);
}
static void
@@ -1087,9 +1011,10 @@ build_ssdt(GArray *table_data, GArray *linker,
}
if (bus) {
+ Aml *scope = aml_scope("PCI0");
/* Scan all PCI buses. Generate tables to support hotplug. */
- build_append_pci_bus_devices(sb_scope->buf, bus,
- pm->pcihp_bridge_en);
+ build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
+ aml_append(sb_scope, scope);
}
}
aml_append(ssdt, sb_scope);