Commit 36db3144 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_platform_for_6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 platform updates from Dave Hansen:
 "Allow CPUs in SGX/HPE Ultraviolet to start using Sub-NUMA clustering
  (SNC) mode. SNC has been around outside the UV world for a while but
  evidently never worked on UV systems.

  SNC is rather notorious for breaking bad assumptions of a 1:1
  relationship between physical sockets and NUMA nodes. The UV code was
  rather prolific with these assumptions and took quite a bit of
  refactoring to remove them"

* tag 'x86_platform_for_6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/platform/uv: Update UV[23] platform code for SNC
  x86/platform/uv: Remove remaining BUG_ON() and BUG() calls
  x86/platform/uv: UV support for sub-NUMA clustering
  x86/platform/uv: Helper functions for allocating and freeing conversion tables
  x86/platform/uv: When searching for minimums, start at INT_MAX not 99999
  x86/platform/uv: Fix printed information in calc_mmioh_map
  x86/platform/uv: Introduce helper function uv_pnode_to_socket.
  x86/platform/uv: Add platform resolving #defines for misc GAM_MMIOH_REDIRECT*
parents a3d763f0 73b3108d
...@@ -177,6 +177,7 @@ struct uv_hub_info_s { ...@@ -177,6 +177,7 @@ struct uv_hub_info_s {
unsigned short nr_possible_cpus; unsigned short nr_possible_cpus;
unsigned short nr_online_cpus; unsigned short nr_online_cpus;
short memory_nid; short memory_nid;
unsigned short *node_to_socket;
}; };
/* CPU specific info with a pointer to the hub common info struct */ /* CPU specific info with a pointer to the hub common info struct */
...@@ -519,25 +520,30 @@ static inline int uv_socket_to_node(int socket) ...@@ -519,25 +520,30 @@ static inline int uv_socket_to_node(int socket)
return _uv_socket_to_node(socket, uv_hub_info->socket_to_node); return _uv_socket_to_node(socket, uv_hub_info->socket_to_node);
} }
static inline int uv_pnode_to_socket(int pnode)
{
unsigned short *p2s = uv_hub_info->pnode_to_socket;
return p2s ? p2s[pnode - uv_hub_info->min_pnode] : pnode;
}
/* pnode, offset --> socket virtual */ /* pnode, offset --> socket virtual */
static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset) static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
{ {
unsigned int m_val = uv_hub_info->m_val; unsigned int m_val = uv_hub_info->m_val;
unsigned long base; unsigned long base;
unsigned short sockid, node, *p2s; unsigned short sockid;
if (m_val) if (m_val)
return __va(((unsigned long)pnode << m_val) | offset); return __va(((unsigned long)pnode << m_val) | offset);
p2s = uv_hub_info->pnode_to_socket; sockid = uv_pnode_to_socket(pnode);
sockid = p2s ? p2s[pnode - uv_hub_info->min_pnode] : pnode;
node = uv_socket_to_node(sockid);
/* limit address of previous socket is our base, except node 0 is 0 */ /* limit address of previous socket is our base, except node 0 is 0 */
if (!node) if (sockid == 0)
return __va((unsigned long)offset); return __va((unsigned long)offset);
base = (unsigned long)(uv_hub_info->gr_table[node - 1].limit); base = (unsigned long)(uv_hub_info->gr_table[sockid - 1].limit);
return __va(base << UV_GAM_RANGE_SHFT | offset); return __va(base << UV_GAM_RANGE_SHFT | offset);
} }
...@@ -644,7 +650,7 @@ static inline int uv_cpu_blade_processor_id(int cpu) ...@@ -644,7 +650,7 @@ static inline int uv_cpu_blade_processor_id(int cpu)
/* Blade number to Node number (UV2..UV4 is 1:1) */ /* Blade number to Node number (UV2..UV4 is 1:1) */
static inline int uv_blade_to_node(int blade) static inline int uv_blade_to_node(int blade)
{ {
return blade; return uv_socket_to_node(blade);
} }
/* Blade number of current cpu. Numnbered 0 .. <#blades -1> */ /* Blade number of current cpu. Numnbered 0 .. <#blades -1> */
...@@ -656,23 +662,27 @@ static inline int uv_numa_blade_id(void) ...@@ -656,23 +662,27 @@ static inline int uv_numa_blade_id(void)
/* /*
* Convert linux node number to the UV blade number. * Convert linux node number to the UV blade number.
* .. Currently for UV2 thru UV4 the node and the blade are identical. * .. Currently for UV2 thru UV4 the node and the blade are identical.
* .. If this changes then you MUST check references to this function! * .. UV5 needs conversion when sub-numa clustering is enabled.
*/ */
static inline int uv_node_to_blade_id(int nid) static inline int uv_node_to_blade_id(int nid)
{ {
return nid; unsigned short *n2s = uv_hub_info->node_to_socket;
return n2s ? n2s[nid] : nid;
} }
/* Convert a CPU number to the UV blade number */ /* Convert a CPU number to the UV blade number */
static inline int uv_cpu_to_blade_id(int cpu) static inline int uv_cpu_to_blade_id(int cpu)
{ {
return uv_node_to_blade_id(cpu_to_node(cpu)); return uv_cpu_hub_info(cpu)->numa_blade_id;
} }
/* Convert a blade id to the PNODE of the blade */ /* Convert a blade id to the PNODE of the blade */
static inline int uv_blade_to_pnode(int bid) static inline int uv_blade_to_pnode(int bid)
{ {
return uv_hub_info_list(uv_blade_to_node(bid))->pnode; unsigned short *s2p = uv_hub_info->socket_to_pnode;
return s2p ? s2p[bid] : bid;
} }
/* Nid of memory node on blade. -1 if no blade-local memory */ /* Nid of memory node on blade. -1 if no blade-local memory */
......
...@@ -4199,6 +4199,13 @@ union uvh_rh_gam_mmioh_overlay_config1_u { ...@@ -4199,6 +4199,13 @@ union uvh_rh_gam_mmioh_overlay_config1_u {
#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT 0 #define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT 0
#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK 0x0000000000007fffUL #define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK 0x0000000000007fffUL
/* UVH common defines */
#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK ( \
is_uv(UV4A) ? UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK : \
is_uv(UV4) ? UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK : \
is_uv(UV3) ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK : \
0)
union uvh_rh_gam_mmioh_redirect_config0_u { union uvh_rh_gam_mmioh_redirect_config0_u {
unsigned long v; unsigned long v;
...@@ -4247,8 +4254,8 @@ union uvh_rh_gam_mmioh_redirect_config0_u { ...@@ -4247,8 +4254,8 @@ union uvh_rh_gam_mmioh_redirect_config0_u {
0) 0)
/* UV4A unique defines */ /* UV4A unique defines */
#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT 0 #define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT 0
#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK 0x0000000000000fffUL #define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK 0x0000000000000fffUL
/* UV4 unique defines */ /* UV4 unique defines */
#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT 0 #define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT 0
...@@ -4258,6 +4265,13 @@ union uvh_rh_gam_mmioh_redirect_config0_u { ...@@ -4258,6 +4265,13 @@ union uvh_rh_gam_mmioh_redirect_config0_u {
#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT 0 #define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT 0
#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK 0x0000000000007fffUL #define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK 0x0000000000007fffUL
/* UVH common defines */
#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK ( \
is_uv(UV4A) ? UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK : \
is_uv(UV4) ? UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK : \
is_uv(UV3) ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK : \
0)
union uvh_rh_gam_mmioh_redirect_config1_u { union uvh_rh_gam_mmioh_redirect_config1_u {
unsigned long v; unsigned long v;
......
...@@ -546,7 +546,6 @@ unsigned long sn_rtc_cycles_per_second; ...@@ -546,7 +546,6 @@ 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 */ /* The following values are used for the per node hub info struct */
static __initdata unsigned short *_node_to_pnode;
static __initdata unsigned short _min_socket, _max_socket; static __initdata unsigned short _min_socket, _max_socket;
static __initdata unsigned short _min_pnode, _max_pnode, _gr_table_len; 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_range_entry *uv_gre_table;
...@@ -554,6 +553,7 @@ static __initdata struct uv_gam_parameters *uv_gp_table; ...@@ -554,6 +553,7 @@ static __initdata struct uv_gam_parameters *uv_gp_table;
static __initdata unsigned short *_socket_to_node; static __initdata unsigned short *_socket_to_node;
static __initdata unsigned short *_socket_to_pnode; static __initdata unsigned short *_socket_to_pnode;
static __initdata unsigned short *_pnode_to_socket; static __initdata unsigned short *_pnode_to_socket;
static __initdata unsigned short *_node_to_socket;
static __initdata struct uv_gam_range_s *_gr_table; static __initdata struct uv_gam_range_s *_gr_table;
...@@ -617,7 +617,8 @@ static __init void build_uv_gr_table(void) ...@@ -617,7 +617,8 @@ static __init void build_uv_gr_table(void)
bytes = _gr_table_len * sizeof(struct uv_gam_range_s); bytes = _gr_table_len * sizeof(struct uv_gam_range_s);
grt = kzalloc(bytes, GFP_KERNEL); grt = kzalloc(bytes, GFP_KERNEL);
BUG_ON(!grt); if (WARN_ON_ONCE(!grt))
return;
_gr_table = grt; _gr_table = grt;
for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) { for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) {
...@@ -1022,7 +1023,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index, ...@@ -1022,7 +1023,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index,
switch (index) { switch (index) {
case UVY_MMIOH0: case UVY_MMIOH0:
mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0; mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0;
nasid_mask = UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK; nasid_mask = UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK;
n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH; n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH;
min_nasid = min_pnode; min_nasid = min_pnode;
max_nasid = max_pnode; max_nasid = max_pnode;
...@@ -1030,7 +1031,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index, ...@@ -1030,7 +1031,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index,
break; break;
case UVY_MMIOH1: case UVY_MMIOH1:
mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1; mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1;
nasid_mask = UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK; nasid_mask = UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK;
n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH; n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH;
min_nasid = min_pnode; min_nasid = min_pnode;
max_nasid = max_pnode; max_nasid = max_pnode;
...@@ -1038,7 +1039,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index, ...@@ -1038,7 +1039,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index,
break; break;
case UVX_MMIOH0: case UVX_MMIOH0:
mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0; mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0;
nasid_mask = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK; nasid_mask = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK;
n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH; n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH;
min_nasid = min_pnode * 2; min_nasid = min_pnode * 2;
max_nasid = max_pnode * 2; max_nasid = max_pnode * 2;
...@@ -1046,7 +1047,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index, ...@@ -1046,7 +1047,7 @@ static void __init calc_mmioh_map(enum mmioh_arch index,
break; break;
case UVX_MMIOH1: case UVX_MMIOH1:
mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1; mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1;
nasid_mask = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK; nasid_mask = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK;
n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH; n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH;
min_nasid = min_pnode * 2; min_nasid = min_pnode * 2;
max_nasid = max_pnode * 2; max_nasid = max_pnode * 2;
...@@ -1072,8 +1073,9 @@ static void __init calc_mmioh_map(enum mmioh_arch index, ...@@ -1072,8 +1073,9 @@ static void __init calc_mmioh_map(enum mmioh_arch index,
/* Invalid NASID check */ /* Invalid NASID check */
if (nasid < min_nasid || max_nasid < nasid) { if (nasid < min_nasid || max_nasid < nasid) {
pr_err("UV:%s:Invalid NASID:%x (range:%x..%x)\n", /* Not an error: unused table entries get "poison" values */
__func__, index, min_nasid, max_nasid); pr_debug("UV:%s:Invalid NASID(%x):%x (range:%x..%x)\n",
__func__, index, nasid, min_nasid, max_nasid);
nasid = -1; nasid = -1;
} }
...@@ -1292,6 +1294,7 @@ static void __init uv_init_hub_info(struct uv_hub_info_s *hi) ...@@ -1292,6 +1294,7 @@ static void __init uv_init_hub_info(struct uv_hub_info_s *hi)
hi->nasid_shift = uv_cpuid.nasid_shift; hi->nasid_shift = uv_cpuid.nasid_shift;
hi->min_pnode = _min_pnode; hi->min_pnode = _min_pnode;
hi->min_socket = _min_socket; hi->min_socket = _min_socket;
hi->node_to_socket = _node_to_socket;
hi->pnode_to_socket = _pnode_to_socket; hi->pnode_to_socket = _pnode_to_socket;
hi->socket_to_node = _socket_to_node; hi->socket_to_node = _socket_to_node;
hi->socket_to_pnode = _socket_to_pnode; hi->socket_to_pnode = _socket_to_pnode;
...@@ -1348,7 +1351,7 @@ static void __init decode_gam_rng_tbl(unsigned long ptr) ...@@ -1348,7 +1351,7 @@ static void __init decode_gam_rng_tbl(unsigned long ptr)
struct uv_gam_range_entry *gre = (struct uv_gam_range_entry *)ptr; struct uv_gam_range_entry *gre = (struct uv_gam_range_entry *)ptr;
unsigned long lgre = 0, gend = 0; unsigned long lgre = 0, gend = 0;
int index = 0; int index = 0;
int sock_min = 999999, pnode_min = 99999; int sock_min = INT_MAX, pnode_min = INT_MAX;
int sock_max = -1, pnode_max = -1; int sock_max = -1, pnode_max = -1;
uv_gre_table = gre; uv_gre_table = gre;
...@@ -1459,11 +1462,37 @@ static int __init decode_uv_systab(void) ...@@ -1459,11 +1462,37 @@ static int __init decode_uv_systab(void)
return 0; return 0;
} }
/*
* Given a bitmask 'bits' representing presnt blades, numbered
* starting at 'base', masking off unused high bits of blade number
* with 'mask', update the minimum and maximum blade numbers that we
* have found. (Masking with 'mask' necessary because of BIOS
* treatment of system partitioning when creating this table we are
* interpreting.)
*/
static inline void blade_update_min_max(unsigned long bits, int base, int mask, int *min, int *max)
{
int first, last;
if (!bits)
return;
first = (base + __ffs(bits)) & mask;
last = (base + __fls(bits)) & mask;
if (*min > first)
*min = first;
if (*max < last)
*max = last;
}
/* Set up physical blade translations from UVH_NODE_PRESENT_TABLE */ /* Set up physical blade translations from UVH_NODE_PRESENT_TABLE */
static __init void boot_init_possible_blades(struct uv_hub_info_s *hub_info) static __init void boot_init_possible_blades(struct uv_hub_info_s *hub_info)
{ {
unsigned long np; unsigned long np;
int i, uv_pb = 0; int i, uv_pb = 0;
int sock_min = INT_MAX, sock_max = -1, s_mask;
s_mask = (1 << uv_cpuid.n_skt) - 1;
if (UVH_NODE_PRESENT_TABLE) { if (UVH_NODE_PRESENT_TABLE) {
pr_info("UV: NODE_PRESENT_DEPTH = %d\n", pr_info("UV: NODE_PRESENT_DEPTH = %d\n",
...@@ -1471,35 +1500,82 @@ static __init void boot_init_possible_blades(struct uv_hub_info_s *hub_info) ...@@ -1471,35 +1500,82 @@ static __init void boot_init_possible_blades(struct uv_hub_info_s *hub_info)
for (i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) { for (i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) {
np = uv_read_local_mmr(UVH_NODE_PRESENT_TABLE + i * 8); np = uv_read_local_mmr(UVH_NODE_PRESENT_TABLE + i * 8);
pr_info("UV: NODE_PRESENT(%d) = 0x%016lx\n", i, np); pr_info("UV: NODE_PRESENT(%d) = 0x%016lx\n", i, np);
uv_pb += hweight64(np); blade_update_min_max(np, i * 64, s_mask, &sock_min, &sock_max);
} }
} }
if (UVH_NODE_PRESENT_0) { if (UVH_NODE_PRESENT_0) {
np = uv_read_local_mmr(UVH_NODE_PRESENT_0); np = uv_read_local_mmr(UVH_NODE_PRESENT_0);
pr_info("UV: NODE_PRESENT_0 = 0x%016lx\n", np); pr_info("UV: NODE_PRESENT_0 = 0x%016lx\n", np);
uv_pb += hweight64(np); blade_update_min_max(np, 0, s_mask, &sock_min, &sock_max);
} }
if (UVH_NODE_PRESENT_1) { if (UVH_NODE_PRESENT_1) {
np = uv_read_local_mmr(UVH_NODE_PRESENT_1); np = uv_read_local_mmr(UVH_NODE_PRESENT_1);
pr_info("UV: NODE_PRESENT_1 = 0x%016lx\n", np); pr_info("UV: NODE_PRESENT_1 = 0x%016lx\n", np);
uv_pb += hweight64(np); blade_update_min_max(np, 64, s_mask, &sock_min, &sock_max);
}
/* Only update if we actually found some bits indicating blades present */
if (sock_max >= sock_min) {
_min_socket = sock_min;
_max_socket = sock_max;
uv_pb = sock_max - sock_min + 1;
} }
if (uv_possible_blades != uv_pb) if (uv_possible_blades != uv_pb)
uv_possible_blades = uv_pb; uv_possible_blades = uv_pb;
pr_info("UV: number nodes/possible blades %d\n", uv_pb); pr_info("UV: number nodes/possible blades %d (%d - %d)\n",
uv_pb, sock_min, sock_max);
}
static int __init alloc_conv_table(int num_elem, unsigned short **table)
{
int i;
size_t bytes;
bytes = num_elem * sizeof(*table[0]);
*table = kmalloc(bytes, GFP_KERNEL);
if (WARN_ON_ONCE(!*table))
return -ENOMEM;
for (i = 0; i < num_elem; i++)
((unsigned short *)*table)[i] = SOCK_EMPTY;
return 0;
} }
/* Remove conversion table if it's 1:1 */
#define FREE_1_TO_1_TABLE(tbl, min, max, max2) free_1_to_1_table(&tbl, #tbl, min, max, max2)
static void __init free_1_to_1_table(unsigned short **tp, char *tname, int min, int max, int max2)
{
int i;
unsigned short *table = *tp;
if (table == NULL)
return;
if (max != max2)
return;
for (i = 0; i < max; i++) {
if (i != table[i])
return;
}
kfree(table);
*tp = NULL;
pr_info("UV: %s is 1:1, conversion table removed\n", tname);
}
/*
* Build Socket Tables
* If the number of nodes is >1 per socket, socket to node table will
* contain lowest node number on that socket.
*/
static void __init build_socket_tables(void) static void __init build_socket_tables(void)
{ {
struct uv_gam_range_entry *gre = uv_gre_table; struct uv_gam_range_entry *gre = uv_gre_table;
int num, nump; int nums, numn, nump;
int cpu, i, lnid; int cpu, i, lnid;
int minsock = _min_socket; int minsock = _min_socket;
int maxsock = _max_socket; int maxsock = _max_socket;
int minpnode = _min_pnode; int minpnode = _min_pnode;
int maxpnode = _max_pnode; int maxpnode = _max_pnode;
size_t bytes;
if (!gre) { if (!gre) {
if (is_uv2_hub() || is_uv3_hub()) { if (is_uv2_hub() || is_uv3_hub()) {
...@@ -1507,38 +1583,35 @@ static void __init build_socket_tables(void) ...@@ -1507,38 +1583,35 @@ static void __init build_socket_tables(void)
return; return;
} }
pr_err("UV: Error: UVsystab address translations not available!\n"); pr_err("UV: Error: UVsystab address translations not available!\n");
BUG(); WARN_ON_ONCE(!gre);
return;
} }
/* Build socket id -> node id, pnode */ numn = num_possible_nodes();
num = maxsock - minsock + 1;
bytes = num * sizeof(_socket_to_node[0]);
_socket_to_node = kmalloc(bytes, GFP_KERNEL);
_socket_to_pnode = kmalloc(bytes, GFP_KERNEL);
nump = maxpnode - minpnode + 1; nump = maxpnode - minpnode + 1;
bytes = nump * sizeof(_pnode_to_socket[0]); nums = maxsock - minsock + 1;
_pnode_to_socket = kmalloc(bytes, GFP_KERNEL);
BUG_ON(!_socket_to_node || !_socket_to_pnode || !_pnode_to_socket); /* Allocate and clear tables */
if ((alloc_conv_table(nump, &_pnode_to_socket) < 0)
for (i = 0; i < num; i++) || (alloc_conv_table(nums, &_socket_to_pnode) < 0)
_socket_to_node[i] = _socket_to_pnode[i] = SOCK_EMPTY; || (alloc_conv_table(numn, &_node_to_socket) < 0)
|| (alloc_conv_table(nums, &_socket_to_node) < 0)) {
for (i = 0; i < nump; i++) kfree(_pnode_to_socket);
_pnode_to_socket[i] = SOCK_EMPTY; kfree(_socket_to_pnode);
kfree(_node_to_socket);
return;
}
/* Fill in pnode/node/addr conversion list values: */ /* Fill in pnode/node/addr conversion list values: */
pr_info("UV: GAM Building socket/pnode conversion tables\n");
for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) { for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) {
if (gre->type == UV_GAM_RANGE_TYPE_HOLE) if (gre->type == UV_GAM_RANGE_TYPE_HOLE)
continue; continue;
i = gre->sockid - minsock; i = gre->sockid - minsock;
/* Duplicate: */ if (_socket_to_pnode[i] == SOCK_EMPTY)
if (_socket_to_pnode[i] != SOCK_EMPTY)
continue;
_socket_to_pnode[i] = gre->pnode; _socket_to_pnode[i] = gre->pnode;
i = gre->pnode - minpnode; i = gre->pnode - minpnode;
if (_pnode_to_socket[i] == SOCK_EMPTY)
_pnode_to_socket[i] = gre->sockid; _pnode_to_socket[i] = gre->sockid;
pr_info("UV: sid:%02x type:%d nasid:%04x pn:%02x pn2s:%2x\n", pr_info("UV: sid:%02x type:%d nasid:%04x pn:%02x pn2s:%2x\n",
...@@ -1549,66 +1622,39 @@ static void __init build_socket_tables(void) ...@@ -1549,66 +1622,39 @@ static void __init build_socket_tables(void)
/* Set socket -> node values: */ /* Set socket -> node values: */
lnid = NUMA_NO_NODE; lnid = NUMA_NO_NODE;
for_each_present_cpu(cpu) { for_each_possible_cpu(cpu) {
int nid = cpu_to_node(cpu); int nid = cpu_to_node(cpu);
int apicid, sockid; int apicid, sockid;
if (lnid == nid) if (lnid == nid)
continue; continue;
lnid = nid; lnid = nid;
apicid = per_cpu(x86_cpu_to_apicid, cpu); apicid = per_cpu(x86_cpu_to_apicid, cpu);
sockid = apicid >> uv_cpuid.socketid_shift; sockid = apicid >> uv_cpuid.socketid_shift;
_socket_to_node[sockid - minsock] = nid;
pr_info("UV: sid:%02x: apicid:%04x node:%2d\n",
sockid, apicid, nid);
}
/* Set up physical blade to pnode translation from GAM Range Table: */ if (_socket_to_node[sockid - minsock] == SOCK_EMPTY)
bytes = num_possible_nodes() * sizeof(_node_to_pnode[0]); _socket_to_node[sockid - minsock] = nid;
_node_to_pnode = kmalloc(bytes, GFP_KERNEL);
BUG_ON(!_node_to_pnode);
for (lnid = 0; lnid < num_possible_nodes(); lnid++) { if (_node_to_socket[nid] == SOCK_EMPTY)
unsigned short sockid; _node_to_socket[nid] = sockid;
for (sockid = minsock; sockid <= maxsock; sockid++) { pr_info("UV: sid:%02x: apicid:%04x socket:%02d node:%03x s2n:%03x\n",
if (lnid == _socket_to_node[sockid - minsock]) { sockid,
_node_to_pnode[lnid] = _socket_to_pnode[sockid - minsock]; apicid,
break; _node_to_socket[nid],
} nid,
} _socket_to_node[sockid - minsock]);
if (sockid > maxsock) {
pr_err("UV: socket for node %d not found!\n", lnid);
BUG();
}
} }
/* /*
* If socket id == pnode or socket id == node for all nodes, * If e.g. socket id == pnode for all pnodes,
* system runs faster by removing corresponding conversion table. * system runs faster by removing corresponding conversion table.
*/ */
pr_info("UV: Checking socket->node/pnode for identity maps\n"); FREE_1_TO_1_TABLE(_socket_to_node, _min_socket, nums, numn);
if (minsock == 0) { FREE_1_TO_1_TABLE(_node_to_socket, _min_socket, nums, numn);
for (i = 0; i < num; i++) FREE_1_TO_1_TABLE(_socket_to_pnode, _min_pnode, nums, nump);
if (_socket_to_node[i] == SOCK_EMPTY || i != _socket_to_node[i]) FREE_1_TO_1_TABLE(_pnode_to_socket, _min_pnode, nums, nump);
break;
if (i >= num) {
kfree(_socket_to_node);
_socket_to_node = NULL;
pr_info("UV: 1:1 socket_to_node table removed\n");
}
}
if (minsock == minpnode) {
for (i = 0; i < num; i++)
if (_socket_to_pnode[i] != SOCK_EMPTY &&
_socket_to_pnode[i] != i + minpnode)
break;
if (i >= num) {
kfree(_socket_to_pnode);
_socket_to_pnode = NULL;
pr_info("UV: 1:1 socket_to_pnode table removed\n");
}
}
} }
/* Check which reboot to use */ /* Check which reboot to use */
...@@ -1692,12 +1738,13 @@ static __init int uv_system_init_hubless(void) ...@@ -1692,12 +1738,13 @@ static __init int uv_system_init_hubless(void)
static void __init uv_system_init_hub(void) static void __init uv_system_init_hub(void)
{ {
struct uv_hub_info_s hub_info = {0}; struct uv_hub_info_s hub_info = {0};
int bytes, cpu, nodeid; int bytes, cpu, nodeid, bid;
unsigned short min_pnode = 9999, max_pnode = 0; unsigned short min_pnode = USHRT_MAX, max_pnode = 0;
char *hub = is_uv5_hub() ? "UV500" : char *hub = is_uv5_hub() ? "UV500" :
is_uv4_hub() ? "UV400" : is_uv4_hub() ? "UV400" :
is_uv3_hub() ? "UV300" : is_uv3_hub() ? "UV300" :
is_uv2_hub() ? "UV2000/3000" : NULL; is_uv2_hub() ? "UV2000/3000" : NULL;
struct uv_hub_info_s **uv_hub_info_list_blade;
if (!hub) { if (!hub) {
pr_err("UV: Unknown/unsupported UV hub\n"); pr_err("UV: Unknown/unsupported UV hub\n");
...@@ -1720,9 +1767,12 @@ static void __init uv_system_init_hub(void) ...@@ -1720,9 +1767,12 @@ static void __init uv_system_init_hub(void)
build_uv_gr_table(); build_uv_gr_table();
set_block_size(); set_block_size();
uv_init_hub_info(&hub_info); uv_init_hub_info(&hub_info);
uv_possible_blades = num_possible_nodes(); /* If UV2 or UV3 may need to get # blades from HW */
if (!_node_to_pnode) if (is_uv(UV2|UV3) && !uv_gre_table)
boot_init_possible_blades(&hub_info); boot_init_possible_blades(&hub_info);
else
/* min/max sockets set in decode_gam_rng_tbl */
uv_possible_blades = (_max_socket - _min_socket) + 1;
/* uv_num_possible_blades() is really the hub count: */ /* uv_num_possible_blades() is really the hub count: */
pr_info("UV: Found %d hubs, %d nodes, %d CPUs\n", uv_num_possible_blades(), num_possible_nodes(), num_possible_cpus()); pr_info("UV: Found %d hubs, %d nodes, %d CPUs\n", uv_num_possible_blades(), num_possible_nodes(), num_possible_cpus());
...@@ -1731,79 +1781,98 @@ static void __init uv_system_init_hub(void) ...@@ -1731,79 +1781,98 @@ static void __init uv_system_init_hub(void)
hub_info.coherency_domain_number = sn_coherency_id; hub_info.coherency_domain_number = sn_coherency_id;
uv_rtc_init(); uv_rtc_init();
/*
* __uv_hub_info_list[] is indexed by node, but there is only
* one hub_info structure per blade. First, allocate one
* structure per blade. Further down we create a per-node
* table (__uv_hub_info_list[]) pointing to hub_info
* structures for the correct blade.
*/
bytes = sizeof(void *) * uv_num_possible_blades(); bytes = sizeof(void *) * uv_num_possible_blades();
__uv_hub_info_list = kzalloc(bytes, GFP_KERNEL); uv_hub_info_list_blade = kzalloc(bytes, GFP_KERNEL);
BUG_ON(!__uv_hub_info_list); if (WARN_ON_ONCE(!uv_hub_info_list_blade))
return;
bytes = sizeof(struct uv_hub_info_s); bytes = sizeof(struct uv_hub_info_s);
for_each_node(nodeid) { for_each_possible_blade(bid) {
struct uv_hub_info_s *new_hub; struct uv_hub_info_s *new_hub;
if (__uv_hub_info_list[nodeid]) { /* Allocate & fill new per hub info list */
pr_err("UV: Node %d UV HUB already initialized!?\n", nodeid); new_hub = (bid == 0) ? &uv_hub_info_node0
BUG(); : kzalloc_node(bytes, GFP_KERNEL, uv_blade_to_node(bid));
if (WARN_ON_ONCE(!new_hub)) {
/* do not kfree() bid 0, which is statically allocated */
while (--bid > 0)
kfree(uv_hub_info_list_blade[bid]);
kfree(uv_hub_info_list_blade);
return;
} }
/* Allocate new per hub info list */ uv_hub_info_list_blade[bid] = new_hub;
new_hub = (nodeid == 0) ? &uv_hub_info_node0 : kzalloc_node(bytes, GFP_KERNEL, nodeid);
BUG_ON(!new_hub);
__uv_hub_info_list[nodeid] = new_hub;
new_hub = uv_hub_info_list(nodeid);
BUG_ON(!new_hub);
*new_hub = hub_info; *new_hub = hub_info;
/* Use information from GAM table if available: */ /* Use information from GAM table if available: */
if (_node_to_pnode) if (uv_gre_table)
new_hub->pnode = _node_to_pnode[nodeid]; new_hub->pnode = uv_blade_to_pnode(bid);
else /* Or fill in during CPU loop: */ else /* Or fill in during CPU loop: */
new_hub->pnode = 0xffff; new_hub->pnode = 0xffff;
new_hub->numa_blade_id = uv_node_to_blade_id(nodeid); new_hub->numa_blade_id = bid;
new_hub->memory_nid = NUMA_NO_NODE; new_hub->memory_nid = NUMA_NO_NODE;
new_hub->nr_possible_cpus = 0; new_hub->nr_possible_cpus = 0;
new_hub->nr_online_cpus = 0; new_hub->nr_online_cpus = 0;
} }
/*
* Now populate __uv_hub_info_list[] for each node with the
* pointer to the struct for the blade it resides on.
*/
bytes = sizeof(void *) * num_possible_nodes();
__uv_hub_info_list = kzalloc(bytes, GFP_KERNEL);
if (WARN_ON_ONCE(!__uv_hub_info_list)) {
for_each_possible_blade(bid)
/* bid 0 is statically allocated */
if (bid != 0)
kfree(uv_hub_info_list_blade[bid]);
kfree(uv_hub_info_list_blade);
return;
}
for_each_node(nodeid)
__uv_hub_info_list[nodeid] = uv_hub_info_list_blade[uv_node_to_blade_id(nodeid)];
/* Initialize per CPU info: */ /* Initialize per CPU info: */
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
int apicid = per_cpu(x86_cpu_to_apicid, cpu); int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
int numa_node_id; unsigned short bid;
unsigned short pnode; unsigned short pnode;
nodeid = cpu_to_node(cpu);
numa_node_id = numa_cpu_node(cpu);
pnode = uv_apicid_to_pnode(apicid); pnode = uv_apicid_to_pnode(apicid);
bid = uv_pnode_to_socket(pnode) - _min_socket;
uv_cpu_info_per(cpu)->p_uv_hub_info = uv_hub_info_list(nodeid); uv_cpu_info_per(cpu)->p_uv_hub_info = uv_hub_info_list_blade[bid];
uv_cpu_info_per(cpu)->blade_cpu_id = uv_cpu_hub_info(cpu)->nr_possible_cpus++; uv_cpu_info_per(cpu)->blade_cpu_id = uv_cpu_hub_info(cpu)->nr_possible_cpus++;
if (uv_cpu_hub_info(cpu)->memory_nid == NUMA_NO_NODE) if (uv_cpu_hub_info(cpu)->memory_nid == NUMA_NO_NODE)
uv_cpu_hub_info(cpu)->memory_nid = cpu_to_node(cpu); uv_cpu_hub_info(cpu)->memory_nid = cpu_to_node(cpu);
/* Init memoryless node: */ if (uv_cpu_hub_info(cpu)->pnode == 0xffff)
if (nodeid != numa_node_id &&
uv_hub_info_list(numa_node_id)->pnode == 0xffff)
uv_hub_info_list(numa_node_id)->pnode = pnode;
else if (uv_cpu_hub_info(cpu)->pnode == 0xffff)
uv_cpu_hub_info(cpu)->pnode = pnode; uv_cpu_hub_info(cpu)->pnode = pnode;
} }
for_each_node(nodeid) { for_each_possible_blade(bid) {
unsigned short pnode = uv_hub_info_list(nodeid)->pnode; unsigned short pnode = uv_hub_info_list_blade[bid]->pnode;
/* Add pnode info for pre-GAM list nodes without CPUs: */ if (pnode == 0xffff)
if (pnode == 0xffff) { continue;
unsigned long paddr;
paddr = node_start_pfn(nodeid) << PAGE_SHIFT;
pnode = uv_gpa_to_pnode(uv_soc_phys_ram_to_gpa(paddr));
uv_hub_info_list(nodeid)->pnode = pnode;
}
min_pnode = min(pnode, min_pnode); min_pnode = min(pnode, min_pnode);
max_pnode = max(pnode, max_pnode); max_pnode = max(pnode, max_pnode);
pr_info("UV: UVHUB node:%2d pn:%02x nrcpus:%d\n", pr_info("UV: HUB:%2d pn:%02x nrcpus:%d\n",
nodeid, bid,
uv_hub_info_list(nodeid)->pnode, uv_hub_info_list_blade[bid]->pnode,
uv_hub_info_list(nodeid)->nr_possible_cpus); uv_hub_info_list_blade[bid]->nr_possible_cpus);
} }
pr_info("UV: min_pnode:%02x max_pnode:%02x\n", min_pnode, max_pnode); pr_info("UV: min_pnode:%02x max_pnode:%02x\n", min_pnode, max_pnode);
...@@ -1811,6 +1880,9 @@ static void __init uv_system_init_hub(void) ...@@ -1811,6 +1880,9 @@ static void __init uv_system_init_hub(void)
map_mmr_high(max_pnode); map_mmr_high(max_pnode);
map_mmioh_high(min_pnode, max_pnode); map_mmioh_high(min_pnode, max_pnode);
kfree(uv_hub_info_list_blade);
uv_hub_info_list_blade = NULL;
uv_nmi_setup(); uv_nmi_setup();
uv_cpu_init(); uv_cpu_init();
uv_setup_proc_files(0); uv_setup_proc_files(0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment