Skip to content

Commit c85375c

Browse files
Mike TravisIngo Molnar
authored andcommitted
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 <[email protected]> Tested-by: John Estabrook <[email protected]> Tested-by: Gary Kroening <[email protected]> Tested-by: Nathan Zimmer <[email protected]> Signed-off-by: Mike Travis <[email protected]> Cc: Andrew Banman <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Len Brown <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Russ Anderson <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 6e27b91 commit c85375c

File tree

2 files changed

+209
-18
lines changed

2 files changed

+209
-18
lines changed

arch/x86/include/asm/uv/uv_hub.h

Lines changed: 114 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <asm/types.h>
2121
#include <asm/percpu.h>
2222
#include <asm/uv/uv_mmrs.h>
23+
#include <asm/uv/bios.h>
2324
#include <asm/irq_vectors.h>
2425
#include <asm/io_apic.h>
2526

@@ -104,7 +105,6 @@
104105
* processor APICID register.
105106
*/
106107

107-
108108
/*
109109
* Maximum number of bricks in all partitions and in all coherency domains.
110110
* This is the total number of bricks accessible in the numalink fabric. It
@@ -139,6 +139,14 @@ struct uv_scir_s {
139139
unsigned char enabled;
140140
};
141141

142+
/* GAM (globally addressed memory) range table */
143+
struct 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+
142150
/*
143151
* The following defines attributes of the HUB chip. These attributes are
144152
* frequently referenced and are kept in a common per hub struct.
@@ -152,8 +160,12 @@ struct uv_hub_info_s {
152160
unsigned short *socket_to_node;
153161
unsigned short *socket_to_pnode;
154162
unsigned short *pnode_to_socket;
163+
struct uv_gam_range_s *gr_table;
155164
unsigned short min_socket;
156165
unsigned short min_pnode;
166+
unsigned char m_val;
167+
unsigned char n_val;
168+
unsigned char gr_table_len;
157169
unsigned char hub_revision;
158170
unsigned char apic_pnode_shift;
159171
unsigned char gpa_shift;
@@ -169,8 +181,6 @@ struct uv_hub_info_s {
169181
unsigned short pnode_mask;
170182
unsigned short coherency_domain_number;
171183
unsigned short numa_blade_id;
172-
unsigned char m_val;
173-
unsigned char n_val;
174184
unsigned short nr_possible_cpus;
175185
unsigned short nr_online_cpus;
176186
short memory_nid;
@@ -419,18 +429,74 @@ union uvh_apicid {
419429
* between socket virtual and socket physical addresses.
420430
*/
421431

432+
/* global bits offset - number of local address bits in gpa for this UV arch */
433+
static 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 */
440+
static 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 */
457+
static 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+) */
469+
static 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+) */
476+
static inline unsigned long uv_gpa_nasid(void *v)
477+
{
478+
return uv_soc_phys_ram_to_nasid(__pa(v));
479+
}
480+
422481
/* socket phys RAM --> UV global physical address */
423482
static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr)
424483
{
484+
unsigned int m_val = uv_hub_info->m_val;
485+
425486
if (paddr < uv_hub_info->lowmem_remap_top)
426487
paddr |= uv_hub_info->lowmem_remap_base;
427488
paddr |= uv_hub_info->gnode_upper;
428-
paddr = ((paddr << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
429-
((paddr >> uv_hub_info->m_val) << uv_hub_info->n_lshift);
489+
if (m_val)
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;
430497
return paddr;
431498
}
432499

433-
434500
/* socket virtual --> UV global physical address */
435501
static inline unsigned long uv_gpa(void *v)
436502
{
@@ -450,20 +516,27 @@ static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa)
450516
unsigned long paddr;
451517
unsigned long remap_base = uv_hub_info->lowmem_remap_base;
452518
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);
453524

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);
456525
paddr = gpa & uv_hub_info->gpa_mask;
457526
if (paddr >= remap_base && paddr < remap_base + remap_top)
458527
paddr -= remap_base;
459528
return paddr;
460529
}
461530

462-
463531
/* gpa -> gnode */
464532
static inline unsigned long uv_gpa_to_gnode(unsigned long gpa)
465533
{
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;
467540
}
468541

469542
/* gpa -> pnode */
@@ -475,21 +548,45 @@ static inline int uv_gpa_to_pnode(unsigned long gpa)
475548
/* gpa -> node offset */
476549
static inline unsigned long uv_gpa_to_offset(unsigned long gpa)
477550
{
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);
479557
}
480558

481-
/* pnode, offset --> socket virtual */
482-
static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
559+
/* Convert socket to node */
560+
static inline int _uv_socket_to_node(int socket, unsigned short *s2nid)
483561
{
484-
return __va(((unsigned long)pnode << uv_hub_info->m_val) | offset);
562+
return s2nid ? s2nid[socket - uv_hub_info->min_socket] : socket;
485563
}
486564

487-
/* Convert socket to node */
488565
static inline int uv_socket_to_node(int socket)
489566
{
490-
unsigned short *s2nid = uv_hub_info->socket_to_node;
567+
return _uv_socket_to_node(socket, uv_hub_info->socket_to_node);
568+
}
491569

492-
return s2nid ? s2nid[socket - uv_hub_info->min_socket] : socket;
570+
/* pnode, offset --> socket virtual */
571+
static 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);
493590
}
494591

495592
/* Extract/Convert a PNODE from an APICID (full apicid, not processor subset) */

arch/x86/kernel/apic/x2apic_uv_x.c

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ static __initdata struct uv_gam_parameters *uv_gp_table;
310310
static __initdata unsigned short *_socket_to_node;
311311
static __initdata unsigned short *_socket_to_pnode;
312312
static __initdata unsigned short *_pnode_to_socket;
313+
static __initdata struct uv_gam_range_s *_gr_table;
313314
#define SOCK_EMPTY ((unsigned short)~0)
314315

315316
extern int uv_hub_info_version(void)
@@ -318,6 +319,97 @@ extern int uv_hub_info_version(void)
318319
}
319320
EXPORT_SYMBOL(uv_hub_info_version);
320321

322+
/* Build GAM range lookup table */
323+
static __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+
321413
static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
322414
{
323415
unsigned long val;
@@ -992,6 +1084,8 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
9921084
hub_info->pnode_to_socket = _pnode_to_socket;
9931085
hub_info->socket_to_node = _socket_to_node;
9941086
hub_info->socket_to_pnode = _socket_to_pnode;
1087+
hub_info->gr_table_len = _gr_table_len;
1088+
hub_info->gr_table = _gr_table;
9951089
hub_info->gpa_mask = mn.m_val ?
9961090
(1UL << (mn.m_val + mn.n_val)) - 1 :
9971091
(1UL << uv_cpuid.gpa_shift) - 1;
@@ -1086,7 +1180,6 @@ static void __init decode_gam_rng_tbl(unsigned long ptr)
10861180
if (pnode_max < gre->pnode)
10871181
pnode_max = gre->pnode;
10881182
}
1089-
10901183
_min_socket = sock_min;
10911184
_max_socket = sock_max;
10921185
_min_pnode = pnode_min;
@@ -1332,6 +1425,7 @@ void __init uv_system_init(void)
13321425
uv_bios_init(); /* get uv_systab for decoding */
13331426
decode_uv_systab();
13341427
build_socket_tables();
1428+
build_uv_gr_table();
13351429
uv_init_hub_info(&hub_info);
13361430
uv_possible_blades = num_possible_nodes();
13371431
if (!_node_to_pnode)

0 commit comments

Comments
 (0)