To support multiple pci domains of pxb-pcie device in qemu, we need to setup mcfg range in seabios. We use [0x80000000, 0xb0000000) to hold new domain mcfg table for now, and we need to retrieve the desired mcfg size of each pxb-pcie from a hidden bar because they may not need the whole 256 busses, which also enables us to support more domains within a limited range (768MB)
Signed-off-by: Zihan Yang whois.zihan.yang@gmail.com --- src/fw/dev-q35.h | 7 +++++++ src/fw/pciinit.c | 32 ++++++++++++++++++++++++++++++++ src/hw/pci_ids.h | 1 + 3 files changed, 40 insertions(+)
diff --git a/src/fw/dev-q35.h b/src/fw/dev-q35.h index 201825d..229cd81 100644 --- a/src/fw/dev-q35.h +++ b/src/fw/dev-q35.h @@ -49,4 +49,11 @@ #define ICH9_APM_ACPI_ENABLE 0x2 #define ICH9_APM_ACPI_DISABLE 0x3
+#define PXB_PCIE_HOST_BRIDGE_MCFG_BAR 0x50 /* 64bit register */ +#define PXB_PCIE_HOST_BRIDGE_MCFG_SIZE 0x58 /* 32bit register */ +#define PXB_PCIE_HOST_BRIDGE_ENABLE Q35_HOST_BRIDGE_PCIEXBAREN +/* pxb-pcie can use [0x80000000, 0xb0000000), be careful not to overflow */ +#define PXB_PCIE_HOST_BRIDGE_MCFG_SIZE_ADDR 0x80000000 +#define PXB_PCIE_HOST_BRIDGE_MCFG_SIZE_ADDR_UPPER Q35_HOST_BRIDGE_PCIEXBAR_ADDR + #endif // dev-q35.h diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index c0634bc..e0ac22c 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -51,6 +51,7 @@ u64 pcimem_end = BUILD_PCIMEM_END; u64 pcimem64_start = BUILD_PCIMEM64_START; u64 pcimem64_end = BUILD_PCIMEM64_END; u64 pci_io_low_end = 0xa000; +u64 pxb_pcie_mcfg_base = PXB_PCIE_HOST_BRIDGE_MCFG_SIZE_ADDR;
struct pci_region_entry { struct pci_device *dev; @@ -507,11 +508,42 @@ static void mch_mem_addr_setup(struct pci_device *dev, void *arg) pci_io_low_end = acpi_pm_base; }
+static void pxb_pcie_mem_addr_setup(struct pci_device *dev, void *arg) +{ + u64 mcfg_base; + u32 mcfg_size = pci_config_readl(dev->bdf, PXB_PCIE_HOST_BRIDGE_MCFG_SIZE); + + /* 0 means this pxb-pcie still resides in pci domain 0 */ + if (mcfg_size == 0) + return; + + if (pxb_pcie_mcfg_base + mcfg_size > + PXB_PCIE_HOST_BRIDGE_MCFG_SIZE_ADDR_UPPER) { + dprintf(1, "PCI: Not enough space to hold new pci domains\n"); + return; + } + + mcfg_base = pxb_pcie_mcfg_base; + pxb_pcie_mcfg_base += mcfg_size; + + /* First clear old mmio, taken care of by QEMU */ + pci_config_writel(dev->bdf, PXB_PCIE_HOST_BRIDGE_MCFG_BAR, 0); + /* Update MCFG base */ + pci_config_writel(dev->bdf, PXB_PCIE_HOST_BRIDGE_MCFG_BAR + 4, + mcfg_base >> 32); + pci_config_writel(dev->bdf, PXB_PCIE_HOST_BRIDGE_MCFG_BAR, + (mcfg_base & 0xffffffff) | PXB_PCIE_HOST_BRIDGE_ENABLE); + + e820_add(mcfg_base, mcfg_size, E820_RESERVED); +} + static const struct pci_device_id pci_platform_tbl[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, i440fx_mem_addr_setup), PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH, mch_mem_addr_setup), + PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_PXB_HOST, + pxb_pcie_mem_addr_setup), PCI_DEVICE_END };
diff --git a/src/hw/pci_ids.h b/src/hw/pci_ids.h index 1096461..b495920 100644 --- a/src/hw/pci_ids.h +++ b/src/hw/pci_ids.h @@ -2266,6 +2266,7 @@ #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_ROOT_PORT 0x000C #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 +#define PCI_DEVICE_ID_REDHAT_PXB_HOST 0x000B
#define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29