aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2020-09-24 10:53:36 +0200
committerGerd Hoffmann <kraxel@redhat.com>2020-10-15 11:21:43 +0200
commit90d8e56a1ee818f5f45b4dd84daaa13d80fff8e4 (patch)
tree438e944ed85c984e63a2c3b96c31de48ee398919
parent118b792662dfcbd630c2224e844963549d4ebe92 (diff)
downloadseabios-microvm.tar.gz
pci: add qemu gpex host bridge support.microvm
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 <kraxel@redhat.com>
-rw-r--r--src/fw/paravirt.c62
1 files changed, 62 insertions, 0 deletions
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
@@ -198,6 +198,67 @@ static void msr_feature_control_setup(void)
}
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)
{
if (!CONFIG_QEMU)
@@ -240,6 +301,7 @@ qemu_platform_setup(void)
if (RsdpAddr) {
acpi_dsdt_parse();
+ gpex_setup();
virtio_mmio_setup_acpi();
return;
}