IMX6DQRM Rev4, in chapter 48.3.9.3, specifies that for inbound iATU
with no address match: 'If there is no match, then the address is
untranslated.'
The current model implementation registers inbound region 0 as
untranslated dummy, intending to serve as a passing medium for
the no-match address behavior using MemoryRegion.
However, a bug exists where the Linux Kernel driver of Designware PCIe
RC is unaware that inbound region 0 is registered for special setup.
During Kernel driver initialization, the driver overwrites the target
address to 0x1111_0000 and later disables all regions, rendering the
untranslated passing medium ineffective.
Consequently, TLP cannot pass iATU, and the transaction is blocked.
To address this issue, we propose "inbound untranslated pass" which is
consistently enabled and distinct from the usage of iATU regions.
We achieve this by introducing a new MemoryRegion with the
lowest priority to prevent conflicts with configured iATU regions.
This fix has been tested with the integration of Designware PCIe RC
along with the e1000e Ethernet card, ensuring proper functioning of
network transmissions and MSI interrupts.
Signed-off-by: Max Hsu <max.hsu@sifive.com>
---
hw/pci-host/designware.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
index f477f97847..83dd9b1aaf 100644
--- a/hw/pci-host/designware.c
+++ b/hw/pci-host/designware.c
@@ -487,17 +487,28 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
}
/*
- * 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.
+ * For HW iATU address no match behavior, the TLP should continue with
+ * untranslated address.
*
- * NOTE: This will not work correctly for the case when first
- * configured inbound window is window 0
+ * We emulate this behavior by adding extra MemoryRegions to create a
+ * 1:1 mapping between PCI address space and cpu address space within
+ * the 64-bit range, encompassing both inbound and outbound directions.
+ *
+ * To avoid interfering with the configured iATU regions and potentially
+ * producing incorrect addresses, the two untranslated regions are set
+ * to have the lowest priority.
*/
- viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][0];
- viewport->cr[1] = DESIGNWARE_PCIE_ATU_ENABLE;
- designware_pcie_update_viewport(root, viewport);
+ MemoryRegion *inbound_untranslated = g_new(MemoryRegion, 1);
+
+ memory_region_init_alias(inbound_untranslated, OBJECT(root),
+ "inbound untranslated pass",
+ get_system_memory(), dummy_offset, dummy_size);
+ memory_region_add_subregion_overlap(&host->pci.address_space_root,
+ dummy_offset, inbound_untranslated,
+ INT32_MIN);
+ memory_region_set_size(inbound_untranslated, UINT64_MAX);
+ memory_region_set_address(inbound_untranslated, 0x0ULL);
+ memory_region_set_enabled(inbound_untranslated, true);
memory_region_init_io(&root->msi.iomem, OBJECT(root),
&designware_pci_host_msi_ops,
--
2.34.1