From patchwork Tue Dec 16 10:58:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Igor Mammedov X-Patchwork-Id: 421860 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 6A80314010B for ; Tue, 16 Dec 2014 22:02:03 +1100 (AEDT) Received: from localhost ([::1]:44007 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y0ptB-0005V8-KC for incoming@patchwork.ozlabs.org; Tue, 16 Dec 2014 06:02:01 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53588) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y0pqL-0000m4-Ti for qemu-devel@nongnu.org; Tue, 16 Dec 2014 05:59:12 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Y0pqF-0006w2-JF for qemu-devel@nongnu.org; Tue, 16 Dec 2014 05:59:05 -0500 Received: from mx1.redhat.com ([209.132.183.28]:35099) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y0pqF-0006vs-A1 for qemu-devel@nongnu.org; Tue, 16 Dec 2014 05:58:59 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sBGAwwnv012030 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Tue, 16 Dec 2014 05:58:58 -0500 Received: from dell-pet610-01.lab.eng.brq.redhat.com (dell-pet610-01.lab.eng.brq.redhat.com [10.34.42.20]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sBGAwmDO018554; Tue, 16 Dec 2014 05:58:57 -0500 From: Igor Mammedov To: qemu-devel@nongnu.org Date: Tue, 16 Dec 2014 10:58:44 +0000 Message-Id: <1418727524-6790-9-git-send-email-imammedo@redhat.com> In-Reply-To: <1418727524-6790-1-git-send-email-imammedo@redhat.com> References: <1418727524-6790-1-git-send-email-imammedo@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: marcel.a@redhat.com, mst@redhat.com Subject: [Qemu-devel] [PATCH V2 8/8] pc: acpi-build: simplify PCI bus tree generation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org it basicaly does the same as original approach, * just without bus/notify tables tracking (less obscure) which is easier to follow. * drops unnecessary loops and bitmaps, creating devices and notification method in the same loop. * saves us ~100LOC Signed-off-by: Igor Mammedov --- hw/i386/acpi-build.c | 262 ++++++++++++++++----------------------------------- 1 file changed, 80 insertions(+), 182 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 707ac7e..f18b294 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -95,7 +95,6 @@ typedef struct AcpiPmInfo { typedef struct AcpiMiscInfo { bool has_hpet; bool has_tpm; - DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX); const unsigned char *dsdt_code; unsigned dsdt_size; uint16_t pvpanic_port; @@ -641,242 +640,147 @@ static void acpi_set_pci_info(void) } } -static void build_pci_bus_state_init(AcpiBuildPciBusHotplugState *state, - AcpiBuildPciBusHotplugState *parent, - bool pcihp_bridge_en) +static void build_append_pcihp_notify(GArray *method, int slot) { - state->parent = parent; - state->device_table = build_alloc_array(); - state->notify_table = build_alloc_array(); - state->pcihp_bridge_en = pcihp_bridge_en; -} + GArray *notify; -static void build_pci_bus_state_cleanup(AcpiBuildPciBusHotplugState *state) -{ - build_free_array(state->device_table); - build_free_array(state->notify_table); + notify = build_alloc_array(); + build_append_byte(notify, 0x7B); /* AndOp */ + build_append_byte(notify, 0x68); /* Arg0Op */ + build_append_int(notify, 0x1U << slot); + build_append_byte(notify, 0x00); /* NullName */ + build_append_byte(notify, 0x86); /* NotifyOp */ + build_append_namestring(notify, "S%.02X", PCI_DEVFN(slot, 0)); + build_append_byte(notify, 0x69); /* Arg1Op */ + + /* Pack it up */ + build_package(notify, 0xA0 /* IfOp */); + build_append_array(method, notify); + build_free_array(notify); } -static void *build_pci_bus_begin(PCIBus *bus, void *parent_state) +static void build_append_pcihp_dev(GArray *table, int slot) { - AcpiBuildPciBusHotplugState *parent = parent_state; - AcpiBuildPciBusHotplugState *child = g_malloc(sizeof *child); - - build_pci_bus_state_init(child, parent, parent->pcihp_bridge_en); + void *pcihp = acpi_data_push(table, ACPI_PCINOHP_SIZEOF); - return child; + memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF); + patch_pcinohp(slot, pcihp); } -static void build_pci_bus_end(PCIBus *bus, void *bus_state) +static void build_append_pci_bus_devices(GArray *parent_scope, PCIBus *bus, + bool pcihp_bridge_en) { - AcpiBuildPciBusHotplugState *child = bus_state; - AcpiBuildPciBusHotplugState *parent = child->parent; GArray *bus_table = build_alloc_array(); - DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX); - DECLARE_BITMAP(slot_device_present, PCI_SLOT_MAX); - DECLARE_BITMAP(slot_device_system, PCI_SLOT_MAX); - DECLARE_BITMAP(slot_device_vga, PCI_SLOT_MAX); - DECLARE_BITMAP(slot_device_qxl, PCI_SLOT_MAX); - uint8_t op; - int i; + GArray *method = NULL; QObject *bsel; - GArray *method; - bool bus_hotplug_support = false; - - /* - * Skip bridge subtree creation if bridge hotplug is disabled - * to make acpi tables compatible with legacy machine types. - */ - if (!child->pcihp_bridge_en && bus->parent_dev) { - return; - } + PCIBus *sec; + int i; if (bus->parent_dev) { - op = 0x82; /* DeviceOp */ - build_append_namestring(bus_table, "S%.02X", - bus->parent_dev->devfn); - build_append_byte(bus_table, 0x08); /* NameOp */ - build_append_namestring(bus_table, "_SUN"); - build_append_value(bus_table, PCI_SLOT(bus->parent_dev->devfn), 1); - build_append_byte(bus_table, 0x08); /* NameOp */ - build_append_namestring(bus_table, "_ADR"); - build_append_value(bus_table, (PCI_SLOT(bus->parent_dev->devfn) << 16) | - PCI_FUNC(bus->parent_dev->devfn), 4); + build_append_namestring(bus_table, "S%.02X_", bus->parent_dev->devfn); } else { - op = 0x10; /* ScopeOp */; build_append_namestring(bus_table, "PCI0"); } - bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); + 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))); - memset(slot_hotplug_enable, 0xff, sizeof slot_hotplug_enable); - } else { - /* No bsel - no slots are hot-pluggable */ - memset(slot_hotplug_enable, 0x00, sizeof slot_hotplug_enable); + method = build_alloc_method("DVNT", 2); } - memset(slot_device_present, 0x00, sizeof slot_device_present); - memset(slot_device_system, 0x00, sizeof slot_device_present); - memset(slot_device_vga, 0x00, sizeof slot_device_vga); - memset(slot_device_qxl, 0x00, sizeof slot_device_qxl); - for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) { DeviceClass *dc; PCIDeviceClass *pc; PCIDevice *pdev = bus->devices[i]; int slot = PCI_SLOT(i); - bool bridge_in_acpi; if (!pdev) { + build_append_pcihp_dev(bus_table, slot); + if (method) { + build_append_pcihp_notify(method, slot); + } continue; } - set_bit(slot, slot_device_present); pc = PCI_DEVICE_GET_CLASS(pdev); dc = DEVICE_GET_CLASS(pdev); - /* When hotplug for bridges is enabled, bridges are - * described in ACPI separately (see build_pci_bus_end). - * In this case they aren't themselves hot-pluggable. - */ - bridge_in_acpi = pc->is_bridge && child->pcihp_bridge_en; - - if (pc->class_id == PCI_CLASS_BRIDGE_ISA || bridge_in_acpi) { - set_bit(slot, slot_device_system); + if (pc->class_id == PCI_CLASS_BRIDGE_ISA) { + continue; } if (pc->class_id == PCI_CLASS_DISPLAY_VGA) { - set_bit(slot, slot_device_vga); if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) { - set_bit(slot, slot_device_qxl); + void *pcihp = acpi_data_push(bus_table, + ACPI_PCIQXL_SIZEOF); + memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF); + patch_pciqxl(slot, pcihp); + } else { + void *pcihp = acpi_data_push(bus_table, + ACPI_PCIVGA_SIZEOF); + memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF); + patch_pcivga(slot, pcihp); } - } - - if (!dc->hotpluggable || pc->is_bridge) { - clear_bit(slot, slot_hotplug_enable); - } - } - - /* Append Device object for each slot */ - for (i = 0; i < PCI_SLOT_MAX; i++) { - bool can_eject = test_bit(i, slot_hotplug_enable); - bool present = test_bit(i, slot_device_present); - bool vga = test_bit(i, slot_device_vga); - bool qxl = test_bit(i, slot_device_qxl); - bool system = test_bit(i, slot_device_system); - if (can_eject) { + } else if (dc->hotpluggable && !pc->is_bridge) { void *pcihp = acpi_data_push(bus_table, ACPI_PCIHP_SIZEOF); memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF); - patch_pcihp(i, pcihp); - bus_hotplug_support = true; - } else if (qxl) { - void *pcihp = acpi_data_push(bus_table, - ACPI_PCIQXL_SIZEOF); - memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF); - patch_pciqxl(i, pcihp); - } else if (vga) { - void *pcihp = acpi_data_push(bus_table, - ACPI_PCIVGA_SIZEOF); - memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF); - patch_pcivga(i, pcihp); - } else if (system) { - /* Nothing to do: system devices are in DSDT or in SSDT above. */ - } else if (present) { - void *pcihp = acpi_data_push(bus_table, - ACPI_PCINOHP_SIZEOF); - memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF); - patch_pcinohp(i, pcihp); - } - } - - if (bsel) { - method = build_alloc_method("DVNT", 2); - - for (i = 0; i < PCI_SLOT_MAX; i++) { - GArray *notify; - uint8_t op; + patch_pcihp(slot, pcihp); - if (!test_bit(i, slot_hotplug_enable)) { - continue; + if (method) { + build_append_pcihp_notify(method, slot); } + } else { + build_append_pcihp_dev(bus_table, slot); - notify = build_alloc_array(); - op = 0xA0; /* IfOp */ - - build_append_byte(notify, 0x7B); /* AndOp */ - build_append_byte(notify, 0x68); /* Arg0Op */ - build_append_int(notify, 0x1U << i); - build_append_byte(notify, 0x00); /* NullName */ - build_append_byte(notify, 0x86); /* NotifyOp */ - build_append_namestring(notify, "S%.02X", PCI_DEVFN(i, 0)); - build_append_byte(notify, 0x69); /* Arg1Op */ - - /* Pack it up */ - build_package(notify, op); - - build_append_array(method, notify); + if (pc->is_bridge) { + PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); - build_free_array(notify); + build_append_pci_bus_devices(bus_table, sec_bus, + pcihp_bridge_en); + } } + } + if (method) { build_append_and_cleanup_method(bus_table, method); } /* Append PCNT method to notify about events on local and child buses. * Add unconditionally for root since DSDT expects it. */ - if (bus_hotplug_support || child->notify_table->len || !bus->parent_dev) { - method = build_alloc_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 */ - } - - /* Notify about child bus events in any case */ - build_append_array(method, child->notify_table); - - build_append_and_cleanup_method(bus_table, method); - - /* Append description of child buses */ - build_append_array(bus_table, child->device_table); + method = build_alloc_method("PCNT", 0); - /* Pack it up */ - if (bus->parent_dev) { - build_extop_package(bus_table, op); - } else { - build_package(bus_table, op); - } - - /* Append our bus description to parent table */ - build_append_array(parent->device_table, bus_table); + /* 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 */ + } - /* Also tell parent how to notify us, invoking PCNT method. - * At the moment this is not needed for root as we have a single root. - */ - if (bus->parent_dev) { - build_append_namestring(parent->notify_table, "^PCNT.S%.02X", - bus->parent_dev->devfn); + /* 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); } } - qobject_decref(bsel); + 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); - build_pci_bus_state_cleanup(child); - g_free(child); } static void patch_pci_windows(PcPciInfo *pci, uint8_t *start, unsigned size) @@ -1008,7 +912,6 @@ build_ssdt(GArray *table_data, GArray *linker, } { - AcpiBuildPciBusHotplugState hotplug_state; Object *pci_host; PCIBus *bus = NULL; bool ambiguous; @@ -1018,16 +921,11 @@ build_ssdt(GArray *table_data, GArray *linker, bus = PCI_HOST_BRIDGE(pci_host)->bus; } - build_pci_bus_state_init(&hotplug_state, NULL, pm->pcihp_bridge_en); - if (bus) { /* Scan all PCI buses. Generate tables to support hotplug. */ - pci_for_each_bus_depth_first(bus, build_pci_bus_begin, - build_pci_bus_end, &hotplug_state); + build_append_pci_bus_devices(sb_scope, bus, + pm->pcihp_bridge_en); } - - build_append_array(sb_scope, hotplug_state.device_table); - build_pci_bus_state_cleanup(&hotplug_state); } build_package(sb_scope, op); build_append_array(table_data, sb_scope);