aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
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 /arch/x86/kernel
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>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c139
1 files changed, 139 insertions, 0 deletions
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)