diff --git a/Start-consolidating-AMD-specific-stuff.patch b/Start-consolidating-AMD-specific-stuff.patch new file mode 100644 index 0000000..dc87f39 --- /dev/null +++ b/Start-consolidating-AMD-specific-stuff.patch @@ -0,0 +1,665 @@ +From 4388981628ad9e2daba956210284017e1133cb99 Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Wed, 7 May 2014 22:41:15 +0200 +Subject: [PATCH] Start consolidating AMD-specific stuff + +... in order to concentrate decoding for all families in amd.[ch]. Pass +down cpu type in decode_amd_mc. + +Signed-off-by: Borislav Petkov +--- + Makefile | 2 +- + k8.c => amd.c | 9 +++++---- + k8.h => amd.h | 5 ++++- + mcelog.c | 8 ++++---- + 4 files changed, 14 insertions(+), 10 deletions(-) + rename k8.c => amd.c (97%) + rename k8.h => amd.h (79%) + +Index: mcelog-1.0.1/Makefile +=================================================================== +--- mcelog-1.0.1.orig/Makefile ++++ mcelog-1.0.1/Makefile +@@ -29,7 +29,7 @@ all: mcelog + + .PHONY: install clean depend + +-OBJ := p4.o k8.o mcelog.o dmi.o tsc.o core2.o bitfield.o intel.o \ ++OBJ := p4.o amd.o mcelog.o dmi.o tsc.o core2.o bitfield.o intel.o \ + nehalem.o dunnington.o tulsa.o config.o memutil.o msg.o \ + eventloop.o leaky-bucket.o memdb.o server.o trigger.o \ + client.o cache.o sysfs.o yellow.o page.o rbtree.o \ +Index: mcelog-1.0.1/k8.c +=================================================================== +--- mcelog-1.0.1.orig/k8.c ++++ /dev/null +@@ -1,281 +0,0 @@ +-/* Based on K8 decoding code written for the 2.4 kernel by Andi Kleen and +- * Eric Morton. Hacked and extended for mcelog by AK. +- * +- * Original copyright: +- * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. +- * Additional K8 decoding and simplification Copyright 2003 Eric Morton, Newisys Inc +- * K8 threshold counters decoding Copyright 2005,2006 Jacob Shin, AMD Inc. +- * +- * Subject to the GNU General Public License +- */ +- +-#include +-#include "mcelog.h" +-#include "k8.h" +- +-static char *k8bank[] = { +- "data cache", +- "instruction cache", +- "bus unit", +- "load/store unit", +- "northbridge", +- "fixed-issue reoder" +-}; +-static char *transaction[] = { +- "instruction", "data", "generic", "reserved" +-}; +-static char *cachelevel[] = { +- "0", "1", "2", "generic" +-}; +-static char *memtrans[] = { +- "generic error", "generic read", "generic write", "data read", +- "data write", "instruction fetch", "prefetch", "evict", "snoop", +- "?", "?", "?", "?", "?", "?", "?" +-}; +-static char *partproc[] = { +- "local node origin", "local node response", +- "local node observed", "generic participation" +-}; +-static char *timeout[] = { +- "request didn't time out", +- "request timed out" +-}; +-static char *memoryio[] = { +- "memory", "res.", "i/o", "generic" +-}; +-static char *nbextendederr[] = { +- "RAM ECC error", +- "CRC error", +- "Sync error", +- "Master abort", +- "Target abort", +- "GART error", +- "RMW error", +- "Watchdog error", +- "RAM Chipkill ECC error", +- "DEV Error", +- "Link Data Error", +- "Link Protocol Error", +- "NB Array Error", +- "DRAM Parity Error", +- "Link Retry", +- "Tablew Walk Data Error", +- "L3 Cache Data Error", +- "L3 Cache Tag Error", +- "L3 Cache LRU Error" +-}; +-static char *highbits[32] = { +- [31] = "valid", +- [30] = "error overflow (multiple errors)", +- [29] = "error uncorrected", +- [28] = "error enable", +- [27] = "misc error valid", +- [26] = "error address valid", +- [25] = "processor context corrupt", +- [24] = "res24", +- [23] = "res23", +- /* 22-15 ecc syndrome bits */ +- [14] = "corrected ecc error", +- [13] = "uncorrected ecc error", +- [12] = "res12", +- [11] = "L3 subcache in error bit 1", +- [10] = "L3 subcache in error bit 0", +- [9] = "sublink or DRAM channel", +- [8] = "error found by scrub", +- /* 7-4 ht link number of error */ +- [3] = "err cpu3", +- [2] = "err cpu2", +- [1] = "err cpu1", +- [0] = "err cpu0", +-}; +-static char *k8threshold[] = { +- [0 ... K8_MCELOG_THRESHOLD_DRAM_ECC - 1] = "Unknow threshold counter", +- [K8_MCELOG_THRESHOLD_DRAM_ECC] = "MC4_MISC0 DRAM threshold", +- [K8_MCELOG_THRESHOLD_LINK] = "MC4_MISC1 Link threshold", +- [K8_MCELOG_THRESHOLD_L3_CACHE] = "MC4_MISC2 L3 Cache threshold", +- [K8_MCELOG_THRESHOLD_FBDIMM] = "MC4_MISC3 FBDIMM threshold", +- [K8_MCELOG_THRESHOLD_FBDIMM + 1 ... +- K8_MCE_THRESHOLD_TOP - K8_MCE_THRESHOLD_BASE - 1] = +- "Unknown threshold counter", +-}; +- +- +-static void decode_k8_generic_errcode(u64 status) +-{ +- unsigned short errcode = status & 0xffff; +- int i; +- +- for (i=0; i<32; i++) { +- if (i==31 || i==28 || i==26) +- continue; +- if (highbits[i] && (status & (1ULL<<(i+32)))) { +- Wprintf( " bit%d = %s\n", i+32, highbits[i]); +- } +- } +- +- if ((errcode & 0xFFF0) == 0x0010) { +- Wprintf( " TLB error '%s transaction, level %s'\n", +- transaction[(errcode >> 2) & 3], +- cachelevel[errcode & 3]); +- } +- else if ((errcode & 0xFF00) == 0x0100) { +- Wprintf( " memory/cache error '%s mem transaction, %s transaction, level %s'\n", +- memtrans[(errcode >> 4) & 0xf], +- transaction[(errcode >> 2) & 3], +- cachelevel[errcode & 3]); +- } +- else if ((errcode & 0xF800) == 0x0800) { +- Wprintf( " bus error '%s, %s\n %s mem transaction\n %s access, level %s'\n", +- partproc[(errcode >> 9) & 0x3], +- timeout[(errcode >> 8) & 1], +- memtrans[(errcode >> 4) & 0xf], +- memoryio[(errcode >> 2) & 0x3], +- cachelevel[(errcode & 0x3)]); +- } +-} +- +-static void decode_k8_dc_mc(u64 status, int *err) +-{ +- unsigned short exterrcode = (status >> 16) & 0x0f; +- unsigned short errcode = status & 0xffff; +- +- if(status&(3ULL<<45)) { +- Wprintf( " Data cache ECC error (syndrome %x)", +- (u32) (status >> 47) & 0xff); +- if(status&(1ULL<<40)) { +- Wprintf(" found by scrubber"); +- } +- Wprintf("\n"); +- } +- +- if ((errcode & 0xFFF0) == 0x0010) { +- Wprintf( " TLB parity error in %s array\n", +- (exterrcode == 0) ? "physical" : "virtual"); +- } +- +- decode_k8_generic_errcode(status); +-} +- +-static void decode_k8_ic_mc(u64 status, int *err) +-{ +- unsigned short exterrcode = (status >> 16) & 0x0f; +- unsigned short errcode = status & 0xffff; +- +- if(status&(3ULL<<45)) { +- Wprintf(" Instruction cache ECC error\n"); +- } +- +- if ((errcode & 0xFFF0) == 0x0010) { +- Wprintf(" TLB parity error in %s array\n", +- (exterrcode == 0) ? "physical" : "virtual"); +- } +- +- decode_k8_generic_errcode(status); +-} +- +-static void decode_k8_bu_mc(u64 status, int *err) +-{ +- unsigned short exterrcode = (status >> 16) & 0x0f; +- +- if(status&(3ULL<<45)) { +- Wprintf(" L2 cache ECC error\n"); +- } +- +- Wprintf(" %s array error\n", +- (exterrcode == 0) ? "Bus or cache" : "Cache tag"); +- +- decode_k8_generic_errcode(status); +-} +- +-static void decode_k8_ls_mc(u64 status, int *err) +-{ +- decode_k8_generic_errcode(status); +-} +- +-static void decode_k8_nb_mc(u64 status, int *memerr) +-{ +- unsigned short exterrcode = (status >> 16) & 0x0f; +- +- Wprintf(" Northbridge %s\n", nbextendederr[exterrcode]); +- +- switch (exterrcode) { +- case 0: +- *memerr = 1; +- Wprintf(" ECC syndrome = %x\n", +- (u32) (status >> 47) & 0xff); +- break; +- case 8: +- *memerr = 1; +- Wprintf(" Chipkill ECC syndrome = %x\n", +- (u32) ((((status >> 24) & 0xff) << 8) | ((status >> 47) & 0xff))); +- break; +- case 1: +- case 2: +- case 3: +- case 4: +- case 6: +- Wprintf(" link number = %x\n", +- (u32) (status >> 36) & 0xf); +- break; +- } +- +- decode_k8_generic_errcode(status); +-} +- +-static void decode_k8_fr_mc(u64 status, int *err) +-{ +- decode_k8_generic_errcode(status); +-} +- +-static void decode_k8_threshold(u64 misc) +-{ +- if (misc & MCI_THRESHOLD_OVER) +- Wprintf(" Threshold error count overflow\n"); +-} +- +-typedef void (*decoder_t)(u64, int *ismemerr); +- +-static decoder_t decoders[] = { +- [0] = decode_k8_dc_mc, +- [1] = decode_k8_ic_mc, +- [2] = decode_k8_bu_mc, +- [3] = decode_k8_ls_mc, +- [4] = decode_k8_nb_mc, +- [5] = decode_k8_fr_mc, +-}; +- +-void decode_k8_mc(struct mce *mce, int *ismemerr) +-{ +- if (mce->bank < NELE(decoders)) +- decoders[mce->bank](mce->status, ismemerr); +- else if (mce->bank >= K8_MCE_THRESHOLD_BASE && +- mce->bank < K8_MCE_THRESHOLD_TOP) +- decode_k8_threshold(mce->misc); +- else +- Wprintf(" no decoder for unknown bank %u\n", mce->bank); +-} +- +-char *k8_bank_name(unsigned num) +-{ +- static char buf[64]; +- char *s = "unknown"; +- if (num < NELE(k8bank)) +- s = k8bank[num]; +- else if (num >= K8_MCE_THRESHOLD_BASE && +- num < K8_MCE_THRESHOLD_TOP) +- s = k8threshold[num - K8_MCE_THRESHOLD_BASE]; +- buf[sizeof(buf)-1] = 0; +- snprintf(buf, sizeof(buf) - 1, "%u %s", num, s); +- return buf; +-} +- +-int mce_filter_k8(struct mce *m) +-{ +- /* Filter out GART errors */ +- if (m->bank == 4) { +- unsigned short exterrcode = (m->status >> 16) & 0x0f; +- if (exterrcode == 5 && (m->status & (1ULL<<61))) +- return 0; +- } +- return 1; +-} +Index: mcelog-1.0.1/amd.c +=================================================================== +--- /dev/null ++++ mcelog-1.0.1/amd.c +@@ -0,0 +1,282 @@ ++/* Based on K8 decoding code written for the 2.4 kernel by Andi Kleen and ++ * Eric Morton. Hacked and extended for mcelog by AK. ++ * Extended to support all AMD families by Borislav Petkov, SUSE Labs. ++ * ++ * Original copyright: ++ * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. ++ * Additional K8 decoding and simplification Copyright 2003 Eric Morton, Newisys Inc ++ * K8 threshold counters decoding Copyright 2005,2006 Jacob Shin, AMD Inc. ++ * ++ * Subject to the GNU General Public License ++ */ ++ ++#include ++#include "mcelog.h" ++#include "amd.h" ++ ++static char *k8bank[] = { ++ "data cache", ++ "instruction cache", ++ "bus unit", ++ "load/store unit", ++ "northbridge", ++ "fixed-issue reoder" ++}; ++static char *transaction[] = { ++ "instruction", "data", "generic", "reserved" ++}; ++static char *cachelevel[] = { ++ "0", "1", "2", "generic" ++}; ++static char *memtrans[] = { ++ "generic error", "generic read", "generic write", "data read", ++ "data write", "instruction fetch", "prefetch", "evict", "snoop", ++ "?", "?", "?", "?", "?", "?", "?" ++}; ++static char *partproc[] = { ++ "local node origin", "local node response", ++ "local node observed", "generic participation" ++}; ++static char *timeout[] = { ++ "request didn't time out", ++ "request timed out" ++}; ++static char *memoryio[] = { ++ "memory", "res.", "i/o", "generic" ++}; ++static char *nbextendederr[] = { ++ "RAM ECC error", ++ "CRC error", ++ "Sync error", ++ "Master abort", ++ "Target abort", ++ "GART error", ++ "RMW error", ++ "Watchdog error", ++ "RAM Chipkill ECC error", ++ "DEV Error", ++ "Link Data Error", ++ "Link Protocol Error", ++ "NB Array Error", ++ "DRAM Parity Error", ++ "Link Retry", ++ "Tablew Walk Data Error", ++ "L3 Cache Data Error", ++ "L3 Cache Tag Error", ++ "L3 Cache LRU Error" ++}; ++static char *highbits[32] = { ++ [31] = "valid", ++ [30] = "error overflow (multiple errors)", ++ [29] = "error uncorrected", ++ [28] = "error enable", ++ [27] = "misc error valid", ++ [26] = "error address valid", ++ [25] = "processor context corrupt", ++ [24] = "res24", ++ [23] = "res23", ++ /* 22-15 ecc syndrome bits */ ++ [14] = "corrected ecc error", ++ [13] = "uncorrected ecc error", ++ [12] = "res12", ++ [11] = "L3 subcache in error bit 1", ++ [10] = "L3 subcache in error bit 0", ++ [9] = "sublink or DRAM channel", ++ [8] = "error found by scrub", ++ /* 7-4 ht link number of error */ ++ [3] = "err cpu3", ++ [2] = "err cpu2", ++ [1] = "err cpu1", ++ [0] = "err cpu0", ++}; ++static char *k8threshold[] = { ++ [0 ... K8_MCELOG_THRESHOLD_DRAM_ECC - 1] = "Unknow threshold counter", ++ [K8_MCELOG_THRESHOLD_DRAM_ECC] = "MC4_MISC0 DRAM threshold", ++ [K8_MCELOG_THRESHOLD_LINK] = "MC4_MISC1 Link threshold", ++ [K8_MCELOG_THRESHOLD_L3_CACHE] = "MC4_MISC2 L3 Cache threshold", ++ [K8_MCELOG_THRESHOLD_FBDIMM] = "MC4_MISC3 FBDIMM threshold", ++ [K8_MCELOG_THRESHOLD_FBDIMM + 1 ... ++ K8_MCE_THRESHOLD_TOP - K8_MCE_THRESHOLD_BASE - 1] = ++ "Unknown threshold counter", ++}; ++ ++ ++static void decode_k8_generic_errcode(u64 status) ++{ ++ unsigned short errcode = status & 0xffff; ++ int i; ++ ++ for (i=0; i<32; i++) { ++ if (i==31 || i==28 || i==26) ++ continue; ++ if (highbits[i] && (status & (1ULL<<(i+32)))) { ++ Wprintf( " bit%d = %s\n", i+32, highbits[i]); ++ } ++ } ++ ++ if ((errcode & 0xFFF0) == 0x0010) { ++ Wprintf( " TLB error '%s transaction, level %s'\n", ++ transaction[(errcode >> 2) & 3], ++ cachelevel[errcode & 3]); ++ } ++ else if ((errcode & 0xFF00) == 0x0100) { ++ Wprintf( " memory/cache error '%s mem transaction, %s transaction, level %s'\n", ++ memtrans[(errcode >> 4) & 0xf], ++ transaction[(errcode >> 2) & 3], ++ cachelevel[errcode & 3]); ++ } ++ else if ((errcode & 0xF800) == 0x0800) { ++ Wprintf( " bus error '%s, %s\n %s mem transaction\n %s access, level %s'\n", ++ partproc[(errcode >> 9) & 0x3], ++ timeout[(errcode >> 8) & 1], ++ memtrans[(errcode >> 4) & 0xf], ++ memoryio[(errcode >> 2) & 0x3], ++ cachelevel[(errcode & 0x3)]); ++ } ++} ++ ++static void decode_k8_dc_mc(u64 status, int *err) ++{ ++ unsigned short exterrcode = (status >> 16) & 0x0f; ++ unsigned short errcode = status & 0xffff; ++ ++ if(status&(3ULL<<45)) { ++ Wprintf( " Data cache ECC error (syndrome %x)", ++ (u32) (status >> 47) & 0xff); ++ if(status&(1ULL<<40)) { ++ Wprintf(" found by scrubber"); ++ } ++ Wprintf("\n"); ++ } ++ ++ if ((errcode & 0xFFF0) == 0x0010) { ++ Wprintf( " TLB parity error in %s array\n", ++ (exterrcode == 0) ? "physical" : "virtual"); ++ } ++ ++ decode_k8_generic_errcode(status); ++} ++ ++static void decode_k8_ic_mc(u64 status, int *err) ++{ ++ unsigned short exterrcode = (status >> 16) & 0x0f; ++ unsigned short errcode = status & 0xffff; ++ ++ if(status&(3ULL<<45)) { ++ Wprintf(" Instruction cache ECC error\n"); ++ } ++ ++ if ((errcode & 0xFFF0) == 0x0010) { ++ Wprintf(" TLB parity error in %s array\n", ++ (exterrcode == 0) ? "physical" : "virtual"); ++ } ++ ++ decode_k8_generic_errcode(status); ++} ++ ++static void decode_k8_bu_mc(u64 status, int *err) ++{ ++ unsigned short exterrcode = (status >> 16) & 0x0f; ++ ++ if(status&(3ULL<<45)) { ++ Wprintf(" L2 cache ECC error\n"); ++ } ++ ++ Wprintf(" %s array error\n", ++ (exterrcode == 0) ? "Bus or cache" : "Cache tag"); ++ ++ decode_k8_generic_errcode(status); ++} ++ ++static void decode_k8_ls_mc(u64 status, int *err) ++{ ++ decode_k8_generic_errcode(status); ++} ++ ++static void decode_k8_nb_mc(u64 status, int *memerr) ++{ ++ unsigned short exterrcode = (status >> 16) & 0x0f; ++ ++ Wprintf(" Northbridge %s\n", nbextendederr[exterrcode]); ++ ++ switch (exterrcode) { ++ case 0: ++ *memerr = 1; ++ Wprintf(" ECC syndrome = %x\n", ++ (u32) (status >> 47) & 0xff); ++ break; ++ case 8: ++ *memerr = 1; ++ Wprintf(" Chipkill ECC syndrome = %x\n", ++ (u32) ((((status >> 24) & 0xff) << 8) | ((status >> 47) & 0xff))); ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 6: ++ Wprintf(" link number = %x\n", ++ (u32) (status >> 36) & 0xf); ++ break; ++ } ++ ++ decode_k8_generic_errcode(status); ++} ++ ++static void decode_k8_fr_mc(u64 status, int *err) ++{ ++ decode_k8_generic_errcode(status); ++} ++ ++static void decode_k8_threshold(u64 misc) ++{ ++ if (misc & MCI_THRESHOLD_OVER) ++ Wprintf(" Threshold error count overflow\n"); ++} ++ ++typedef void (*decoder_t)(u64, int *ismemerr); ++ ++static decoder_t decoders[] = { ++ [0] = decode_k8_dc_mc, ++ [1] = decode_k8_ic_mc, ++ [2] = decode_k8_bu_mc, ++ [3] = decode_k8_ls_mc, ++ [4] = decode_k8_nb_mc, ++ [5] = decode_k8_fr_mc, ++}; ++ ++void decode_amd_mc(enum cputype cpu, struct mce *mce, int *ismemerr) ++{ ++ if (mce->bank < NELE(decoders)) ++ decoders[mce->bank](mce->status, ismemerr); ++ else if (mce->bank >= K8_MCE_THRESHOLD_BASE && ++ mce->bank < K8_MCE_THRESHOLD_TOP) ++ decode_k8_threshold(mce->misc); ++ else ++ Wprintf(" no decoder for unknown bank %u\n", mce->bank); ++} ++ ++char *k8_bank_name(unsigned num) ++{ ++ static char buf[64]; ++ char *s = "unknown"; ++ if (num < NELE(k8bank)) ++ s = k8bank[num]; ++ else if (num >= K8_MCE_THRESHOLD_BASE && ++ num < K8_MCE_THRESHOLD_TOP) ++ s = k8threshold[num - K8_MCE_THRESHOLD_BASE]; ++ buf[sizeof(buf)-1] = 0; ++ snprintf(buf, sizeof(buf) - 1, "%u %s", num, s); ++ return buf; ++} ++ ++int mce_filter_k8(struct mce *m) ++{ ++ /* Filter out GART errors */ ++ if (m->bank == 4) { ++ unsigned short exterrcode = (m->status >> 16) & 0x0f; ++ if (exterrcode == 5 && (m->status & (1ULL<<61))) ++ return 0; ++ } ++ return 1; ++} +Index: mcelog-1.0.1/k8.h +=================================================================== +--- mcelog-1.0.1.orig/k8.h ++++ /dev/null +@@ -1,11 +0,0 @@ +-char *k8_bank_name(unsigned num); +-void decode_k8_mc(struct mce *mce, int *ismemerr); +-int mce_filter_k8(struct mce *m); +- +-#define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1) /* MCE_AMD */ +-#define K8_MCE_THRESHOLD_TOP (K8_MCE_THRESHOLD_BASE + 6 * 9) +- +-#define K8_MCELOG_THRESHOLD_DRAM_ECC (4 * 9 + 0) +-#define K8_MCELOG_THRESHOLD_LINK (4 * 9 + 1) +-#define K8_MCELOG_THRESHOLD_L3_CACHE (4 * 9 + 2) +-#define K8_MCELOG_THRESHOLD_FBDIMM (4 * 9 + 3) +Index: mcelog-1.0.1/amd.h +=================================================================== +--- /dev/null ++++ mcelog-1.0.1/amd.h +@@ -0,0 +1,14 @@ ++char *k8_bank_name(unsigned num); ++void decode_amd_mc(enum cputype, struct mce *mce, int *ismemerr); ++int mce_filter_k8(struct mce *m); ++ ++#define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1) /* MCE_AMD */ ++#define K8_MCE_THRESHOLD_TOP (K8_MCE_THRESHOLD_BASE + 6 * 9) ++ ++#define K8_MCELOG_THRESHOLD_DRAM_ECC (4 * 9 + 0) ++#define K8_MCELOG_THRESHOLD_LINK (4 * 9 + 1) ++#define K8_MCELOG_THRESHOLD_L3_CACHE (4 * 9 + 2) ++#define K8_MCELOG_THRESHOLD_FBDIMM (4 * 9 + 3) ++ ++#define CASE_AMD_CPUS \ ++ case CPU_K8 +Index: mcelog-1.0.1/mcelog.c +=================================================================== +--- mcelog-1.0.1.orig/mcelog.c ++++ mcelog-1.0.1/mcelog.c +@@ -41,7 +41,7 @@ + #include + #include "mcelog.h" + #include "paths.h" +-#include "k8.h" ++#include "amd.h" + #include "intel.h" + #include "p4.h" + #include "dmi.h" +@@ -397,9 +397,9 @@ static void dump_mce(struct mce *m, unsi + time_t t = m->time; + Wprintf("TIME %llu %s", m->time, ctime(&t)); + } +- switch (cputype) { +- case CPU_K8: +- decode_k8_mc(m, &ismemerr); ++ switch (cputype) { ++ CASE_AMD_CPUS: ++ decode_amd_mc(cputype, m, &ismemerr); + break; + CASE_INTEL_CPUS: + decode_intel_mc(m, cputype, &ismemerr, recordlen); diff --git a/add-defines.patch b/add-defines.patch new file mode 100644 index 0000000..aef08e7 --- /dev/null +++ b/add-defines.patch @@ -0,0 +1,73 @@ +Add AMD-specific defines and helpers + +Signed-off-by: Borislav Petkov +Index: mcelog/amd.h +=================================================================== +--- mcelog.orig/amd.h 2014-05-08 01:10:26.000000000 +0200 ++++ mcelog/amd.h 2014-05-08 01:18:50.000000000 +0200 +@@ -10,5 +10,65 @@ int mce_filter_k8(struct mce *m); + #define K8_MCELOG_THRESHOLD_L3_CACHE (4 * 9 + 2) + #define K8_MCELOG_THRESHOLD_FBDIMM (4 * 9 + 3) + ++#define EC(x) ((x) & 0xffff) ++#define XEC(x, mask) (((x) >> 16) & mask) ++ ++#define LOW_SYNDROME(x) (((x) >> 15) & 0xff) ++#define HIGH_SYNDROME(x) (((x) >> 24) & 0xff) ++ ++#define TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010) ++#define MEM_ERROR(x) (((x) & 0xFF00) == 0x0100) ++#define BUS_ERROR(x) (((x) & 0xF800) == 0x0800) ++#define INT_ERROR(x) (((x) & 0xF4FF) == 0x0400) ++ ++#define TT(x) (((x) >> 2) & 0x3) ++#define TT_MSG(x) tt_msgs[TT(x)] ++#define II(x) (((x) >> 2) & 0x3) ++#define II_MSG(x) ii_msgs[II(x)] ++#define LL(x) ((x) & 0x3) ++#define LL_MSG(x) ll_msgs[LL(x)] ++#define TO(x) (((x) >> 8) & 0x1) ++#define TO_MSG(x) to_msgs[TO(x)] ++#define PP(x) (((x) >> 9) & 0x3) ++#define PP_MSG(x) pp_msgs[PP(x)] ++#define UU(x) (((x) >> 8) & 0x3) ++#define UU_MSG(x) uu_msgs[UU(x)] ++ ++#define R4(x) (((x) >> 4) & 0xf) ++#define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!") ++ + #define CASE_AMD_CPUS \ + case CPU_K8 ++ ++enum tt_ids { ++ TT_INSTR = 0, ++ TT_DATA, ++ TT_GEN, ++ TT_RESV, ++}; ++ ++enum ll_ids { ++ LL_RESV = 0, ++ LL_L1, ++ LL_L2, ++ LL_LG, ++}; ++ ++enum ii_ids { ++ II_MEM = 0, ++ II_RESV, ++ II_IO, ++ II_GEN, ++}; ++ ++enum rrrr_ids { ++ R4_GEN = 0, ++ R4_RD, ++ R4_WR, ++ R4_DRD, ++ R4_DWR, ++ R4_IRD, ++ R4_PREF, ++ R4_EVICT, ++ R4_SNOOP, ++}; diff --git a/add-f10h-support.patch b/add-f10h-support.patch new file mode 100644 index 0000000..a5f44bb --- /dev/null +++ b/add-f10h-support.patch @@ -0,0 +1,728 @@ +Add F10h decoding support + +Signed-off-by: Borislav Petkov +Index: mcelog-1.0.1/amd.c +=================================================================== +--- mcelog-1.0.1.orig/amd.c ++++ mcelog-1.0.1/amd.c +@@ -14,7 +14,7 @@ + #include "mcelog.h" + #include "amd.h" + +-static char *k8bank[] = { ++static const char * const k8bank[] = { + "data cache", + "instruction cache", + "bus unit", +@@ -22,28 +22,34 @@ static char *k8bank[] = { + "northbridge", + "fixed-issue reoder" + }; +-static char *transaction[] = { ++static const char * const transaction[] = { + "instruction", "data", "generic", "reserved" +-}; +-static char *cachelevel[] = { ++}; ++static const char * const cachelevel[] = { + "0", "1", "2", "generic" + }; +-static char *memtrans[] = { ++static const char * const memtrans[] = { + "generic error", "generic read", "generic write", "data read", + "data write", "instruction fetch", "prefetch", "evict", "snoop", + "?", "?", "?", "?", "?", "?", "?" + }; +-static char *partproc[] = { +- "local node origin", "local node response", +- "local node observed", "generic participation" ++static const char * const partproc[] = { ++ "local node origin", ++ "local node response", ++ "local node observed", ++ "generic participation" + }; +-static char *timeout[] = { ++static const char * const timeout[] = { + "request didn't time out", + "request timed out" + }; +-static char *memoryio[] = { ++static const char * const memoryio[] = { + "memory", "res.", "i/o", "generic" + }; ++ ++/* internal error type */ ++static const char * const uu_msgs[] = { "RESV", "RESV", "HWA", "RESV" }; ++ + static char *nbextendederr[] = { + "RAM ECC error", + "CRC error", +@@ -65,6 +71,46 @@ static char *nbextendederr[] = { + "L3 Cache Tag Error", + "L3 Cache LRU Error" + }; ++ ++static const char * const mc4_mce_desc[] = { ++ "DRAM ECC error detected on the NB", ++ "CRC error detected on HT link", ++ "Link-defined sync error packets detected on HT link", ++ "HT Master abort", ++ "HT Target abort", ++ "Invalid GART PTE entry during GART table walk", ++ "Unsupported atomic RMW received from an IO link", ++ "Watchdog timeout due to lack of progress", ++ "DRAM ECC error detected on the NB", ++ "SVM DMA Exclusion Vector error", ++ "HT data error detected on link", ++ "Protocol error (link, L3, probe filter)", ++ "NB internal arrays parity error", ++ "DRAM addr/ctl signals parity error", ++ "IO link transmission error", ++ "L3 data cache ECC error", /* xec = 0x1c */ ++ "L3 cache tag error", ++ "L3 LRU parity bits error", ++ "ECC Error in the Probe Filter directory" ++}; ++ ++static const char * const mc5_mce_desc[] = { ++ "CPU Watchdog timer expire", ++ "Wakeup array dest tag", ++ "AG payload array", ++ "EX payload array", ++ "IDRF array", ++ "Retire dispatch queue", ++ "Mapper checkpoint array", ++ "Physical register file EX0 port", ++ "Physical register file EX1 port", ++ "Physical register file AG0 port", ++ "Physical register file AG1 port", ++ "Flag register file", ++ "DE error occurred", ++ "Retire status queue" ++}; ++ + static char *highbits[32] = { + [31] = "valid", + [30] = "error overflow (multiple errors)", +@@ -100,6 +146,21 @@ static char *k8threshold[] = { + "Unknown threshold counter", + }; + ++static u8 xec_mask = 0xf; ++ ++enum cputype select_amd_cputype(u32 family) ++{ ++ switch (family) { ++ case 0xf: ++ return CPU_K8; ++ case 0x10: ++ return CPU_F10H; ++ default: ++ break; ++ } ++ ++ return CPU_GENERIC; ++} + + static void decode_k8_generic_errcode(u64 status) + { +@@ -245,21 +306,393 @@ static decoder_t decoders[] = { + [5] = decode_k8_fr_mc, + }; + +-void decode_amd_mc(enum cputype cpu, struct mce *mce, int *ismemerr) ++static bool k8_mc1_mce(u16 ec, u8 xec) ++{ ++ u8 ll = LL(ec); ++ bool ret = true; ++ ++ if (!MEM_ERROR(ec)) ++ return false; ++ ++ if (ll == 0x2) ++ Wprintf("during a linefill from L2.\n"); ++ else if (ll == 0x1) { ++ switch (R4(ec)) { ++ case R4_IRD: ++ Wprintf("Parity error during data load.\n"); ++ break; ++ ++ case R4_EVICT: ++ Wprintf("Copyback Parity/Victim error.\n"); ++ break; ++ ++ case R4_SNOOP: ++ Wprintf("Tag Snoop error.\n"); ++ break; ++ ++ default: ++ ret = false; ++ break; ++ } ++ } else ++ ret = false; ++ ++ return ret; ++} ++ ++static bool f12h_mc0_mce(u16 ec, u8 xec) ++{ ++ bool ret = false; ++ ++ if (MEM_ERROR(ec)) { ++ u8 ll = LL(ec); ++ ret = true; ++ ++ if (ll == LL_L2) ++ Wprintf("aduring L1 linefill from L2.\n"); ++ else if (ll == LL_L1) ++ Wprintf("Data/Tag %s error.\n", R4_MSG(ec)); ++ else ++ ret = false; ++ } ++ return ret; ++} ++ ++static bool f10h_mc0_mce(u16 ec, u8 xec) ++{ ++ if (R4(ec) == R4_GEN && LL(ec) == LL_L1) { ++ Wprintf("during data scrub.\n"); ++ return true; ++ } ++ return f12h_mc0_mce(ec, xec); ++} ++ ++static void decode_mc0_mce(struct amd_decoder_ops *ops, struct mce *m) ++{ ++ u16 ec = EC(m->status); ++ u8 xec = XEC(m->status, xec_mask); ++ ++ Wprintf(" MC0 Error: "); ++ ++ /* TLB error signatures are the same across families */ ++ if (TLB_ERROR(ec)) { ++ if (TT(ec) == TT_DATA) { ++ Wprintf("%s TLB %s.\n", LL_MSG(ec), ++ ((xec == 2) ? "locked miss" ++ : (xec ? "multimatch" : "parity"))); ++ return; ++ } ++ } else if (ops->mc0_mce(ec, xec)) ++ ; ++ else ++ Eprintf("Corrupted MC0 MCE info?\n"); ++} ++ ++static void decode_mc1_mce(struct amd_decoder_ops *ops, struct mce *m) + { +- if (mce->bank < NELE(decoders)) +- decoders[mce->bank](mce->status, ismemerr); +- else if (mce->bank >= K8_MCE_THRESHOLD_BASE && +- mce->bank < K8_MCE_THRESHOLD_TOP) +- decode_k8_threshold(mce->misc); ++ u16 ec = EC(m->status); ++ u8 xec = XEC(m->status, xec_mask); ++ ++ Wprintf(" MC1 Error: "); ++ ++ if (TLB_ERROR(ec)) ++ Wprintf("%s TLB %s.\n", LL_MSG(ec), ++ (xec ? "multimatch" : "parity error")); ++ else if (BUS_ERROR(ec)) { ++ bool k8 = ((ops->cpu == AMD_K8) && (m->status & BIT_64(58))); ++ ++ Wprintf("during %s.\n", (k8 ? "system linefill" : "NB data read")); ++ } else if (ops->mc1_mce(ec, xec)) ++ ; + else +- Wprintf(" no decoder for unknown bank %u\n", mce->bank); ++ Eprintf("Corrupted MC1 MCE info?\n"); ++} ++ ++static bool k8_mc2_mce(u16 ec, u8 xec) ++{ ++ bool ret = true; ++ ++ if (xec == 0x1) ++ Wprintf(" in the write data buffers.\n"); ++ else if (xec == 0x3) ++ Wprintf(" in the victim data buffers.\n"); ++ else if (xec == 0x2 && MEM_ERROR(ec)) ++ Wprintf(": %s error in the L2 cache tags.\n", R4_MSG(ec)); ++ else if (xec == 0x0) { ++ if (TLB_ERROR(ec)) ++ Wprintf(": %s error in a Page Descriptor Cache or " ++ "Guest TLB.\n", TT_MSG(ec)); ++ else if (BUS_ERROR(ec)) ++ Wprintf(": %s/ECC error in data read from NB: %s.\n", ++ R4_MSG(ec), PP_MSG(ec)); ++ else if (MEM_ERROR(ec)) { ++ u8 r4 = R4(ec); ++ ++ if (r4 >= 0x7) ++ Wprintf(": %s error during data copyback.\n", ++ R4_MSG(ec)); ++ else if (r4 <= 0x1) ++ Wprintf(": %s parity/ECC error during data " ++ "access from L2.\n", R4_MSG(ec)); ++ else ++ ret = false; ++ } else ++ ret = false; ++ } else ++ ret = false; ++ ++ return ret; ++} ++ ++static void decode_mc2_mce(struct amd_decoder_ops *ops, struct mce *m) ++{ ++ u16 ec = EC(m->status); ++ u8 xec = XEC(m->status, xec_mask); ++ ++ Wprintf(" MC2 Error: "); ++ ++ if (!ops->mc2_mce(ec, xec)) ++ Eprintf("Corrupted MC2 MCE info?\n"); ++} ++ ++static void decode_mc3_mce(struct amd_decoder_ops *ops, struct mce *m) ++{ ++ u16 ec = EC(m->status); ++ u8 xec = XEC(m->status, xec_mask); ++ ++ if (ops->cpu >= AMD_F14H) { ++ Eprintf("You shouldn't be seeing MC3 MCE on this cpu family," ++ " please report on LKML.\n"); ++ return; ++ } ++ ++ Wprintf(" MC3 Error"); ++ ++ if (xec == 0x0) { ++ u8 r4 = R4(ec); ++ ++ if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR)) ++ goto wrong_mc3_mce; ++ ++ Wprintf(" during %s.\n", R4_MSG(ec)); ++ } else ++ goto wrong_mc3_mce; ++ ++ return; ++ ++wrong_mc3_mce: ++ Eprintf("Corrupted MC3 MCE info?\n"); ++} ++ ++static void decode_mc4_mce(struct amd_decoder_ops *ops, struct mce *m) ++{ ++ u16 ec = EC(m->status); ++ u8 xec = XEC(m->status, 0x1f); ++ u8 offset = 0; ++ ++ Wprintf(" MC4 Error: "); ++ ++ switch (xec) { ++ case 0x0 ... 0xe: ++ ++ /* special handling for DRAM ECCs */ ++ if (xec == 0x0 || xec == 0x8) { ++ /* no ECCs on F11h */ ++ if (ops->cpu == AMD_F11H) ++ goto wrong_mc4_mce; ++ ++ Wprintf("%s.\n", mc4_mce_desc[xec]); ++ return; ++ } ++ break; ++ ++ case 0xf: ++ if (TLB_ERROR(ec)) ++ Wprintf("GART Table Walk data error.\n"); ++ else if (BUS_ERROR(ec)) ++ Wprintf("DMA Exclusion Vector Table Walk error.\n"); ++ else ++ goto wrong_mc4_mce; ++ return; ++ ++ case 0x19: ++ if (ops->cpu >= AMD_F15H || ops->cpu <= AMD_F16H) ++ Wprintf("Compute Unit Data Error.\n"); ++ else ++ goto wrong_mc4_mce; ++ return; ++ ++ case 0x1c ... 0x1f: ++ offset = 13; ++ break; ++ ++ default: ++ goto wrong_mc4_mce; ++ } ++ ++ Wprintf("%s.\n", mc4_mce_desc[xec - offset]); ++ return; ++ ++ wrong_mc4_mce: ++ Eprintf("Corrupted MC4 MCE info?\n"); ++} ++ ++static void decode_mc5_mce(struct amd_decoder_ops *ops, struct mce *m) ++{ ++ u8 xec = XEC(m->status, xec_mask); ++ ++ if (ops->cpu == AMD_K8 || ops->cpu == AMD_F11H) ++ goto wrong_mc5_mce; ++ ++ Wprintf(" MC5 Error: "); ++ ++ if (xec == 0x0 || xec == 0xc) ++ Wprintf("%s.\n", mc5_mce_desc[xec]); ++ else if (xec <= 0xd) ++ Wprintf("%s parity error.\n", mc5_mce_desc[xec]); ++ else ++ goto wrong_mc5_mce; ++ ++ return; ++ ++ wrong_mc5_mce: ++ Eprintf("Corrupted MC5 MCE info?\n"); ++} ++ ++static void decode_mc6_mce(struct mce *m) ++{ ++ u8 xec = XEC(m->status, xec_mask); ++ ++ Wprintf(" MC6 Error: "); ++ ++ switch (xec) { ++ case 0x1: ++ Wprintf("Free List"); ++ break; ++ ++ case 0x2: ++ Wprintf("Physical Register File"); ++ break; ++ ++ case 0x3: ++ Wprintf("Retire Queue"); ++ break; ++ ++ case 0x4: ++ Wprintf("Scheduler table"); ++ break; ++ ++ case 0x5: ++ Wprintf("Status Register File"); ++ break; ++ ++ default: ++ goto wrong_mc6_mce; ++ break; ++ } ++ ++ Wprintf(" parity error.\n"); ++ ++ return; ++ ++ wrong_mc6_mce: ++ Eprintf("Corrupted MC6 MCE info?\n"); ++} ++ ++static inline void amd_decode_err_code(u16 ec) ++{ ++ if (INT_ERROR(ec)) { ++ Wprintf(" internal: %s\n", UU_MSG(ec)); ++ return; ++ } ++ ++ Wprintf(" cache level: %s", LL_MSG(ec)); ++ ++ if (BUS_ERROR(ec)) ++ Wprintf(", mem/io: %s", II_MSG(ec)); ++ else ++ Wprintf(", tx: %s", TT_MSG(ec)); ++ ++ if (MEM_ERROR(ec) || BUS_ERROR(ec)) { ++ Wprintf(", mem-tx: %s", R4_MSG(ec)); ++ ++ if (BUS_ERROR(ec)) ++ Wprintf(", part-proc: %s (%s)", PP_MSG(ec), TO_MSG(ec)); ++ } ++ ++ Wprintf("\n"); ++} ++ ++struct amd_decoder_ops fam_ops[] = { ++ [AMD_F10H] = { ++ .cpu = AMD_F10H, ++ .mc0_mce = f10h_mc0_mce, ++ .mc1_mce = k8_mc1_mce, ++ .mc2_mce = k8_mc2_mce, ++ }, ++}; ++ ++static void __decode_amd_mc(enum cputype cpu, struct mce *mce) ++{ ++ struct amd_decoder_ops *ops; ++ ++ switch (cpu) { ++ case CPU_F10H: ++ ops = &fam_ops[AMD_F10H]; ++ break; ++ default: ++ Eprintf("Huh? What family is it: 0x%x?!\n", cpu); ++ return; ++ break; ++ } ++ ++ switch (mce->bank) { ++ case 0: ++ decode_mc0_mce(ops, mce); ++ break; ++ case 1: ++ decode_mc1_mce(ops, mce); ++ break; ++ case 2: ++ decode_mc2_mce(ops, mce); ++ break; ++ case 3: ++ decode_mc3_mce(ops, mce); ++ break; ++ case 4: ++ decode_mc4_mce(ops, mce); ++ break; ++ case 5: ++ decode_mc5_mce(ops, mce); ++ break; ++ case 6: ++ decode_mc6_mce(mce); ++ break; ++ ++ default: ++ break; ++ } ++ amd_decode_err_code(mce->status & 0xffff); ++} ++ ++void decode_amd_mc(enum cputype cpu, struct mce *mce, int *ismemerr) ++{ ++ if (cpu == CPU_K8) { ++ if (mce->bank < NELE(decoders)) ++ decoders[mce->bank](mce->status, ismemerr); ++ else if (mce->bank >= K8_MCE_THRESHOLD_BASE && ++ mce->bank < K8_MCE_THRESHOLD_TOP) ++ decode_k8_threshold(mce->misc); ++ else ++ Wprintf(" no decoder for unknown bank %u\n", mce->bank); ++ } else ++ __decode_amd_mc(cpu, mce); + } + + char *k8_bank_name(unsigned num) + { + static char buf[64]; +- char *s = "unknown"; ++ const char *s = "unknown"; + if (num < NELE(k8bank)) + s = k8bank[num]; + else if (num >= K8_MCE_THRESHOLD_BASE && +@@ -270,13 +703,16 @@ char *k8_bank_name(unsigned num) + return buf; + } + +-int mce_filter_k8(struct mce *m) +-{ +- /* Filter out GART errors */ +- if (m->bank == 4) { +- unsigned short exterrcode = (m->status >> 16) & 0x0f; +- if (exterrcode == 5 && (m->status & (1ULL<<61))) ++int mce_filter_amd(struct mce *m) ++{ ++ /* ++ * NB GART TLB error reporting is disabled by default. ++ */ ++ if (m->bank == 4) { ++ u8 xec = (m->status >> 16) & 0x1f; ++ ++ if (xec == 0x5 && (m->status & BIT_64(61))) + return 0; +- } +- return 1; ++ } ++ return 1; + } +Index: mcelog-1.0.1/amd.h +=================================================================== +--- mcelog-1.0.1.orig/amd.h ++++ mcelog-1.0.1/amd.h +@@ -1,6 +1,25 @@ ++#include ++ + char *k8_bank_name(unsigned num); + void decode_amd_mc(enum cputype, struct mce *mce, int *ismemerr); +-int mce_filter_k8(struct mce *m); ++int mce_filter_amd(struct mce *m); ++enum cputype select_amd_cputype(u32 family); ++ ++enum amdcpu { ++ AMD_K8 = 0, ++ AMD_F10H, ++ AMD_F11H, ++ AMD_F14H, ++ AMD_F15H, ++ AMD_F16H, ++}; ++ ++struct amd_decoder_ops { ++ enum amdcpu cpu; ++ bool (*mc0_mce)(u16, u8); ++ bool (*mc1_mce)(u16, u8); ++ bool (*mc2_mce)(u16, u8); ++}; + + #define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1) /* MCE_AMD */ + #define K8_MCE_THRESHOLD_TOP (K8_MCE_THRESHOLD_BASE + 6 * 9) +@@ -10,6 +29,8 @@ int mce_filter_k8(struct mce *m); + #define K8_MCELOG_THRESHOLD_L3_CACHE (4 * 9 + 2) + #define K8_MCELOG_THRESHOLD_FBDIMM (4 * 9 + 3) + ++#define BIT_64(n) (1ULL << (n)) ++ + #define EC(x) ((x) & 0xffff) + #define XEC(x, mask) (((x) >> 16) & mask) + +@@ -22,23 +43,20 @@ int mce_filter_k8(struct mce *m); + #define INT_ERROR(x) (((x) & 0xF4FF) == 0x0400) + + #define TT(x) (((x) >> 2) & 0x3) +-#define TT_MSG(x) tt_msgs[TT(x)] ++#define TT_MSG(x) transaction[TT(x)] + #define II(x) (((x) >> 2) & 0x3) +-#define II_MSG(x) ii_msgs[II(x)] ++#define II_MSG(x) memoryio[II(x)] + #define LL(x) ((x) & 0x3) +-#define LL_MSG(x) ll_msgs[LL(x)] ++#define LL_MSG(x) cachelevel[LL(x)] + #define TO(x) (((x) >> 8) & 0x1) +-#define TO_MSG(x) to_msgs[TO(x)] ++#define TO_MSG(x) timeout[TO(x)] + #define PP(x) (((x) >> 9) & 0x3) +-#define PP_MSG(x) pp_msgs[PP(x)] ++#define PP_MSG(x) partproc[PP(x)] + #define UU(x) (((x) >> 8) & 0x3) + #define UU_MSG(x) uu_msgs[UU(x)] + + #define R4(x) (((x) >> 4) & 0xf) +-#define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!") +- +-#define CASE_AMD_CPUS \ +- case CPU_K8 ++#define R4_MSG(x) ((R4(x) < 9) ? memtrans[R4(x)] : "Wrong R4!") + + enum tt_ids { + TT_INSTR = 0, +@@ -72,3 +90,7 @@ enum rrrr_ids { + R4_EVICT, + R4_SNOOP, + }; ++ ++#define CASE_AMD_CPUS \ ++ case CPU_K8: \ ++ case CPU_F10H +Index: mcelog-1.0.1/mcelog.h +=================================================================== +--- mcelog-1.0.1.orig/mcelog.h ++++ mcelog-1.0.1/mcelog.h +@@ -107,6 +107,7 @@ enum cputype { + CPU_P6OLD, + CPU_CORE2, /* 65nm and 45nm */ + CPU_K8, ++ CPU_F10H, + CPU_P4, + CPU_NEHALEM, + CPU_DUNNINGTON, +Index: mcelog-1.0.1/mcelog.c +=================================================================== +--- mcelog-1.0.1.orig/mcelog.c ++++ mcelog-1.0.1/mcelog.c +@@ -142,19 +142,20 @@ static void resolveaddr(unsigned long ad + + static int mce_filter(struct mce *m, unsigned recordlen) + { +- if (!filter_bogus) ++ if (!filter_bogus) + return 1; ++ + /* Filter out known broken MCEs */ + switch (cputype) { +- case CPU_K8: +- return mce_filter_k8(m); ++ CASE_AMD_CPUS: ++ return mce_filter_amd(m); + /* add more buggy CPUs here */ + CASE_INTEL_CPUS: + return mce_filter_intel(m, recordlen); + default: + case CPU_GENERIC: + return 1; +- } ++ } + } + + static void print_tsc(int cpunum, __u64 tsc, unsigned long time) +@@ -221,6 +222,7 @@ static char *cputype_name[] = { + [CPU_P6OLD] = "Intel PPro/P2/P3/old Xeon", + [CPU_CORE2] = "Intel Core", /* 65nm and 45nm */ + [CPU_K8] = "AMD K8 and derivates", ++ [CPU_F10H] = "AMD Greyhound", + [CPU_P4] = "Intel P4", + [CPU_NEHALEM] = "Intel Xeon 5500 series / Core i3/5/7 (\"Nehalem/Westmere\")", + [CPU_DUNNINGTON] = "Intel Xeon 7400 series", +@@ -239,6 +241,7 @@ static struct config_choice cpu_choices[ + { "p6old", CPU_P6OLD }, + { "core2", CPU_CORE2 }, + { "k8", CPU_K8 }, ++ { "f10h", CPU_F10H }, + { "p4", CPU_P4 }, + { "dunnington", CPU_DUNNINGTON }, + { "xeon74xx", CPU_DUNNINGTON }, +@@ -330,15 +333,13 @@ static enum cputype setup_cpuid(u32 cpuv + + parse_cpuid(cpuid, &family, &model); + +- switch (cpuvendor) { ++ switch (cpuvendor) { + case X86_VENDOR_INTEL: + return select_intel_cputype(family, model); + case X86_VENDOR_AMD: +- if (family >= 15 && family <= 17) +- return CPU_K8; +- /* FALL THROUGH */ ++ return select_amd_cputype(family); + default: +- Eprintf("Unknown CPU type vendor %u family %x model %x", ++ Eprintf("Unknown CPU type vendor %u family %x model %x", + cpuvendor, family, model); + return CPU_GENERIC; + } +@@ -511,14 +512,9 @@ int is_cpu_supported(void) + + } + if (seen == ALL) { +- if (!strcmp(vendor,"AuthenticAMD")) { +- if (family == 15) { +- cputype = CPU_K8; +- } else if (family >= 16) { +- SYSERRprintf("AMD Processor family %d: Please use the edac_mce_amd module instead.\n", family); +- return 0; +- } +- } else if (!strcmp(vendor,"GenuineIntel")) ++ if (!strcmp(vendor,"AuthenticAMD")) ++ cputype = select_amd_cputype(family); ++ else if (!strcmp(vendor,"GenuineIntel")) + cputype = select_intel_cputype(family, model); + /* Add checks for other CPUs here */ + } else { diff --git a/add-f11h-support.patch b/add-f11h-support.patch new file mode 100644 index 0000000..b0b8e7c --- /dev/null +++ b/add-f11h-support.patch @@ -0,0 +1,99 @@ +Add F11h decoding support + +Signed-off-by: Borislav Petkov +Index: mcelog-1.0.1/amd.c +=================================================================== +--- mcelog-1.0.1.orig/amd.c ++++ mcelog-1.0.1/amd.c +@@ -155,6 +155,8 @@ enum cputype select_amd_cputype(u32 fami + return CPU_K8; + case 0x10: + return CPU_F10H; ++ case 0x11: ++ return CPU_F11H; + default: + break; + } +@@ -367,6 +369,16 @@ static bool f10h_mc0_mce(u16 ec, u8 xec) + return f12h_mc0_mce(ec, xec); + } + ++static bool k8_mc0_mce(u16 ec, u8 xec) ++{ ++ if (BUS_ERROR(ec)) { ++ Wprintf("during system linefill.\n"); ++ return true; ++ } ++ ++ return f10h_mc0_mce(ec, xec); ++} ++ + static void decode_mc0_mce(struct amd_decoder_ops *ops, struct mce *m) + { + u16 ec = EC(m->status); +@@ -630,6 +642,12 @@ struct amd_decoder_ops fam_ops[] = { + .mc1_mce = k8_mc1_mce, + .mc2_mce = k8_mc2_mce, + }, ++ [AMD_F11H] = { ++ .cpu = AMD_F11H, ++ .mc0_mce = k8_mc0_mce, ++ .mc1_mce = k8_mc1_mce, ++ .mc2_mce = k8_mc2_mce, ++ }, + }; + + static void __decode_amd_mc(enum cputype cpu, struct mce *mce) +@@ -640,6 +658,9 @@ static void __decode_amd_mc(enum cputype + case CPU_F10H: + ops = &fam_ops[AMD_F10H]; + break; ++ case CPU_F11H: ++ ops = &fam_ops[AMD_F11H]; ++ break; + default: + Eprintf("Huh? What family is it: 0x%x?!\n", cpu); + return; +Index: mcelog-1.0.1/amd.h +=================================================================== +--- mcelog-1.0.1.orig/amd.h ++++ mcelog-1.0.1/amd.h +@@ -93,4 +93,5 @@ enum rrrr_ids { + + #define CASE_AMD_CPUS \ + case CPU_K8: \ +- case CPU_F10H ++ case CPU_F10H: \ ++ case CPU_F11H +Index: mcelog-1.0.1/mcelog.h +=================================================================== +--- mcelog-1.0.1.orig/mcelog.h ++++ mcelog-1.0.1/mcelog.h +@@ -108,6 +108,7 @@ enum cputype { + CPU_CORE2, /* 65nm and 45nm */ + CPU_K8, + CPU_F10H, ++ CPU_F11H, + CPU_P4, + CPU_NEHALEM, + CPU_DUNNINGTON, +Index: mcelog-1.0.1/mcelog.c +=================================================================== +--- mcelog-1.0.1.orig/mcelog.c ++++ mcelog-1.0.1/mcelog.c +@@ -223,6 +223,7 @@ static char *cputype_name[] = { + [CPU_CORE2] = "Intel Core", /* 65nm and 45nm */ + [CPU_K8] = "AMD K8 and derivates", + [CPU_F10H] = "AMD Greyhound", ++ [CPU_F11H] = "AMD Griffin", + [CPU_P4] = "Intel P4", + [CPU_NEHALEM] = "Intel Xeon 5500 series / Core i3/5/7 (\"Nehalem/Westmere\")", + [CPU_DUNNINGTON] = "Intel Xeon 7400 series", +@@ -242,6 +243,7 @@ static struct config_choice cpu_choices[ + { "core2", CPU_CORE2 }, + { "k8", CPU_K8 }, + { "f10h", CPU_F10H }, ++ { "f11h", CPU_F11H }, + { "p4", CPU_P4 }, + { "dunnington", CPU_DUNNINGTON }, + { "xeon74xx", CPU_DUNNINGTON }, diff --git a/add-f12h-support.patch b/add-f12h-support.patch new file mode 100644 index 0000000..8d96d2b --- /dev/null +++ b/add-f12h-support.patch @@ -0,0 +1,90 @@ +Add F12h decoding support + +Signed-off-by: Borislav Petkov +Index: mcelog-1.0.1/amd.c +=================================================================== +--- mcelog-1.0.1.orig/amd.c ++++ mcelog-1.0.1/amd.c +@@ -157,6 +157,8 @@ enum cputype select_amd_cputype(u32 fami + return CPU_F10H; + case 0x11: + return CPU_F11H; ++ case 0x12: ++ return CPU_F12H; + default: + break; + } +@@ -648,6 +650,12 @@ struct amd_decoder_ops fam_ops[] = { + .mc1_mce = k8_mc1_mce, + .mc2_mce = k8_mc2_mce, + }, ++ [AMD_F12H] = { ++ .cpu = AMD_F12H, ++ .mc0_mce = f12h_mc0_mce, ++ .mc1_mce = k8_mc1_mce, ++ .mc2_mce = k8_mc2_mce, ++ }, + }; + + static void __decode_amd_mc(enum cputype cpu, struct mce *mce) +@@ -661,6 +669,9 @@ static void __decode_amd_mc(enum cputype + case CPU_F11H: + ops = &fam_ops[AMD_F11H]; + break; ++ case CPU_F12H: ++ ops = &fam_ops[AMD_F12H]; ++ break; + default: + Eprintf("Huh? What family is it: 0x%x?!\n", cpu); + return; +Index: mcelog-1.0.1/amd.h +=================================================================== +--- mcelog-1.0.1.orig/amd.h ++++ mcelog-1.0.1/amd.h +@@ -9,6 +9,7 @@ enum amdcpu { + AMD_K8 = 0, + AMD_F10H, + AMD_F11H, ++ AMD_F12H, + AMD_F14H, + AMD_F15H, + AMD_F16H, +@@ -94,4 +95,5 @@ enum rrrr_ids { + #define CASE_AMD_CPUS \ + case CPU_K8: \ + case CPU_F10H: \ +- case CPU_F11H ++ case CPU_F11H: \ ++ case CPU_F12H +Index: mcelog-1.0.1/mcelog.h +=================================================================== +--- mcelog-1.0.1.orig/mcelog.h ++++ mcelog-1.0.1/mcelog.h +@@ -109,6 +109,7 @@ enum cputype { + CPU_K8, + CPU_F10H, + CPU_F11H, ++ CPU_F12H, + CPU_P4, + CPU_NEHALEM, + CPU_DUNNINGTON, +Index: mcelog-1.0.1/mcelog.c +=================================================================== +--- mcelog-1.0.1.orig/mcelog.c ++++ mcelog-1.0.1/mcelog.c +@@ -224,6 +224,7 @@ static char *cputype_name[] = { + [CPU_K8] = "AMD K8 and derivates", + [CPU_F10H] = "AMD Greyhound", + [CPU_F11H] = "AMD Griffin", ++ [CPU_F12H] = "AMD Llano", + [CPU_P4] = "Intel P4", + [CPU_NEHALEM] = "Intel Xeon 5500 series / Core i3/5/7 (\"Nehalem/Westmere\")", + [CPU_DUNNINGTON] = "Intel Xeon 7400 series", +@@ -244,6 +245,7 @@ static struct config_choice cpu_choices[ + { "k8", CPU_K8 }, + { "f10h", CPU_F10H }, + { "f11h", CPU_F11H }, ++ { "f12h", CPU_F12H }, + { "p4", CPU_P4 }, + { "dunnington", CPU_DUNNINGTON }, + { "xeon74xx", CPU_DUNNINGTON }, diff --git a/add-f14h-support.patch b/add-f14h-support.patch new file mode 100644 index 0000000..08df5a1 --- /dev/null +++ b/add-f14h-support.patch @@ -0,0 +1,173 @@ +Add F14h decoding support + +Signed-off-by: Borislav Petkov +Index: mcelog-1.0.1/amd.c +=================================================================== +--- mcelog-1.0.1.orig/amd.c ++++ mcelog-1.0.1/amd.c +@@ -159,6 +159,8 @@ enum cputype select_amd_cputype(u32 fami + return CPU_F11H; + case 0x12: + return CPU_F12H; ++ case 0x14: ++ return CPU_F14H; + default: + break; + } +@@ -381,6 +383,58 @@ static bool k8_mc0_mce(u16 ec, u8 xec) + return f10h_mc0_mce(ec, xec); + } + ++static bool cat_mc0_mce(u16 ec, u8 xec) ++{ ++ u8 r4 = R4(ec); ++ bool ret = true; ++ ++ if (MEM_ERROR(ec)) { ++ ++ if (TT(ec) != TT_DATA || LL(ec) != LL_L1) ++ return false; ++ ++ switch (r4) { ++ case R4_DRD: ++ case R4_DWR: ++ Wprintf("Data/Tag parity error due to %s.\n", ++ (r4 == R4_DRD ? "load/hw prf" : "store")); ++ break; ++ case R4_EVICT: ++ Wprintf("Copyback parity error on a tag miss.\n"); ++ break; ++ case R4_SNOOP: ++ Wprintf("Tag parity error during snoop.\n"); ++ break; ++ default: ++ ret = false; ++ } ++ } else if (BUS_ERROR(ec)) { ++ ++ if ((II(ec) != II_MEM && II(ec) != II_IO) || LL(ec) != LL_LG) ++ return false; ++ ++ Wprintf("System read data error on a "); ++ ++ switch (r4) { ++ case R4_RD: ++ Wprintf("TLB reload.\n"); ++ break; ++ case R4_DWR: ++ Wprintf("store.\n"); ++ break; ++ case R4_DRD: ++ Wprintf("load.\n"); ++ break; ++ default: ++ ret = false; ++ } ++ } else { ++ ret = false; ++ } ++ ++ return ret; ++} ++ + static void decode_mc0_mce(struct amd_decoder_ops *ops, struct mce *m) + { + u16 ec = EC(m->status); +@@ -402,6 +456,31 @@ static void decode_mc0_mce(struct amd_de + Eprintf("Corrupted MC0 MCE info?\n"); + } + ++static bool cat_mc1_mce(u16 ec, u8 xec) ++{ ++ u8 r4 = R4(ec); ++ bool ret = true; ++ ++ if (!MEM_ERROR(ec)) ++ return false; ++ ++ if (TT(ec) != TT_INSTR) ++ return false; ++ ++ if (r4 == R4_IRD) ++ Wprintf("Data/tag array parity error for a tag hit.\n"); ++ else if (r4 == R4_SNOOP) ++ Wprintf("Tag error during snoop/victimization.\n"); ++ else if (xec == 0x0) ++ Wprintf("Tag parity error from victim castout.\n"); ++ else if (xec == 0x2) ++ Wprintf("Microcode patch RAM parity error.\n"); ++ else ++ ret = false; ++ ++ return ret; ++} ++ + static void decode_mc1_mce(struct amd_decoder_ops *ops, struct mce *m) + { + u16 ec = EC(m->status); +@@ -656,6 +735,12 @@ struct amd_decoder_ops fam_ops[] = { + .mc1_mce = k8_mc1_mce, + .mc2_mce = k8_mc2_mce, + }, ++ [AMD_F14H] = { ++ .cpu = AMD_F14H, ++ .mc0_mce = cat_mc0_mce, ++ .mc1_mce = cat_mc1_mce, ++ .mc2_mce = k8_mc2_mce, ++ }, + }; + + static void __decode_amd_mc(enum cputype cpu, struct mce *mce) +@@ -672,6 +757,9 @@ static void __decode_amd_mc(enum cputype + case CPU_F12H: + ops = &fam_ops[AMD_F12H]; + break; ++ case CPU_F14H: ++ ops = &fam_ops[AMD_F14H]; ++ break; + default: + Eprintf("Huh? What family is it: 0x%x?!\n", cpu); + return; +Index: mcelog-1.0.1/mcelog.h +=================================================================== +--- mcelog-1.0.1.orig/mcelog.h ++++ mcelog-1.0.1/mcelog.h +@@ -110,6 +110,7 @@ enum cputype { + CPU_F10H, + CPU_F11H, + CPU_F12H, ++ CPU_F14H, + CPU_P4, + CPU_NEHALEM, + CPU_DUNNINGTON, +Index: mcelog-1.0.1/amd.h +=================================================================== +--- mcelog-1.0.1.orig/amd.h ++++ mcelog-1.0.1/amd.h +@@ -96,4 +96,5 @@ enum rrrr_ids { + case CPU_K8: \ + case CPU_F10H: \ + case CPU_F11H: \ +- case CPU_F12H ++ case CPU_F12H: \ ++ case CPU_F14H +Index: mcelog-1.0.1/mcelog.c +=================================================================== +--- mcelog-1.0.1.orig/mcelog.c ++++ mcelog-1.0.1/mcelog.c +@@ -225,6 +225,7 @@ static char *cputype_name[] = { + [CPU_F10H] = "AMD Greyhound", + [CPU_F11H] = "AMD Griffin", + [CPU_F12H] = "AMD Llano", ++ [CPU_F14H] = "AMD Bobcat", + [CPU_P4] = "Intel P4", + [CPU_NEHALEM] = "Intel Xeon 5500 series / Core i3/5/7 (\"Nehalem/Westmere\")", + [CPU_DUNNINGTON] = "Intel Xeon 7400 series", +@@ -246,6 +247,7 @@ static struct config_choice cpu_choices[ + { "f10h", CPU_F10H }, + { "f11h", CPU_F11H }, + { "f12h", CPU_F12H }, ++ { "f14h", CPU_F14H }, + { "p4", CPU_P4 }, + { "dunnington", CPU_DUNNINGTON }, + { "xeon74xx", CPU_DUNNINGTON }, diff --git a/add-f15h-support.patch b/add-f15h-support.patch new file mode 100644 index 0000000..ed952ef --- /dev/null +++ b/add-f15h-support.patch @@ -0,0 +1,259 @@ +Add F15h decoding support + +Signed-off-by: Borislav Petkov +Index: mcelog-1.0.1/amd.c +=================================================================== +--- mcelog-1.0.1.orig/amd.c ++++ mcelog-1.0.1/amd.c +@@ -72,6 +72,43 @@ static char *nbextendederr[] = { + "L3 Cache LRU Error" + }; + ++static const char * const f15h_mc1_mce_desc[] = { ++ "UC during a demand linefill from L2", ++ "Parity error during data load from IC", ++ "Parity error for IC valid bit", ++ "Main tag parity error", ++ "Parity error in prediction queue", ++ "PFB data/address parity error", ++ "Parity error in the branch status reg", ++ "PFB promotion address error", ++ "Tag error during probe/victimization", ++ "Parity error for IC probe tag valid bit", ++ "PFB non-cacheable bit parity error", ++ "PFB valid bit parity error", /* xec = 0xd */ ++ "Microcode Patch Buffer", /* xec = 010 */ ++ "uop queue", ++ "insn buffer", ++ "predecode buffer", ++ "fetch address FIFO" ++}; ++ ++static const char * const f15h_mc2_mce_desc[] = { ++ "Fill ECC error on data fills", /* xec = 0x4 */ ++ "Fill parity error on insn fills", ++ "Prefetcher request FIFO parity error", ++ "PRQ address parity error", ++ "PRQ data parity error", ++ "WCC Tag ECC error", ++ "WCC Data ECC error", ++ "WCB Data parity error", ++ "VB Data ECC or parity error", ++ "L2 Tag ECC error", /* xec = 0x10 */ ++ "Hard L2 Tag ECC error", ++ "Multiple hits on L2 tag", ++ "XAB parity error", ++ "PRB address parity error" ++}; ++ + static const char * const mc4_mce_desc[] = { + "DRAM ECC error detected on the NB", + "CRC error detected on HT link", +@@ -161,6 +198,8 @@ enum cputype select_amd_cputype(u32 fami + return CPU_F12H; + case 0x14: + return CPU_F14H; ++ case 0x15: ++ return CPU_F15H; + default: + break; + } +@@ -435,6 +474,53 @@ static bool cat_mc0_mce(u16 ec, u8 xec) + return ret; + } + ++static bool f15h_mc0_mce(u16 ec, u8 xec) ++{ ++ bool ret = true; ++ ++ if (MEM_ERROR(ec)) { ++ ++ switch (xec) { ++ case 0x0: ++ Wprintf("Data Array access error.\n"); ++ break; ++ ++ case 0x1: ++ Wprintf("UC error during a linefill from L2/NB.\n"); ++ break; ++ ++ case 0x2: ++ case 0x11: ++ Wprintf("STQ access error.\n"); ++ break; ++ ++ case 0x3: ++ Wprintf("SCB access error.\n"); ++ break; ++ ++ case 0x10: ++ Wprintf("Tag error.\n"); ++ break; ++ ++ case 0x12: ++ Wprintf("LDQ access error.\n"); ++ break; ++ ++ default: ++ ret = false; ++ } ++ } else if (BUS_ERROR(ec)) { ++ ++ if (!xec) ++ Wprintf("System Read Data Error.\n"); ++ else ++ Wprintf(" Internal error condition type %d.\n", xec); ++ } else ++ ret = false; ++ ++ return ret; ++} ++ + static void decode_mc0_mce(struct amd_decoder_ops *ops, struct mce *m) + { + u16 ec = EC(m->status); +@@ -481,6 +567,36 @@ static bool cat_mc1_mce(u16 ec, u8 xec) + return ret; + } + ++static bool f15h_mc1_mce(u16 ec, u8 xec) ++{ ++ bool ret = true; ++ ++ if (!MEM_ERROR(ec)) ++ return false; ++ ++ switch (xec) { ++ case 0x0 ... 0xa: ++ Wprintf("%s.\n", f15h_mc1_mce_desc[xec]); ++ break; ++ ++ case 0xd: ++ Wprintf("%s.\n", f15h_mc1_mce_desc[xec-2]); ++ break; ++ ++ case 0x10: ++ Wprintf("%s.\n", f15h_mc1_mce_desc[xec-4]); ++ break; ++ ++ case 0x11 ... 0x14: ++ Wprintf("Decoder %s parity error.\n", f15h_mc1_mce_desc[xec-4]); ++ break; ++ ++ default: ++ ret = false; ++ } ++ return ret; ++} ++ + static void decode_mc1_mce(struct amd_decoder_ops *ops, struct mce *m) + { + u16 ec = EC(m->status); +@@ -537,6 +653,40 @@ static bool k8_mc2_mce(u16 ec, u8 xec) + return ret; + } + ++static bool f15h_mc2_mce(u16 ec, u8 xec) ++{ ++ bool ret = true; ++ ++ if (TLB_ERROR(ec)) { ++ if (xec == 0x0) ++ Wprintf("Data parity TLB read error.\n"); ++ else if (xec == 0x1) ++ Wprintf("Poison data provided for TLB fill.\n"); ++ else ++ ret = false; ++ } else if (BUS_ERROR(ec)) { ++ if (xec > 2) ++ ret = false; ++ ++ Wprintf("Error during attempted NB data read.\n"); ++ } else if (MEM_ERROR(ec)) { ++ switch (xec) { ++ case 0x4 ... 0xc: ++ Wprintf("%s.\n", f15h_mc2_mce_desc[xec - 0x4]); ++ break; ++ ++ case 0x10 ... 0x14: ++ Wprintf("%s.\n", f15h_mc2_mce_desc[xec - 0x7]); ++ break; ++ ++ default: ++ ret = false; ++ } ++ } ++ ++ return ret; ++} ++ + static void decode_mc2_mce(struct amd_decoder_ops *ops, struct mce *m) + { + u16 ec = EC(m->status); +@@ -741,6 +891,12 @@ struct amd_decoder_ops fam_ops[] = { + .mc1_mce = cat_mc1_mce, + .mc2_mce = k8_mc2_mce, + }, ++ [AMD_F15H] = { ++ .cpu = AMD_F15H, ++ .mc0_mce = f15h_mc0_mce, ++ .mc1_mce = f15h_mc1_mce, ++ .mc2_mce = f15h_mc2_mce, ++ }, + }; + + static void __decode_amd_mc(enum cputype cpu, struct mce *mce) +@@ -760,6 +916,10 @@ static void __decode_amd_mc(enum cputype + case CPU_F14H: + ops = &fam_ops[AMD_F14H]; + break; ++ case CPU_F15H: ++ xec_mask = 0x1f; ++ ops = &fam_ops[AMD_F15H]; ++ break; + default: + Eprintf("Huh? What family is it: 0x%x?!\n", cpu); + return; +Index: mcelog-1.0.1/mcelog.h +=================================================================== +--- mcelog-1.0.1.orig/mcelog.h ++++ mcelog-1.0.1/mcelog.h +@@ -111,6 +111,7 @@ enum cputype { + CPU_F11H, + CPU_F12H, + CPU_F14H, ++ CPU_F15H, + CPU_P4, + CPU_NEHALEM, + CPU_DUNNINGTON, +Index: mcelog-1.0.1/amd.h +=================================================================== +--- mcelog-1.0.1.orig/amd.h ++++ mcelog-1.0.1/amd.h +@@ -97,4 +97,5 @@ enum rrrr_ids { + case CPU_F10H: \ + case CPU_F11H: \ + case CPU_F12H: \ +- case CPU_F14H ++ case CPU_F14H: \ ++ case CPU_F15H +Index: mcelog-1.0.1/mcelog.c +=================================================================== +--- mcelog-1.0.1.orig/mcelog.c ++++ mcelog-1.0.1/mcelog.c +@@ -226,6 +226,7 @@ static char *cputype_name[] = { + [CPU_F11H] = "AMD Griffin", + [CPU_F12H] = "AMD Llano", + [CPU_F14H] = "AMD Bobcat", ++ [CPU_F15H] = "AMD Bulldozer", + [CPU_P4] = "Intel P4", + [CPU_NEHALEM] = "Intel Xeon 5500 series / Core i3/5/7 (\"Nehalem/Westmere\")", + [CPU_DUNNINGTON] = "Intel Xeon 7400 series", +@@ -248,6 +249,7 @@ static struct config_choice cpu_choices[ + { "f11h", CPU_F11H }, + { "f12h", CPU_F12H }, + { "f14h", CPU_F14H }, ++ { "f15h", CPU_F15H }, + { "p4", CPU_P4 }, + { "dunnington", CPU_DUNNINGTON }, + { "xeon74xx", CPU_DUNNINGTON }, diff --git a/add-f16h-support.patch b/add-f16h-support.patch new file mode 100644 index 0000000..a6a4def --- /dev/null +++ b/add-f16h-support.patch @@ -0,0 +1,131 @@ +Add F16h decoding support + +Signed-off-by: Borislav Petkov +Index: mcelog-1.0.1/amd.c +=================================================================== +--- mcelog-1.0.1.orig/amd.c ++++ mcelog-1.0.1/amd.c +@@ -200,6 +200,8 @@ enum cputype select_amd_cputype(u32 fami + return CPU_F14H; + case 0x15: + return CPU_F15H; ++ case 0x16: ++ return CPU_F16H; + default: + break; + } +@@ -687,6 +689,47 @@ static bool f15h_mc2_mce(u16 ec, u8 xec) + return ret; + } + ++static bool f16h_mc2_mce(u16 ec, u8 xec) ++{ ++ u8 r4 = R4(ec); ++ ++ if (!MEM_ERROR(ec)) ++ return false; ++ ++ switch (xec) { ++ case 0x04 ... 0x05: ++ Wprintf("%cBUFF parity error.\n", (r4 == R4_RD) ? 'I' : 'O'); ++ break; ++ ++ case 0x09 ... 0x0b: ++ case 0x0d ... 0x0f: ++ Wprintf("ECC error in L2 tag (%s).\n", ++ ((r4 == R4_GEN) ? "BankReq" : ++ ((r4 == R4_SNOOP) ? "Prb" : "Fill"))); ++ break; ++ ++ case 0x10 ... 0x19: ++ case 0x1b: ++ Wprintf("ECC error in L2 data array (%s).\n", ++ (((r4 == R4_RD) && !(xec & 0x3)) ? "Hit" : ++ ((r4 == R4_GEN) ? "Attr" : ++ ((r4 == R4_EVICT) ? "Vict" : "Fill")))); ++ break; ++ ++ case 0x1c ... 0x1d: ++ case 0x1f: ++ Wprintf("Parity error in L2 attribute bits (%s).\n", ++ ((r4 == R4_RD) ? "Hit" : ++ ((r4 == R4_GEN) ? "Attr" : "Fill"))); ++ break; ++ ++ default: ++ return false; ++ } ++ ++ return true; ++} ++ + static void decode_mc2_mce(struct amd_decoder_ops *ops, struct mce *m) + { + u16 ec = EC(m->status); +@@ -897,6 +940,12 @@ struct amd_decoder_ops fam_ops[] = { + .mc1_mce = f15h_mc1_mce, + .mc2_mce = f15h_mc2_mce, + }, ++ [AMD_F16H] = { ++ .cpu = AMD_F16H, ++ .mc0_mce = cat_mc0_mce, ++ .mc1_mce = cat_mc1_mce, ++ .mc2_mce = f16h_mc2_mce, ++ }, + }; + + static void __decode_amd_mc(enum cputype cpu, struct mce *mce) +@@ -920,6 +969,10 @@ static void __decode_amd_mc(enum cputype + xec_mask = 0x1f; + ops = &fam_ops[AMD_F15H]; + break; ++ case CPU_F16H: ++ xec_mask = 0x1f; ++ ops = &fam_ops[AMD_F16H]; ++ break; + default: + Eprintf("Huh? What family is it: 0x%x?!\n", cpu); + return; +Index: mcelog-1.0.1/mcelog.h +=================================================================== +--- mcelog-1.0.1.orig/mcelog.h ++++ mcelog-1.0.1/mcelog.h +@@ -112,6 +112,7 @@ enum cputype { + CPU_F12H, + CPU_F14H, + CPU_F15H, ++ CPU_F16H, + CPU_P4, + CPU_NEHALEM, + CPU_DUNNINGTON, +Index: mcelog-1.0.1/amd.h +=================================================================== +--- mcelog-1.0.1.orig/amd.h ++++ mcelog-1.0.1/amd.h +@@ -98,4 +98,5 @@ enum rrrr_ids { + case CPU_F11H: \ + case CPU_F12H: \ + case CPU_F14H: \ +- case CPU_F15H ++ case CPU_F15H: \ ++ case CPU_F16H +Index: mcelog-1.0.1/mcelog.c +=================================================================== +--- mcelog-1.0.1.orig/mcelog.c ++++ mcelog-1.0.1/mcelog.c +@@ -227,6 +227,7 @@ static char *cputype_name[] = { + [CPU_F12H] = "AMD Llano", + [CPU_F14H] = "AMD Bobcat", + [CPU_F15H] = "AMD Bulldozer", ++ [CPU_F16H] = "AMD Jaguar", + [CPU_P4] = "Intel P4", + [CPU_NEHALEM] = "Intel Xeon 5500 series / Core i3/5/7 (\"Nehalem/Westmere\")", + [CPU_DUNNINGTON] = "Intel Xeon 7400 series", +@@ -250,6 +251,7 @@ static struct config_choice cpu_choices[ + { "f12h", CPU_F12H }, + { "f14h", CPU_F14H }, + { "f15h", CPU_F15H }, ++ { "f16h", CPU_F16H }, + { "p4", CPU_P4 }, + { "dunnington", CPU_DUNNINGTON }, + { "xeon74xx", CPU_DUNNINGTON }, diff --git a/mcelog.changes b/mcelog.changes index 2bed1a3..9fa8614 100644 --- a/mcelog.changes +++ b/mcelog.changes @@ -1,3 +1,17 @@ +------------------------------------------------------------------- +Fri May 16 15:47:18 UTC 2014 - trenn@suse.de + +- Add mce decoding support for latest AMD CPUs (bnc#871881). +- Implementation done by Borislav Petkov + * Add patches/Start-consolidating-AMD-specific-stuff.patch + * Add add-defines.patch + * Add add-f10h-support.patch + * Add add-f11h-support.patch + * Add add-f12h-support.patch + * Add add-f14h-support.patch + * Add add-f15h-support.patch + * Add add-f16h-support.patch + ------------------------------------------------------------------- Mon Apr 28 16:49:38 UTC 2014 - trenn@suse.de diff --git a/mcelog.spec b/mcelog.spec index 262845f..284be88 100644 --- a/mcelog.spec +++ b/mcelog.spec @@ -35,6 +35,14 @@ Source4: 90-mcelog.rules Source6: README.email_setup Patch1: email.patch Patch2: mcelog_invert_prefill_db_warning.patch +Patch3: Start-consolidating-AMD-specific-stuff.patch +Patch4: patches/add-defines.patch +Patch5: patches/add-f10h-support.patch +Patch6: patches/add-f11h-support.patch +Patch7: patches/add-f12h-support.patch +Patch8: patches/add-f14h-support.patch +Patch9: patches/add-f15h-support.patch +Patch10: patches/add-f16h-support.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build PreReq: %fillup_prereq Url: https://git.kernel.org/cgit/utils/cpu/mce/mcelog.git @@ -62,6 +70,14 @@ Authors: %setup -q %patch1 -p1 %patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 %build export SUSE_ASNEEDED=0 diff --git a/mcelog.systemd b/mcelog.systemd index b97582a..fa087c2 100644 --- a/mcelog.systemd +++ b/mcelog.systemd @@ -4,7 +4,6 @@ ConditionVirtualization=false [Service] EnvironmentFile=-/etc/sysconfig/mcelog -#warning: if this fails is due to a known kernel bug, fix that instead ! ExecStart=/usr/sbin/mcelog --ignorenodev --daemon --foreground StandardOutput=syslog