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 | |
| 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
| -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) |
