diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 19:33:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 19:33:05 -0400 |
commit | 7c6809ff2bd63d4c97ce9e0b94d39d5180842c48 (patch) | |
tree | 468edefc99809bbea6eb087d36faf0a4652e7abf /arch/x86 | |
parent | 96a3d998fb92c28b9862297fcf93a24d8a0eac1d (diff) | |
parent | 879d5ad0dc3b096170c8f985b1465de5dca88de8 (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.c | 66 |
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 | ||
52 | static enum uv_system_type uv_system_type; | 52 | static enum uv_system_type uv_system_type; |
53 | static u64 gru_start_paddr, gru_end_paddr; | 53 | static u64 gru_start_paddr, gru_end_paddr; |
54 | static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr; | ||
55 | static u64 gru_dist_lmask, gru_dist_umask; | ||
54 | static union uvh_apicid uvh_apicid; | 56 | static union uvh_apicid uvh_apicid; |
55 | int uv_min_hub_revision_id; | 57 | int uv_min_hub_revision_id; |
56 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); | 58 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); |
@@ -72,7 +74,20 @@ static unsigned long __init uv_early_read_mmr(unsigned long addr) | |||
72 | 74 | ||
73 | static inline bool is_GRU_range(u64 start, u64 end) | 75 | static 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 | ||
78 | static bool uv_is_untracked_pat_range(u64 start, u64 end) | 93 | static 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 | ||
488 | static __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 | |||
473 | static __init void map_gru_high(int max_pnode) | 520 | static __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 | ||
488 | static __init void map_mmr_high(int max_pnode) | 540 | static __init void map_mmr_high(int max_pnode) |