diff options
author | Yazen Ghannam <yazen.ghannam@amd.com> | 2019-08-21 19:59:55 -0400 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2019-08-22 13:08:49 -0400 |
commit | d971e28e2ce4696fcc32998c8aced5e47701fffe (patch) | |
tree | b9b306b2f52b0a4c075b6246be0c711604b25683 /drivers/edac | |
parent | 718d58514ebc5740f80460ae7b73c57a01eac4c2 (diff) |
EDAC/amd64: Support more than two controllers for chip selects handling
The struct chip_select array that's used for saving chip select bases
and masks is fixed at length of two. There should be one struct
chip_select for each controller, so this array should be increased to
support systems that may have more than two controllers.
Increase the size of the struct chip_select array to eight, which is the
largest number of controllers per die currently supported on AMD
systems.
Fix number of DIMMs and Chip Select bases/masks on Family17h, because
AMD Family 17h systems support 2 DIMMs, 4 CS bases, and 2 CS masks per
channel.
Also, carve out the Family 17h+ reading of the bases/masks into a
separate function. This effectively reverts the original bases/masks
reading code to before Family 17h support was added.
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: "linux-edac@vger.kernel.org" <linux-edac@vger.kernel.org>
Cc: James Morse <james.morse@arm.com>
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Tony Luck <tony.luck@intel.com>
Link: https://lkml.kernel.org/r/20190821235938.118710-2-Yazen.Ghannam@amd.com
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/amd64_edac.c | 123 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.h | 5 |
2 files changed, 71 insertions, 57 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 873437be86d9..dd60cf5a3d96 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -810,7 +810,7 @@ static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) | |||
810 | 810 | ||
811 | edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl); | 811 | edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl); |
812 | 812 | ||
813 | for (dimm = 0; dimm < 4; dimm++) { | 813 | for (dimm = 0; dimm < 2; dimm++) { |
814 | size0 = 0; | 814 | size0 = 0; |
815 | cs0 = dimm * 2; | 815 | cs0 = dimm * 2; |
816 | 816 | ||
@@ -942,89 +942,102 @@ static void prep_chip_selects(struct amd64_pvt *pvt) | |||
942 | } else if (pvt->fam == 0x15 && pvt->model == 0x30) { | 942 | } else if (pvt->fam == 0x15 && pvt->model == 0x30) { |
943 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; | 943 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; |
944 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; | 944 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; |
945 | } else if (pvt->fam >= 0x17) { | ||
946 | int umc; | ||
947 | |||
948 | for_each_umc(umc) { | ||
949 | pvt->csels[umc].b_cnt = 4; | ||
950 | pvt->csels[umc].m_cnt = 2; | ||
951 | } | ||
952 | |||
945 | } else { | 953 | } else { |
946 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; | 954 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; |
947 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; | 955 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; |
948 | } | 956 | } |
949 | } | 957 | } |
950 | 958 | ||
959 | static void read_umc_base_mask(struct amd64_pvt *pvt) | ||
960 | { | ||
961 | u32 umc_base_reg, umc_mask_reg; | ||
962 | u32 base_reg, mask_reg; | ||
963 | u32 *base, *mask; | ||
964 | int cs, umc; | ||
965 | |||
966 | for_each_umc(umc) { | ||
967 | umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR; | ||
968 | |||
969 | for_each_chip_select(cs, umc, pvt) { | ||
970 | base = &pvt->csels[umc].csbases[cs]; | ||
971 | |||
972 | base_reg = umc_base_reg + (cs * 4); | ||
973 | |||
974 | if (!amd_smn_read(pvt->mc_node_id, base_reg, base)) | ||
975 | edac_dbg(0, " DCSB%d[%d]=0x%08x reg: 0x%x\n", | ||
976 | umc, cs, *base, base_reg); | ||
977 | } | ||
978 | |||
979 | umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK; | ||
980 | |||
981 | for_each_chip_select_mask(cs, umc, pvt) { | ||
982 | mask = &pvt->csels[umc].csmasks[cs]; | ||
983 | |||
984 | mask_reg = umc_mask_reg + (cs * 4); | ||
985 | |||
986 | if (!amd_smn_read(pvt->mc_node_id, mask_reg, mask)) | ||
987 | edac_dbg(0, " DCSM%d[%d]=0x%08x reg: 0x%x\n", | ||
988 | umc, cs, *mask, mask_reg); | ||
989 | } | ||
990 | } | ||
991 | } | ||
992 | |||
951 | /* | 993 | /* |
952 | * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers | 994 | * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers |
953 | */ | 995 | */ |
954 | static void read_dct_base_mask(struct amd64_pvt *pvt) | 996 | static void read_dct_base_mask(struct amd64_pvt *pvt) |
955 | { | 997 | { |
956 | int base_reg0, base_reg1, mask_reg0, mask_reg1, cs; | 998 | int cs; |
957 | 999 | ||
958 | prep_chip_selects(pvt); | 1000 | prep_chip_selects(pvt); |
959 | 1001 | ||
960 | if (pvt->umc) { | 1002 | if (pvt->umc) |
961 | base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR; | 1003 | return read_umc_base_mask(pvt); |
962 | base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR; | ||
963 | mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK; | ||
964 | mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK; | ||
965 | } else { | ||
966 | base_reg0 = DCSB0; | ||
967 | base_reg1 = DCSB1; | ||
968 | mask_reg0 = DCSM0; | ||
969 | mask_reg1 = DCSM1; | ||
970 | } | ||
971 | 1004 | ||
972 | for_each_chip_select(cs, 0, pvt) { | 1005 | for_each_chip_select(cs, 0, pvt) { |
973 | int reg0 = base_reg0 + (cs * 4); | 1006 | int reg0 = DCSB0 + (cs * 4); |
974 | int reg1 = base_reg1 + (cs * 4); | 1007 | int reg1 = DCSB1 + (cs * 4); |
975 | u32 *base0 = &pvt->csels[0].csbases[cs]; | 1008 | u32 *base0 = &pvt->csels[0].csbases[cs]; |
976 | u32 *base1 = &pvt->csels[1].csbases[cs]; | 1009 | u32 *base1 = &pvt->csels[1].csbases[cs]; |
977 | 1010 | ||
978 | if (pvt->umc) { | 1011 | if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0)) |
979 | if (!amd_smn_read(pvt->mc_node_id, reg0, base0)) | 1012 | edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", |
980 | edac_dbg(0, " DCSB0[%d]=0x%08x reg: 0x%x\n", | 1013 | cs, *base0, reg0); |
981 | cs, *base0, reg0); | ||
982 | |||
983 | if (!amd_smn_read(pvt->mc_node_id, reg1, base1)) | ||
984 | edac_dbg(0, " DCSB1[%d]=0x%08x reg: 0x%x\n", | ||
985 | cs, *base1, reg1); | ||
986 | } else { | ||
987 | if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0)) | ||
988 | edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", | ||
989 | cs, *base0, reg0); | ||
990 | 1014 | ||
991 | if (pvt->fam == 0xf) | 1015 | if (pvt->fam == 0xf) |
992 | continue; | 1016 | continue; |
993 | 1017 | ||
994 | if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1)) | 1018 | if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1)) |
995 | edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n", | 1019 | edac_dbg(0, " DCSB1[%d]=0x%08x reg: F2x%x\n", |
996 | cs, *base1, (pvt->fam == 0x10) ? reg1 | 1020 | cs, *base1, (pvt->fam == 0x10) ? reg1 |
997 | : reg0); | 1021 | : reg0); |
998 | } | ||
999 | } | 1022 | } |
1000 | 1023 | ||
1001 | for_each_chip_select_mask(cs, 0, pvt) { | 1024 | for_each_chip_select_mask(cs, 0, pvt) { |
1002 | int reg0 = mask_reg0 + (cs * 4); | 1025 | int reg0 = DCSM0 + (cs * 4); |
1003 | int reg1 = mask_reg1 + (cs * 4); | 1026 | int reg1 = DCSM1 + (cs * 4); |
1004 | u32 *mask0 = &pvt->csels[0].csmasks[cs]; | 1027 | u32 *mask0 = &pvt->csels[0].csmasks[cs]; |
1005 | u32 *mask1 = &pvt->csels[1].csmasks[cs]; | 1028 | u32 *mask1 = &pvt->csels[1].csmasks[cs]; |
1006 | 1029 | ||
1007 | if (pvt->umc) { | 1030 | if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0)) |
1008 | if (!amd_smn_read(pvt->mc_node_id, reg0, mask0)) | 1031 | edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", |
1009 | edac_dbg(0, " DCSM0[%d]=0x%08x reg: 0x%x\n", | 1032 | cs, *mask0, reg0); |
1010 | cs, *mask0, reg0); | ||
1011 | |||
1012 | if (!amd_smn_read(pvt->mc_node_id, reg1, mask1)) | ||
1013 | edac_dbg(0, " DCSM1[%d]=0x%08x reg: 0x%x\n", | ||
1014 | cs, *mask1, reg1); | ||
1015 | } else { | ||
1016 | if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0)) | ||
1017 | edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", | ||
1018 | cs, *mask0, reg0); | ||
1019 | 1033 | ||
1020 | if (pvt->fam == 0xf) | 1034 | if (pvt->fam == 0xf) |
1021 | continue; | 1035 | continue; |
1022 | 1036 | ||
1023 | if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1)) | 1037 | if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1)) |
1024 | edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n", | 1038 | edac_dbg(0, " DCSM1[%d]=0x%08x reg: F2x%x\n", |
1025 | cs, *mask1, (pvt->fam == 0x10) ? reg1 | 1039 | cs, *mask1, (pvt->fam == 0x10) ? reg1 |
1026 | : reg0); | 1040 | : reg0); |
1027 | } | ||
1028 | } | 1041 | } |
1029 | } | 1042 | } |
1030 | 1043 | ||
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 8f66472f7adc..4dce6a2ac75f 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
@@ -96,6 +96,7 @@ | |||
96 | /* Hardware limit on ChipSelect rows per MC and processors per system */ | 96 | /* Hardware limit on ChipSelect rows per MC and processors per system */ |
97 | #define NUM_CHIPSELECTS 8 | 97 | #define NUM_CHIPSELECTS 8 |
98 | #define DRAM_RANGES 8 | 98 | #define DRAM_RANGES 8 |
99 | #define NUM_CONTROLLERS 8 | ||
99 | 100 | ||
100 | #define ON true | 101 | #define ON true |
101 | #define OFF false | 102 | #define OFF false |
@@ -351,8 +352,8 @@ struct amd64_pvt { | |||
351 | u32 dbam0; /* DRAM Base Address Mapping reg for DCT0 */ | 352 | u32 dbam0; /* DRAM Base Address Mapping reg for DCT0 */ |
352 | u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */ | 353 | u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */ |
353 | 354 | ||
354 | /* one for each DCT */ | 355 | /* one for each DCT/UMC */ |
355 | struct chip_select csels[2]; | 356 | struct chip_select csels[NUM_CONTROLLERS]; |
356 | 357 | ||
357 | /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */ | 358 | /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */ |
358 | struct dram_range ranges[DRAM_RANGES]; | 359 | struct dram_range ranges[DRAM_RANGES]; |