Skip to content

Commit

Permalink
x86/platform/uv: Update MMIOH references based on new UV5 MMRs.
Browse files Browse the repository at this point in the history
Make modifications to the MMIOH mappings to accommodate changes for UV5.

Signed-off-by: Mike Travis <mike.travis@hpe.com>
Reviewed-by: Steve Wahl <steve.wahl@hpe.com>
  • Loading branch information
mike-travis authored and intel-lab-lkp committed Oct 2, 2020
1 parent cc7436b commit 37f27df
Showing 1 changed file with 143 additions and 68 deletions.
211 changes: 143 additions & 68 deletions arch/x86/kernel/apic/x2apic_uv_x.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -1011,51 +1045,92 @@ 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;
}
fi = li = i;
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;
}
}

Expand Down

0 comments on commit 37f27df

Please sign in to comment.