aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:33:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:33:05 -0400
commit7c6809ff2bd63d4c97ce9e0b94d39d5180842c48 (patch)
tree468edefc99809bbea6eb087d36faf0a4652e7abf /arch/x86
parent96a3d998fb92c28b9862297fcf93a24d8a0eac1d (diff)
parent879d5ad0dc3b096170c8f985b1465de5dca88de8 (diff)
Merge branch 'x86-uv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 UV update from Ingo Molnar: "There's a single commit in this tree, which adds support for a new SGI UV GRU (Global Reference Unit - fast NUMA messaging ASIC) hardware feature to scale up and beyond: an optional distributed mode that will allow per-node address mapping of local GRU space, as opposed to mapping all GRU hardware to the same contiguous high space" * 'x86-uv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/UV: Add GRU distributed mode mappings
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c66
1 files changed, 59 insertions, 7 deletions
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 794f6eb54cd3..39cc7f7acab3 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -51,6 +51,8 @@ DEFINE_PER_CPU(int, x2apic_extra_bits);
51 51
52static enum uv_system_type uv_system_type; 52static enum uv_system_type uv_system_type;
53static u64 gru_start_paddr, gru_end_paddr; 53static u64 gru_start_paddr, gru_end_paddr;
54static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr;
55static u64 gru_dist_lmask, gru_dist_umask;
54static union uvh_apicid uvh_apicid; 56static union uvh_apicid uvh_apicid;
55int uv_min_hub_revision_id; 57int uv_min_hub_revision_id;
56EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); 58EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
@@ -72,7 +74,20 @@ static unsigned long __init uv_early_read_mmr(unsigned long addr)
72 74
73static inline bool is_GRU_range(u64 start, u64 end) 75static inline bool is_GRU_range(u64 start, u64 end)
74{ 76{
75 return start >= gru_start_paddr && end <= gru_end_paddr; 77 if (gru_dist_base) {
78 u64 su = start & gru_dist_umask; /* upper (incl pnode) bits */
79 u64 sl = start & gru_dist_lmask; /* base offset bits */
80 u64 eu = end & gru_dist_umask;
81 u64 el = end & gru_dist_lmask;
82
83 /* Must reside completely within a single GRU range */
84 return (sl == gru_dist_base && el == gru_dist_base &&
85 su >= gru_first_node_paddr &&
86 su <= gru_last_node_paddr &&
87 eu == su);
88 } else {
89 return start >= gru_start_paddr && end <= gru_end_paddr;
90 }
76} 91}
77 92
78static bool uv_is_untracked_pat_range(u64 start, u64 end) 93static bool uv_is_untracked_pat_range(u64 start, u64 end)
@@ -463,26 +478,63 @@ static __init void map_high(char *id, unsigned long base, int pshift,
463 pr_info("UV: Map %s_HI base address NULL\n", id); 478 pr_info("UV: Map %s_HI base address NULL\n", id);
464 return; 479 return;
465 } 480 }
466 pr_info("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes); 481 pr_debug("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes);
467 if (map_type == map_uc) 482 if (map_type == map_uc)
468 init_extra_mapping_uc(paddr, bytes); 483 init_extra_mapping_uc(paddr, bytes);
469 else 484 else
470 init_extra_mapping_wb(paddr, bytes); 485 init_extra_mapping_wb(paddr, bytes);
471} 486}
472 487
488static __init void map_gru_distributed(unsigned long c)
489{
490 union uvh_rh_gam_gru_overlay_config_mmr_u gru;
491 u64 paddr;
492 unsigned long bytes;
493 int nid;
494
495 gru.v = c;
496 /* only base bits 42:28 relevant in dist mode */
497 gru_dist_base = gru.v & 0x000007fff0000000UL;
498 if (!gru_dist_base) {
499 pr_info("UV: Map GRU_DIST base address NULL\n");
500 return;
501 }
502 bytes = 1UL << UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
503 gru_dist_lmask = ((1UL << uv_hub_info->m_val) - 1) & ~(bytes - 1);
504 gru_dist_umask = ~((1UL << uv_hub_info->m_val) - 1);
505 gru_dist_base &= gru_dist_lmask; /* Clear bits above M */
506 for_each_online_node(nid) {
507 paddr = ((u64)uv_node_to_pnode(nid) << uv_hub_info->m_val) |
508 gru_dist_base;
509 init_extra_mapping_wb(paddr, bytes);
510 gru_first_node_paddr = min(paddr, gru_first_node_paddr);
511 gru_last_node_paddr = max(paddr, gru_last_node_paddr);
512 }
513 /* Save upper (63:M) bits of address only for is_GRU_range */
514 gru_first_node_paddr &= gru_dist_umask;
515 gru_last_node_paddr &= gru_dist_umask;
516 pr_debug("UV: Map GRU_DIST base 0x%016llx 0x%016llx - 0x%016llx\n",
517 gru_dist_base, gru_first_node_paddr, gru_last_node_paddr);
518}
519
473static __init void map_gru_high(int max_pnode) 520static __init void map_gru_high(int max_pnode)
474{ 521{
475 union uvh_rh_gam_gru_overlay_config_mmr_u gru; 522 union uvh_rh_gam_gru_overlay_config_mmr_u gru;
476 int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT; 523 int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
477 524
478 gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR); 525 gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
479 if (gru.s.enable) { 526 if (!gru.s.enable) {
480 map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
481 gru_start_paddr = ((u64)gru.s.base << shift);
482 gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
483 } else {
484 pr_info("UV: GRU disabled\n"); 527 pr_info("UV: GRU disabled\n");
528 return;
529 }
530
531 if (is_uv3_hub() && gru.s3.mode) {
532 map_gru_distributed(gru.v);
533 return;
485 } 534 }
535 map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
536 gru_start_paddr = ((u64)gru.s.base << shift);
537 gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
486} 538}
487 539
488static __init void map_mmr_high(int max_pnode) 540static __init void map_mmr_high(int max_pnode)