diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/edac/amd64_edac.c | 204 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.h | 9 |
2 files changed, 117 insertions, 96 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 67541e7d1cfe..70c7d5f5ba5e 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -2624,6 +2624,109 @@ static int amd64_init_csrows(struct mem_ctl_info *mci) | |||
2624 | return empty; | 2624 | return empty; |
2625 | } | 2625 | } |
2626 | 2626 | ||
2627 | /* get all cores on this DCT */ | ||
2628 | static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, int nid) | ||
2629 | { | ||
2630 | int cpu; | ||
2631 | |||
2632 | for_each_online_cpu(cpu) | ||
2633 | if (amd_get_nb_id(cpu) == nid) | ||
2634 | cpumask_set_cpu(cpu, mask); | ||
2635 | } | ||
2636 | |||
2637 | /* check MCG_CTL on all the cpus on this node */ | ||
2638 | static bool amd64_nb_mce_bank_enabled_on_node(int nid) | ||
2639 | { | ||
2640 | cpumask_var_t mask; | ||
2641 | struct msr *msrs; | ||
2642 | int cpu, nbe, idx = 0; | ||
2643 | bool ret = false; | ||
2644 | |||
2645 | if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) { | ||
2646 | amd64_printk(KERN_WARNING, "%s: error allocating mask\n", | ||
2647 | __func__); | ||
2648 | return false; | ||
2649 | } | ||
2650 | |||
2651 | get_cpus_on_this_dct_cpumask(mask, nid); | ||
2652 | |||
2653 | msrs = kzalloc(sizeof(struct msr) * cpumask_weight(mask), GFP_KERNEL); | ||
2654 | if (!msrs) { | ||
2655 | amd64_printk(KERN_WARNING, "%s: error allocating msrs\n", | ||
2656 | __func__); | ||
2657 | free_cpumask_var(mask); | ||
2658 | return false; | ||
2659 | } | ||
2660 | |||
2661 | rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs); | ||
2662 | |||
2663 | for_each_cpu(cpu, mask) { | ||
2664 | nbe = msrs[idx].l & K8_MSR_MCGCTL_NBE; | ||
2665 | |||
2666 | debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n", | ||
2667 | cpu, msrs[idx].q, | ||
2668 | (nbe ? "enabled" : "disabled")); | ||
2669 | |||
2670 | if (!nbe) | ||
2671 | goto out; | ||
2672 | |||
2673 | idx++; | ||
2674 | } | ||
2675 | ret = true; | ||
2676 | |||
2677 | out: | ||
2678 | kfree(msrs); | ||
2679 | free_cpumask_var(mask); | ||
2680 | return ret; | ||
2681 | } | ||
2682 | |||
2683 | static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on) | ||
2684 | { | ||
2685 | cpumask_var_t cmask; | ||
2686 | struct msr *msrs = NULL; | ||
2687 | int cpu, idx = 0; | ||
2688 | |||
2689 | if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) { | ||
2690 | amd64_printk(KERN_WARNING, "%s: error allocating mask\n", | ||
2691 | __func__); | ||
2692 | return false; | ||
2693 | } | ||
2694 | |||
2695 | get_cpus_on_this_dct_cpumask(cmask, pvt->mc_node_id); | ||
2696 | |||
2697 | msrs = kzalloc(sizeof(struct msr) * cpumask_weight(cmask), GFP_KERNEL); | ||
2698 | if (!msrs) { | ||
2699 | amd64_printk(KERN_WARNING, "%s: error allocating msrs\n", | ||
2700 | __func__); | ||
2701 | return -ENOMEM; | ||
2702 | } | ||
2703 | |||
2704 | rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); | ||
2705 | |||
2706 | for_each_cpu(cpu, cmask) { | ||
2707 | |||
2708 | if (on) { | ||
2709 | if (msrs[idx].l & K8_MSR_MCGCTL_NBE) | ||
2710 | pvt->flags.ecc_report = 1; | ||
2711 | |||
2712 | msrs[idx].l |= K8_MSR_MCGCTL_NBE; | ||
2713 | } else { | ||
2714 | /* | ||
2715 | * Turn off ECC reporting only when it was off before | ||
2716 | */ | ||
2717 | if (!pvt->flags.ecc_report) | ||
2718 | msrs[idx].l &= ~K8_MSR_MCGCTL_NBE; | ||
2719 | } | ||
2720 | idx++; | ||
2721 | } | ||
2722 | wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); | ||
2723 | |||
2724 | kfree(msrs); | ||
2725 | free_cpumask_var(cmask); | ||
2726 | |||
2727 | return 0; | ||
2728 | } | ||
2729 | |||
2627 | /* | 2730 | /* |
2628 | * Only if 'ecc_enable_override' is set AND BIOS had ECC disabled, do "we" | 2731 | * Only if 'ecc_enable_override' is set AND BIOS had ECC disabled, do "we" |
2629 | * enable it. | 2732 | * enable it. |
@@ -2631,17 +2734,12 @@ static int amd64_init_csrows(struct mem_ctl_info *mci) | |||
2631 | static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) | 2734 | static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) |
2632 | { | 2735 | { |
2633 | struct amd64_pvt *pvt = mci->pvt_info; | 2736 | struct amd64_pvt *pvt = mci->pvt_info; |
2634 | const struct cpumask *cpumask = cpumask_of_node(pvt->mc_node_id); | 2737 | int err = 0; |
2635 | int cpu, idx = 0, err = 0; | 2738 | u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; |
2636 | struct msr msrs[cpumask_weight(cpumask)]; | ||
2637 | u32 value; | ||
2638 | u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; | ||
2639 | 2739 | ||
2640 | if (!ecc_enable_override) | 2740 | if (!ecc_enable_override) |
2641 | return; | 2741 | return; |
2642 | 2742 | ||
2643 | memset(msrs, 0, sizeof(msrs)); | ||
2644 | |||
2645 | amd64_printk(KERN_WARNING, | 2743 | amd64_printk(KERN_WARNING, |
2646 | "'ecc_enable_override' parameter is active, " | 2744 | "'ecc_enable_override' parameter is active, " |
2647 | "Enabling AMD ECC hardware now: CAUTION\n"); | 2745 | "Enabling AMD ECC hardware now: CAUTION\n"); |
@@ -2657,16 +2755,9 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) | |||
2657 | value |= mask; | 2755 | value |= mask; |
2658 | pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); | 2756 | pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); |
2659 | 2757 | ||
2660 | rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); | 2758 | if (amd64_toggle_ecc_err_reporting(pvt, ON)) |
2661 | 2759 | amd64_printk(KERN_WARNING, "Error enabling ECC reporting over " | |
2662 | for_each_cpu(cpu, cpumask) { | 2760 | "MCGCTL!\n"); |
2663 | if (msrs[idx].l & K8_MSR_MCGCTL_NBE) | ||
2664 | set_bit(idx, &pvt->old_mcgctl); | ||
2665 | |||
2666 | msrs[idx].l |= K8_MSR_MCGCTL_NBE; | ||
2667 | idx++; | ||
2668 | } | ||
2669 | wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); | ||
2670 | 2761 | ||
2671 | err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value); | 2762 | err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value); |
2672 | if (err) | 2763 | if (err) |
@@ -2707,17 +2798,12 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) | |||
2707 | 2798 | ||
2708 | static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) | 2799 | static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) |
2709 | { | 2800 | { |
2710 | const struct cpumask *cpumask = cpumask_of_node(pvt->mc_node_id); | 2801 | int err = 0; |
2711 | int cpu, idx = 0, err = 0; | 2802 | u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; |
2712 | struct msr msrs[cpumask_weight(cpumask)]; | ||
2713 | u32 value; | ||
2714 | u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; | ||
2715 | 2803 | ||
2716 | if (!pvt->nbctl_mcgctl_saved) | 2804 | if (!pvt->nbctl_mcgctl_saved) |
2717 | return; | 2805 | return; |
2718 | 2806 | ||
2719 | memset(msrs, 0, sizeof(msrs)); | ||
2720 | |||
2721 | err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCTL, &value); | 2807 | err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCTL, &value); |
2722 | if (err) | 2808 | if (err) |
2723 | debugf0("Reading K8_NBCTL failed\n"); | 2809 | debugf0("Reading K8_NBCTL failed\n"); |
@@ -2727,72 +2813,9 @@ static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) | |||
2727 | /* restore the NB Enable MCGCTL bit */ | 2813 | /* restore the NB Enable MCGCTL bit */ |
2728 | pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); | 2814 | pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); |
2729 | 2815 | ||
2730 | rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); | 2816 | if (amd64_toggle_ecc_err_reporting(pvt, OFF)) |
2731 | 2817 | amd64_printk(KERN_WARNING, "Error restoring ECC reporting over " | |
2732 | for_each_cpu(cpu, cpumask) { | 2818 | "MCGCTL!\n"); |
2733 | msrs[idx].l &= ~K8_MSR_MCGCTL_NBE; | ||
2734 | msrs[idx].l |= | ||
2735 | test_bit(idx, &pvt->old_mcgctl) << K8_MSR_MCGCTL_NBE; | ||
2736 | idx++; | ||
2737 | } | ||
2738 | |||
2739 | wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); | ||
2740 | } | ||
2741 | |||
2742 | /* get all cores on this DCT */ | ||
2743 | static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, int nid) | ||
2744 | { | ||
2745 | int cpu; | ||
2746 | |||
2747 | for_each_online_cpu(cpu) | ||
2748 | if (amd_get_nb_id(cpu) == nid) | ||
2749 | cpumask_set_cpu(cpu, mask); | ||
2750 | } | ||
2751 | |||
2752 | /* check MCG_CTL on all the cpus on this node */ | ||
2753 | static bool amd64_nb_mce_bank_enabled_on_node(int nid) | ||
2754 | { | ||
2755 | cpumask_var_t mask; | ||
2756 | struct msr *msrs; | ||
2757 | int cpu, nbe, idx = 0; | ||
2758 | bool ret = false; | ||
2759 | |||
2760 | if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) { | ||
2761 | amd64_printk(KERN_WARNING, "%s: error allocating mask\n", | ||
2762 | __func__); | ||
2763 | return false; | ||
2764 | } | ||
2765 | |||
2766 | get_cpus_on_this_dct_cpumask(mask, nid); | ||
2767 | |||
2768 | msrs = kzalloc(sizeof(struct msr) * cpumask_weight(mask), GFP_KERNEL); | ||
2769 | if (!msrs) { | ||
2770 | amd64_printk(KERN_WARNING, "%s: error allocating msrs\n", | ||
2771 | __func__); | ||
2772 | free_cpumask_var(mask); | ||
2773 | return false; | ||
2774 | } | ||
2775 | |||
2776 | rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs); | ||
2777 | |||
2778 | for_each_cpu(cpu, mask) { | ||
2779 | nbe = msrs[idx].l & K8_MSR_MCGCTL_NBE; | ||
2780 | |||
2781 | debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n", | ||
2782 | cpu, msrs[idx].q, | ||
2783 | (nbe ? "enabled" : "disabled")); | ||
2784 | |||
2785 | if (!nbe) | ||
2786 | goto out; | ||
2787 | |||
2788 | idx++; | ||
2789 | } | ||
2790 | ret = true; | ||
2791 | |||
2792 | out: | ||
2793 | kfree(msrs); | ||
2794 | free_cpumask_var(mask); | ||
2795 | return ret; | ||
2796 | } | 2819 | } |
2797 | 2820 | ||
2798 | /* | 2821 | /* |
@@ -2921,7 +2944,6 @@ static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl, | |||
2921 | pvt->ext_model = boot_cpu_data.x86_model >> 4; | 2944 | pvt->ext_model = boot_cpu_data.x86_model >> 4; |
2922 | pvt->mc_type_index = mc_type_index; | 2945 | pvt->mc_type_index = mc_type_index; |
2923 | pvt->ops = family_ops(mc_type_index); | 2946 | pvt->ops = family_ops(mc_type_index); |
2924 | pvt->old_mcgctl = 0; | ||
2925 | 2947 | ||
2926 | /* | 2948 | /* |
2927 | * We have the dram_f2_ctl device as an argument, now go reserve its | 2949 | * We have the dram_f2_ctl device as an argument, now go reserve its |
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index c6f359a85207..bba6c944ff13 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
@@ -147,6 +147,8 @@ | |||
147 | #define MAX_CS_COUNT 8 | 147 | #define MAX_CS_COUNT 8 |
148 | #define DRAM_REG_COUNT 8 | 148 | #define DRAM_REG_COUNT 8 |
149 | 149 | ||
150 | #define ON true | ||
151 | #define OFF false | ||
150 | 152 | ||
151 | /* | 153 | /* |
152 | * PCI-defined configuration space registers | 154 | * PCI-defined configuration space registers |
@@ -386,10 +388,7 @@ enum { | |||
386 | #define K8_NBCAP_DUAL_NODE BIT(1) | 388 | #define K8_NBCAP_DUAL_NODE BIT(1) |
387 | #define K8_NBCAP_DCT_DUAL BIT(0) | 389 | #define K8_NBCAP_DCT_DUAL BIT(0) |
388 | 390 | ||
389 | /* | 391 | /* MSRs */ |
390 | * MSR Regs | ||
391 | */ | ||
392 | #define K8_MSR_MCGCTL 0x017b | ||
393 | #define K8_MSR_MCGCTL_NBE BIT(4) | 392 | #define K8_MSR_MCGCTL_NBE BIT(4) |
394 | 393 | ||
395 | #define K8_MSR_MC4CTL 0x0410 | 394 | #define K8_MSR_MC4CTL 0x0410 |
@@ -487,7 +486,6 @@ struct amd64_pvt { | |||
487 | /* Save old hw registers' values before we modified them */ | 486 | /* Save old hw registers' values before we modified them */ |
488 | u32 nbctl_mcgctl_saved; /* When true, following 2 are valid */ | 487 | u32 nbctl_mcgctl_saved; /* When true, following 2 are valid */ |
489 | u32 old_nbctl; | 488 | u32 old_nbctl; |
490 | unsigned long old_mcgctl; /* per core on this node */ | ||
491 | 489 | ||
492 | /* MC Type Index value: socket F vs Family 10h */ | 490 | /* MC Type Index value: socket F vs Family 10h */ |
493 | u32 mc_type_index; | 491 | u32 mc_type_index; |
@@ -495,6 +493,7 @@ struct amd64_pvt { | |||
495 | /* misc settings */ | 493 | /* misc settings */ |
496 | struct flags { | 494 | struct flags { |
497 | unsigned long cf8_extcfg:1; | 495 | unsigned long cf8_extcfg:1; |
496 | unsigned long ecc_report:1; | ||
498 | } flags; | 497 | } flags; |
499 | }; | 498 | }; |
500 | 499 | ||