From nobody Wed Sep 10 06:39:11 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 40565C6FA8E for ; Fri, 24 Feb 2023 22:59:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229706AbjBXW7z (ORCPT ); Fri, 24 Feb 2023 17:59:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38348 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229524AbjBXW7x (ORCPT ); Fri, 24 Feb 2023 17:59:53 -0500 Received: from mx0b-002e3701.pphosted.com (mx0b-002e3701.pphosted.com [148.163.143.35]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 57720658D8 for ; Fri, 24 Feb 2023 14:59:49 -0800 (PST) Received: from pps.filterd (m0148664.ppops.net [127.0.0.1]) by mx0b-002e3701.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 31OMD6xL001013; Fri, 24 Feb 2023 22:59:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hpe.com; h=from : to : subject : date : message-id : mime-version : content-transfer-encoding; s=pps0720; bh=ngpV1vArc/e4GugfsKRSb5tAogd29w/tqQ0MNFkB+0M=; b=jiGkGdOYBj4cuPNqsRB5g0QSII0tLpfr2BGUGwWXaXd/BJlwUJLcY5Z4OEw7/EGMLfH8 fO3PAH95zyH2bkGWVyNPDWmHFTk1TCCfDFDe7Hh709+Zwfk2QHjyKUNqbC3OAINsqfdv xsFxeYA3GGmgdk9hZ1RTL9+3ve3yT+ZIbLieG1E1HVmOPR3WbRJALbeGyY9I0rdiKz8t cMCyqQBT8AYW/tuJAqTTl2tHXnIR3Xe5GO7mikvt3wW1IlFLkcD5xlU6MZ09tzi54o2D f4C1x9mXGaWj6RbNq2LNmICOZEgHfA3nOwbQhR7fA+VIJ+FPDPnxYtyk4RM63aSo/amR jQ== Received: from p1lg14878.it.hpe.com (p1lg14878.it.hpe.com [16.230.97.204]) by mx0b-002e3701.pphosted.com (PPS) with ESMTPS id 3ny5u208xg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 24 Feb 2023 22:59:06 +0000 Received: from p1lg14886.dc01.its.hpecorp.net (unknown [10.119.18.237]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by p1lg14878.it.hpe.com (Postfix) with ESMTPS id BB285131B8; Fri, 24 Feb 2023 22:59:05 +0000 (UTC) Received: from dog.eag.rdlabs.hpecorp.net (unknown [16.231.227.36]) by p1lg14886.dc01.its.hpecorp.net (Postfix) with ESMTP id 019C1808363; Fri, 24 Feb 2023 22:59:04 +0000 (UTC) Received: by dog.eag.rdlabs.hpecorp.net (Postfix, from userid 200934) id 43875302F4600; Fri, 24 Feb 2023 16:59:04 -0600 (CST) From: Steve Wahl To: Steve Wahl , Dimitri Sivanich , Russ Anderson , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , linux-kernel@vger.kernel.org Subject: [PATCH v4] x86/platform/uv: UV support for sub-NUMA clustering Date: Fri, 24 Feb 2023 16:59:04 -0600 Message-Id: <20230224225904.2618624-1-steve.wahl@hpe.com> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-GUID: BtrNTEXu5Zgo3HovOSidy7CltBYQTlW1 X-Proofpoint-ORIG-GUID: BtrNTEXu5Zgo3HovOSidy7CltBYQTlW1 X-HPE-SCL: -1 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.170.22 definitions=2023-02-24_16,2023-02-24_01,2023-02-09_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1011 impostorscore=0 lowpriorityscore=0 suspectscore=0 mlxlogscore=999 mlxscore=0 phishscore=0 malwarescore=0 bulkscore=0 priorityscore=1501 spamscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2302240185 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Sub-NUMA clustering (SNC) invalidates previous assumptions of a 1:1 relationship between blades, sockets, and nodes. Fix these assumptions and build tables correctly when SNC is enabled. Also replace uses of BUG() and BUG_ON() with WARN_ON() and recovery. Signed-off-by: Steve Wahl --- arch/x86/include/asm/uv/uv_hub.h | 32 ++- arch/x86/kernel/apic/x2apic_uv_x.c | 318 ++++++++++++++++++----------- 2 files changed, 215 insertions(+), 135 deletions(-) v2: Include the subsystem name (x86/platform/uv:) on the first line of the commit (subject line). v3: Use return from WARN_ON_ONCE() to simplify the code, remove memory leaks from memory allocation failure conditions, and remove an unnecessary set of curly braces, per comments from Ingo Molnar. v4: Testing found that some configurations required adding a check for "uv_blade_to_node(bid) =3D=3D SOCK_EMPTY" in uv_system_init_hub(). Testing also found that some uv3 configurations didn't work correctly with the new blade number handling. The range of blade numbers is now needed, not just the count, so calc_mmioh_map() and boot_init_possible_blades() needed some adjustment. And a reviewer suggested using INT_MAX instead of 999999. diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_= hub.h index d3e3197917be..5fa76c2ced51 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -177,6 +177,7 @@ struct uv_hub_info_s { unsigned short nr_possible_cpus; unsigned short nr_online_cpus; short memory_nid; + unsigned short *node_to_socket; }; =20 /* 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) return _uv_socket_to_node(socket, uv_hub_info->socket_to_node); } =20 +static inline int uv_pnode_to_socket(int pnode) +{ + unsigned short *p2s =3D uv_hub_info->pnode_to_socket; + + return p2s ? p2s[pnode - uv_hub_info->min_pnode] : pnode; +} + /* pnode, offset --> socket virtual */ static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offs= et) { unsigned int m_val =3D uv_hub_info->m_val; unsigned long base; - unsigned short sockid, node, *p2s; + unsigned short sockid; =20 if (m_val) return __va(((unsigned long)pnode << m_val) | offset); =20 - p2s =3D uv_hub_info->pnode_to_socket; - sockid =3D p2s ? p2s[pnode - uv_hub_info->min_pnode] : pnode; - node =3D uv_socket_to_node(sockid); + sockid =3D uv_pnode_to_socket(pnode); =20 /* limit address of previous socket is our base, except node 0 is 0 */ - if (!node) + if (sockid =3D=3D 0) return __va((unsigned long)offset); =20 - base =3D (unsigned long)(uv_hub_info->gr_table[node - 1].limit); + base =3D (unsigned long)(uv_hub_info->gr_table[sockid - 1].limit); return __va(base << UV_GAM_RANGE_SHFT | offset); } =20 @@ -644,7 +650,7 @@ static inline int uv_cpu_blade_processor_id(int cpu) /* Blade number to Node number (UV2..UV4 is 1:1) */ static inline int uv_blade_to_node(int blade) { - return blade; + return uv_socket_to_node(blade); } =20 /* Blade number of current cpu. Numnbered 0 .. <#blades -1> */ @@ -656,23 +662,27 @@ static inline int uv_numa_blade_id(void) /* * Convert linux node number to the UV blade number. * .. 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) { - return nid; + unsigned short *n2s =3D uv_hub_info->node_to_socket; + + return n2s ? n2s[nid] : nid; } =20 /* Convert a CPU number to the UV blade number */ 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; } =20 /* Convert a blade id to the PNODE of the blade */ static inline int uv_blade_to_pnode(int bid) { - return uv_hub_info_list(uv_blade_to_node(bid))->pnode; + unsigned short *s2p =3D uv_hub_info->socket_to_pnode; + + return s2p ? s2p[bid] : bid; } =20 /* Nid of memory node on blade. -1 if no blade-local memory */ diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2ap= ic_uv_x.c index 482855227964..4e44929ff6ba 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -546,7 +546,6 @@ unsigned long sn_rtc_cycles_per_second; EXPORT_SYMBOL(sn_rtc_cycles_per_second); =20 /* 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_pnode, _max_pnode, _gr_table_len; static __initdata struct uv_gam_range_entry *uv_gre_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_pnode; static __initdata unsigned short *_pnode_to_socket; +static __initdata unsigned short *_node_to_socket; =20 static __initdata struct uv_gam_range_s *_gr_table; =20 @@ -617,7 +617,8 @@ static __init void build_uv_gr_table(void) =20 bytes =3D _gr_table_len * sizeof(struct uv_gam_range_s); grt =3D kzalloc(bytes, GFP_KERNEL); - BUG_ON(!grt); + if (WARN_ON_ONCE(!grt)) + return; _gr_table =3D grt; =20 for (; gre->type !=3D UV_GAM_RANGE_TYPE_UNUSED; gre++) { @@ -1022,7 +1023,7 @@ static void __init calc_mmioh_map(enum mmioh_arch ind= ex, switch (index) { case UVY_MMIOH0: mmr =3D UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0; - nasid_mask =3D UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK; + nasid_mask =3D UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK; n =3D UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH; min_nasid =3D min_pnode; max_nasid =3D max_pnode; @@ -1030,7 +1031,7 @@ static void __init calc_mmioh_map(enum mmioh_arch ind= ex, break; case UVY_MMIOH1: mmr =3D UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1; - nasid_mask =3D UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK; + nasid_mask =3D UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK; n =3D UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH; min_nasid =3D min_pnode; max_nasid =3D max_pnode; @@ -1038,7 +1039,10 @@ static void __init calc_mmioh_map(enum mmioh_arch in= dex, break; case UVX_MMIOH0: mmr =3D UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0; - nasid_mask =3D UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK; + nasid_mask =3D + is_uv(UV4A) ? UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK : + is_uv(UV4) ? UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK : + UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK; n =3D UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH; min_nasid =3D min_pnode * 2; max_nasid =3D max_pnode * 2; @@ -1046,7 +1050,10 @@ static void __init calc_mmioh_map(enum mmioh_arch in= dex, break; case UVX_MMIOH1: mmr =3D UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1; - nasid_mask =3D UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK; + nasid_mask =3D + is_uv(UV4A) ? UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK : + is_uv(UV4) ? UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK : + UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK; n =3D UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH; min_nasid =3D min_pnode * 2; max_nasid =3D max_pnode * 2; @@ -1072,8 +1079,9 @@ static void __init calc_mmioh_map(enum mmioh_arch ind= ex, =20 /* 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); + /* Not an error: unused table entries get "poison" values */ + pr_debug("UV:%s:Invalid NASID(%x):%x (range:%x..%x)\n", + __func__, index, nasid, min_nasid, max_nasid); nasid =3D -1; } =20 @@ -1292,6 +1300,7 @@ static void __init uv_init_hub_info(struct uv_hub_inf= o_s *hi) hi->nasid_shift =3D uv_cpuid.nasid_shift; hi->min_pnode =3D _min_pnode; hi->min_socket =3D _min_socket; + hi->node_to_socket =3D _node_to_socket; hi->pnode_to_socket =3D _pnode_to_socket; hi->socket_to_node =3D _socket_to_node; hi->socket_to_pnode =3D _socket_to_pnode; @@ -1348,7 +1357,7 @@ static void __init decode_gam_rng_tbl(unsigned long p= tr) struct uv_gam_range_entry *gre =3D (struct uv_gam_range_entry *)ptr; unsigned long lgre =3D 0, gend =3D 0; int index =3D 0; - int sock_min =3D 999999, pnode_min =3D 99999; + int sock_min =3D INT_MAX, pnode_min =3D INT_MAX; int sock_max =3D -1, pnode_max =3D -1; =20 uv_gre_table =3D gre; @@ -1464,6 +1473,9 @@ static __init void boot_init_possible_blades(struct u= v_hub_info_s *hub_info) { unsigned long np; int i, uv_pb =3D 0; + int s, sock_min =3D INT_MAX, sock_max =3D -1, s_mask; + + s_mask =3D (1 << uv_cpuid.n_skt) - 1; =20 if (UVH_NODE_PRESENT_TABLE) { pr_info("UV: NODE_PRESENT_DEPTH =3D %d\n", @@ -1471,35 +1483,101 @@ static __init void boot_init_possible_blades(struc= t uv_hub_info_s *hub_info) for (i =3D 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) { np =3D uv_read_local_mmr(UVH_NODE_PRESENT_TABLE + i * 8); pr_info("UV: NODE_PRESENT(%d) =3D 0x%016lx\n", i, np); - uv_pb +=3D hweight64(np); + if (np) { + s =3D ((i * 64) + __ffs(np)) & s_mask; + if (sock_min > s) + sock_min =3D s; + s =3D ((i * 64) + __fls(np)) & s_mask; + if (sock_max < s) + sock_max =3D s; + } } } if (UVH_NODE_PRESENT_0) { np =3D uv_read_local_mmr(UVH_NODE_PRESENT_0); pr_info("UV: NODE_PRESENT_0 =3D 0x%016lx\n", np); - uv_pb +=3D hweight64(np); + if (np) { + s =3D __ffs(np) & s_mask; + if (sock_min > s) + sock_min =3D s; + s =3D __fls(np) & s_mask; + if (sock_max < s) + sock_max =3D s; + } } if (UVH_NODE_PRESENT_1) { np =3D uv_read_local_mmr(UVH_NODE_PRESENT_1); pr_info("UV: NODE_PRESENT_1 =3D 0x%016lx\n", np); - uv_pb +=3D hweight64(np); + if (np) { + s =3D (64 + __ffs(np)) & s_mask; + if (sock_min > s) + sock_min =3D s; + s =3D (64 + __fls(np)) & s_mask; + if (sock_max < s) + sock_max =3D s; + } + } + if (sock_max >=3D sock_min) { + _min_socket =3D sock_min; + _max_socket =3D sock_max; + uv_pb =3D sock_max - sock_min + 1; } if (uv_possible_blades !=3D uv_pb) uv_possible_blades =3D uv_pb; =20 - 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 =3D num_elem * sizeof(*table[0]); + *table =3D kmalloc(bytes, GFP_KERNEL); + if (WARN_ON_ONCE(!*table)) + return -ENOMEM; + for (i =3D 0; i < num_elem; i++) + ((unsigned short *)*table)[i] =3D SOCK_EMPTY; + return 0; } =20 +/* Remove conversion table if it's 1:1 */ +#define FREE_1_TO_1_TABLE(tbl, min, max, max2) free_1_to_1_table(&tbl, #tb= l, 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 =3D *tp; + + if (table =3D=3D NULL) + return; + if (max !=3D max2) + return; + for (i =3D 0; i < max; i++) { + if (i !=3D table[i]) + return; + } + kfree(table); + *tp =3D 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) { struct uv_gam_range_entry *gre =3D uv_gre_table; - int num, nump; + int nums, numn, nump; int cpu, i, lnid; int minsock =3D _min_socket; int maxsock =3D _max_socket; int minpnode =3D _min_pnode; int maxpnode =3D _max_pnode; - size_t bytes; =20 if (!gre) { if (is_uv2_hub() || is_uv3_hub()) { @@ -1507,39 +1585,36 @@ static void __init build_socket_tables(void) return; } pr_err("UV: Error: UVsystab address translations not available!\n"); - BUG(); + WARN_ON_ONCE(!gre); + return; } =20 - /* Build socket id -> node id, pnode */ - num =3D maxsock - minsock + 1; - bytes =3D num * sizeof(_socket_to_node[0]); - _socket_to_node =3D kmalloc(bytes, GFP_KERNEL); - _socket_to_pnode =3D kmalloc(bytes, GFP_KERNEL); - + numn =3D num_possible_nodes(); nump =3D maxpnode - minpnode + 1; - bytes =3D nump * sizeof(_pnode_to_socket[0]); - _pnode_to_socket =3D kmalloc(bytes, GFP_KERNEL); - BUG_ON(!_socket_to_node || !_socket_to_pnode || !_pnode_to_socket); - - for (i =3D 0; i < num; i++) - _socket_to_node[i] =3D _socket_to_pnode[i] =3D SOCK_EMPTY; - - for (i =3D 0; i < nump; i++) - _pnode_to_socket[i] =3D SOCK_EMPTY; + nums =3D maxsock - minsock + 1; + + /* Allocate and clear tables */ + if ((alloc_conv_table(nump, &_pnode_to_socket) < 0) + || (alloc_conv_table(nums, &_socket_to_pnode) < 0) + || (alloc_conv_table(numn, &_node_to_socket) < 0) + || (alloc_conv_table(nums, &_socket_to_node) < 0)) { + kfree(_pnode_to_socket); + kfree(_socket_to_pnode); + kfree(_node_to_socket); + return; + } =20 /* Fill in pnode/node/addr conversion list values: */ - pr_info("UV: GAM Building socket/pnode conversion tables\n"); for (; gre->type !=3D UV_GAM_RANGE_TYPE_UNUSED; gre++) { if (gre->type =3D=3D UV_GAM_RANGE_TYPE_HOLE) continue; i =3D gre->sockid - minsock; - /* Duplicate: */ - if (_socket_to_pnode[i] !=3D SOCK_EMPTY) - continue; - _socket_to_pnode[i] =3D gre->pnode; + if (_socket_to_pnode[i] =3D=3D SOCK_EMPTY) + _socket_to_pnode[i] =3D gre->pnode; =20 i =3D gre->pnode - minpnode; - _pnode_to_socket[i] =3D gre->sockid; + if (_pnode_to_socket[i] =3D=3D SOCK_EMPTY) + _pnode_to_socket[i] =3D gre->sockid; =20 pr_info("UV: sid:%02x type:%d nasid:%04x pn:%02x pn2s:%2x\n", gre->sockid, gre->type, gre->nasid, @@ -1549,66 +1624,39 @@ static void __init build_socket_tables(void) =20 /* Set socket -> node values: */ lnid =3D NUMA_NO_NODE; - for_each_present_cpu(cpu) { + for_each_possible_cpu(cpu) { int nid =3D cpu_to_node(cpu); int apicid, sockid; =20 if (lnid =3D=3D nid) continue; lnid =3D nid; + apicid =3D per_cpu(x86_cpu_to_apicid, cpu); sockid =3D apicid >> uv_cpuid.socketid_shift; - _socket_to_node[sockid - minsock] =3D nid; - pr_info("UV: sid:%02x: apicid:%04x node:%2d\n", - sockid, apicid, nid); - } =20 - /* Set up physical blade to pnode translation from GAM Range Table: */ - bytes =3D num_possible_nodes() * sizeof(_node_to_pnode[0]); - _node_to_pnode =3D kmalloc(bytes, GFP_KERNEL); - BUG_ON(!_node_to_pnode); + if (_socket_to_node[sockid - minsock] =3D=3D SOCK_EMPTY) + _socket_to_node[sockid - minsock] =3D nid; =20 - for (lnid =3D 0; lnid < num_possible_nodes(); lnid++) { - unsigned short sockid; + if (_node_to_socket[nid] =3D=3D SOCK_EMPTY) + _node_to_socket[nid] =3D sockid; =20 - for (sockid =3D minsock; sockid <=3D maxsock; sockid++) { - if (lnid =3D=3D _socket_to_node[sockid - minsock]) { - _node_to_pnode[lnid] =3D _socket_to_pnode[sockid - minsock]; - break; - } - } - if (sockid > maxsock) { - pr_err("UV: socket for node %d not found!\n", lnid); - BUG(); - } + pr_info("UV: sid:%02x: apicid:%04x socket:%02d node:%03x s2n:%03x\n", + sockid, + apicid, + _node_to_socket[nid], + nid, + _socket_to_node[sockid - minsock]); } =20 /* - * If socket id =3D=3D pnode or socket id =3D=3D node for all nodes, + * If e.g. socket id =3D=3D pnode for all pnodes, * system runs faster by removing corresponding conversion table. */ - pr_info("UV: Checking socket->node/pnode for identity maps\n"); - if (minsock =3D=3D 0) { - for (i =3D 0; i < num; i++) - if (_socket_to_node[i] =3D=3D SOCK_EMPTY || i !=3D _socket_to_node[i]) - break; - if (i >=3D num) { - kfree(_socket_to_node); - _socket_to_node =3D NULL; - pr_info("UV: 1:1 socket_to_node table removed\n"); - } - } - if (minsock =3D=3D minpnode) { - for (i =3D 0; i < num; i++) - if (_socket_to_pnode[i] !=3D SOCK_EMPTY && - _socket_to_pnode[i] !=3D i + minpnode) - break; - if (i >=3D num) { - kfree(_socket_to_pnode); - _socket_to_pnode =3D NULL; - pr_info("UV: 1:1 socket_to_pnode table removed\n"); - } - } + FREE_1_TO_1_TABLE(_socket_to_node, _min_socket, nums, numn); + FREE_1_TO_1_TABLE(_node_to_socket, _min_socket, nums, numn); + FREE_1_TO_1_TABLE(_socket_to_pnode, _min_pnode, nums, nump); + FREE_1_TO_1_TABLE(_pnode_to_socket, _min_pnode, nums, nump); } =20 /* Check which reboot to use */ @@ -1692,12 +1740,13 @@ static __init int uv_system_init_hubless(void) static void __init uv_system_init_hub(void) { struct uv_hub_info_s hub_info =3D {0}; - int bytes, cpu, nodeid; - unsigned short min_pnode =3D 9999, max_pnode =3D 0; + int bytes, cpu, nodeid, bid; + unsigned short min_pnode =3D USHRT_MAX, max_pnode =3D 0; char *hub =3D is_uv5_hub() ? "UV500" : is_uv4_hub() ? "UV400" : is_uv3_hub() ? "UV300" : is_uv2_hub() ? "UV2000/3000" : NULL; + struct uv_hub_info_s **uv_hub_info_list_blade; =20 if (!hub) { pr_err("UV: Unknown/unsupported UV hub\n"); @@ -1720,9 +1769,12 @@ static void __init uv_system_init_hub(void) build_uv_gr_table(); set_block_size(); uv_init_hub_info(&hub_info); - uv_possible_blades =3D num_possible_nodes(); - if (!_node_to_pnode) + /* If UV2 or UV3 may need to get # blades from HW */ + if (is_uv(UV2|UV3) && !uv_gre_table) boot_init_possible_blades(&hub_info); + else + /* min/max sockets set in decode_gam_rng_tbl */ + uv_possible_blades =3D (_max_socket - _min_socket) + 1; =20 /* 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()); @@ -1731,79 +1783,94 @@ static void __init uv_system_init_hub(void) hub_info.coherency_domain_number =3D sn_coherency_id; uv_rtc_init(); =20 + /* + * __uv_hub_info_list[] is indexed by node, but there is only one hub_info + * structure per blade. First, allocate one structure per blade. + */ + bytes =3D sizeof(void *) * uv_num_possible_blades(); - __uv_hub_info_list =3D kzalloc(bytes, GFP_KERNEL); - BUG_ON(!__uv_hub_info_list); + uv_hub_info_list_blade =3D kzalloc(bytes, GFP_KERNEL); + if (WARN_ON_ONCE(!uv_hub_info_list_blade)) + return; =20 bytes =3D sizeof(struct uv_hub_info_s); - for_each_node(nodeid) { + for_each_possible_blade(bid) { struct uv_hub_info_s *new_hub; =20 - if (__uv_hub_info_list[nodeid]) { - pr_err("UV: Node %d UV HUB already initialized!?\n", nodeid); - BUG(); + /* Allocate & fill new per hub info list */ + new_hub =3D (bid =3D=3D 0) ? &uv_hub_info_node0 + : 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 */ - new_hub =3D (nodeid =3D=3D 0) ? &uv_hub_info_node0 : kzalloc_node(bytes= , GFP_KERNEL, nodeid); - BUG_ON(!new_hub); - __uv_hub_info_list[nodeid] =3D new_hub; - new_hub =3D uv_hub_info_list(nodeid); - BUG_ON(!new_hub); + uv_hub_info_list_blade[bid] =3D new_hub; *new_hub =3D hub_info; =20 /* Use information from GAM table if available: */ - if (_node_to_pnode) - new_hub->pnode =3D _node_to_pnode[nodeid]; + if (uv_gre_table) + new_hub->pnode =3D uv_blade_to_pnode(bid); else /* Or fill in during CPU loop: */ new_hub->pnode =3D 0xffff; =20 - new_hub->numa_blade_id =3D uv_node_to_blade_id(nodeid); + new_hub->numa_blade_id =3D bid; new_hub->memory_nid =3D NUMA_NO_NODE; new_hub->nr_possible_cpus =3D 0; new_hub->nr_online_cpus =3D 0; } =20 + /* + * Now populate __uv_hub_info_list[] for each node with the + * pointer to the struct for the blade it resides on. + */ + + bytes =3D sizeof(void *) * num_possible_nodes(); + __uv_hub_info_list =3D kzalloc(bytes, GFP_KERNEL); + if (WARN_ON_ONCE(!__uv_hub_info_list)) { + for_each_possible_blade(bid) + /* bid 0 is statically allocated */ + if (bid !=3D 0) + kfree(uv_hub_info_list_blade[bid]); + kfree(uv_hub_info_list_blade); + return; + } + + for_each_node(nodeid) + __uv_hub_info_list[nodeid] =3D uv_hub_info_list_blade[uv_node_to_blade_i= d(nodeid)]; + /* Initialize per CPU info: */ for_each_possible_cpu(cpu) { - int apicid =3D per_cpu(x86_cpu_to_apicid, cpu); - int numa_node_id; + int apicid =3D early_per_cpu(x86_cpu_to_apicid, cpu); + unsigned short bid; unsigned short pnode; =20 - nodeid =3D cpu_to_node(cpu); - numa_node_id =3D numa_cpu_node(cpu); pnode =3D uv_apicid_to_pnode(apicid); + bid =3D uv_pnode_to_socket(pnode) - _min_socket; =20 - uv_cpu_info_per(cpu)->p_uv_hub_info =3D uv_hub_info_list(nodeid); + uv_cpu_info_per(cpu)->p_uv_hub_info =3D uv_hub_info_list_blade[bid]; uv_cpu_info_per(cpu)->blade_cpu_id =3D uv_cpu_hub_info(cpu)->nr_possible= _cpus++; if (uv_cpu_hub_info(cpu)->memory_nid =3D=3D NUMA_NO_NODE) uv_cpu_hub_info(cpu)->memory_nid =3D cpu_to_node(cpu); =20 - /* Init memoryless node: */ - if (nodeid !=3D numa_node_id && - uv_hub_info_list(numa_node_id)->pnode =3D=3D 0xffff) - uv_hub_info_list(numa_node_id)->pnode =3D pnode; - else if (uv_cpu_hub_info(cpu)->pnode =3D=3D 0xffff) + if (uv_cpu_hub_info(cpu)->pnode =3D=3D 0xffff) uv_cpu_hub_info(cpu)->pnode =3D pnode; } =20 - for_each_node(nodeid) { - unsigned short pnode =3D uv_hub_info_list(nodeid)->pnode; + for_each_possible_blade(bid) { + unsigned short pnode =3D uv_hub_info_list_blade[bid]->pnode; =20 - /* Add pnode info for pre-GAM list nodes without CPUs: */ - if (pnode =3D=3D 0xffff) { - unsigned long paddr; + if (pnode =3D=3D 0xffff) + continue; =20 - paddr =3D node_start_pfn(nodeid) << PAGE_SHIFT; - pnode =3D uv_gpa_to_pnode(uv_soc_phys_ram_to_gpa(paddr)); - uv_hub_info_list(nodeid)->pnode =3D pnode; - } min_pnode =3D min(pnode, min_pnode); max_pnode =3D max(pnode, max_pnode); - pr_info("UV: UVHUB node:%2d pn:%02x nrcpus:%d\n", - nodeid, - uv_hub_info_list(nodeid)->pnode, - uv_hub_info_list(nodeid)->nr_possible_cpus); + pr_info("UV: HUB:%2d pn:%02x nrcpus:%d\n", + bid, + uv_hub_info_list_blade[bid]->pnode, + uv_hub_info_list_blade[bid]->nr_possible_cpus); } =20 pr_info("UV: min_pnode:%02x max_pnode:%02x\n", min_pnode, max_pnode); @@ -1811,6 +1878,9 @@ static void __init uv_system_init_hub(void) map_mmr_high(max_pnode); map_mmioh_high(min_pnode, max_pnode); =20 + kfree(uv_hub_info_list_blade); + uv_hub_info_list_blade =3D NULL; + uv_nmi_setup(); uv_cpu_init(); uv_setup_proc_files(0); --=20 2.26.2