diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2011-03-30 09:42:10 -0400 |
---|---|---|
committer | Borislav Petkov <borislav.petkov@amd.com> | 2011-04-26 10:18:56 -0400 |
commit | c1ae68309b0c1ea67b72e9e94e26b4e819022fc7 (patch) | |
tree | 22ecef8f85044a4bffba23546477b1b79dd08be8 /drivers/edac | |
parent | f08e457cecece7fbbdad3add9defac3373a59b5a (diff) |
amd64_edac: Erratum #637 workaround
F15h CPUs may report a non-DRAM address when reporting an error address
belonging to a CC6 state save area. Add a workaround to detect this
condition and compute the actual DRAM address of the error as documented
in the Revision Guide for AMD Family 15h Models 00h-0Fh Processors.
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/amd64_edac.c | 52 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.h | 1 |
2 files changed, 51 insertions, 2 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index e17de90ba6c6..9a8bebcf6b17 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -931,15 +931,63 @@ static int k8_early_channel_count(struct amd64_pvt *pvt) | |||
931 | /* On F10h and later ErrAddr is MC4_ADDR[47:1] */ | 931 | /* On F10h and later ErrAddr is MC4_ADDR[47:1] */ |
932 | static u64 get_error_address(struct mce *m) | 932 | static u64 get_error_address(struct mce *m) |
933 | { | 933 | { |
934 | struct cpuinfo_x86 *c = &boot_cpu_data; | ||
935 | u64 addr; | ||
934 | u8 start_bit = 1; | 936 | u8 start_bit = 1; |
935 | u8 end_bit = 47; | 937 | u8 end_bit = 47; |
936 | 938 | ||
937 | if (boot_cpu_data.x86 == 0xf) { | 939 | if (c->x86 == 0xf) { |
938 | start_bit = 3; | 940 | start_bit = 3; |
939 | end_bit = 39; | 941 | end_bit = 39; |
940 | } | 942 | } |
941 | 943 | ||
942 | return m->addr & GENMASK(start_bit, end_bit); | 944 | addr = m->addr & GENMASK(start_bit, end_bit); |
945 | |||
946 | /* | ||
947 | * Erratum 637 workaround | ||
948 | */ | ||
949 | if (c->x86 == 0x15) { | ||
950 | struct amd64_pvt *pvt; | ||
951 | u64 cc6_base, tmp_addr; | ||
952 | u32 tmp; | ||
953 | u8 mce_nid, intlv_en; | ||
954 | |||
955 | if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) | ||
956 | return addr; | ||
957 | |||
958 | mce_nid = amd_get_nb_id(m->extcpu); | ||
959 | pvt = mcis[mce_nid]->pvt_info; | ||
960 | |||
961 | amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp); | ||
962 | intlv_en = tmp >> 21 & 0x7; | ||
963 | |||
964 | /* add [47:27] + 3 trailing bits */ | ||
965 | cc6_base = (tmp & GENMASK(0, 20)) << 3; | ||
966 | |||
967 | /* reverse and add DramIntlvEn */ | ||
968 | cc6_base |= intlv_en ^ 0x7; | ||
969 | |||
970 | /* pin at [47:24] */ | ||
971 | cc6_base <<= 24; | ||
972 | |||
973 | if (!intlv_en) | ||
974 | return cc6_base | (addr & GENMASK(0, 23)); | ||
975 | |||
976 | amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); | ||
977 | |||
978 | /* faster log2 */ | ||
979 | tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); | ||
980 | |||
981 | /* OR DramIntlvSel into bits [14:12] */ | ||
982 | tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; | ||
983 | |||
984 | /* add remaining [11:0] bits from original MC4_ADDR */ | ||
985 | tmp_addr |= addr & GENMASK(0, 11); | ||
986 | |||
987 | return cc6_base | tmp_addr; | ||
988 | } | ||
989 | |||
990 | return addr; | ||
943 | } | 991 | } |
944 | 992 | ||
945 | static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) | 993 | static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) |
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 0110930c82ed..9a666cb985b2 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
@@ -196,6 +196,7 @@ | |||
196 | 196 | ||
197 | #define DCT_CFG_SEL 0x10C | 197 | #define DCT_CFG_SEL 0x10C |
198 | 198 | ||
199 | #define DRAM_LOCAL_NODE_BASE 0x120 | ||
199 | #define DRAM_LOCAL_NODE_LIM 0x124 | 200 | #define DRAM_LOCAL_NODE_LIM 0x124 |
200 | 201 | ||
201 | #define DRAM_BASE_HI 0x140 | 202 | #define DRAM_BASE_HI 0x140 |