Skip to content

Commit c1ae683

Browse files
author
Borislav Petkov
committed
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 <[email protected]>
1 parent f08e457 commit c1ae683

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

drivers/edac/amd64_edac.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -931,15 +931,63 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
931931
/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
932932
static u64 get_error_address(struct mce *m)
933933
{
934+
struct cpuinfo_x86 *c = &boot_cpu_data;
935+
u64 addr;
934936
u8 start_bit = 1;
935937
u8 end_bit = 47;
936938

937-
if (boot_cpu_data.x86 == 0xf) {
939+
if (c->x86 == 0xf) {
938940
start_bit = 3;
939941
end_bit = 39;
940942
}
941943

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;
943991
}
944992

945993
static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)

drivers/edac/amd64_edac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196

197197
#define DCT_CFG_SEL 0x10C
198198

199+
#define DRAM_LOCAL_NODE_BASE 0x120
199200
#define DRAM_LOCAL_NODE_LIM 0x124
200201

201202
#define DRAM_BASE_HI 0x140

0 commit comments

Comments
 (0)