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


Reply via email to