提交 1de329c1 编写于 作者: M Mike Travis 提交者: Ingo Molnar

x86/platform/UV: Support UV4 socket address changes

With the UV4 system architecture addressing changes, BIOS now provides
this information via an EFI system table.  This is the initial decoding
of that system table.  It also collects the sizing information for
later allocation of dynamic conversion tables.
Tested-by: NDimitri Sivanich <sivanich@sgi.com>
Tested-by: NJohn Estabrook <estabrook@sgi.com>
Tested-by: NGary Kroening <gfk@sgi.com>
Tested-by: NNathan Zimmer <nzimmer@sgi.com>
Signed-off-by: NMike Travis <travis@sgi.com>
Reviewed-by: NDimitri Sivanich <sivanich@sgi.com>
Cc: Andrew Banman <abanman@sgi.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Len Brown <len.brown@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160429215405.503022681@asylum.americas.sgi.comSigned-off-by: NIngo Molnar <mingo@kernel.org>
上级 ef93bf80
...@@ -147,15 +147,21 @@ struct uv_scir_s { ...@@ -147,15 +147,21 @@ struct uv_scir_s {
*/ */
struct uv_hub_info_s { struct uv_hub_info_s {
unsigned long global_mmr_base; unsigned long global_mmr_base;
unsigned long global_mmr_shift;
unsigned long gpa_mask; unsigned long gpa_mask;
unsigned int gnode_extra; unsigned short min_socket;
unsigned short min_pnode;
unsigned char hub_revision; unsigned char hub_revision;
unsigned char apic_pnode_shift; unsigned char apic_pnode_shift;
unsigned char gpa_shift;
unsigned char m_shift; unsigned char m_shift;
unsigned char n_lshift; unsigned char n_lshift;
unsigned int gnode_extra;
unsigned long gnode_upper; unsigned long gnode_upper;
unsigned long lowmem_remap_top; unsigned long lowmem_remap_top;
unsigned long lowmem_remap_base; unsigned long lowmem_remap_base;
unsigned long global_gru_base;
unsigned long global_gru_shift;
unsigned short pnode; unsigned short pnode;
unsigned short pnode_mask; unsigned short pnode_mask;
unsigned short coherency_domain_number; unsigned short coherency_domain_number;
...@@ -362,7 +368,8 @@ union uvh_apicid { ...@@ -362,7 +368,8 @@ union uvh_apicid {
#define UV_GLOBAL_GRU_MMR_BASE 0x4000000 #define UV_GLOBAL_GRU_MMR_BASE 0x4000000
#define UV_GLOBAL_MMR32_PNODE_SHIFT 15 #define UV_GLOBAL_MMR32_PNODE_SHIFT 15
#define UV_GLOBAL_MMR64_PNODE_SHIFT 26 #define _UV_GLOBAL_MMR64_PNODE_SHIFT 26
#define UV_GLOBAL_MMR64_PNODE_SHIFT (uv_hub_info->global_mmr_shift)
#define UV_GLOBAL_MMR32_PNODE_BITS(p) ((p) << (UV_GLOBAL_MMR32_PNODE_SHIFT)) #define UV_GLOBAL_MMR32_PNODE_BITS(p) ((p) << (UV_GLOBAL_MMR32_PNODE_SHIFT))
......
...@@ -301,7 +301,13 @@ EXPORT_SYMBOL_GPL(uv_possible_blades); ...@@ -301,7 +301,13 @@ EXPORT_SYMBOL_GPL(uv_possible_blades);
unsigned long sn_rtc_cycles_per_second; unsigned long sn_rtc_cycles_per_second;
EXPORT_SYMBOL(sn_rtc_cycles_per_second); EXPORT_SYMBOL(sn_rtc_cycles_per_second);
/* the following values are used for the per node hub info struct */
static __initdata unsigned short *_node_to_pnode; static __initdata unsigned short *_node_to_pnode;
static __initdata unsigned short _min_socket, _max_socket;
static __initdata unsigned short _min_pnode, _max_pnode, _gr_table_len;
static __initdata struct uv_gam_range_entry *uv_gre_table;
static __initdata struct uv_gam_parameters *uv_gp_table;
#define SOCK_EMPTY ((unsigned short)~0)
extern int uv_hub_info_version(void) extern int uv_hub_info_version(void)
{ {
...@@ -978,6 +984,7 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info) ...@@ -978,6 +984,7 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
hub_info->hub_revision = uv_hub_info->hub_revision; hub_info->hub_revision = uv_hub_info->hub_revision;
hub_info->pnode_mask = uv_cpuid.pnode_mask; hub_info->pnode_mask = uv_cpuid.pnode_mask;
hub_info->min_pnode = _min_pnode;
hub_info->gpa_mask = mn.m_val ? hub_info->gpa_mask = mn.m_val ?
(1UL << (mn.m_val + mn.n_val)) - 1 : (1UL << (mn.m_val + mn.n_val)) - 1 :
(1UL << uv_cpuid.gpa_shift) - 1; (1UL << uv_cpuid.gpa_shift) - 1;
...@@ -989,9 +996,19 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info) ...@@ -989,9 +996,19 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
hub_info->gnode_upper = hub_info->gnode_upper =
((unsigned long)hub_info->gnode_extra << mn.m_val); ((unsigned long)hub_info->gnode_extra << mn.m_val);
hub_info->global_mmr_base = if (uv_gp_table) {
uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & hub_info->global_mmr_base = uv_gp_table->mmr_base;
~UV_MMR_ENABLE; hub_info->global_mmr_shift = uv_gp_table->mmr_shift;
hub_info->global_gru_base = uv_gp_table->gru_base;
hub_info->global_gru_shift = uv_gp_table->gru_shift;
hub_info->gpa_shift = uv_gp_table->gpa_shift;
hub_info->gpa_mask = (1UL << hub_info->gpa_shift) - 1;
} else {
hub_info->global_mmr_base =
uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
~UV_MMR_ENABLE;
hub_info->global_mmr_shift = _UV_GLOBAL_MMR64_PNODE_SHIFT;
}
get_lowmem_redirect( get_lowmem_redirect(
&hub_info->lowmem_remap_base, &hub_info->lowmem_remap_top); &hub_info->lowmem_remap_base, &hub_info->lowmem_remap_top);
...@@ -1003,15 +1020,109 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info) ...@@ -1003,15 +1020,109 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
hub_info->n_val, hub_info->m_val, hub_info->n_val, hub_info->m_val,
hub_info->m_shift, hub_info->n_lshift); hub_info->m_shift, hub_info->n_lshift);
pr_info("UV: pnode_mask:0x%x gpa_mask:0x%lx apic_pns:%d\n", pr_info("UV: gpa_mask/shift:0x%lx/%d pnode_mask:0x%x apic_pns:%d\n",
hub_info->pnode_mask, hub_info->gpa_mask, hub_info->gpa_mask, hub_info->gpa_shift,
hub_info->apic_pnode_shift); hub_info->pnode_mask, hub_info->apic_pnode_shift);
pr_info("UV: mmr_base/shift:0x%lx/%ld gru_base/shift:0x%lx/%ld\n",
hub_info->global_mmr_base, hub_info->global_mmr_shift,
hub_info->global_gru_base, hub_info->global_gru_shift);
pr_info("UV: gnode_upper:0x%lx gnode_extra:0x%x\n", pr_info("UV: gnode_upper:0x%lx gnode_extra:0x%x\n",
hub_info->gnode_upper, hub_info->gnode_extra); hub_info->gnode_upper, hub_info->gnode_extra);
}
static void __init decode_gam_params(unsigned long ptr)
{
uv_gp_table = (struct uv_gam_parameters *)ptr;
pr_info("UV: GAM Params...\n");
pr_info("UV: mmr_base/shift:0x%llx/%d gru_base/shift:0x%llx/%d gpa_shift:%d\n",
uv_gp_table->mmr_base, uv_gp_table->mmr_shift,
uv_gp_table->gru_base, uv_gp_table->gru_shift,
uv_gp_table->gpa_shift);
}
static void __init decode_gam_rng_tbl(unsigned long ptr)
{
struct uv_gam_range_entry *gre = (struct uv_gam_range_entry *)ptr;
unsigned long lgre = 0;
int index = 0;
int sock_min = 999999, pnode_min = 99999;
int sock_max = -1, pnode_max = -1;
uv_gre_table = gre;
for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) {
if (!index) {
pr_info("UV: GAM Range Table...\n");
pr_info("UV: # %20s %14s %5s %4s %5s %3s %2s %3s\n",
"Range", "", "Size", "Type", "NASID",
"SID", "PN", "PXM");
}
pr_info(
"UV: %2d: 0x%014lx-0x%014lx %5luG %3d %04x %02x %02x %3d\n",
index++,
(unsigned long)lgre << UV_GAM_RANGE_SHFT,
(unsigned long)gre->limit << UV_GAM_RANGE_SHFT,
((unsigned long)(gre->limit - lgre)) >>
(30 - UV_GAM_RANGE_SHFT), /* 64M -> 1G */
gre->type, gre->nasid, gre->sockid,
gre->pnode, gre->pxm);
lgre = gre->limit;
if (sock_min > gre->sockid)
sock_min = gre->sockid;
if (sock_max < gre->sockid)
sock_max = gre->sockid;
if (pnode_min > gre->pnode)
pnode_min = gre->pnode;
if (pnode_max < gre->pnode)
pnode_max = gre->pnode;
}
_min_socket = sock_min;
_max_socket = sock_max;
_min_pnode = pnode_min;
_max_pnode = pnode_max;
_gr_table_len = index;
pr_info(
"UV: GRT: %d entries, sockets(min:%x,max:%x) pnodes(min:%x,max:%x)\n",
index, _min_socket, _max_socket, _min_pnode, _max_pnode);
}
static void __init decode_uv_systab(void)
{
struct uv_systab *st;
int i;
st = uv_systab;
if ((!st || st->revision < UV_SYSTAB_VERSION_UV4) && !is_uv4_hub())
return;
if (st->revision != UV_SYSTAB_VERSION_UV4_LATEST) {
pr_crit(
"UV: BIOS UVsystab version(%x) mismatch, expecting(%x)\n",
st->revision, UV_SYSTAB_VERSION_UV4_LATEST);
BUG();
}
pr_info("UV: global MMR base 0x%lx\n", hub_info->global_mmr_base); for (i = 0; st->entry[i].type != UV_SYSTAB_TYPE_UNUSED; i++) {
unsigned long ptr = st->entry[i].offset;
if (!ptr)
continue;
ptr = ptr + (unsigned long)st;
switch (st->entry[i].type) {
case UV_SYSTAB_TYPE_GAM_PARAMS:
decode_gam_params(ptr);
break;
case UV_SYSTAB_TYPE_GAM_RNG_TBL:
decode_gam_rng_tbl(ptr);
break;
}
}
} }
/* /*
...@@ -1080,6 +1191,8 @@ void __init uv_system_init(void) ...@@ -1080,6 +1191,8 @@ void __init uv_system_init(void)
if (is_uv1_hub()) if (is_uv1_hub())
map_low_mmrs(); map_low_mmrs();
uv_bios_init(); /* get uv_systab for decoding */
decode_uv_systab();
uv_init_hub_info(&hub_info); uv_init_hub_info(&hub_info);
uv_possible_blades = num_possible_nodes(); uv_possible_blades = num_possible_nodes();
if (!_node_to_pnode) if (!_node_to_pnode)
...@@ -1091,7 +1204,6 @@ void __init uv_system_init(void) ...@@ -1091,7 +1204,6 @@ void __init uv_system_init(void)
num_possible_nodes(), num_possible_nodes(),
num_possible_cpus()); num_possible_cpus());
uv_bios_init();
uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, &sn_coherency_id, uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, &sn_coherency_id,
&sn_region_size, &system_serial_number); &sn_region_size, &system_serial_number);
hub_info.coherency_domain_number = sn_coherency_id; hub_info.coherency_domain_number = sn_coherency_id;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册