[PATCH 06/11] hw/pci-host/astro: Fix LMMIO DIRECT mappings

Helge Deller posted 11 patches 2 days, 3 hours ago
Maintainers: Richard Henderson <richard.henderson@linaro.org>, Helge Deller <deller@gmx.de>
[PATCH 06/11] hw/pci-host/astro: Fix LMMIO DIRECT mappings
Posted by Helge Deller 2 days, 3 hours ago
From: Helge Deller <deller@gmx.de>

Fix the existing code which has the mask wrong.
Implement the direct mapping via overlapping subregion with priority 3
to make sure the direct mapping gets precedence over the LMMIO region.

Signed-off-by: Helge Deller <deller@gmx.de>
---
 hw/pci-host/astro.c | 39 +++++++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c
index 4af35ea92f..e1d73258c4 100644
--- a/hw/pci-host/astro.c
+++ b/hw/pci-host/astro.c
@@ -607,9 +607,13 @@ static void adjust_LMMIO_DIRECT_mapping(AstroState *s, unsigned int reg_index)
     MemoryRegion *lmmio_alias;
     unsigned int lmmio_index, map_route;
     hwaddr map_addr;
-    uint32_t map_size;
+    uint32_t map_size, map_enabled;
     struct ElroyState *elroy;
 
+    /* each LMMIO may access from 1 MB up to 64 MB */
+    const unsigned int lmmio_mask = ~(1 * MiB - 1);
+    const unsigned int lmmio_max_size = 64 * MiB;
+
     /* pointer to LMMIO_DIRECT entry */
     lmmio_index = reg_index / 3;
     lmmio_alias = &s->lmmio_direct[lmmio_index];
@@ -622,31 +626,38 @@ static void adjust_LMMIO_DIRECT_mapping(AstroState *s, unsigned int reg_index)
     map_route &= (ELROY_NUM - 1);
     elroy = s->elroy[map_route];
 
+    /* make sure the lmmio region is initially turned off */
     if (lmmio_alias->enabled) {
         memory_region_set_enabled(lmmio_alias, false);
     }
 
+    /* do sanity checks and calculate mmio size */
+    map_enabled = map_addr & 1;
+    map_addr &= lmmio_mask;
+    map_size &= lmmio_mask;
+    map_size = MIN(map_size, lmmio_max_size);
     map_addr = F_EXTEND(map_addr);
-    map_addr &= TARGET_PAGE_MASK;
-    map_size = (~map_size) + 1;
-    map_size &= TARGET_PAGE_MASK;
 
-    /* exit if disabled or zero map size */
-    if (!(map_addr & 1) || !map_size) {
+    /* exit if disabled or has zero size. */
+    if (!map_enabled || !map_size) {
         return;
     }
 
-    if (!memory_region_size(lmmio_alias)) {
+    if (!lmmio_alias->name) {
+        char lmmio_name[32];
+        snprintf(lmmio_name, sizeof(lmmio_name),
+                 "LMMIO-DIRECT-%u", lmmio_index);
         memory_region_init_alias(lmmio_alias, OBJECT(elroy),
-                        "pci-lmmmio-alias", &elroy->pci_mmio,
+                        lmmio_name, &elroy->pci_mmio,
                         (uint32_t) map_addr, map_size);
-        memory_region_add_subregion(get_system_memory(), map_addr,
-                                 lmmio_alias);
-    } else {
-        memory_region_set_alias_offset(lmmio_alias, map_addr);
-        memory_region_set_size(lmmio_alias, map_size);
-        memory_region_set_enabled(lmmio_alias, true);
+        memory_region_add_subregion_overlap(get_system_memory(),
+                        map_addr, lmmio_alias, 3);
     }
+
+    memory_region_set_address(lmmio_alias, map_addr);
+    memory_region_set_alias_offset(lmmio_alias, (uint32_t) map_addr);
+    memory_region_set_size(lmmio_alias, map_size);
+    memory_region_set_enabled(lmmio_alias, true);
 }
 
 static MemTxResult astro_chip_read_with_attrs(void *opaque, hwaddr addr,
-- 
2.53.0