Linux clears all inbound viewport mappings which results in the default mapping set up during realize() to be cleared. Fix that by introducing a fallback memory region which gets enabled if no inbound viewports are configured, as the real HW would do.
Signed-off-by: Bernhard Beschow <shen...@gmail.com> --- include/hw/pci-host/designware.h | 1 + hw/pci-host/designware.c | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/hw/pci-host/designware.h b/include/hw/pci-host/designware.h index 34beee1285..342b09fd08 100644 --- a/include/hw/pci-host/designware.h +++ b/include/hw/pci-host/designware.h @@ -86,6 +86,7 @@ struct DesignwarePCIEHost { struct { AddressSpace address_space; MemoryRegion address_space_root; + MemoryRegion address_space_root_default; MemoryRegion memory; MemoryRegion io; diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index 2fd60a4817..d71133a456 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -347,6 +347,17 @@ static void designware_pcie_update_viewport(DesignwarePCIERoot *root, break; } } + + bool one_mapped = false; + for (int j = 0; j < DESIGNWARE_PCIE_NUM_VIEWPORTS; j++) { + one_mapped |= memory_region_is_mapped(&root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][j].mem); + } + + /* + * If no inbound iATU windows are configured, HW defaults to + * letting inbound TLPs to pass in. + */ + memory_region_set_enabled(&host->pci.address_space_root_default, !one_mapped); } static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, @@ -477,19 +488,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp) viewport->target = 0x0000000000000000ULL; viewport->limit = UINT32_MAX; viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM; - - /* - * If no inbound iATU windows are configured, HW defaults to - * letting inbound TLPs to pass in. We emulate that by explicitly - * configuring first inbound window to cover all of target's - * address space. - * - * NOTE: This will not work correctly for the case when first - * configured inbound window is window 0 - */ - viewport->cr[1] = (viewport->inbound && j == 0) - ? DESIGNWARE_PCIE_ATU_ENABLE - : 0; + viewport->cr[1] = 0; designware_pcie_update_viewport(root, viewport); } @@ -706,6 +705,11 @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp) address_space_init(&s->pci.address_space, &s->pci.address_space_root, "pcie-bus-address-space"); + memory_region_init_alias(&s->pci.address_space_root_default, OBJECT(s), + "pcie-bus-inbound-default", get_system_memory(), + 0, UINT32_MAX); + memory_region_add_subregion_overlap(&s->pci.address_space_root, 0, + &s->pci.address_space_root_default, -10); pci_setup_iommu(pci->bus, &designware_iommu_ops, s); qdev_realize(DEVICE(&s->root), BUS(pci->bus), &error_fatal); -- 2.50.1