diff options
-rw-r--r-- | arch/x86/kernel/apic/x2apic_uv_x.c | 206 |
1 files changed, 171 insertions, 35 deletions
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 8cfade9510a4..794f6eb54cd3 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * SGI UV APIC functions (note: not an Intel compatible APIC) | 6 | * SGI UV APIC functions (note: not an Intel compatible APIC) |
7 | * | 7 | * |
8 | * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved. | 8 | * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved. |
9 | */ | 9 | */ |
10 | #include <linux/cpumask.h> | 10 | #include <linux/cpumask.h> |
11 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
@@ -91,10 +91,16 @@ static int __init early_get_pnodeid(void) | |||
91 | m_n_config.v = uv_early_read_mmr(UVH_RH_GAM_CONFIG_MMR); | 91 | m_n_config.v = uv_early_read_mmr(UVH_RH_GAM_CONFIG_MMR); |
92 | uv_min_hub_revision_id = node_id.s.revision; | 92 | uv_min_hub_revision_id = node_id.s.revision; |
93 | 93 | ||
94 | if (node_id.s.part_number == UV2_HUB_PART_NUMBER) | 94 | switch (node_id.s.part_number) { |
95 | uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1; | 95 | case UV2_HUB_PART_NUMBER: |
96 | if (node_id.s.part_number == UV2_HUB_PART_NUMBER_X) | 96 | case UV2_HUB_PART_NUMBER_X: |
97 | uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1; | 97 | uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1; |
98 | break; | ||
99 | case UV3_HUB_PART_NUMBER: | ||
100 | case UV3_HUB_PART_NUMBER_X: | ||
101 | uv_min_hub_revision_id += UV3_HUB_REVISION_BASE - 1; | ||
102 | break; | ||
103 | } | ||
98 | 104 | ||
99 | uv_hub_info->hub_revision = uv_min_hub_revision_id; | 105 | uv_hub_info->hub_revision = uv_min_hub_revision_id; |
100 | pnode = (node_id.s.node_id >> 1) & ((1 << m_n_config.s.n_skt) - 1); | 106 | pnode = (node_id.s.node_id >> 1) & ((1 << m_n_config.s.n_skt) - 1); |
@@ -130,13 +136,16 @@ static void __init uv_set_apicid_hibit(void) | |||
130 | 136 | ||
131 | static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) | 137 | static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) |
132 | { | 138 | { |
133 | int pnodeid, is_uv1, is_uv2; | 139 | int pnodeid, is_uv1, is_uv2, is_uv3; |
134 | 140 | ||
135 | is_uv1 = !strcmp(oem_id, "SGI"); | 141 | is_uv1 = !strcmp(oem_id, "SGI"); |
136 | is_uv2 = !strcmp(oem_id, "SGI2"); | 142 | is_uv2 = !strcmp(oem_id, "SGI2"); |
137 | if (is_uv1 || is_uv2) { | 143 | is_uv3 = !strncmp(oem_id, "SGI3", 4); /* there are varieties of UV3 */ |
144 | if (is_uv1 || is_uv2 || is_uv3) { | ||
138 | uv_hub_info->hub_revision = | 145 | uv_hub_info->hub_revision = |
139 | is_uv1 ? UV1_HUB_REVISION_BASE : UV2_HUB_REVISION_BASE; | 146 | (is_uv1 ? UV1_HUB_REVISION_BASE : |
147 | (is_uv2 ? UV2_HUB_REVISION_BASE : | ||
148 | UV3_HUB_REVISION_BASE)); | ||
140 | pnodeid = early_get_pnodeid(); | 149 | pnodeid = early_get_pnodeid(); |
141 | early_get_apic_pnode_shift(); | 150 | early_get_apic_pnode_shift(); |
142 | x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range; | 151 | x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range; |
@@ -450,14 +459,17 @@ static __init void map_high(char *id, unsigned long base, int pshift, | |||
450 | 459 | ||
451 | paddr = base << pshift; | 460 | paddr = base << pshift; |
452 | bytes = (1UL << bshift) * (max_pnode + 1); | 461 | bytes = (1UL << bshift) * (max_pnode + 1); |
453 | printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, | 462 | if (!paddr) { |
454 | paddr + bytes); | 463 | pr_info("UV: Map %s_HI base address NULL\n", id); |
464 | return; | ||
465 | } | ||
466 | pr_info("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes); | ||
455 | if (map_type == map_uc) | 467 | if (map_type == map_uc) |
456 | init_extra_mapping_uc(paddr, bytes); | 468 | init_extra_mapping_uc(paddr, bytes); |
457 | else | 469 | else |
458 | init_extra_mapping_wb(paddr, bytes); | 470 | init_extra_mapping_wb(paddr, bytes); |
459 | |||
460 | } | 471 | } |
472 | |||
461 | static __init void map_gru_high(int max_pnode) | 473 | static __init void map_gru_high(int max_pnode) |
462 | { | 474 | { |
463 | union uvh_rh_gam_gru_overlay_config_mmr_u gru; | 475 | union uvh_rh_gam_gru_overlay_config_mmr_u gru; |
@@ -468,7 +480,8 @@ static __init void map_gru_high(int max_pnode) | |||
468 | map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb); | 480 | map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb); |
469 | gru_start_paddr = ((u64)gru.s.base << shift); | 481 | gru_start_paddr = ((u64)gru.s.base << shift); |
470 | gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1); | 482 | gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1); |
471 | 483 | } else { | |
484 | pr_info("UV: GRU disabled\n"); | ||
472 | } | 485 | } |
473 | } | 486 | } |
474 | 487 | ||
@@ -480,23 +493,146 @@ static __init void map_mmr_high(int max_pnode) | |||
480 | mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR); | 493 | mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR); |
481 | if (mmr.s.enable) | 494 | if (mmr.s.enable) |
482 | map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc); | 495 | map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc); |
496 | else | ||
497 | pr_info("UV: MMR disabled\n"); | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * This commonality works because both 0 & 1 versions of the MMIOH OVERLAY | ||
502 | * and REDIRECT MMR regs are exactly the same on UV3. | ||
503 | */ | ||
504 | struct mmioh_config { | ||
505 | unsigned long overlay; | ||
506 | unsigned long redirect; | ||
507 | char *id; | ||
508 | }; | ||
509 | |||
510 | static __initdata struct mmioh_config mmiohs[] = { | ||
511 | { | ||
512 | UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR, | ||
513 | UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR, | ||
514 | "MMIOH0" | ||
515 | }, | ||
516 | { | ||
517 | UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR, | ||
518 | UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR, | ||
519 | "MMIOH1" | ||
520 | }, | ||
521 | }; | ||
522 | |||
523 | static __init void map_mmioh_high_uv3(int index, int min_pnode, int max_pnode) | ||
524 | { | ||
525 | union uv3h_rh_gam_mmioh_overlay_config0_mmr_u overlay; | ||
526 | unsigned long mmr; | ||
527 | unsigned long base; | ||
528 | int i, n, shift, m_io, max_io; | ||
529 | int nasid, lnasid, fi, li; | ||
530 | char *id; | ||
531 | |||
532 | id = mmiohs[index].id; | ||
533 | overlay.v = uv_read_local_mmr(mmiohs[index].overlay); | ||
534 | pr_info("UV: %s overlay 0x%lx base:0x%x m_io:%d\n", | ||
535 | id, overlay.v, overlay.s3.base, overlay.s3.m_io); | ||
536 | if (!overlay.s3.enable) { | ||
537 | pr_info("UV: %s disabled\n", id); | ||
538 | return; | ||
539 | } | ||
540 | |||
541 | shift = UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_SHFT; | ||
542 | base = (unsigned long)overlay.s3.base; | ||
543 | m_io = overlay.s3.m_io; | ||
544 | mmr = mmiohs[index].redirect; | ||
545 | n = UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH; | ||
546 | min_pnode *= 2; /* convert to NASID */ | ||
547 | max_pnode *= 2; | ||
548 | max_io = lnasid = fi = li = -1; | ||
549 | |||
550 | for (i = 0; i < n; i++) { | ||
551 | union uv3h_rh_gam_mmioh_redirect_config0_mmr_u redirect; | ||
552 | |||
553 | redirect.v = uv_read_local_mmr(mmr + i * 8); | ||
554 | nasid = redirect.s3.nasid; | ||
555 | if (nasid < min_pnode || max_pnode < nasid) | ||
556 | nasid = -1; /* invalid NASID */ | ||
557 | |||
558 | if (nasid == lnasid) { | ||
559 | li = i; | ||
560 | if (i != n-1) /* last entry check */ | ||
561 | continue; | ||
562 | } | ||
563 | |||
564 | /* check if we have a cached (or last) redirect to print */ | ||
565 | if (lnasid != -1 || (i == n-1 && nasid != -1)) { | ||
566 | unsigned long addr1, addr2; | ||
567 | int f, l; | ||
568 | |||
569 | if (lnasid == -1) { | ||
570 | f = l = i; | ||
571 | lnasid = nasid; | ||
572 | } else { | ||
573 | f = fi; | ||
574 | l = li; | ||
575 | } | ||
576 | addr1 = (base << shift) + | ||
577 | f * (unsigned long)(1 << m_io); | ||
578 | addr2 = (base << shift) + | ||
579 | (l + 1) * (unsigned long)(1 << m_io); | ||
580 | pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx - 0x%016lx\n", | ||
581 | id, fi, li, lnasid, addr1, addr2); | ||
582 | if (max_io < l) | ||
583 | max_io = l; | ||
584 | } | ||
585 | fi = li = i; | ||
586 | lnasid = nasid; | ||
587 | } | ||
588 | |||
589 | pr_info("UV: %s base:0x%lx shift:%d M_IO:%d MAX_IO:%d\n", | ||
590 | id, base, shift, m_io, max_io); | ||
591 | |||
592 | if (max_io >= 0) | ||
593 | map_high(id, base, shift, m_io, max_io, map_uc); | ||
483 | } | 594 | } |
484 | 595 | ||
485 | static __init void map_mmioh_high(int max_pnode) | 596 | static __init void map_mmioh_high(int min_pnode, int max_pnode) |
486 | { | 597 | { |
487 | union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh; | 598 | union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh; |
488 | int shift; | 599 | unsigned long mmr, base; |
600 | int shift, enable, m_io, n_io; | ||
489 | 601 | ||
490 | mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR); | 602 | if (is_uv3_hub()) { |
491 | if (is_uv1_hub() && mmioh.s1.enable) { | 603 | /* Map both MMIOH Regions */ |
492 | shift = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT; | 604 | map_mmioh_high_uv3(0, min_pnode, max_pnode); |
493 | map_high("MMIOH", mmioh.s1.base, shift, mmioh.s1.m_io, | 605 | map_mmioh_high_uv3(1, min_pnode, max_pnode); |
494 | max_pnode, map_uc); | 606 | return; |
495 | } | 607 | } |
496 | if (is_uv2_hub() && mmioh.s2.enable) { | 608 | |
609 | if (is_uv1_hub()) { | ||
610 | mmr = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR; | ||
611 | shift = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT; | ||
612 | mmioh.v = uv_read_local_mmr(mmr); | ||
613 | enable = !!mmioh.s1.enable; | ||
614 | base = mmioh.s1.base; | ||
615 | m_io = mmioh.s1.m_io; | ||
616 | n_io = mmioh.s1.n_io; | ||
617 | } else if (is_uv2_hub()) { | ||
618 | mmr = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR; | ||
497 | shift = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT; | 619 | shift = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT; |
498 | map_high("MMIOH", mmioh.s2.base, shift, mmioh.s2.m_io, | 620 | mmioh.v = uv_read_local_mmr(mmr); |
499 | max_pnode, map_uc); | 621 | enable = !!mmioh.s2.enable; |
622 | base = mmioh.s2.base; | ||
623 | m_io = mmioh.s2.m_io; | ||
624 | n_io = mmioh.s2.n_io; | ||
625 | } else | ||
626 | return; | ||
627 | |||
628 | if (enable) { | ||
629 | max_pnode &= (1 << n_io) - 1; | ||
630 | pr_info( | ||
631 | "UV: base:0x%lx shift:%d N_IO:%d M_IO:%d max_pnode:0x%x\n", | ||
632 | base, shift, m_io, n_io, max_pnode); | ||
633 | map_high("MMIOH", base, shift, m_io, max_pnode, map_uc); | ||
634 | } else { | ||
635 | pr_info("UV: MMIOH disabled\n"); | ||
500 | } | 636 | } |
501 | } | 637 | } |
502 | 638 | ||
@@ -724,42 +860,41 @@ void uv_nmi_init(void) | |||
724 | void __init uv_system_init(void) | 860 | void __init uv_system_init(void) |
725 | { | 861 | { |
726 | union uvh_rh_gam_config_mmr_u m_n_config; | 862 | union uvh_rh_gam_config_mmr_u m_n_config; |
727 | union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh; | ||
728 | union uvh_node_id_u node_id; | 863 | union uvh_node_id_u node_id; |
729 | unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size; | 864 | unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size; |
730 | int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val, n_io; | 865 | int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val; |
731 | int gnode_extra, max_pnode = 0; | 866 | int gnode_extra, min_pnode = 999999, max_pnode = -1; |
732 | unsigned long mmr_base, present, paddr; | 867 | unsigned long mmr_base, present, paddr; |
733 | unsigned short pnode_mask, pnode_io_mask; | 868 | unsigned short pnode_mask; |
869 | char *hub = (is_uv1_hub() ? "UV1" : | ||
870 | (is_uv2_hub() ? "UV2" : | ||
871 | "UV3")); | ||
734 | 872 | ||
735 | printk(KERN_INFO "UV: Found %s hub\n", is_uv1_hub() ? "UV1" : "UV2"); | 873 | pr_info("UV: Found %s hub\n", hub); |
736 | map_low_mmrs(); | 874 | map_low_mmrs(); |
737 | 875 | ||
738 | m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR ); | 876 | m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR ); |
739 | m_val = m_n_config.s.m_skt; | 877 | m_val = m_n_config.s.m_skt; |
740 | n_val = m_n_config.s.n_skt; | 878 | n_val = m_n_config.s.n_skt; |
741 | mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR); | 879 | pnode_mask = (1 << n_val) - 1; |
742 | n_io = is_uv1_hub() ? mmioh.s1.n_io : mmioh.s2.n_io; | ||
743 | mmr_base = | 880 | mmr_base = |
744 | uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & | 881 | uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & |
745 | ~UV_MMR_ENABLE; | 882 | ~UV_MMR_ENABLE; |
746 | pnode_mask = (1 << n_val) - 1; | ||
747 | pnode_io_mask = (1 << n_io) - 1; | ||
748 | 883 | ||
749 | node_id.v = uv_read_local_mmr(UVH_NODE_ID); | 884 | node_id.v = uv_read_local_mmr(UVH_NODE_ID); |
750 | gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1; | 885 | gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1; |
751 | gnode_upper = ((unsigned long)gnode_extra << m_val); | 886 | gnode_upper = ((unsigned long)gnode_extra << m_val); |
752 | printk(KERN_INFO "UV: N %d, M %d, N_IO: %d, gnode_upper 0x%lx, gnode_extra 0x%x, pnode_mask 0x%x, pnode_io_mask 0x%x\n", | 887 | pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x\n", |
753 | n_val, m_val, n_io, gnode_upper, gnode_extra, pnode_mask, pnode_io_mask); | 888 | n_val, m_val, pnode_mask, gnode_upper, gnode_extra); |
754 | 889 | ||
755 | printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base); | 890 | pr_info("UV: global MMR base 0x%lx\n", mmr_base); |
756 | 891 | ||
757 | for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) | 892 | for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) |
758 | uv_possible_blades += | 893 | uv_possible_blades += |
759 | hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8)); | 894 | hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8)); |
760 | 895 | ||
761 | /* uv_num_possible_blades() is really the hub count */ | 896 | /* uv_num_possible_blades() is really the hub count */ |
762 | printk(KERN_INFO "UV: Found %d blades, %d hubs\n", | 897 | pr_info("UV: Found %d blades, %d hubs\n", |
763 | is_uv1_hub() ? uv_num_possible_blades() : | 898 | is_uv1_hub() ? uv_num_possible_blades() : |
764 | (uv_num_possible_blades() + 1) / 2, | 899 | (uv_num_possible_blades() + 1) / 2, |
765 | uv_num_possible_blades()); | 900 | uv_num_possible_blades()); |
@@ -794,6 +929,7 @@ void __init uv_system_init(void) | |||
794 | uv_blade_info[blade].nr_possible_cpus = 0; | 929 | uv_blade_info[blade].nr_possible_cpus = 0; |
795 | uv_blade_info[blade].nr_online_cpus = 0; | 930 | uv_blade_info[blade].nr_online_cpus = 0; |
796 | spin_lock_init(&uv_blade_info[blade].nmi_lock); | 931 | spin_lock_init(&uv_blade_info[blade].nmi_lock); |
932 | min_pnode = min(pnode, min_pnode); | ||
797 | max_pnode = max(pnode, max_pnode); | 933 | max_pnode = max(pnode, max_pnode); |
798 | blade++; | 934 | blade++; |
799 | } | 935 | } |
@@ -856,7 +992,7 @@ void __init uv_system_init(void) | |||
856 | 992 | ||
857 | map_gru_high(max_pnode); | 993 | map_gru_high(max_pnode); |
858 | map_mmr_high(max_pnode); | 994 | map_mmr_high(max_pnode); |
859 | map_mmioh_high(max_pnode & pnode_io_mask); | 995 | map_mmioh_high(min_pnode, max_pnode); |
860 | 996 | ||
861 | uv_cpu_init(); | 997 | uv_cpu_init(); |
862 | uv_scir_register_cpu_notifier(); | 998 | uv_scir_register_cpu_notifier(); |