| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | #include "amd64_edac.h" |
|---|
| 2 | 3 | #include <asm/amd_nb.h> |
|---|
| 3 | 4 | |
|---|
| 4 | 5 | static struct edac_pci_ctl_info *pci_ctl; |
|---|
| 5 | | - |
|---|
| 6 | | -static int report_gart_errors; |
|---|
| 7 | | -module_param(report_gart_errors, int, 0644); |
|---|
| 8 | 6 | |
|---|
| 9 | 7 | /* |
|---|
| 10 | 8 | * Set by command line parameter. If BIOS has enabled the ECC, this override is |
|---|
| .. | .. |
|---|
| 14 | 12 | module_param(ecc_enable_override, int, 0644); |
|---|
| 15 | 13 | |
|---|
| 16 | 14 | static struct msr __percpu *msrs; |
|---|
| 15 | + |
|---|
| 16 | +static struct amd64_family_type *fam_type; |
|---|
| 17 | 17 | |
|---|
| 18 | 18 | /* Per-node stuff */ |
|---|
| 19 | 19 | static struct ecc_settings **ecc_stngs; |
|---|
| .. | .. |
|---|
| 214 | 214 | |
|---|
| 215 | 215 | scrubval = scrubrates[i].scrubval; |
|---|
| 216 | 216 | |
|---|
| 217 | | - if (pvt->fam == 0x17) { |
|---|
| 217 | + if (pvt->umc) { |
|---|
| 218 | 218 | __f17h_set_scrubval(pvt, scrubval); |
|---|
| 219 | 219 | } else if (pvt->fam == 0x15 && pvt->model == 0x60) { |
|---|
| 220 | 220 | f15h_select_dct(pvt, 0); |
|---|
| .. | .. |
|---|
| 256 | 256 | int i, retval = -EINVAL; |
|---|
| 257 | 257 | u32 scrubval = 0; |
|---|
| 258 | 258 | |
|---|
| 259 | | - switch (pvt->fam) { |
|---|
| 260 | | - case 0x15: |
|---|
| 261 | | - /* Erratum #505 */ |
|---|
| 262 | | - if (pvt->model < 0x10) |
|---|
| 263 | | - f15h_select_dct(pvt, 0); |
|---|
| 264 | | - |
|---|
| 265 | | - if (pvt->model == 0x60) |
|---|
| 266 | | - amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval); |
|---|
| 267 | | - else |
|---|
| 268 | | - amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); |
|---|
| 269 | | - break; |
|---|
| 270 | | - |
|---|
| 271 | | - case 0x17: |
|---|
| 259 | + if (pvt->umc) { |
|---|
| 272 | 260 | amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval); |
|---|
| 273 | 261 | if (scrubval & BIT(0)) { |
|---|
| 274 | 262 | amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval); |
|---|
| .. | .. |
|---|
| 277 | 265 | } else { |
|---|
| 278 | 266 | scrubval = 0; |
|---|
| 279 | 267 | } |
|---|
| 280 | | - break; |
|---|
| 268 | + } else if (pvt->fam == 0x15) { |
|---|
| 269 | + /* Erratum #505 */ |
|---|
| 270 | + if (pvt->model < 0x10) |
|---|
| 271 | + f15h_select_dct(pvt, 0); |
|---|
| 281 | 272 | |
|---|
| 282 | | - default: |
|---|
| 273 | + if (pvt->model == 0x60) |
|---|
| 274 | + amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval); |
|---|
| 275 | + else |
|---|
| 276 | + amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); |
|---|
| 277 | + } else { |
|---|
| 283 | 278 | amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); |
|---|
| 284 | | - break; |
|---|
| 285 | 279 | } |
|---|
| 286 | 280 | |
|---|
| 287 | 281 | scrubval = scrubval & 0x001F; |
|---|
| .. | .. |
|---|
| 452 | 446 | |
|---|
| 453 | 447 | #define for_each_chip_select_mask(i, dct, pvt) \ |
|---|
| 454 | 448 | for (i = 0; i < pvt->csels[dct].m_cnt; i++) |
|---|
| 449 | + |
|---|
| 450 | +#define for_each_umc(i) \ |
|---|
| 451 | + for (i = 0; i < fam_type->max_mcs; i++) |
|---|
| 455 | 452 | |
|---|
| 456 | 453 | /* |
|---|
| 457 | 454 | * @input_addr is an InputAddr associated with the node given by mci. Return the |
|---|
| .. | .. |
|---|
| 726 | 723 | if (pvt->umc) { |
|---|
| 727 | 724 | u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0; |
|---|
| 728 | 725 | |
|---|
| 729 | | - for (i = 0; i < NUM_UMCS; i++) { |
|---|
| 726 | + for_each_umc(i) { |
|---|
| 730 | 727 | if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT)) |
|---|
| 731 | 728 | continue; |
|---|
| 732 | 729 | |
|---|
| .. | .. |
|---|
| 785 | 782 | (dclr & BIT(15)) ? "yes" : "no"); |
|---|
| 786 | 783 | } |
|---|
| 787 | 784 | |
|---|
| 785 | +#define CS_EVEN_PRIMARY BIT(0) |
|---|
| 786 | +#define CS_ODD_PRIMARY BIT(1) |
|---|
| 787 | +#define CS_EVEN_SECONDARY BIT(2) |
|---|
| 788 | +#define CS_ODD_SECONDARY BIT(3) |
|---|
| 789 | +#define CS_3R_INTERLEAVE BIT(4) |
|---|
| 790 | + |
|---|
| 791 | +#define CS_EVEN (CS_EVEN_PRIMARY | CS_EVEN_SECONDARY) |
|---|
| 792 | +#define CS_ODD (CS_ODD_PRIMARY | CS_ODD_SECONDARY) |
|---|
| 793 | + |
|---|
| 794 | +static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt) |
|---|
| 795 | +{ |
|---|
| 796 | + u8 base, count = 0; |
|---|
| 797 | + int cs_mode = 0; |
|---|
| 798 | + |
|---|
| 799 | + if (csrow_enabled(2 * dimm, ctrl, pvt)) |
|---|
| 800 | + cs_mode |= CS_EVEN_PRIMARY; |
|---|
| 801 | + |
|---|
| 802 | + if (csrow_enabled(2 * dimm + 1, ctrl, pvt)) |
|---|
| 803 | + cs_mode |= CS_ODD_PRIMARY; |
|---|
| 804 | + |
|---|
| 805 | + /* Asymmetric dual-rank DIMM support. */ |
|---|
| 806 | + if (csrow_sec_enabled(2 * dimm + 1, ctrl, pvt)) |
|---|
| 807 | + cs_mode |= CS_ODD_SECONDARY; |
|---|
| 808 | + |
|---|
| 809 | + /* |
|---|
| 810 | + * 3 Rank inteleaving support. |
|---|
| 811 | + * There should be only three bases enabled and their two masks should |
|---|
| 812 | + * be equal. |
|---|
| 813 | + */ |
|---|
| 814 | + for_each_chip_select(base, ctrl, pvt) |
|---|
| 815 | + count += csrow_enabled(base, ctrl, pvt); |
|---|
| 816 | + |
|---|
| 817 | + if (count == 3 && |
|---|
| 818 | + pvt->csels[ctrl].csmasks[0] == pvt->csels[ctrl].csmasks[1]) { |
|---|
| 819 | + edac_dbg(1, "3R interleaving in use.\n"); |
|---|
| 820 | + cs_mode |= CS_3R_INTERLEAVE; |
|---|
| 821 | + } |
|---|
| 822 | + |
|---|
| 823 | + return cs_mode; |
|---|
| 824 | +} |
|---|
| 825 | + |
|---|
| 788 | 826 | static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) |
|---|
| 789 | 827 | { |
|---|
| 790 | | - int dimm, size0, size1, cs0, cs1; |
|---|
| 828 | + int dimm, size0, size1, cs0, cs1, cs_mode; |
|---|
| 791 | 829 | |
|---|
| 792 | 830 | edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl); |
|---|
| 793 | 831 | |
|---|
| 794 | | - for (dimm = 0; dimm < 4; dimm++) { |
|---|
| 795 | | - size0 = 0; |
|---|
| 832 | + for (dimm = 0; dimm < 2; dimm++) { |
|---|
| 796 | 833 | cs0 = dimm * 2; |
|---|
| 797 | | - |
|---|
| 798 | | - if (csrow_enabled(cs0, ctrl, pvt)) |
|---|
| 799 | | - size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs0); |
|---|
| 800 | | - |
|---|
| 801 | | - size1 = 0; |
|---|
| 802 | 834 | cs1 = dimm * 2 + 1; |
|---|
| 803 | 835 | |
|---|
| 804 | | - if (csrow_enabled(cs1, ctrl, pvt)) |
|---|
| 805 | | - size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1); |
|---|
| 836 | + cs_mode = f17_get_cs_mode(dimm, ctrl, pvt); |
|---|
| 837 | + |
|---|
| 838 | + size0 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs0); |
|---|
| 839 | + size1 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs1); |
|---|
| 806 | 840 | |
|---|
| 807 | 841 | amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", |
|---|
| 808 | 842 | cs0, size0, |
|---|
| .. | .. |
|---|
| 815 | 849 | struct amd64_umc *umc; |
|---|
| 816 | 850 | u32 i, tmp, umc_base; |
|---|
| 817 | 851 | |
|---|
| 818 | | - for (i = 0; i < NUM_UMCS; i++) { |
|---|
| 852 | + for_each_umc(i) { |
|---|
| 819 | 853 | umc_base = get_umc_base(i); |
|---|
| 820 | 854 | umc = &pvt->umc[i]; |
|---|
| 821 | 855 | |
|---|
| .. | .. |
|---|
| 898 | 932 | |
|---|
| 899 | 933 | edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no"); |
|---|
| 900 | 934 | |
|---|
| 901 | | - amd64_info("using %s syndromes.\n", |
|---|
| 902 | | - ((pvt->ecc_sym_sz == 8) ? "x8" : "x4")); |
|---|
| 935 | + amd64_info("using x%u syndromes.\n", pvt->ecc_sym_sz); |
|---|
| 903 | 936 | } |
|---|
| 904 | 937 | |
|---|
| 905 | 938 | /* |
|---|
| .. | .. |
|---|
| 913 | 946 | } else if (pvt->fam == 0x15 && pvt->model == 0x30) { |
|---|
| 914 | 947 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; |
|---|
| 915 | 948 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; |
|---|
| 949 | + } else if (pvt->fam >= 0x17) { |
|---|
| 950 | + int umc; |
|---|
| 951 | + |
|---|
| 952 | + for_each_umc(umc) { |
|---|
| 953 | + pvt->csels[umc].b_cnt = 4; |
|---|
| 954 | + pvt->csels[umc].m_cnt = 2; |
|---|
| 955 | + } |
|---|
| 956 | + |
|---|
| 916 | 957 | } else { |
|---|
| 917 | 958 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; |
|---|
| 918 | 959 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; |
|---|
| 960 | + } |
|---|
| 961 | +} |
|---|
| 962 | + |
|---|
| 963 | +static void read_umc_base_mask(struct amd64_pvt *pvt) |
|---|
| 964 | +{ |
|---|
| 965 | + u32 umc_base_reg, umc_base_reg_sec; |
|---|
| 966 | + u32 umc_mask_reg, umc_mask_reg_sec; |
|---|
| 967 | + u32 base_reg, base_reg_sec; |
|---|
| 968 | + u32 mask_reg, mask_reg_sec; |
|---|
| 969 | + u32 *base, *base_sec; |
|---|
| 970 | + u32 *mask, *mask_sec; |
|---|
| 971 | + int cs, umc; |
|---|
| 972 | + |
|---|
| 973 | + for_each_umc(umc) { |
|---|
| 974 | + umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR; |
|---|
| 975 | + umc_base_reg_sec = get_umc_base(umc) + UMCCH_BASE_ADDR_SEC; |
|---|
| 976 | + |
|---|
| 977 | + for_each_chip_select(cs, umc, pvt) { |
|---|
| 978 | + base = &pvt->csels[umc].csbases[cs]; |
|---|
| 979 | + base_sec = &pvt->csels[umc].csbases_sec[cs]; |
|---|
| 980 | + |
|---|
| 981 | + base_reg = umc_base_reg + (cs * 4); |
|---|
| 982 | + base_reg_sec = umc_base_reg_sec + (cs * 4); |
|---|
| 983 | + |
|---|
| 984 | + if (!amd_smn_read(pvt->mc_node_id, base_reg, base)) |
|---|
| 985 | + edac_dbg(0, " DCSB%d[%d]=0x%08x reg: 0x%x\n", |
|---|
| 986 | + umc, cs, *base, base_reg); |
|---|
| 987 | + |
|---|
| 988 | + if (!amd_smn_read(pvt->mc_node_id, base_reg_sec, base_sec)) |
|---|
| 989 | + edac_dbg(0, " DCSB_SEC%d[%d]=0x%08x reg: 0x%x\n", |
|---|
| 990 | + umc, cs, *base_sec, base_reg_sec); |
|---|
| 991 | + } |
|---|
| 992 | + |
|---|
| 993 | + umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK; |
|---|
| 994 | + umc_mask_reg_sec = get_umc_base(umc) + UMCCH_ADDR_MASK_SEC; |
|---|
| 995 | + |
|---|
| 996 | + for_each_chip_select_mask(cs, umc, pvt) { |
|---|
| 997 | + mask = &pvt->csels[umc].csmasks[cs]; |
|---|
| 998 | + mask_sec = &pvt->csels[umc].csmasks_sec[cs]; |
|---|
| 999 | + |
|---|
| 1000 | + mask_reg = umc_mask_reg + (cs * 4); |
|---|
| 1001 | + mask_reg_sec = umc_mask_reg_sec + (cs * 4); |
|---|
| 1002 | + |
|---|
| 1003 | + if (!amd_smn_read(pvt->mc_node_id, mask_reg, mask)) |
|---|
| 1004 | + edac_dbg(0, " DCSM%d[%d]=0x%08x reg: 0x%x\n", |
|---|
| 1005 | + umc, cs, *mask, mask_reg); |
|---|
| 1006 | + |
|---|
| 1007 | + if (!amd_smn_read(pvt->mc_node_id, mask_reg_sec, mask_sec)) |
|---|
| 1008 | + edac_dbg(0, " DCSM_SEC%d[%d]=0x%08x reg: 0x%x\n", |
|---|
| 1009 | + umc, cs, *mask_sec, mask_reg_sec); |
|---|
| 1010 | + } |
|---|
| 919 | 1011 | } |
|---|
| 920 | 1012 | } |
|---|
| 921 | 1013 | |
|---|
| .. | .. |
|---|
| 924 | 1016 | */ |
|---|
| 925 | 1017 | static void read_dct_base_mask(struct amd64_pvt *pvt) |
|---|
| 926 | 1018 | { |
|---|
| 927 | | - int base_reg0, base_reg1, mask_reg0, mask_reg1, cs; |
|---|
| 1019 | + int cs; |
|---|
| 928 | 1020 | |
|---|
| 929 | 1021 | prep_chip_selects(pvt); |
|---|
| 930 | 1022 | |
|---|
| 931 | | - if (pvt->umc) { |
|---|
| 932 | | - base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR; |
|---|
| 933 | | - base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR; |
|---|
| 934 | | - mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK; |
|---|
| 935 | | - mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK; |
|---|
| 936 | | - } else { |
|---|
| 937 | | - base_reg0 = DCSB0; |
|---|
| 938 | | - base_reg1 = DCSB1; |
|---|
| 939 | | - mask_reg0 = DCSM0; |
|---|
| 940 | | - mask_reg1 = DCSM1; |
|---|
| 941 | | - } |
|---|
| 1023 | + if (pvt->umc) |
|---|
| 1024 | + return read_umc_base_mask(pvt); |
|---|
| 942 | 1025 | |
|---|
| 943 | 1026 | for_each_chip_select(cs, 0, pvt) { |
|---|
| 944 | | - int reg0 = base_reg0 + (cs * 4); |
|---|
| 945 | | - int reg1 = base_reg1 + (cs * 4); |
|---|
| 1027 | + int reg0 = DCSB0 + (cs * 4); |
|---|
| 1028 | + int reg1 = DCSB1 + (cs * 4); |
|---|
| 946 | 1029 | u32 *base0 = &pvt->csels[0].csbases[cs]; |
|---|
| 947 | 1030 | u32 *base1 = &pvt->csels[1].csbases[cs]; |
|---|
| 948 | 1031 | |
|---|
| 949 | | - if (pvt->umc) { |
|---|
| 950 | | - if (!amd_smn_read(pvt->mc_node_id, reg0, base0)) |
|---|
| 951 | | - edac_dbg(0, " DCSB0[%d]=0x%08x reg: 0x%x\n", |
|---|
| 952 | | - cs, *base0, reg0); |
|---|
| 1032 | + if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0)) |
|---|
| 1033 | + edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", |
|---|
| 1034 | + cs, *base0, reg0); |
|---|
| 953 | 1035 | |
|---|
| 954 | | - if (!amd_smn_read(pvt->mc_node_id, reg1, base1)) |
|---|
| 955 | | - edac_dbg(0, " DCSB1[%d]=0x%08x reg: 0x%x\n", |
|---|
| 956 | | - cs, *base1, reg1); |
|---|
| 957 | | - } else { |
|---|
| 958 | | - if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0)) |
|---|
| 959 | | - edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", |
|---|
| 960 | | - cs, *base0, reg0); |
|---|
| 1036 | + if (pvt->fam == 0xf) |
|---|
| 1037 | + continue; |
|---|
| 961 | 1038 | |
|---|
| 962 | | - if (pvt->fam == 0xf) |
|---|
| 963 | | - continue; |
|---|
| 964 | | - |
|---|
| 965 | | - if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1)) |
|---|
| 966 | | - edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n", |
|---|
| 967 | | - cs, *base1, (pvt->fam == 0x10) ? reg1 |
|---|
| 968 | | - : reg0); |
|---|
| 969 | | - } |
|---|
| 1039 | + if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1)) |
|---|
| 1040 | + edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n", |
|---|
| 1041 | + cs, *base1, (pvt->fam == 0x10) ? reg1 |
|---|
| 1042 | + : reg0); |
|---|
| 970 | 1043 | } |
|---|
| 971 | 1044 | |
|---|
| 972 | 1045 | for_each_chip_select_mask(cs, 0, pvt) { |
|---|
| 973 | | - int reg0 = mask_reg0 + (cs * 4); |
|---|
| 974 | | - int reg1 = mask_reg1 + (cs * 4); |
|---|
| 1046 | + int reg0 = DCSM0 + (cs * 4); |
|---|
| 1047 | + int reg1 = DCSM1 + (cs * 4); |
|---|
| 975 | 1048 | u32 *mask0 = &pvt->csels[0].csmasks[cs]; |
|---|
| 976 | 1049 | u32 *mask1 = &pvt->csels[1].csmasks[cs]; |
|---|
| 977 | 1050 | |
|---|
| 978 | | - if (pvt->umc) { |
|---|
| 979 | | - if (!amd_smn_read(pvt->mc_node_id, reg0, mask0)) |
|---|
| 980 | | - edac_dbg(0, " DCSM0[%d]=0x%08x reg: 0x%x\n", |
|---|
| 981 | | - cs, *mask0, reg0); |
|---|
| 1051 | + if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0)) |
|---|
| 1052 | + edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", |
|---|
| 1053 | + cs, *mask0, reg0); |
|---|
| 982 | 1054 | |
|---|
| 983 | | - if (!amd_smn_read(pvt->mc_node_id, reg1, mask1)) |
|---|
| 984 | | - edac_dbg(0, " DCSM1[%d]=0x%08x reg: 0x%x\n", |
|---|
| 985 | | - cs, *mask1, reg1); |
|---|
| 986 | | - } else { |
|---|
| 987 | | - if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0)) |
|---|
| 988 | | - edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", |
|---|
| 989 | | - cs, *mask0, reg0); |
|---|
| 1055 | + if (pvt->fam == 0xf) |
|---|
| 1056 | + continue; |
|---|
| 990 | 1057 | |
|---|
| 991 | | - if (pvt->fam == 0xf) |
|---|
| 992 | | - continue; |
|---|
| 993 | | - |
|---|
| 994 | | - if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1)) |
|---|
| 995 | | - edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n", |
|---|
| 996 | | - cs, *mask1, (pvt->fam == 0x10) ? reg1 |
|---|
| 997 | | - : reg0); |
|---|
| 998 | | - } |
|---|
| 1058 | + if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1)) |
|---|
| 1059 | + edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n", |
|---|
| 1060 | + cs, *mask1, (pvt->fam == 0x10) ? reg1 |
|---|
| 1061 | + : reg0); |
|---|
| 999 | 1062 | } |
|---|
| 1000 | 1063 | } |
|---|
| 1001 | 1064 | |
|---|
| 1002 | 1065 | static void determine_memory_type(struct amd64_pvt *pvt) |
|---|
| 1003 | 1066 | { |
|---|
| 1004 | 1067 | u32 dram_ctrl, dcsm; |
|---|
| 1068 | + |
|---|
| 1069 | + if (pvt->umc) { |
|---|
| 1070 | + if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5)) |
|---|
| 1071 | + pvt->dram_type = MEM_LRDDR4; |
|---|
| 1072 | + else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4)) |
|---|
| 1073 | + pvt->dram_type = MEM_RDDR4; |
|---|
| 1074 | + else |
|---|
| 1075 | + pvt->dram_type = MEM_DDR4; |
|---|
| 1076 | + return; |
|---|
| 1077 | + } |
|---|
| 1005 | 1078 | |
|---|
| 1006 | 1079 | switch (pvt->fam) { |
|---|
| 1007 | 1080 | case 0xf: |
|---|
| .. | .. |
|---|
| 1047 | 1120 | |
|---|
| 1048 | 1121 | case 0x16: |
|---|
| 1049 | 1122 | goto ddr3; |
|---|
| 1050 | | - |
|---|
| 1051 | | - case 0x17: |
|---|
| 1052 | | - if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5)) |
|---|
| 1053 | | - pvt->dram_type = MEM_LRDDR4; |
|---|
| 1054 | | - else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4)) |
|---|
| 1055 | | - pvt->dram_type = MEM_RDDR4; |
|---|
| 1056 | | - else |
|---|
| 1057 | | - pvt->dram_type = MEM_DDR4; |
|---|
| 1058 | | - return; |
|---|
| 1059 | 1123 | |
|---|
| 1060 | 1124 | default: |
|---|
| 1061 | 1125 | WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam); |
|---|
| .. | .. |
|---|
| 1391 | 1455 | int i, channels = 0; |
|---|
| 1392 | 1456 | |
|---|
| 1393 | 1457 | /* SDP Control bit 31 (SdpInit) is clear for unused UMC channels */ |
|---|
| 1394 | | - for (i = 0; i < NUM_UMCS; i++) |
|---|
| 1458 | + for_each_umc(i) |
|---|
| 1395 | 1459 | channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT); |
|---|
| 1396 | 1460 | |
|---|
| 1397 | 1461 | amd64_info("MCT channel count: %d\n", channels); |
|---|
| .. | .. |
|---|
| 1526 | 1590 | return ddr3_cs_size(cs_mode, false); |
|---|
| 1527 | 1591 | } |
|---|
| 1528 | 1592 | |
|---|
| 1529 | | -static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc, |
|---|
| 1593 | +static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc, |
|---|
| 1530 | 1594 | unsigned int cs_mode, int csrow_nr) |
|---|
| 1531 | 1595 | { |
|---|
| 1532 | | - u32 base_addr = pvt->csels[umc].csbases[csrow_nr]; |
|---|
| 1596 | + u32 addr_mask_orig, addr_mask_deinterleaved; |
|---|
| 1597 | + u32 msb, weight, num_zero_bits; |
|---|
| 1598 | + int dimm, size = 0; |
|---|
| 1533 | 1599 | |
|---|
| 1534 | | - /* Each mask is used for every two base addresses. */ |
|---|
| 1535 | | - u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1]; |
|---|
| 1600 | + /* No Chip Selects are enabled. */ |
|---|
| 1601 | + if (!cs_mode) |
|---|
| 1602 | + return size; |
|---|
| 1536 | 1603 | |
|---|
| 1537 | | - /* Register [31:1] = Address [39:9]. Size is in kBs here. */ |
|---|
| 1538 | | - u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1; |
|---|
| 1604 | + /* Requested size of an even CS but none are enabled. */ |
|---|
| 1605 | + if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1)) |
|---|
| 1606 | + return size; |
|---|
| 1539 | 1607 | |
|---|
| 1540 | | - edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x\n", base_addr, addr_mask); |
|---|
| 1608 | + /* Requested size of an odd CS but none are enabled. */ |
|---|
| 1609 | + if (!(cs_mode & CS_ODD) && (csrow_nr & 1)) |
|---|
| 1610 | + return size; |
|---|
| 1611 | + |
|---|
| 1612 | + /* |
|---|
| 1613 | + * There is one mask per DIMM, and two Chip Selects per DIMM. |
|---|
| 1614 | + * CS0 and CS1 -> DIMM0 |
|---|
| 1615 | + * CS2 and CS3 -> DIMM1 |
|---|
| 1616 | + */ |
|---|
| 1617 | + dimm = csrow_nr >> 1; |
|---|
| 1618 | + |
|---|
| 1619 | + /* Asymmetric dual-rank DIMM support. */ |
|---|
| 1620 | + if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY)) |
|---|
| 1621 | + addr_mask_orig = pvt->csels[umc].csmasks_sec[dimm]; |
|---|
| 1622 | + else |
|---|
| 1623 | + addr_mask_orig = pvt->csels[umc].csmasks[dimm]; |
|---|
| 1624 | + |
|---|
| 1625 | + /* |
|---|
| 1626 | + * The number of zero bits in the mask is equal to the number of bits |
|---|
| 1627 | + * in a full mask minus the number of bits in the current mask. |
|---|
| 1628 | + * |
|---|
| 1629 | + * The MSB is the number of bits in the full mask because BIT[0] is |
|---|
| 1630 | + * always 0. |
|---|
| 1631 | + * |
|---|
| 1632 | + * In the special 3 Rank interleaving case, a single bit is flipped |
|---|
| 1633 | + * without swapping with the most significant bit. This can be handled |
|---|
| 1634 | + * by keeping the MSB where it is and ignoring the single zero bit. |
|---|
| 1635 | + */ |
|---|
| 1636 | + msb = fls(addr_mask_orig) - 1; |
|---|
| 1637 | + weight = hweight_long(addr_mask_orig); |
|---|
| 1638 | + num_zero_bits = msb - weight - !!(cs_mode & CS_3R_INTERLEAVE); |
|---|
| 1639 | + |
|---|
| 1640 | + /* Take the number of zero bits off from the top of the mask. */ |
|---|
| 1641 | + addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1); |
|---|
| 1642 | + |
|---|
| 1643 | + edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm); |
|---|
| 1644 | + edac_dbg(1, " Original AddrMask: 0x%x\n", addr_mask_orig); |
|---|
| 1645 | + edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved); |
|---|
| 1646 | + |
|---|
| 1647 | + /* Register [31:1] = Address [39:9]. Size is in kBs here. */ |
|---|
| 1648 | + size = (addr_mask_deinterleaved >> 2) + 1; |
|---|
| 1541 | 1649 | |
|---|
| 1542 | 1650 | /* Return size in MBs. */ |
|---|
| 1543 | 1651 | return size >> 10; |
|---|
| .. | .. |
|---|
| 2130 | 2238 | .ctl_name = "K8", |
|---|
| 2131 | 2239 | .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP, |
|---|
| 2132 | 2240 | .f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, |
|---|
| 2241 | + .max_mcs = 2, |
|---|
| 2133 | 2242 | .ops = { |
|---|
| 2134 | 2243 | .early_channel_count = k8_early_channel_count, |
|---|
| 2135 | 2244 | .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, |
|---|
| .. | .. |
|---|
| 2140 | 2249 | .ctl_name = "F10h", |
|---|
| 2141 | 2250 | .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP, |
|---|
| 2142 | 2251 | .f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM, |
|---|
| 2252 | + .max_mcs = 2, |
|---|
| 2143 | 2253 | .ops = { |
|---|
| 2144 | 2254 | .early_channel_count = f1x_early_channel_count, |
|---|
| 2145 | 2255 | .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, |
|---|
| .. | .. |
|---|
| 2150 | 2260 | .ctl_name = "F15h", |
|---|
| 2151 | 2261 | .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1, |
|---|
| 2152 | 2262 | .f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2, |
|---|
| 2263 | + .max_mcs = 2, |
|---|
| 2153 | 2264 | .ops = { |
|---|
| 2154 | 2265 | .early_channel_count = f1x_early_channel_count, |
|---|
| 2155 | 2266 | .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, |
|---|
| .. | .. |
|---|
| 2160 | 2271 | .ctl_name = "F15h_M30h", |
|---|
| 2161 | 2272 | .f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1, |
|---|
| 2162 | 2273 | .f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2, |
|---|
| 2274 | + .max_mcs = 2, |
|---|
| 2163 | 2275 | .ops = { |
|---|
| 2164 | 2276 | .early_channel_count = f1x_early_channel_count, |
|---|
| 2165 | 2277 | .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, |
|---|
| .. | .. |
|---|
| 2170 | 2282 | .ctl_name = "F15h_M60h", |
|---|
| 2171 | 2283 | .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1, |
|---|
| 2172 | 2284 | .f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2, |
|---|
| 2285 | + .max_mcs = 2, |
|---|
| 2173 | 2286 | .ops = { |
|---|
| 2174 | 2287 | .early_channel_count = f1x_early_channel_count, |
|---|
| 2175 | 2288 | .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, |
|---|
| .. | .. |
|---|
| 2180 | 2293 | .ctl_name = "F16h", |
|---|
| 2181 | 2294 | .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1, |
|---|
| 2182 | 2295 | .f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2, |
|---|
| 2296 | + .max_mcs = 2, |
|---|
| 2183 | 2297 | .ops = { |
|---|
| 2184 | 2298 | .early_channel_count = f1x_early_channel_count, |
|---|
| 2185 | 2299 | .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, |
|---|
| .. | .. |
|---|
| 2190 | 2304 | .ctl_name = "F16h_M30h", |
|---|
| 2191 | 2305 | .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1, |
|---|
| 2192 | 2306 | .f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2, |
|---|
| 2307 | + .max_mcs = 2, |
|---|
| 2193 | 2308 | .ops = { |
|---|
| 2194 | 2309 | .early_channel_count = f1x_early_channel_count, |
|---|
| 2195 | 2310 | .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, |
|---|
| .. | .. |
|---|
| 2200 | 2315 | .ctl_name = "F17h", |
|---|
| 2201 | 2316 | .f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0, |
|---|
| 2202 | 2317 | .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6, |
|---|
| 2318 | + .max_mcs = 2, |
|---|
| 2203 | 2319 | .ops = { |
|---|
| 2204 | 2320 | .early_channel_count = f17_early_channel_count, |
|---|
| 2205 | | - .dbam_to_cs = f17_base_addr_to_cs_size, |
|---|
| 2321 | + .dbam_to_cs = f17_addr_mask_to_cs_size, |
|---|
| 2206 | 2322 | } |
|---|
| 2207 | 2323 | }, |
|---|
| 2208 | 2324 | [F17_M10H_CPUS] = { |
|---|
| 2209 | 2325 | .ctl_name = "F17h_M10h", |
|---|
| 2210 | 2326 | .f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0, |
|---|
| 2211 | 2327 | .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6, |
|---|
| 2328 | + .max_mcs = 2, |
|---|
| 2212 | 2329 | .ops = { |
|---|
| 2213 | 2330 | .early_channel_count = f17_early_channel_count, |
|---|
| 2214 | | - .dbam_to_cs = f17_base_addr_to_cs_size, |
|---|
| 2331 | + .dbam_to_cs = f17_addr_mask_to_cs_size, |
|---|
| 2215 | 2332 | } |
|---|
| 2216 | 2333 | }, |
|---|
| 2217 | 2334 | [F17_M30H_CPUS] = { |
|---|
| 2218 | 2335 | .ctl_name = "F17h_M30h", |
|---|
| 2219 | 2336 | .f0_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F0, |
|---|
| 2220 | 2337 | .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6, |
|---|
| 2338 | + .max_mcs = 8, |
|---|
| 2221 | 2339 | .ops = { |
|---|
| 2222 | 2340 | .early_channel_count = f17_early_channel_count, |
|---|
| 2223 | | - .dbam_to_cs = f17_base_addr_to_cs_size, |
|---|
| 2341 | + .dbam_to_cs = f17_addr_mask_to_cs_size, |
|---|
| 2342 | + } |
|---|
| 2343 | + }, |
|---|
| 2344 | + [F17_M60H_CPUS] = { |
|---|
| 2345 | + .ctl_name = "F17h_M60h", |
|---|
| 2346 | + .f0_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F0, |
|---|
| 2347 | + .f6_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F6, |
|---|
| 2348 | + .max_mcs = 2, |
|---|
| 2349 | + .ops = { |
|---|
| 2350 | + .early_channel_count = f17_early_channel_count, |
|---|
| 2351 | + .dbam_to_cs = f17_addr_mask_to_cs_size, |
|---|
| 2352 | + } |
|---|
| 2353 | + }, |
|---|
| 2354 | + [F17_M70H_CPUS] = { |
|---|
| 2355 | + .ctl_name = "F17h_M70h", |
|---|
| 2356 | + .f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0, |
|---|
| 2357 | + .f6_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F6, |
|---|
| 2358 | + .max_mcs = 2, |
|---|
| 2359 | + .ops = { |
|---|
| 2360 | + .early_channel_count = f17_early_channel_count, |
|---|
| 2361 | + .dbam_to_cs = f17_addr_mask_to_cs_size, |
|---|
| 2362 | + } |
|---|
| 2363 | + }, |
|---|
| 2364 | + [F19_CPUS] = { |
|---|
| 2365 | + .ctl_name = "F19h", |
|---|
| 2366 | + .f0_id = PCI_DEVICE_ID_AMD_19H_DF_F0, |
|---|
| 2367 | + .f6_id = PCI_DEVICE_ID_AMD_19H_DF_F6, |
|---|
| 2368 | + .max_mcs = 8, |
|---|
| 2369 | + .ops = { |
|---|
| 2370 | + .early_channel_count = f17_early_channel_count, |
|---|
| 2371 | + .dbam_to_cs = f17_addr_mask_to_cs_size, |
|---|
| 2224 | 2372 | } |
|---|
| 2225 | 2373 | }, |
|---|
| 2226 | 2374 | }; |
|---|
| .. | .. |
|---|
| 2476 | 2624 | * To find the UMC channel represented by this bank we need to match on its |
|---|
| 2477 | 2625 | * instance_id. The instance_id of a bank is held in the lower 32 bits of its |
|---|
| 2478 | 2626 | * IPID. |
|---|
| 2627 | + * |
|---|
| 2628 | + * Currently, we can derive the channel number by looking at the 6th nibble in |
|---|
| 2629 | + * the instance_id. For example, instance_id=0xYXXXXX where Y is the channel |
|---|
| 2630 | + * number. |
|---|
| 2479 | 2631 | */ |
|---|
| 2480 | | -static int find_umc_channel(struct amd64_pvt *pvt, struct mce *m) |
|---|
| 2632 | +static int find_umc_channel(struct mce *m) |
|---|
| 2481 | 2633 | { |
|---|
| 2482 | | - u32 umc_instance_id[] = {0x50f00, 0x150f00}; |
|---|
| 2483 | | - u32 instance_id = m->ipid & GENMASK(31, 0); |
|---|
| 2484 | | - int i, channel = -1; |
|---|
| 2485 | | - |
|---|
| 2486 | | - for (i = 0; i < ARRAY_SIZE(umc_instance_id); i++) |
|---|
| 2487 | | - if (umc_instance_id[i] == instance_id) |
|---|
| 2488 | | - channel = i; |
|---|
| 2489 | | - |
|---|
| 2490 | | - return channel; |
|---|
| 2634 | + return (m->ipid & GENMASK(31, 0)) >> 20; |
|---|
| 2491 | 2635 | } |
|---|
| 2492 | 2636 | |
|---|
| 2493 | 2637 | static void decode_umc_error(int node_id, struct mce *m) |
|---|
| .. | .. |
|---|
| 2509 | 2653 | if (m->status & MCI_STATUS_DEFERRED) |
|---|
| 2510 | 2654 | ecc_type = 3; |
|---|
| 2511 | 2655 | |
|---|
| 2512 | | - err.channel = find_umc_channel(pvt, m); |
|---|
| 2513 | | - if (err.channel < 0) { |
|---|
| 2514 | | - err.err_code = ERR_CHANNEL; |
|---|
| 2515 | | - goto log_error; |
|---|
| 2516 | | - } |
|---|
| 2656 | + err.channel = find_umc_channel(m); |
|---|
| 2517 | 2657 | |
|---|
| 2518 | 2658 | if (!(m->status & MCI_STATUS_SYNDV)) { |
|---|
| 2519 | 2659 | err.err_code = ERR_SYND; |
|---|
| .. | .. |
|---|
| 2621 | 2761 | if (pvt->umc) { |
|---|
| 2622 | 2762 | u8 i; |
|---|
| 2623 | 2763 | |
|---|
| 2624 | | - for (i = 0; i < NUM_UMCS; i++) { |
|---|
| 2764 | + for_each_umc(i) { |
|---|
| 2625 | 2765 | /* Check enabled channels only: */ |
|---|
| 2626 | | - if ((pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) && |
|---|
| 2627 | | - (pvt->umc[i].ecc_ctrl & BIT(7))) { |
|---|
| 2628 | | - pvt->ecc_sym_sz = 8; |
|---|
| 2629 | | - break; |
|---|
| 2766 | + if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) { |
|---|
| 2767 | + if (pvt->umc[i].ecc_ctrl & BIT(9)) { |
|---|
| 2768 | + pvt->ecc_sym_sz = 16; |
|---|
| 2769 | + return; |
|---|
| 2770 | + } else if (pvt->umc[i].ecc_ctrl & BIT(7)) { |
|---|
| 2771 | + pvt->ecc_sym_sz = 8; |
|---|
| 2772 | + return; |
|---|
| 2773 | + } |
|---|
| 2630 | 2774 | } |
|---|
| 2631 | 2775 | } |
|---|
| 2632 | | - |
|---|
| 2633 | | - return; |
|---|
| 2634 | | - } |
|---|
| 2635 | | - |
|---|
| 2636 | | - if (pvt->fam >= 0x10) { |
|---|
| 2776 | + } else if (pvt->fam >= 0x10) { |
|---|
| 2637 | 2777 | u32 tmp; |
|---|
| 2638 | 2778 | |
|---|
| 2639 | 2779 | amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); |
|---|
| .. | .. |
|---|
| 2657 | 2797 | u32 i, umc_base; |
|---|
| 2658 | 2798 | |
|---|
| 2659 | 2799 | /* Read registers from each UMC */ |
|---|
| 2660 | | - for (i = 0; i < NUM_UMCS; i++) { |
|---|
| 2800 | + for_each_umc(i) { |
|---|
| 2661 | 2801 | |
|---|
| 2662 | 2802 | umc_base = get_umc_base(i); |
|---|
| 2663 | 2803 | umc = &pvt->umc[i]; |
|---|
| .. | .. |
|---|
| 2749 | 2889 | edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]); |
|---|
| 2750 | 2890 | |
|---|
| 2751 | 2891 | determine_ecc_sym_sz(pvt); |
|---|
| 2752 | | - |
|---|
| 2753 | | - dump_misc_regs(pvt); |
|---|
| 2754 | 2892 | } |
|---|
| 2755 | 2893 | |
|---|
| 2756 | 2894 | /* |
|---|
| .. | .. |
|---|
| 2793 | 2931 | int csrow_nr = csrow_nr_orig; |
|---|
| 2794 | 2932 | u32 cs_mode, nr_pages; |
|---|
| 2795 | 2933 | |
|---|
| 2796 | | - if (!pvt->umc) |
|---|
| 2934 | + if (!pvt->umc) { |
|---|
| 2797 | 2935 | csrow_nr >>= 1; |
|---|
| 2798 | | - |
|---|
| 2799 | | - cs_mode = DBAM_DIMM(csrow_nr, dbam); |
|---|
| 2936 | + cs_mode = DBAM_DIMM(csrow_nr, dbam); |
|---|
| 2937 | + } else { |
|---|
| 2938 | + cs_mode = f17_get_cs_mode(csrow_nr >> 1, dct, pvt); |
|---|
| 2939 | + } |
|---|
| 2800 | 2940 | |
|---|
| 2801 | 2941 | nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr); |
|---|
| 2802 | 2942 | nr_pages <<= 20 - PAGE_SHIFT; |
|---|
| .. | .. |
|---|
| 2806 | 2946 | edac_dbg(0, "nr_pages/channel: %u\n", nr_pages); |
|---|
| 2807 | 2947 | |
|---|
| 2808 | 2948 | return nr_pages; |
|---|
| 2949 | +} |
|---|
| 2950 | + |
|---|
| 2951 | +static int init_csrows_df(struct mem_ctl_info *mci) |
|---|
| 2952 | +{ |
|---|
| 2953 | + struct amd64_pvt *pvt = mci->pvt_info; |
|---|
| 2954 | + enum edac_type edac_mode = EDAC_NONE; |
|---|
| 2955 | + enum dev_type dev_type = DEV_UNKNOWN; |
|---|
| 2956 | + struct dimm_info *dimm; |
|---|
| 2957 | + int empty = 1; |
|---|
| 2958 | + u8 umc, cs; |
|---|
| 2959 | + |
|---|
| 2960 | + if (mci->edac_ctl_cap & EDAC_FLAG_S16ECD16ED) { |
|---|
| 2961 | + edac_mode = EDAC_S16ECD16ED; |
|---|
| 2962 | + dev_type = DEV_X16; |
|---|
| 2963 | + } else if (mci->edac_ctl_cap & EDAC_FLAG_S8ECD8ED) { |
|---|
| 2964 | + edac_mode = EDAC_S8ECD8ED; |
|---|
| 2965 | + dev_type = DEV_X8; |
|---|
| 2966 | + } else if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) { |
|---|
| 2967 | + edac_mode = EDAC_S4ECD4ED; |
|---|
| 2968 | + dev_type = DEV_X4; |
|---|
| 2969 | + } else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) { |
|---|
| 2970 | + edac_mode = EDAC_SECDED; |
|---|
| 2971 | + } |
|---|
| 2972 | + |
|---|
| 2973 | + for_each_umc(umc) { |
|---|
| 2974 | + for_each_chip_select(cs, umc, pvt) { |
|---|
| 2975 | + if (!csrow_enabled(cs, umc, pvt)) |
|---|
| 2976 | + continue; |
|---|
| 2977 | + |
|---|
| 2978 | + empty = 0; |
|---|
| 2979 | + dimm = mci->csrows[cs]->channels[umc]->dimm; |
|---|
| 2980 | + |
|---|
| 2981 | + edac_dbg(1, "MC node: %d, csrow: %d\n", |
|---|
| 2982 | + pvt->mc_node_id, cs); |
|---|
| 2983 | + |
|---|
| 2984 | + dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs); |
|---|
| 2985 | + dimm->mtype = pvt->dram_type; |
|---|
| 2986 | + dimm->edac_mode = edac_mode; |
|---|
| 2987 | + dimm->dtype = dev_type; |
|---|
| 2988 | + dimm->grain = 64; |
|---|
| 2989 | + } |
|---|
| 2990 | + } |
|---|
| 2991 | + |
|---|
| 2992 | + return empty; |
|---|
| 2809 | 2993 | } |
|---|
| 2810 | 2994 | |
|---|
| 2811 | 2995 | /* |
|---|
| .. | .. |
|---|
| 2822 | 3006 | int nr_pages = 0; |
|---|
| 2823 | 3007 | u32 val; |
|---|
| 2824 | 3008 | |
|---|
| 2825 | | - if (!pvt->umc) { |
|---|
| 2826 | | - amd64_read_pci_cfg(pvt->F3, NBCFG, &val); |
|---|
| 3009 | + if (pvt->umc) |
|---|
| 3010 | + return init_csrows_df(mci); |
|---|
| 2827 | 3011 | |
|---|
| 2828 | | - pvt->nbcfg = val; |
|---|
| 3012 | + amd64_read_pci_cfg(pvt->F3, NBCFG, &val); |
|---|
| 2829 | 3013 | |
|---|
| 2830 | | - edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n", |
|---|
| 2831 | | - pvt->mc_node_id, val, |
|---|
| 2832 | | - !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); |
|---|
| 2833 | | - } |
|---|
| 3014 | + pvt->nbcfg = val; |
|---|
| 3015 | + |
|---|
| 3016 | + edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n", |
|---|
| 3017 | + pvt->mc_node_id, val, |
|---|
| 3018 | + !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); |
|---|
| 2834 | 3019 | |
|---|
| 2835 | 3020 | /* |
|---|
| 2836 | 3021 | * We iterate over DCT0 here but we look at DCT1 in parallel, if needed. |
|---|
| .. | .. |
|---|
| 2867 | 3052 | edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages); |
|---|
| 2868 | 3053 | |
|---|
| 2869 | 3054 | /* Determine DIMM ECC mode: */ |
|---|
| 2870 | | - if (pvt->umc) { |
|---|
| 2871 | | - if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) |
|---|
| 2872 | | - edac_mode = EDAC_S4ECD4ED; |
|---|
| 2873 | | - else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) |
|---|
| 2874 | | - edac_mode = EDAC_SECDED; |
|---|
| 2875 | | - |
|---|
| 2876 | | - } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) { |
|---|
| 3055 | + if (pvt->nbcfg & NBCFG_ECC_ENABLE) { |
|---|
| 2877 | 3056 | edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL) |
|---|
| 2878 | 3057 | ? EDAC_S4ECD4ED |
|---|
| 2879 | 3058 | : EDAC_SECDED; |
|---|
| .. | .. |
|---|
| 3050 | 3229 | amd64_warn("Error restoring NB MCGCTL settings!\n"); |
|---|
| 3051 | 3230 | } |
|---|
| 3052 | 3231 | |
|---|
| 3053 | | -/* |
|---|
| 3054 | | - * EDAC requires that the BIOS have ECC enabled before |
|---|
| 3055 | | - * taking over the processing of ECC errors. A command line |
|---|
| 3056 | | - * option allows to force-enable hardware ECC later in |
|---|
| 3057 | | - * enable_ecc_error_reporting(). |
|---|
| 3058 | | - */ |
|---|
| 3059 | | -static const char *ecc_msg = |
|---|
| 3060 | | - "ECC disabled in the BIOS or no ECC capability, module will not load.\n" |
|---|
| 3061 | | - " Either enable ECC checking or force module loading by setting " |
|---|
| 3062 | | - "'ecc_enable_override'.\n" |
|---|
| 3063 | | - " (Note that use of the override may cause unknown side effects.)\n"; |
|---|
| 3064 | | - |
|---|
| 3065 | | -static bool ecc_enabled(struct pci_dev *F3, u16 nid) |
|---|
| 3232 | +static bool ecc_enabled(struct amd64_pvt *pvt) |
|---|
| 3066 | 3233 | { |
|---|
| 3234 | + u16 nid = pvt->mc_node_id; |
|---|
| 3067 | 3235 | bool nb_mce_en = false; |
|---|
| 3068 | 3236 | u8 ecc_en = 0, i; |
|---|
| 3069 | 3237 | u32 value; |
|---|
| 3070 | 3238 | |
|---|
| 3071 | 3239 | if (boot_cpu_data.x86 >= 0x17) { |
|---|
| 3072 | 3240 | u8 umc_en_mask = 0, ecc_en_mask = 0; |
|---|
| 3241 | + struct amd64_umc *umc; |
|---|
| 3073 | 3242 | |
|---|
| 3074 | | - for (i = 0; i < NUM_UMCS; i++) { |
|---|
| 3075 | | - u32 base = get_umc_base(i); |
|---|
| 3243 | + for_each_umc(i) { |
|---|
| 3244 | + umc = &pvt->umc[i]; |
|---|
| 3076 | 3245 | |
|---|
| 3077 | 3246 | /* Only check enabled UMCs. */ |
|---|
| 3078 | | - if (amd_smn_read(nid, base + UMCCH_SDP_CTRL, &value)) |
|---|
| 3079 | | - continue; |
|---|
| 3080 | | - |
|---|
| 3081 | | - if (!(value & UMC_SDP_INIT)) |
|---|
| 3247 | + if (!(umc->sdp_ctrl & UMC_SDP_INIT)) |
|---|
| 3082 | 3248 | continue; |
|---|
| 3083 | 3249 | |
|---|
| 3084 | 3250 | umc_en_mask |= BIT(i); |
|---|
| 3085 | 3251 | |
|---|
| 3086 | | - if (amd_smn_read(nid, base + UMCCH_UMC_CAP_HI, &value)) |
|---|
| 3087 | | - continue; |
|---|
| 3088 | | - |
|---|
| 3089 | | - if (value & UMC_ECC_ENABLED) |
|---|
| 3252 | + if (umc->umc_cap_hi & UMC_ECC_ENABLED) |
|---|
| 3090 | 3253 | ecc_en_mask |= BIT(i); |
|---|
| 3091 | 3254 | } |
|---|
| 3092 | 3255 | |
|---|
| .. | .. |
|---|
| 3099 | 3262 | /* Assume UMC MCA banks are enabled. */ |
|---|
| 3100 | 3263 | nb_mce_en = true; |
|---|
| 3101 | 3264 | } else { |
|---|
| 3102 | | - amd64_read_pci_cfg(F3, NBCFG, &value); |
|---|
| 3265 | + amd64_read_pci_cfg(pvt->F3, NBCFG, &value); |
|---|
| 3103 | 3266 | |
|---|
| 3104 | 3267 | ecc_en = !!(value & NBCFG_ECC_ENABLE); |
|---|
| 3105 | 3268 | |
|---|
| .. | .. |
|---|
| 3112 | 3275 | amd64_info("Node %d: DRAM ECC %s.\n", |
|---|
| 3113 | 3276 | nid, (ecc_en ? "enabled" : "disabled")); |
|---|
| 3114 | 3277 | |
|---|
| 3115 | | - if (!ecc_en || !nb_mce_en) { |
|---|
| 3116 | | - amd64_info("%s", ecc_msg); |
|---|
| 3278 | + if (!ecc_en || !nb_mce_en) |
|---|
| 3117 | 3279 | return false; |
|---|
| 3118 | | - } |
|---|
| 3119 | | - return true; |
|---|
| 3280 | + else |
|---|
| 3281 | + return true; |
|---|
| 3120 | 3282 | } |
|---|
| 3121 | 3283 | |
|---|
| 3122 | 3284 | static inline void |
|---|
| .. | .. |
|---|
| 3124 | 3286 | { |
|---|
| 3125 | 3287 | u8 i, ecc_en = 1, cpk_en = 1, dev_x4 = 1, dev_x16 = 1; |
|---|
| 3126 | 3288 | |
|---|
| 3127 | | - for (i = 0; i < NUM_UMCS; i++) { |
|---|
| 3289 | + for_each_umc(i) { |
|---|
| 3128 | 3290 | if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) { |
|---|
| 3129 | 3291 | ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED); |
|---|
| 3130 | 3292 | cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP); |
|---|
| .. | .. |
|---|
| 3150 | 3312 | } |
|---|
| 3151 | 3313 | } |
|---|
| 3152 | 3314 | |
|---|
| 3153 | | -static void setup_mci_misc_attrs(struct mem_ctl_info *mci, |
|---|
| 3154 | | - struct amd64_family_type *fam) |
|---|
| 3315 | +static void setup_mci_misc_attrs(struct mem_ctl_info *mci) |
|---|
| 3155 | 3316 | { |
|---|
| 3156 | 3317 | struct amd64_pvt *pvt = mci->pvt_info; |
|---|
| 3157 | 3318 | |
|---|
| .. | .. |
|---|
| 3170 | 3331 | |
|---|
| 3171 | 3332 | mci->edac_cap = determine_edac_cap(pvt); |
|---|
| 3172 | 3333 | mci->mod_name = EDAC_MOD_STR; |
|---|
| 3173 | | - mci->ctl_name = fam->ctl_name; |
|---|
| 3334 | + mci->ctl_name = fam_type->ctl_name; |
|---|
| 3174 | 3335 | mci->dev_name = pci_name(pvt->F3); |
|---|
| 3175 | 3336 | mci->ctl_page_to_phys = NULL; |
|---|
| 3176 | 3337 | |
|---|
| .. | .. |
|---|
| 3184 | 3345 | */ |
|---|
| 3185 | 3346 | static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) |
|---|
| 3186 | 3347 | { |
|---|
| 3187 | | - struct amd64_family_type *fam_type = NULL; |
|---|
| 3188 | | - |
|---|
| 3189 | 3348 | pvt->ext_model = boot_cpu_data.x86_model >> 4; |
|---|
| 3190 | 3349 | pvt->stepping = boot_cpu_data.x86_stepping; |
|---|
| 3191 | 3350 | pvt->model = boot_cpu_data.x86_model; |
|---|
| .. | .. |
|---|
| 3211 | 3370 | fam_type = &family_types[F15_M60H_CPUS]; |
|---|
| 3212 | 3371 | pvt->ops = &family_types[F15_M60H_CPUS].ops; |
|---|
| 3213 | 3372 | break; |
|---|
| 3373 | + /* Richland is only client */ |
|---|
| 3374 | + } else if (pvt->model == 0x13) { |
|---|
| 3375 | + return NULL; |
|---|
| 3376 | + } else { |
|---|
| 3377 | + fam_type = &family_types[F15_CPUS]; |
|---|
| 3378 | + pvt->ops = &family_types[F15_CPUS].ops; |
|---|
| 3214 | 3379 | } |
|---|
| 3215 | | - |
|---|
| 3216 | | - fam_type = &family_types[F15_CPUS]; |
|---|
| 3217 | | - pvt->ops = &family_types[F15_CPUS].ops; |
|---|
| 3218 | 3380 | break; |
|---|
| 3219 | 3381 | |
|---|
| 3220 | 3382 | case 0x16: |
|---|
| .. | .. |
|---|
| 3236 | 3398 | fam_type = &family_types[F17_M30H_CPUS]; |
|---|
| 3237 | 3399 | pvt->ops = &family_types[F17_M30H_CPUS].ops; |
|---|
| 3238 | 3400 | break; |
|---|
| 3401 | + } else if (pvt->model >= 0x60 && pvt->model <= 0x6f) { |
|---|
| 3402 | + fam_type = &family_types[F17_M60H_CPUS]; |
|---|
| 3403 | + pvt->ops = &family_types[F17_M60H_CPUS].ops; |
|---|
| 3404 | + break; |
|---|
| 3405 | + } else if (pvt->model >= 0x70 && pvt->model <= 0x7f) { |
|---|
| 3406 | + fam_type = &family_types[F17_M70H_CPUS]; |
|---|
| 3407 | + pvt->ops = &family_types[F17_M70H_CPUS].ops; |
|---|
| 3408 | + break; |
|---|
| 3239 | 3409 | } |
|---|
| 3410 | + fallthrough; |
|---|
| 3411 | + case 0x18: |
|---|
| 3240 | 3412 | fam_type = &family_types[F17_CPUS]; |
|---|
| 3241 | 3413 | pvt->ops = &family_types[F17_CPUS].ops; |
|---|
| 3414 | + |
|---|
| 3415 | + if (pvt->fam == 0x18) |
|---|
| 3416 | + family_types[F17_CPUS].ctl_name = "F18h"; |
|---|
| 3417 | + break; |
|---|
| 3418 | + |
|---|
| 3419 | + case 0x19: |
|---|
| 3420 | + if (pvt->model >= 0x20 && pvt->model <= 0x2f) { |
|---|
| 3421 | + fam_type = &family_types[F17_M70H_CPUS]; |
|---|
| 3422 | + pvt->ops = &family_types[F17_M70H_CPUS].ops; |
|---|
| 3423 | + fam_type->ctl_name = "F19h_M20h"; |
|---|
| 3424 | + break; |
|---|
| 3425 | + } |
|---|
| 3426 | + fam_type = &family_types[F19_CPUS]; |
|---|
| 3427 | + pvt->ops = &family_types[F19_CPUS].ops; |
|---|
| 3428 | + family_types[F19_CPUS].ctl_name = "F19h"; |
|---|
| 3242 | 3429 | break; |
|---|
| 3243 | 3430 | |
|---|
| 3244 | 3431 | default: |
|---|
| .. | .. |
|---|
| 3264 | 3451 | NULL |
|---|
| 3265 | 3452 | }; |
|---|
| 3266 | 3453 | |
|---|
| 3267 | | -static int init_one_instance(unsigned int nid) |
|---|
| 3454 | +static int hw_info_get(struct amd64_pvt *pvt) |
|---|
| 3268 | 3455 | { |
|---|
| 3269 | | - struct pci_dev *F3 = node_to_amd_nb(nid)->misc; |
|---|
| 3270 | | - struct amd64_family_type *fam_type = NULL; |
|---|
| 3271 | | - struct mem_ctl_info *mci = NULL; |
|---|
| 3272 | | - struct edac_mc_layer layers[2]; |
|---|
| 3273 | | - struct amd64_pvt *pvt = NULL; |
|---|
| 3274 | 3456 | u16 pci_id1, pci_id2; |
|---|
| 3275 | | - int err = 0, ret; |
|---|
| 3276 | | - |
|---|
| 3277 | | - ret = -ENOMEM; |
|---|
| 3278 | | - pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL); |
|---|
| 3279 | | - if (!pvt) |
|---|
| 3280 | | - goto err_ret; |
|---|
| 3281 | | - |
|---|
| 3282 | | - pvt->mc_node_id = nid; |
|---|
| 3283 | | - pvt->F3 = F3; |
|---|
| 3284 | | - |
|---|
| 3285 | | - ret = -EINVAL; |
|---|
| 3286 | | - fam_type = per_family_init(pvt); |
|---|
| 3287 | | - if (!fam_type) |
|---|
| 3288 | | - goto err_free; |
|---|
| 3457 | + int ret; |
|---|
| 3289 | 3458 | |
|---|
| 3290 | 3459 | if (pvt->fam >= 0x17) { |
|---|
| 3291 | | - pvt->umc = kcalloc(NUM_UMCS, sizeof(struct amd64_umc), GFP_KERNEL); |
|---|
| 3292 | | - if (!pvt->umc) { |
|---|
| 3293 | | - ret = -ENOMEM; |
|---|
| 3294 | | - goto err_free; |
|---|
| 3295 | | - } |
|---|
| 3460 | + pvt->umc = kcalloc(fam_type->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); |
|---|
| 3461 | + if (!pvt->umc) |
|---|
| 3462 | + return -ENOMEM; |
|---|
| 3296 | 3463 | |
|---|
| 3297 | 3464 | pci_id1 = fam_type->f0_id; |
|---|
| 3298 | 3465 | pci_id2 = fam_type->f6_id; |
|---|
| .. | .. |
|---|
| 3301 | 3468 | pci_id2 = fam_type->f2_id; |
|---|
| 3302 | 3469 | } |
|---|
| 3303 | 3470 | |
|---|
| 3304 | | - err = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2); |
|---|
| 3305 | | - if (err) |
|---|
| 3306 | | - goto err_post_init; |
|---|
| 3471 | + ret = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2); |
|---|
| 3472 | + if (ret) |
|---|
| 3473 | + return ret; |
|---|
| 3307 | 3474 | |
|---|
| 3308 | 3475 | read_mc_regs(pvt); |
|---|
| 3476 | + |
|---|
| 3477 | + return 0; |
|---|
| 3478 | +} |
|---|
| 3479 | + |
|---|
| 3480 | +static void hw_info_put(struct amd64_pvt *pvt) |
|---|
| 3481 | +{ |
|---|
| 3482 | + if (pvt->F0 || pvt->F1) |
|---|
| 3483 | + free_mc_sibling_devs(pvt); |
|---|
| 3484 | + |
|---|
| 3485 | + kfree(pvt->umc); |
|---|
| 3486 | +} |
|---|
| 3487 | + |
|---|
| 3488 | +static int init_one_instance(struct amd64_pvt *pvt) |
|---|
| 3489 | +{ |
|---|
| 3490 | + struct mem_ctl_info *mci = NULL; |
|---|
| 3491 | + struct edac_mc_layer layers[2]; |
|---|
| 3492 | + int ret = -EINVAL; |
|---|
| 3309 | 3493 | |
|---|
| 3310 | 3494 | /* |
|---|
| 3311 | 3495 | * We need to determine how many memory channels there are. Then use |
|---|
| 3312 | 3496 | * that information for calculating the size of the dynamic instance |
|---|
| 3313 | 3497 | * tables in the 'mci' structure. |
|---|
| 3314 | 3498 | */ |
|---|
| 3315 | | - ret = -EINVAL; |
|---|
| 3316 | 3499 | pvt->channel_count = pvt->ops->early_channel_count(pvt); |
|---|
| 3317 | 3500 | if (pvt->channel_count < 0) |
|---|
| 3318 | | - goto err_siblings; |
|---|
| 3501 | + return ret; |
|---|
| 3319 | 3502 | |
|---|
| 3320 | 3503 | ret = -ENOMEM; |
|---|
| 3321 | 3504 | layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; |
|---|
| .. | .. |
|---|
| 3328 | 3511 | * only one channel. Also, this simplifies handling later for the price |
|---|
| 3329 | 3512 | * of a couple of KBs tops. |
|---|
| 3330 | 3513 | */ |
|---|
| 3331 | | - layers[1].size = 2; |
|---|
| 3514 | + layers[1].size = fam_type->max_mcs; |
|---|
| 3332 | 3515 | layers[1].is_virt_csrow = false; |
|---|
| 3333 | 3516 | |
|---|
| 3334 | | - mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0); |
|---|
| 3517 | + mci = edac_mc_alloc(pvt->mc_node_id, ARRAY_SIZE(layers), layers, 0); |
|---|
| 3335 | 3518 | if (!mci) |
|---|
| 3336 | | - goto err_siblings; |
|---|
| 3519 | + return ret; |
|---|
| 3337 | 3520 | |
|---|
| 3338 | 3521 | mci->pvt_info = pvt; |
|---|
| 3339 | 3522 | mci->pdev = &pvt->F3->dev; |
|---|
| 3340 | 3523 | |
|---|
| 3341 | | - setup_mci_misc_attrs(mci, fam_type); |
|---|
| 3524 | + setup_mci_misc_attrs(mci); |
|---|
| 3342 | 3525 | |
|---|
| 3343 | 3526 | if (init_csrows(mci)) |
|---|
| 3344 | 3527 | mci->edac_cap = EDAC_FLAG_NONE; |
|---|
| .. | .. |
|---|
| 3346 | 3529 | ret = -ENODEV; |
|---|
| 3347 | 3530 | if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) { |
|---|
| 3348 | 3531 | edac_dbg(1, "failed edac_mc_add_mc()\n"); |
|---|
| 3349 | | - goto err_add_mc; |
|---|
| 3532 | + edac_mc_free(mci); |
|---|
| 3533 | + return ret; |
|---|
| 3350 | 3534 | } |
|---|
| 3351 | 3535 | |
|---|
| 3352 | 3536 | return 0; |
|---|
| 3537 | +} |
|---|
| 3353 | 3538 | |
|---|
| 3354 | | -err_add_mc: |
|---|
| 3355 | | - edac_mc_free(mci); |
|---|
| 3539 | +static bool instance_has_memory(struct amd64_pvt *pvt) |
|---|
| 3540 | +{ |
|---|
| 3541 | + bool cs_enabled = false; |
|---|
| 3542 | + int cs = 0, dct = 0; |
|---|
| 3356 | 3543 | |
|---|
| 3357 | | -err_siblings: |
|---|
| 3358 | | - free_mc_sibling_devs(pvt); |
|---|
| 3544 | + for (dct = 0; dct < fam_type->max_mcs; dct++) { |
|---|
| 3545 | + for_each_chip_select(cs, dct, pvt) |
|---|
| 3546 | + cs_enabled |= csrow_enabled(cs, dct, pvt); |
|---|
| 3547 | + } |
|---|
| 3359 | 3548 | |
|---|
| 3360 | | -err_post_init: |
|---|
| 3361 | | - if (pvt->fam >= 0x17) |
|---|
| 3362 | | - kfree(pvt->umc); |
|---|
| 3363 | | - |
|---|
| 3364 | | -err_free: |
|---|
| 3365 | | - kfree(pvt); |
|---|
| 3366 | | - |
|---|
| 3367 | | -err_ret: |
|---|
| 3368 | | - return ret; |
|---|
| 3549 | + return cs_enabled; |
|---|
| 3369 | 3550 | } |
|---|
| 3370 | 3551 | |
|---|
| 3371 | 3552 | static int probe_one_instance(unsigned int nid) |
|---|
| 3372 | 3553 | { |
|---|
| 3373 | 3554 | struct pci_dev *F3 = node_to_amd_nb(nid)->misc; |
|---|
| 3555 | + struct amd64_pvt *pvt = NULL; |
|---|
| 3374 | 3556 | struct ecc_settings *s; |
|---|
| 3375 | 3557 | int ret; |
|---|
| 3376 | 3558 | |
|---|
| .. | .. |
|---|
| 3381 | 3563 | |
|---|
| 3382 | 3564 | ecc_stngs[nid] = s; |
|---|
| 3383 | 3565 | |
|---|
| 3384 | | - if (!ecc_enabled(F3, nid)) { |
|---|
| 3385 | | - ret = 0; |
|---|
| 3566 | + pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL); |
|---|
| 3567 | + if (!pvt) |
|---|
| 3568 | + goto err_settings; |
|---|
| 3569 | + |
|---|
| 3570 | + pvt->mc_node_id = nid; |
|---|
| 3571 | + pvt->F3 = F3; |
|---|
| 3572 | + |
|---|
| 3573 | + ret = -ENODEV; |
|---|
| 3574 | + fam_type = per_family_init(pvt); |
|---|
| 3575 | + if (!fam_type) |
|---|
| 3576 | + goto err_enable; |
|---|
| 3577 | + |
|---|
| 3578 | + ret = hw_info_get(pvt); |
|---|
| 3579 | + if (ret < 0) |
|---|
| 3580 | + goto err_enable; |
|---|
| 3581 | + |
|---|
| 3582 | + ret = 0; |
|---|
| 3583 | + if (!instance_has_memory(pvt)) { |
|---|
| 3584 | + amd64_info("Node %d: No DIMMs detected.\n", nid); |
|---|
| 3585 | + goto err_enable; |
|---|
| 3586 | + } |
|---|
| 3587 | + |
|---|
| 3588 | + if (!ecc_enabled(pvt)) { |
|---|
| 3589 | + ret = -ENODEV; |
|---|
| 3386 | 3590 | |
|---|
| 3387 | 3591 | if (!ecc_enable_override) |
|---|
| 3388 | 3592 | goto err_enable; |
|---|
| .. | .. |
|---|
| 3397 | 3601 | goto err_enable; |
|---|
| 3398 | 3602 | } |
|---|
| 3399 | 3603 | |
|---|
| 3400 | | - ret = init_one_instance(nid); |
|---|
| 3604 | + ret = init_one_instance(pvt); |
|---|
| 3401 | 3605 | if (ret < 0) { |
|---|
| 3402 | 3606 | amd64_err("Error probing instance: %d\n", nid); |
|---|
| 3403 | 3607 | |
|---|
| .. | .. |
|---|
| 3407 | 3611 | goto err_enable; |
|---|
| 3408 | 3612 | } |
|---|
| 3409 | 3613 | |
|---|
| 3614 | + dump_misc_regs(pvt); |
|---|
| 3615 | + |
|---|
| 3410 | 3616 | return ret; |
|---|
| 3411 | 3617 | |
|---|
| 3412 | 3618 | err_enable: |
|---|
| 3619 | + hw_info_put(pvt); |
|---|
| 3620 | + kfree(pvt); |
|---|
| 3621 | + |
|---|
| 3622 | +err_settings: |
|---|
| 3413 | 3623 | kfree(s); |
|---|
| 3414 | 3624 | ecc_stngs[nid] = NULL; |
|---|
| 3415 | 3625 | |
|---|
| .. | .. |
|---|
| 3424 | 3634 | struct mem_ctl_info *mci; |
|---|
| 3425 | 3635 | struct amd64_pvt *pvt; |
|---|
| 3426 | 3636 | |
|---|
| 3427 | | - mci = find_mci_by_dev(&F3->dev); |
|---|
| 3428 | | - WARN_ON(!mci); |
|---|
| 3429 | | - |
|---|
| 3430 | 3637 | /* Remove from EDAC CORE tracking list */ |
|---|
| 3431 | 3638 | mci = edac_mc_del_mc(&F3->dev); |
|---|
| 3432 | 3639 | if (!mci) |
|---|
| .. | .. |
|---|
| 3436 | 3643 | |
|---|
| 3437 | 3644 | restore_ecc_error_reporting(s, nid, F3); |
|---|
| 3438 | 3645 | |
|---|
| 3439 | | - free_mc_sibling_devs(pvt); |
|---|
| 3440 | | - |
|---|
| 3441 | 3646 | kfree(ecc_stngs[nid]); |
|---|
| 3442 | 3647 | ecc_stngs[nid] = NULL; |
|---|
| 3443 | 3648 | |
|---|
| 3444 | 3649 | /* Free the EDAC CORE resources */ |
|---|
| 3445 | 3650 | mci->pvt_info = NULL; |
|---|
| 3446 | 3651 | |
|---|
| 3652 | + hw_info_put(pvt); |
|---|
| 3447 | 3653 | kfree(pvt); |
|---|
| 3448 | 3654 | edac_mc_free(mci); |
|---|
| 3449 | 3655 | } |
|---|
| .. | .. |
|---|
| 3461 | 3667 | } |
|---|
| 3462 | 3668 | |
|---|
| 3463 | 3669 | static const struct x86_cpu_id amd64_cpuids[] = { |
|---|
| 3464 | | - { X86_VENDOR_AMD, 0xF, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, |
|---|
| 3465 | | - { X86_VENDOR_AMD, 0x10, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, |
|---|
| 3466 | | - { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, |
|---|
| 3467 | | - { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, |
|---|
| 3468 | | - { X86_VENDOR_AMD, 0x17, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, |
|---|
| 3670 | + X86_MATCH_VENDOR_FAM(AMD, 0x0F, NULL), |
|---|
| 3671 | + X86_MATCH_VENDOR_FAM(AMD, 0x10, NULL), |
|---|
| 3672 | + X86_MATCH_VENDOR_FAM(AMD, 0x15, NULL), |
|---|
| 3673 | + X86_MATCH_VENDOR_FAM(AMD, 0x16, NULL), |
|---|
| 3674 | + X86_MATCH_VENDOR_FAM(AMD, 0x17, NULL), |
|---|
| 3675 | + X86_MATCH_VENDOR_FAM(HYGON, 0x18, NULL), |
|---|
| 3676 | + X86_MATCH_VENDOR_FAM(AMD, 0x19, NULL), |
|---|
| 3469 | 3677 | { } |
|---|
| 3470 | 3678 | }; |
|---|
| 3471 | 3679 | MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids); |
|---|
| .. | .. |
|---|
| 3514 | 3722 | } |
|---|
| 3515 | 3723 | |
|---|
| 3516 | 3724 | /* register stuff with EDAC MCE */ |
|---|
| 3517 | | - if (report_gart_errors) |
|---|
| 3518 | | - amd_report_gart_errors(true); |
|---|
| 3519 | | - |
|---|
| 3520 | 3725 | if (boot_cpu_data.x86 >= 0x17) |
|---|
| 3521 | 3726 | amd_register_ecc_decoder(decode_umc_error); |
|---|
| 3522 | 3727 | else |
|---|
| .. | .. |
|---|
| 3553 | 3758 | edac_pci_release_generic_ctl(pci_ctl); |
|---|
| 3554 | 3759 | |
|---|
| 3555 | 3760 | /* unregister from EDAC MCE */ |
|---|
| 3556 | | - amd_report_gart_errors(false); |
|---|
| 3557 | | - |
|---|
| 3558 | 3761 | if (boot_cpu_data.x86 >= 0x17) |
|---|
| 3559 | 3762 | amd_unregister_ecc_decoder(decode_umc_error); |
|---|
| 3560 | 3763 | else |
|---|