Make modifications to the MMIOH mappings to accommodate changes for UV5.

Signed-off-by: Mike Travis <mike.tra...@hpe.com>
Reviewed-by: Steve Wahl <steve.w...@hpe.com>
---
 arch/x86/kernel/apic/x2apic_uv_x.c | 211 +++++++++++++++++++----------
 1 file changed, 143 insertions(+), 68 deletions(-)

diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c 
b/arch/x86/kernel/apic/x2apic_uv_x.c
index 353825a0b327..746a56466066 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -228,6 +228,13 @@ static void __init uv_tsc_check_sync(void)
                mark_tsc_unstable("UV BIOS");
 }
 
+/* Selector for (4|4A|5) structs */
+#define uvxy_field(sname, field, undef) (      \
+       is_uv(UV4A) ? sname.s4a.field :         \
+       is_uv(UV4) ? sname.s4.field :           \
+       is_uv(UV3) ? sname.s3.field :           \
+       undef)
+
 /* [Copied from arch/x86/kernel/cpu/topology.c:detect_extended_topology()] */
 
 #define SMT_LEVEL                      0       /* Leaf 0xb SMT level */
@@ -882,6 +889,7 @@ static __init void get_lowmem_redirect(unsigned long *base, 
unsigned long *size)
 }
 
 enum map_type {map_wb, map_uc};
+static const char * const mt[] = { "WB", "UC" };
 
 static __init void map_high(char *id, unsigned long base, int pshift, int 
bshift, int max_pnode, enum map_type map_type)
 {
@@ -893,11 +901,13 @@ static __init void map_high(char *id, unsigned long base, 
int pshift, int bshift
                pr_info("UV: Map %s_HI base address NULL\n", id);
                return;
        }
-       pr_debug("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes);
        if (map_type == map_uc)
                init_extra_mapping_uc(paddr, bytes);
        else
                init_extra_mapping_wb(paddr, bytes);
+
+       pr_info("UV: Map %s_HI 0x%lx - 0x%lx %s (%d segments)\n",
+               id, paddr, paddr + bytes, mt[map_type], max_pnode + 1);
 }
 
 static __init void map_gru_high(int max_pnode)
@@ -931,52 +941,73 @@ static __init void map_mmr_high(int max_pnode)
                pr_info("UV: MMR disabled\n");
 }
 
-/* UV3/4 have identical MMIOH overlay configs, UV4A is slightly different */
-static __init void map_mmioh_high_uv34(int index, int min_pnode, int max_pnode)
-{
-       unsigned long overlay;
-       unsigned long mmr;
-       unsigned long base;
-       unsigned long nasid_mask;
-       unsigned long m_overlay;
-       int i, n, shift, m_io, max_io;
-       int nasid, lnasid, fi, li;
-       char *id;
-
-       if (index == 0) {
-               id = "MMIOH0";
-               m_overlay = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0;
-               overlay = uv_read_local_mmr(m_overlay);
-               base = overlay & UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK;
+/* Arch specific ENUM cases */
+enum mmioh_arch {
+       UV2_MMIOH = -1,
+       UVY_MMIOH0, UVY_MMIOH1,
+       UVX_MMIOH0, UVX_MMIOH1,
+};
+
+/* Calculate and Map MMIOH Regions */
+void __init calc_mmioh_map(enum mmioh_arch index, int min_pnode, int max_pnode,
+       int shift, unsigned long base, int m_io, int n_io)
+{
+       unsigned long mmr, nasid_mask;
+       int nasid, min_nasid, max_nasid, lnasid, mapped;
+       int i, fi, li, n, max_io;
+       char id[8];
+
+       /* One (UV2) mapping */
+       if (index == UV2_MMIOH) {
+               strncpy(id, "MMIOH", sizeof(id));
+               max_io = max_pnode;
+               mapped = 0;
+               goto map_exit;
+       }
+
+       /* small and large MMIOH mappings */
+       switch (index) {
+       case UVY_MMIOH0:
+               mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0;
+               nasid_mask = UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK;
+               n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH;
+               min_nasid = min_pnode;
+               max_nasid = max_pnode;
+               mapped = 1;
+               break;
+       case UVY_MMIOH1:
+               mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1;
+               nasid_mask = UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK;
+               n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH;
+               min_nasid = min_pnode;
+               max_nasid = max_pnode;
+               mapped = 1;
+               break;
+       case UVX_MMIOH0:
                mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0;
-               m_io = (overlay & UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_MASK)
-                       >> UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_SHFT;
-               shift = UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_SHFT;
+               nasid_mask = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK;
                n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH;
-               nasid_mask = UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK;
-       } else {
-               id = "MMIOH1";
-               m_overlay = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1;
-               overlay = uv_read_local_mmr(m_overlay);
-               base = overlay & UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK;
+               min_nasid = min_pnode * 2;
+               max_nasid = max_pnode * 2;
+               mapped = 1;
+               break;
+       case UVX_MMIOH1:
                mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1;
-               m_io = (overlay & UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_MASK)
-                       >> UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_SHFT;
-               shift = UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_SHFT;
+               nasid_mask = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK;
                n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH;
-               nasid_mask = UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK;
-       }
-       pr_info("UV: %s overlay 0x%lx base:0x%lx m_io:%d\n", id, overlay, base, 
m_io);
-       if (!(overlay & UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_MASK)) {
-               pr_info("UV: %s disabled\n", id);
+               min_nasid = min_pnode * 2;
+               max_nasid = max_pnode * 2;
+               mapped = 1;
+               break;
+       default:
+               pr_err("UV:%s:Invalid mapping type:%d\n", __func__, index);
                return;
        }
 
-       /* Convert to NASID: */
-       min_pnode *= 2;
-       max_pnode *= 2;
-       max_io = lnasid = fi = li = -1;
+       /* enum values chosen so (index mod 2) is MMIOH 0/1 (low/high) */
+       snprintf(id, sizeof(id), "MMIOH%d", index%2);
 
+       max_io = lnasid = fi = li = -1;
        for (i = 0; i < n; i++) {
                unsigned long m_redirect = mmr + i * 8;
                unsigned long redirect = uv_read_local_mmr(m_redirect);
@@ -986,9 +1017,12 @@ static __init void map_mmioh_high_uv34(int index, int 
min_pnode, int max_pnode)
                        pr_info("UV: %s redirect base 0x%lx(@0x%lx) 0x%04x\n",
                                id, redirect, m_redirect, nasid);
 
-               /* Invalid NASID: */
-               if (nasid < min_pnode || max_pnode < nasid)
+               /* Invalid NASID check */
+               if (nasid < min_nasid || max_nasid < nasid) {
+                       pr_err("UV:%s:Invalid NASID:%x (range:%x..%x)\n",
+                               __func__, index, min_nasid, max_nasid );
                        nasid = -1;
+               }
 
                if (nasid == lnasid) {
                        li = i;
@@ -1011,7 +1045,8 @@ static __init void map_mmioh_high_uv34(int index, int 
min_pnode, int max_pnode)
                        }
                        addr1 = (base << shift) + f * (1ULL << m_io);
                        addr2 = (base << shift) + (l + 1) * (1ULL << m_io);
-                       pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx 
- 0x%016lx\n", id, fi, li, lnasid, addr1, addr2);
+                       pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx 
- 0x%016lx\n",
+                               id, fi, li, lnasid, addr1, addr2);
                        if (max_io < l)
                                max_io = l;
                }
@@ -1019,43 +1054,83 @@ static __init void map_mmioh_high_uv34(int index, int 
min_pnode, int max_pnode)
                lnasid = nasid;
        }
 
-       pr_info("UV: %s base:0x%lx shift:%d M_IO:%d MAX_IO:%d\n", id, base, 
shift, m_io, max_io);
+map_exit:
+       pr_info("UV: %s base:0x%lx shift:%d m_io:%d max_io:%d max_pnode:0x%x\n",
+               id, base, shift, m_io, max_io, max_pnode);
 
-       if (max_io >= 0)
+       if (max_io >= 0 && !mapped)
                map_high(id, base, shift, m_io, max_io, map_uc);
 }
 
 static __init void map_mmioh_high(int min_pnode, int max_pnode)
 {
-       union uvh_rh_gam_mmioh_overlay_config_u mmioh;
-       unsigned long mmr, base;
-       int shift, enable, m_io, n_io;
+       /* UVY flavor */
+       if (UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0) {
+               union uvh_rh10_gam_mmioh_overlay_config0_u mmioh0;
+               union uvh_rh10_gam_mmioh_overlay_config1_u mmioh1;
+
+               mmioh0.v = 
uv_read_local_mmr(UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0);
+               if (unlikely(mmioh0.s.enable == 0))
+                       pr_info("UV: MMIOH0 disabled\n");
+               else
+                       calc_mmioh_map(UVY_MMIOH0, min_pnode, max_pnode,
+                               UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT,
+                               mmioh0.s.base, mmioh0.s.m_io, mmioh0.s.n_io);
 
-       if (is_uv3_hub() || is_uv4_hub()) {
-               /* Map both MMIOH regions: */
-               map_mmioh_high_uv34(0, min_pnode, max_pnode);
-               map_mmioh_high_uv34(1, min_pnode, max_pnode);
+               mmioh1.v = 
uv_read_local_mmr(UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1);
+               if (unlikely(mmioh1.s.enable == 0))
+                       pr_info("UV: MMIOH1 disabled\n");
+               else
+                       calc_mmioh_map(UVY_MMIOH1, min_pnode, max_pnode,
+                               UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT,
+                               mmioh1.s.base, mmioh1.s.m_io, mmioh1.s.n_io);
                return;
        }
+       /* UVX flavor */
+       if (UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0) {
+               union uvh_rh_gam_mmioh_overlay_config0_u mmioh0;
+               union uvh_rh_gam_mmioh_overlay_config1_u mmioh1;
+
+               mmioh0.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0);
+               if (unlikely(mmioh0.s.enable == 0))
+                       pr_info("UV: MMIOH0 disabled\n");
+               else {
+                       unsigned long base = uvxy_field(mmioh0, base, 0);
+                       int m_io = uvxy_field(mmioh0, m_io, 0);
+                       int n_io = uvxy_field(mmioh0, n_io, 0);
+
+                       calc_mmioh_map(UVX_MMIOH0, min_pnode, max_pnode,
+                               UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT,
+                               base, m_io, n_io);
+               }
 
-       if (is_uv2_hub()) {
-               mmr     = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG;
-               shift   = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_BASE_SHFT;
-               mmioh.v = uv_read_local_mmr(mmr);
-               enable  = !!mmioh.s2.enable;
-               base    = mmioh.s2.base;
-               m_io    = mmioh.s2.m_io;
-               n_io    = mmioh.s2.n_io;
-
-               if (enable) {
-                       max_pnode &= (1 << n_io) - 1;
-                       pr_info(
-                       "UV: base:0x%lx shift:%d N_IO:%d M_IO:%d 
max_pnode:0x%x\n",
-                               base, shift, m_io, n_io, max_pnode);
-                       map_high("MMIOH", base, shift, m_io, max_pnode, map_uc);
-               } else {
-                       pr_info("UV: MMIOH disabled\n");
+               mmioh1.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1);
+               if (unlikely(mmioh1.s.enable == 0))
+                       pr_info("UV: MMIOH1 disabled\n");
+               else {
+                       unsigned long base = uvxy_field(mmioh1, base, 0);
+                       int m_io = uvxy_field(mmioh1, m_io, 0);
+                       int n_io = uvxy_field(mmioh1, n_io, 0);
+
+                       calc_mmioh_map(UVX_MMIOH1, min_pnode, max_pnode,
+                               UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT,
+                               base, m_io, n_io);
                }
+               return;
+       }
+
+       /* UV2 flavor */
+       if (UVH_RH_GAM_MMIOH_OVERLAY_CONFIG) {
+               union uvh_rh_gam_mmioh_overlay_config_u mmioh;
+
+               mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG);
+               if (unlikely(mmioh.s2.enable == 0))
+                       pr_info("UV: MMIOH disabled\n");
+               else
+                       calc_mmioh_map(UV2_MMIOH, min_pnode, max_pnode,
+                               UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_BASE_SHFT,
+                               mmioh.s2.base, mmioh.s2.m_io, mmioh.s2.n_io);
+               return;
        }
 }
 
-- 
2.21.0

Reply via email to