aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Travis <travis@sgi.com>2016-04-29 17:54:21 -0400
committerIngo Molnar <mingo@kernel.org>2016-05-04 02:48:50 -0400
commitc85375cd19966d5dd854cd8b8eada9be8f21fac1 (patch)
tree7b1619a3033b49947c653df80474263aa0153e4a
parent6e27b91cf46834391c59062d3f26d277cc299f4b (diff)
x86/platform/UV: Update physical address conversions for UV4
This patch builds support for the new conversions of physical addresses to and from sockets, pnodes and nodes in UV4. It is designed to be as efficient as possible as lookups are done inside an interrupt context in some cases. It will be further optimized when physical hardware is available to measure execution time. 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> 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.841051741@asylum.americas.sgi.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/uv/uv_hub.h131
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c96
2 files changed, 209 insertions, 18 deletions
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index 6900161e1684..ae979f7740f7 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -20,6 +20,7 @@
20#include <asm/types.h> 20#include <asm/types.h>
21#include <asm/percpu.h> 21#include <asm/percpu.h>
22#include <asm/uv/uv_mmrs.h> 22#include <asm/uv/uv_mmrs.h>
23#include <asm/uv/bios.h>
23#include <asm/irq_vectors.h> 24#include <asm/irq_vectors.h>
24#include <asm/io_apic.h> 25#include <asm/io_apic.h>
25 26
@@ -104,7 +105,6 @@
104 * processor APICID register. 105 * processor APICID register.
105 */ 106 */
106 107
107
108/* 108/*
109 * Maximum number of bricks in all partitions and in all coherency domains. 109 * Maximum number of bricks in all partitions and in all coherency domains.
110 * This is the total number of bricks accessible in the numalink fabric. It 110 * This is the total number of bricks accessible in the numalink fabric. It
@@ -139,6 +139,14 @@ struct uv_scir_s {
139 unsigned char enabled; 139 unsigned char enabled;
140}; 140};
141 141
142/* GAM (globally addressed memory) range table */
143struct uv_gam_range_s {
144 u32 limit; /* PA bits 56:26 (GAM_RANGE_SHFT) */
145 u16 nasid; /* node's global physical address */
146 s8 base; /* entry index of node's base addr */
147 u8 reserved;
148};
149
142/* 150/*
143 * The following defines attributes of the HUB chip. These attributes are 151 * The following defines attributes of the HUB chip. These attributes are
144 * frequently referenced and are kept in a common per hub struct. 152 * frequently referenced and are kept in a common per hub struct.
@@ -152,8 +160,12 @@ struct uv_hub_info_s {
152 unsigned short *socket_to_node; 160 unsigned short *socket_to_node;
153 unsigned short *socket_to_pnode; 161 unsigned short *socket_to_pnode;
154 unsigned short *pnode_to_socket; 162 unsigned short *pnode_to_socket;
163 struct uv_gam_range_s *gr_table;
155 unsigned short min_socket; 164 unsigned short min_socket;
156 unsigned short min_pnode; 165 unsigned short min_pnode;
166 unsigned char m_val;
167 unsigned char n_val;
168 unsigned char gr_table_len;
157 unsigned char hub_revision; 169 unsigned char hub_revision;
158 unsigned char apic_pnode_shift; 170 unsigned char apic_pnode_shift;
159 unsigned char gpa_shift; 171 unsigned char gpa_shift;
@@ -169,8 +181,6 @@ struct uv_hub_info_s {
169 unsigned short pnode_mask; 181 unsigned short pnode_mask;
170 unsigned short coherency_domain_number; 182 unsigned short coherency_domain_number;
171 unsigned short numa_blade_id; 183 unsigned short numa_blade_id;
172 unsigned char m_val;
173 unsigned char n_val;
174 unsigned short nr_possible_cpus; 184 unsigned short nr_possible_cpus;
175 unsigned short nr_online_cpus; 185 unsigned short nr_online_cpus;
176 short memory_nid; 186 short memory_nid;
@@ -419,18 +429,74 @@ union uvh_apicid {
419 * between socket virtual and socket physical addresses. 429 * between socket virtual and socket physical addresses.
420 */ 430 */
421 431
432/* global bits offset - number of local address bits in gpa for this UV arch */
433static inline unsigned int uv_gpa_shift(void)
434{
435 return uv_hub_info->gpa_shift;
436}
437#define _uv_gpa_shift
438
439/* Find node that has the address range that contains global address */
440static inline struct uv_gam_range_s *uv_gam_range(unsigned long pa)
441{
442 struct uv_gam_range_s *gr = uv_hub_info->gr_table;
443 unsigned long pal = (pa & uv_hub_info->gpa_mask) >> UV_GAM_RANGE_SHFT;
444 int i, num = uv_hub_info->gr_table_len;
445
446 if (gr) {
447 for (i = 0; i < num; i++, gr++) {
448 if (pal < gr->limit)
449 return gr;
450 }
451 }
452 pr_crit("UV: GAM Range for 0x%lx not found at %p!\n", pa, gr);
453 BUG();
454}
455
456/* Return base address of node that contains global address */
457static inline unsigned long uv_gam_range_base(unsigned long pa)
458{
459 struct uv_gam_range_s *gr = uv_gam_range(pa);
460 int base = gr->base;
461
462 if (base < 0)
463 return 0UL;
464
465 return uv_hub_info->gr_table[base].limit;
466}
467
468/* socket phys RAM --> UV global NASID (UV4+) */
469static inline unsigned long uv_soc_phys_ram_to_nasid(unsigned long paddr)
470{
471 return uv_gam_range(paddr)->nasid;
472}
473#define _uv_soc_phys_ram_to_nasid
474
475/* socket virtual --> UV global NASID (UV4+) */
476static inline unsigned long uv_gpa_nasid(void *v)
477{
478 return uv_soc_phys_ram_to_nasid(__pa(v));
479}
480
422/* socket phys RAM --> UV global physical address */ 481/* socket phys RAM --> UV global physical address */
423static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr) 482static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr)
424{ 483{
484 unsigned int m_val = uv_hub_info->m_val;
485
425 if (paddr < uv_hub_info->lowmem_remap_top) 486 if (paddr < uv_hub_info->lowmem_remap_top)
426 paddr |= uv_hub_info->lowmem_remap_base; 487 paddr |= uv_hub_info->lowmem_remap_base;
427 paddr |= uv_hub_info->gnode_upper; 488 paddr |= uv_hub_info->gnode_upper;
428 paddr = ((paddr << uv_hub_info->m_shift) >> uv_hub_info->m_shift) | 489 if (m_val)
429 ((paddr >> uv_hub_info->m_val) << uv_hub_info->n_lshift); 490 paddr = ((paddr << uv_hub_info->m_shift)
491 >> uv_hub_info->m_shift) |
492 ((paddr >> uv_hub_info->m_val)
493 << uv_hub_info->n_lshift);
494 else
495 paddr |= uv_soc_phys_ram_to_nasid(paddr)
496 << uv_hub_info->gpa_shift;
430 return paddr; 497 return paddr;
431} 498}
432 499
433
434/* socket virtual --> UV global physical address */ 500/* socket virtual --> UV global physical address */
435static inline unsigned long uv_gpa(void *v) 501static inline unsigned long uv_gpa(void *v)
436{ 502{
@@ -450,20 +516,27 @@ static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa)
450 unsigned long paddr; 516 unsigned long paddr;
451 unsigned long remap_base = uv_hub_info->lowmem_remap_base; 517 unsigned long remap_base = uv_hub_info->lowmem_remap_base;
452 unsigned long remap_top = uv_hub_info->lowmem_remap_top; 518 unsigned long remap_top = uv_hub_info->lowmem_remap_top;
519 unsigned int m_val = uv_hub_info->m_val;
520
521 if (m_val)
522 gpa = ((gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
523 ((gpa >> uv_hub_info->n_lshift) << uv_hub_info->m_val);
453 524
454 gpa = ((gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
455 ((gpa >> uv_hub_info->n_lshift) << uv_hub_info->m_val);
456 paddr = gpa & uv_hub_info->gpa_mask; 525 paddr = gpa & uv_hub_info->gpa_mask;
457 if (paddr >= remap_base && paddr < remap_base + remap_top) 526 if (paddr >= remap_base && paddr < remap_base + remap_top)
458 paddr -= remap_base; 527 paddr -= remap_base;
459 return paddr; 528 return paddr;
460} 529}
461 530
462
463/* gpa -> gnode */ 531/* gpa -> gnode */
464static inline unsigned long uv_gpa_to_gnode(unsigned long gpa) 532static inline unsigned long uv_gpa_to_gnode(unsigned long gpa)
465{ 533{
466 return gpa >> uv_hub_info->n_lshift; 534 unsigned int n_lshift = uv_hub_info->n_lshift;
535
536 if (n_lshift)
537 return gpa >> n_lshift;
538
539 return uv_gam_range(gpa)->nasid >> 1;
467} 540}
468 541
469/* gpa -> pnode */ 542/* gpa -> pnode */
@@ -475,21 +548,45 @@ static inline int uv_gpa_to_pnode(unsigned long gpa)
475/* gpa -> node offset */ 548/* gpa -> node offset */
476static inline unsigned long uv_gpa_to_offset(unsigned long gpa) 549static inline unsigned long uv_gpa_to_offset(unsigned long gpa)
477{ 550{
478 return (gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift; 551 unsigned int m_shift = uv_hub_info->m_shift;
552
553 if (m_shift)
554 return (gpa << m_shift) >> m_shift;
555
556 return (gpa & uv_hub_info->gpa_mask) - uv_gam_range_base(gpa);
479} 557}
480 558
481/* pnode, offset --> socket virtual */ 559/* Convert socket to node */
482static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset) 560static inline int _uv_socket_to_node(int socket, unsigned short *s2nid)
483{ 561{
484 return __va(((unsigned long)pnode << uv_hub_info->m_val) | offset); 562 return s2nid ? s2nid[socket - uv_hub_info->min_socket] : socket;
485} 563}
486 564
487/* Convert socket to node */
488static inline int uv_socket_to_node(int socket) 565static inline int uv_socket_to_node(int socket)
489{ 566{
490 unsigned short *s2nid = uv_hub_info->socket_to_node; 567 return _uv_socket_to_node(socket, uv_hub_info->socket_to_node);
568}
491 569
492 return s2nid ? s2nid[socket - uv_hub_info->min_socket] : socket; 570/* pnode, offset --> socket virtual */
571static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
572{
573 unsigned int m_val = uv_hub_info->m_val;
574 unsigned long base;
575 unsigned short sockid, node, *p2s;
576
577 if (m_val)
578 return __va(((unsigned long)pnode << m_val) | offset);
579
580 p2s = uv_hub_info->pnode_to_socket;
581 sockid = p2s ? p2s[pnode - uv_hub_info->min_pnode] : pnode;
582 node = uv_socket_to_node(sockid);
583
584 /* limit address of previous socket is our base, except node 0 is 0 */
585 if (!node)
586 return __va((unsigned long)offset);
587
588 base = (unsigned long)(uv_hub_info->gr_table[node - 1].limit);
589 return __va(base << UV_GAM_RANGE_SHFT | offset);
493} 590}
494 591
495/* Extract/Convert a PNODE from an APICID (full apicid, not processor subset) */ 592/* Extract/Convert a PNODE from an APICID (full apicid, not processor subset) */
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 259c3dd889c6..65a40d4a95fe 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -310,6 +310,7 @@ static __initdata struct uv_gam_parameters *uv_gp_table;
310static __initdata unsigned short *_socket_to_node; 310static __initdata unsigned short *_socket_to_node;
311static __initdata unsigned short *_socket_to_pnode; 311static __initdata unsigned short *_socket_to_pnode;
312static __initdata unsigned short *_pnode_to_socket; 312static __initdata unsigned short *_pnode_to_socket;
313static __initdata struct uv_gam_range_s *_gr_table;
313#define SOCK_EMPTY ((unsigned short)~0) 314#define SOCK_EMPTY ((unsigned short)~0)
314 315
315extern int uv_hub_info_version(void) 316extern int uv_hub_info_version(void)
@@ -318,6 +319,97 @@ extern int uv_hub_info_version(void)
318} 319}
319EXPORT_SYMBOL(uv_hub_info_version); 320EXPORT_SYMBOL(uv_hub_info_version);
320 321
322/* Build GAM range lookup table */
323static __init void build_uv_gr_table(void)
324{
325 struct uv_gam_range_entry *gre = uv_gre_table;
326 struct uv_gam_range_s *grt;
327 unsigned long last_limit = 0, ram_limit = 0;
328 int bytes, i, sid, lsid = -1;
329
330 if (!gre)
331 return;
332
333 bytes = _gr_table_len * sizeof(struct uv_gam_range_s);
334 grt = kzalloc(bytes, GFP_KERNEL);
335 BUG_ON(!grt);
336 _gr_table = grt;
337
338 for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) {
339 if (gre->type == UV_GAM_RANGE_TYPE_HOLE) {
340 if (!ram_limit) { /* mark hole between ram/non-ram */
341 ram_limit = last_limit;
342 last_limit = gre->limit;
343 lsid++;
344 continue;
345 }
346 last_limit = gre->limit;
347 pr_info("UV: extra hole in GAM RE table @%d\n",
348 (int)(gre - uv_gre_table));
349 continue;
350 }
351 if (_max_socket < gre->sockid) {
352 pr_err("UV: GAM table sockid(%d) too large(>%d) @%d\n",
353 gre->sockid, _max_socket,
354 (int)(gre - uv_gre_table));
355 continue;
356 }
357 sid = gre->sockid - _min_socket;
358 if (lsid < sid) { /* new range */
359 grt = &_gr_table[sid];
360 grt->base = lsid;
361 grt->nasid = gre->nasid;
362 grt->limit = last_limit = gre->limit;
363 lsid = sid;
364 continue;
365 }
366 if (lsid == sid && !ram_limit) { /* update range */
367 if (grt->limit == last_limit) { /* .. if contiguous */
368 grt->limit = last_limit = gre->limit;
369 continue;
370 }
371 }
372 if (!ram_limit) { /* non-contiguous ram range */
373 grt++;
374 grt->base = sid - 1;
375 grt->nasid = gre->nasid;
376 grt->limit = last_limit = gre->limit;
377 continue;
378 }
379 grt++; /* non-contiguous/non-ram */
380 grt->base = grt - _gr_table; /* base is this entry */
381 grt->nasid = gre->nasid;
382 grt->limit = last_limit = gre->limit;
383 lsid++;
384 }
385
386 /* shorten table if possible */
387 grt++;
388 i = grt - _gr_table;
389 if (i < _gr_table_len) {
390 void *ret;
391
392 bytes = i * sizeof(struct uv_gam_range_s);
393 ret = krealloc(_gr_table, bytes, GFP_KERNEL);
394 if (ret) {
395 _gr_table = ret;
396 _gr_table_len = i;
397 }
398 }
399
400 /* display resultant gam range table */
401 for (i = 0, grt = _gr_table; i < _gr_table_len; i++, grt++) {
402 int gb = grt->base;
403 unsigned long start = gb < 0 ? 0 :
404 (unsigned long)_gr_table[gb].limit << UV_GAM_RANGE_SHFT;
405 unsigned long end =
406 (unsigned long)grt->limit << UV_GAM_RANGE_SHFT;
407
408 pr_info("UV: GAM Range %2d %04x 0x%013lx-0x%013lx (%d)\n",
409 i, grt->nasid, start, end, gb);
410 }
411}
412
321static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip) 413static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
322{ 414{
323 unsigned long val; 415 unsigned long val;
@@ -992,6 +1084,8 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
992 hub_info->pnode_to_socket = _pnode_to_socket; 1084 hub_info->pnode_to_socket = _pnode_to_socket;
993 hub_info->socket_to_node = _socket_to_node; 1085 hub_info->socket_to_node = _socket_to_node;
994 hub_info->socket_to_pnode = _socket_to_pnode; 1086 hub_info->socket_to_pnode = _socket_to_pnode;
1087 hub_info->gr_table_len = _gr_table_len;
1088 hub_info->gr_table = _gr_table;
995 hub_info->gpa_mask = mn.m_val ? 1089 hub_info->gpa_mask = mn.m_val ?
996 (1UL << (mn.m_val + mn.n_val)) - 1 : 1090 (1UL << (mn.m_val + mn.n_val)) - 1 :
997 (1UL << uv_cpuid.gpa_shift) - 1; 1091 (1UL << uv_cpuid.gpa_shift) - 1;
@@ -1086,7 +1180,6 @@ static void __init decode_gam_rng_tbl(unsigned long ptr)
1086 if (pnode_max < gre->pnode) 1180 if (pnode_max < gre->pnode)
1087 pnode_max = gre->pnode; 1181 pnode_max = gre->pnode;
1088 } 1182 }
1089
1090 _min_socket = sock_min; 1183 _min_socket = sock_min;
1091 _max_socket = sock_max; 1184 _max_socket = sock_max;
1092 _min_pnode = pnode_min; 1185 _min_pnode = pnode_min;
@@ -1332,6 +1425,7 @@ void __init uv_system_init(void)
1332 uv_bios_init(); /* get uv_systab for decoding */ 1425 uv_bios_init(); /* get uv_systab for decoding */
1333 decode_uv_systab(); 1426 decode_uv_systab();
1334 build_socket_tables(); 1427 build_socket_tables();
1428 build_uv_gr_table();
1335 uv_init_hub_info(&hub_info); 1429 uv_init_hub_info(&hub_info);
1336 uv_possible_blades = num_possible_nodes(); 1430 uv_possible_blades = num_possible_nodes();
1337 if (!_node_to_pnode) 1431 if (!_node_to_pnode)