From 90d8e56a1ee818f5f45b4dd84daaa13d80fff8e4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 24 Sep 2020 10:53:36 +0200 Subject: pci: add qemu gpex host bridge support. Find PCIe root using ACPI DSDT table. Setup PCI bars. initialize PCI devices. Working: - finds + drives xhci-pci / virtio-pci devices. TODO / known issues: - ioport setup is broken. - bootorder needs fixing. - 64bit mmio window not supported. - irq routing not supported. - pci config access in real mode is broken (not using mmconfig). - this breaks pcibios support. - which in turn breaks vgabios. - fixable via temporary modeswitch to 32bit. - which of course adds overhead. Also: - needed in the first place for microvm? Signed-off-by: Gerd Hoffmann --- src/fw/paravirt.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index fba4e52d..76070e18 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -197,6 +197,67 @@ static void msr_feature_control_setup(void) wrmsr_smp(MSR_IA32_FEATURE_CONTROL, feature_control_bits); } +void +gpex_setup(void) +{ + u16 pcie_eisaid = 0x0a08; + u16 ecam_eisaid = 0x0c02; + u16 link_eisaid = 0x0c0f; + struct acpi_device *pcie; + struct acpi_device *ecam; + struct acpi_device *link; + u64 min, max, irq; + + if (!hlist_empty(&PCIDevices)) { + dprintf(1, "%s: have pci devices, skipping\n", __func__); + return; + } + + pcie = acpi_dsdt_find_eisaid(NULL, pcie_eisaid); + if (!pcie) + return; + + for (ecam = acpi_dsdt_find_eisaid(NULL, ecam_eisaid); + ecam != NULL; + ecam = acpi_dsdt_find_eisaid(ecam, ecam_eisaid)) { + if (acpi_dsdt_is_parent(ecam, pcie)) + break; + } + if (!ecam) + return; + + if (acpi_dsdt_find_mem(ecam, &min, &max) < 0) + return; + dprintf(1, "%s: mmconfig: %llx -> %llx\n", __func__, min, max); + pci_enable_mmconfig(min, "gpex"); + + if (acpi_dsdt_find_io(pcie, &min, &max) < 0) + dprintf(1, "%s: no io window [ TODO ]\n", __func__); + else + dprintf(1, "%s: io: %llx -> %llx [ TODO ]\n", __func__, min, max); + + if (acpi_dsdt_find_mem(pcie, &pcimem_start, &pcimem_end) < 0) + return; + dprintf(1, "%s: mmio32: %llx -> %llx\n", __func__, pcimem_start, pcimem_end); + + dprintf(1, "%s: mmio64: [ TODO ]\n", __func__); + + for (link = acpi_dsdt_find_eisaid(NULL, link_eisaid); + link != NULL; + link = acpi_dsdt_find_eisaid(link, link_eisaid)) { + if (!acpi_dsdt_is_parent(link, pcie)) + continue; + if (acpi_dsdt_find_irq(link, &irq) < 0) + continue; + dprintf(1, "%s: %s -> uid %lld, irq %lld [ TODO ]\n", __func__, + acpi_dsdt_name(link), acpi_dsdt_uid(link), irq); + } + + dprintf(1, "=== PCI device probing ===\n"); + pci_probe_devices(); + pci_setup_alloc(); +} + void qemu_platform_setup(void) { @@ -240,6 +301,7 @@ qemu_platform_setup(void) if (RsdpAddr) { acpi_dsdt_parse(); + gpex_setup(); virtio_mmio_setup_acpi(); return; } -- cgit