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 <shentey@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