aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Travis <travis@sgi.com>2016-04-29 17:54:20 -0400
committerIngo Molnar <mingo@kernel.org>2016-05-04 02:48:50 -0400
commit6e27b91cf46834391c59062d3f26d277cc299f4b (patch)
treed10d55887af099646a6e8c8fd14b0ff4bfea711d
parent1de329c10d9fbac4031f8eb30c4921c6efbf9faa (diff)
x86/platform/UV: Build GAM reference tables
An aspect of the UV4 system architecture changes involve changing the way sockets, nodes, and pnodes are translated between one another. Decode the information from the BIOS provided EFI system table to build the needed conversion tables. Tested-by: Dimitri Sivanich <sivanich@sgi.com> Tested-by: John Estabrook <estabrook@sgi.com> Tested-by: Gary Kroening <gfk@sgi.com> Tested-by: Nathan Zimmer <nzimmer@sgi.com> Signed-off-by: Mike Travis <travis@sgi.com> Reviewed-by: Dimitri 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.673495324@asylum.americas.sgi.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/uv/uv_hub.h18
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c139
2 files changed, 155 insertions, 2 deletions
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index 1978e4b8dcff..6900161e1684 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -149,6 +149,9 @@ struct uv_hub_info_s {
149 unsigned long global_mmr_base; 149 unsigned long global_mmr_base;
150 unsigned long global_mmr_shift; 150 unsigned long global_mmr_shift;
151 unsigned long gpa_mask; 151 unsigned long gpa_mask;
152 unsigned short *socket_to_node;
153 unsigned short *socket_to_pnode;
154 unsigned short *pnode_to_socket;
152 unsigned short min_socket; 155 unsigned short min_socket;
153 unsigned short min_pnode; 156 unsigned short min_pnode;
154 unsigned char hub_revision; 157 unsigned char hub_revision;
@@ -481,10 +484,21 @@ static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
481 return __va(((unsigned long)pnode << uv_hub_info->m_val) | offset); 484 return __va(((unsigned long)pnode << uv_hub_info->m_val) | offset);
482} 485}
483 486
484/* Extract a PNODE from an APICID (full apicid, not processor subset) */ 487/* Convert socket to node */
488static inline int uv_socket_to_node(int socket)
489{
490 unsigned short *s2nid = uv_hub_info->socket_to_node;
491
492 return s2nid ? s2nid[socket - uv_hub_info->min_socket] : socket;
493}
494
495/* Extract/Convert a PNODE from an APICID (full apicid, not processor subset) */
485static inline int uv_apicid_to_pnode(int apicid) 496static inline int uv_apicid_to_pnode(int apicid)
486{ 497{
487 return (apicid >> uv_hub_info->apic_pnode_shift); 498 int pnode = apicid >> uv_hub_info->apic_pnode_shift;
499 unsigned short *s2pn = uv_hub_info->socket_to_pnode;
500
501 return s2pn ? s2pn[pnode - uv_hub_info->min_socket] : pnode;
488} 502}
489 503
490/* Convert an apicid to the socket number on the blade */ 504/* Convert an apicid to the socket number on the blade */
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 128f47e7b018..259c3dd889c6 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -307,6 +307,9 @@ static __initdata unsigned short _min_socket, _max_socket;
307static __initdata unsigned short _min_pnode, _max_pnode, _gr_table_len; 307static __initdata unsigned short _min_pnode, _max_pnode, _gr_table_len;
308static __initdata struct uv_gam_range_entry *uv_gre_table; 308static __initdata struct uv_gam_range_entry *uv_gre_table;
309static __initdata struct uv_gam_parameters *uv_gp_table; 309static __initdata struct uv_gam_parameters *uv_gp_table;
310static __initdata unsigned short *_socket_to_node;
311static __initdata unsigned short *_socket_to_pnode;
312static __initdata unsigned short *_pnode_to_socket;
310#define SOCK_EMPTY ((unsigned short)~0) 313#define SOCK_EMPTY ((unsigned short)~0)
311 314
312extern int uv_hub_info_version(void) 315extern int uv_hub_info_version(void)
@@ -985,6 +988,10 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
985 hub_info->hub_revision = uv_hub_info->hub_revision; 988 hub_info->hub_revision = uv_hub_info->hub_revision;
986 hub_info->pnode_mask = uv_cpuid.pnode_mask; 989 hub_info->pnode_mask = uv_cpuid.pnode_mask;
987 hub_info->min_pnode = _min_pnode; 990 hub_info->min_pnode = _min_pnode;
991 hub_info->min_socket = _min_socket;
992 hub_info->pnode_to_socket = _pnode_to_socket;
993 hub_info->socket_to_node = _socket_to_node;
994 hub_info->socket_to_pnode = _socket_to_pnode;
988 hub_info->gpa_mask = mn.m_val ? 995 hub_info->gpa_mask = mn.m_val ?
989 (1UL << (mn.m_val + mn.n_val)) - 1 : 996 (1UL << (mn.m_val + mn.n_val)) - 1 :
990 (1UL << uv_cpuid.gpa_shift) - 1; 997 (1UL << uv_cpuid.gpa_shift) - 1;
@@ -1171,6 +1178,137 @@ static __init void boot_init_possible_blades(struct uv_hub_info_s *hub_info)
1171 } 1178 }
1172} 1179}
1173 1180
1181static void __init build_socket_tables(void)
1182{
1183 struct uv_gam_range_entry *gre = uv_gre_table;
1184 int num, nump;
1185 int cpu, i, lnid;
1186 int minsock = _min_socket;
1187 int maxsock = _max_socket;
1188 int minpnode = _min_pnode;
1189 int maxpnode = _max_pnode;
1190 size_t bytes;
1191
1192 if (!gre) {
1193 if (is_uv1_hub() || is_uv2_hub() || is_uv3_hub()) {
1194 pr_info("UV: No UVsystab socket table, ignoring\n");
1195 return; /* not required */
1196 }
1197 pr_crit(
1198 "UV: Error: UVsystab address translations not available!\n");
1199 BUG();
1200 }
1201
1202 /* build socket id -> node id, pnode */
1203 num = maxsock - minsock + 1;
1204 bytes = num * sizeof(_socket_to_node[0]);
1205 _socket_to_node = kmalloc(bytes, GFP_KERNEL);
1206 _socket_to_pnode = kmalloc(bytes, GFP_KERNEL);
1207
1208 nump = maxpnode - minpnode + 1;
1209 bytes = nump * sizeof(_pnode_to_socket[0]);
1210 _pnode_to_socket = kmalloc(bytes, GFP_KERNEL);
1211 BUG_ON(!_socket_to_node || !_socket_to_pnode || !_pnode_to_socket);
1212
1213 for (i = 0; i < num; i++)
1214 _socket_to_node[i] = _socket_to_pnode[i] = SOCK_EMPTY;
1215
1216 for (i = 0; i < nump; i++)
1217 _pnode_to_socket[i] = SOCK_EMPTY;
1218
1219 /* fill in pnode/node/addr conversion list values */
1220 pr_info("UV: GAM Building socket/pnode/pxm conversion tables\n");
1221 for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) {
1222 if (gre->type == UV_GAM_RANGE_TYPE_HOLE)
1223 continue;
1224 i = gre->sockid - minsock;
1225 if (_socket_to_pnode[i] != SOCK_EMPTY)
1226 continue; /* duplicate */
1227 _socket_to_pnode[i] = gre->pnode;
1228 _socket_to_node[i] = gre->pxm;
1229
1230 i = gre->pnode - minpnode;
1231 _pnode_to_socket[i] = gre->sockid;
1232
1233 pr_info(
1234 "UV: sid:%02x type:%d nasid:%04x pn:%02x pxm:%2d pn2s:%2x\n",
1235 gre->sockid, gre->type, gre->nasid,
1236 _socket_to_pnode[gre->sockid - minsock],
1237 _socket_to_node[gre->sockid - minsock],
1238 _pnode_to_socket[gre->pnode - minpnode]);
1239 }
1240
1241 /* check socket -> node values */
1242 lnid = -1;
1243 for_each_present_cpu(cpu) {
1244 int nid = cpu_to_node(cpu);
1245 int apicid, sockid;
1246
1247 if (lnid == nid)
1248 continue;
1249 lnid = nid;
1250 apicid = per_cpu(x86_cpu_to_apicid, cpu);
1251 sockid = apicid >> uv_cpuid.socketid_shift;
1252 i = sockid - minsock;
1253
1254 if (nid != _socket_to_node[i]) {
1255 pr_warn(
1256 "UV: %02x: type:%d socket:%02x PXM:%02x != node:%2d\n",
1257 i, sockid, gre->type, _socket_to_node[i], nid);
1258 _socket_to_node[i] = nid;
1259 }
1260 }
1261
1262 /* Setup physical blade to pnode translation from GAM Range Table */
1263 bytes = num_possible_nodes() * sizeof(_node_to_pnode[0]);
1264 _node_to_pnode = kmalloc(bytes, GFP_KERNEL);
1265 BUG_ON(!_node_to_pnode);
1266
1267 for (lnid = 0; lnid < num_possible_nodes(); lnid++) {
1268 unsigned short sockid;
1269
1270 for (sockid = minsock; sockid <= maxsock; sockid++) {
1271 if (lnid == _socket_to_node[sockid - minsock]) {
1272 _node_to_pnode[lnid] =
1273 _socket_to_pnode[sockid - minsock];
1274 break;
1275 }
1276 }
1277 if (sockid > maxsock) {
1278 pr_err("UV: socket for node %d not found!\n", lnid);
1279 BUG();
1280 }
1281 }
1282
1283 /*
1284 * If socket id == pnode or socket id == node for all nodes,
1285 * system runs faster by removing corresponding conversion table.
1286 */
1287 pr_info("UV: Checking socket->node/pnode for identity maps\n");
1288 if (minsock == 0) {
1289 for (i = 0; i < num; i++)
1290 if (_socket_to_node[i] == SOCK_EMPTY ||
1291 i != _socket_to_node[i])
1292 break;
1293 if (i >= num) {
1294 kfree(_socket_to_node);
1295 _socket_to_node = NULL;
1296 pr_info("UV: 1:1 socket_to_node table removed\n");
1297 }
1298 }
1299 if (minsock == minpnode) {
1300 for (i = 0; i < num; i++)
1301 if (_socket_to_pnode[i] != SOCK_EMPTY &&
1302 _socket_to_pnode[i] != i + minpnode)
1303 break;
1304 if (i >= num) {
1305 kfree(_socket_to_pnode);
1306 _socket_to_pnode = NULL;
1307 pr_info("UV: 1:1 socket_to_pnode table removed\n");
1308 }
1309 }
1310}
1311
1174void __init uv_system_init(void) 1312void __init uv_system_init(void)
1175{ 1313{
1176 struct uv_hub_info_s hub_info = {0}; 1314 struct uv_hub_info_s hub_info = {0};
@@ -1193,6 +1331,7 @@ void __init uv_system_init(void)
1193 1331
1194 uv_bios_init(); /* get uv_systab for decoding */ 1332 uv_bios_init(); /* get uv_systab for decoding */
1195 decode_uv_systab(); 1333 decode_uv_systab();
1334 build_socket_tables();
1196 uv_init_hub_info(&hub_info); 1335 uv_init_hub_info(&hub_info);
1197 uv_possible_blades = num_possible_nodes(); 1336 uv_possible_blades = num_possible_nodes();
1198 if (!_node_to_pnode) 1337 if (!_node_to_pnode)