aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2011-03-30 09:42:10 -0400
committerBorislav Petkov <borislav.petkov@amd.com>2011-04-26 10:18:56 -0400
commitc1ae68309b0c1ea67b72e9e94e26b4e819022fc7 (patch)
tree22ecef8f85044a4bffba23546477b1b79dd08be8 /drivers
parentf08e457cecece7fbbdad3add9defac3373a59b5a (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')
-rw-r--r--drivers/edac/amd64_edac.c52
-rw-r--r--drivers/edac/amd64_edac.h1
2 files changed, 51 insertions, 2 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index e17de90ba6c..9a8bebcf6b1 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] */
932static u64 get_error_address(struct mce *m) 932static 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
945static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) 993static 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 0110930c82e..9a666cb985b 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