]> www.infradead.org Git - users/mchehab/rasdaemon.git/commitdiff
Improve MCE parser for AMD k8
authorMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 16 May 2013 11:16:12 +0000 (08:16 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 16 May 2013 14:44:57 +0000 (11:44 -0300)
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
mce-amd-k8.c
mce-intel.c
ras-aer-handler.c
ras-mce-handler.c
ras-mce-handler.h

index baa3fe0ef427a130f8178c08898e540c528479d8..7cdaa1487e282a4a90fbba420245287cdbd4524a 100644 (file)
 */
 
 #include <stdio.h>
+#include <string.h>
 
 #include "ras-mce-handler.h"
 
 #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)
@@ -118,224 +120,274 @@ static char *highbits[32] = {
        [0] = "err cpu0",
 };
 
-static void decode_k8_generic_errcode(struct ras_events *ras,
-                                     struct trace_seq *s, struct mce_event *e)
+#define IGNORE_HIGHBITS                ((1 << 31) || (1 << 28) || (1 << 26))
+
+static void decode_k8_generic_errcode(uint64_t status, char *buf, size_t *len)
 {
-       uint64_t status = e->status;
+       char tmp_buf[4096];
        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)))) {
-                       trace_seq_printf(s,  "       bit%d = %s\n", i + 32, highbits[i]);
-               }
+       int i, n;
+       char *p = buf;
+
+       /* Translate the highest bits */
+       n = bitfield_msg(tmp_buf, sizeof(*len), highbits, 32, IGNORE_HIGHBITS,
+                        32, status);
+       if (n) {
+               n = snprintf(p, *len, "%s ", tmp_buf);
+               p += n;
+               *len -= n;
        }
 
        if ((errcode & 0xfff0) == 0x0010) {
-               trace_seq_printf(s,  "  TLB error '%s transaction, level %s'\n",
+               n = snprintf(p, *len, "LB error '%s transaction, level %s'",
                       transaction[(errcode >> 2) & 3],
                       cachelevel[errcode & 3]);
+               p += n;
+               *len -= n;
        }
        else if ((errcode & 0xff00) == 0x0100) {
-               trace_seq_printf(s,  "  memory/cache error '%s mem transaction, %s transaction, level %s'\n",
-                      memtrans[(errcode >> 4) & 0xf],
-                      transaction[(errcode >> 2) & 3],
-                      cachelevel[errcode & 3]);
+               n = snprintf(p, *len,
+                            "memory/cache error '%s mem transaction, %s transaction, level %s'",
+                            memtrans[(errcode >> 4) & 0xf],
+                            transaction[(errcode >> 2) & 3],
+                            cachelevel[errcode & 3]);
+               p += n;
+               *len -= n;
        }
        else if ((errcode & 0xf800) == 0x0800) {
-               trace_seq_printf(s,  "  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)]);
+               n = snprintf(p, *len,
+                            "bus error '%s, %s: %s mem transaction, %s access, level %s'",
+                            partproc[(errcode >> 9) & 0x3],
+                            timeout[(errcode >> 8) & 1],
+                            memtrans[(errcode >> 4) & 0xf],
+                            memoryio[(errcode >> 2) & 0x3],
+                            cachelevel[(errcode & 0x3)]);
+               p += n;
+               *len -= n;
        }
 }
 
-static void decode_k8_dc_mc(struct ras_events *ras,
-                           struct trace_seq *s, struct mce_event *e)
+static void decode_k8_dc_mc(uint64_t status, char *buf, size_t *len)
 {
-       uint64_t status = e->status;
        unsigned short exterrcode = (status >> 16) & 0x0f;
        unsigned short errcode = status & 0xffff;
+       int n;
+       char *p = buf;
 
-       if(status & (3ULL << 45)) {
-               trace_seq_printf(s,  "  Data cache ECC error (syndrome %x)",
+       if (status & (3ULL << 45)) {
+               n = snprintf(p, *len, "Data cache ECC error (syndrome %x)",
                       (uint32_t) (status >> 47) & 0xff);
-               if(status&(1ULL << 40)) {
-                       trace_seq_printf(s, " found by scrubber");
+               p += n;
+               *len -= n;
+               if(status & (1ULL << 40)) {
+                       n = snprintf(p, *len, " found by scrubber");
+                       p += n;
+                       *len -= n;
                }
-               trace_seq_printf(s, "\n");
        }
 
        if ((errcode & 0xfff0) == 0x0010) {
-               trace_seq_printf(s,  "  TLB parity error in %s array\n",
+               if (p != buf) {
+                       n = snprintf(p, *len, " ");
+                       p += n;
+                       *len -= n;
+               }
+               n = snprintf(p, *len, "TLB parity error in %s array",
                       (exterrcode == 0) ? "physical" : "virtual");
+               p += n;
+               *len -= n;
+       }
+
+       if (p != buf) {
+               n = snprintf(p, *len, " ");
+               p += n;
+               *len -= n;
        }
 
-       decode_k8_generic_errcode(ras, s, e);
+       decode_k8_generic_errcode(status, p, len);
 }
 
-static void decode_k8_ic_mc(struct ras_events *ras,
-                           struct trace_seq *s, struct mce_event *e)
+static void decode_k8_ic_mc(uint64_t status, char *buf, size_t *len)
 {
-       uint64_t status = e->status;
        unsigned short exterrcode = (status >> 16) & 0x0f;
        unsigned short errcode = status & 0xffff;
+       int n;
+       char *p = buf;
 
-       if(status & (3ULL << 45)) {
-               trace_seq_printf(s, "  Instruction cache ECC error\n");
+       if (status & (3ULL << 45)) {
+               n = snprintf(p, *len, "Instruction cache ECC error");
+               p += n;
+               *len -= n;
        }
 
        if ((errcode & 0xfff0) == 0x0010) {
-               trace_seq_printf(s, "  TLB parity error in %s array\n",
+               if (p != buf) {
+                       n = snprintf(p, *len, " ");
+                       p += n;
+                       *len -= n;
+               }
+               n = snprintf(p, *len, "TLB parity error in %s array",
                       (exterrcode == 0) ? "physical" : "virtual");
+               p += n;
+               *len -= n;
+       }
+       if (p != buf) {
+               n = snprintf(p, *len, " ");
+               p += n;
+               *len -= n;
        }
 
-       decode_k8_generic_errcode(ras, s, e);
+       decode_k8_generic_errcode(status, p, len);
 }
 
-static void decode_k8_bu_mc(struct ras_events *ras,
-                           struct trace_seq *s, struct mce_event *e)
+static void decode_k8_bu_mc(uint64_t status, char *buf, size_t *len)
 {
-       uint64_t status = e->status;
        unsigned short exterrcode = (status >> 16) & 0x0f;
+       int n;
+       char *p = buf;
+
+       if (status & (3ULL << 45)) {
+               n = snprintf(p, *len, "L2 cache ECC error");
+               p += n;
+               *len -= n;
+       }
 
-       if(status & (3ULL << 45)) {
-               trace_seq_printf(s, "  L2 cache ECC error\n");
+       if (p != buf) {
+               n = snprintf(p, *len, " ");
+               p += n;
+               *len -= n;
        }
 
-       trace_seq_printf(s, "  %s array error\n",
-              (exterrcode == 0) ? "Bus or cache" : "Cache tag");
+       n = snprintf(p, *len, "%s array error",
+                   !exterrcode ? "Bus or cache" : "Cache tag");
 
-       decode_k8_generic_errcode(ras, s, e);
-}
+       if (p != buf) {
+               n = snprintf(p, *len, " ");
+               p += n;
+               *len -= n;
+       }
 
-static void decode_k8_ls_mc(struct ras_events *ras,
-                           struct trace_seq *s, struct mce_event *e)
-{
-       decode_k8_generic_errcode(ras, s, e);
+       decode_k8_generic_errcode(status, p, len);
 }
 
-static void decode_k8_nb_mc(struct ras_events *ras,
-                           struct trace_seq *s, struct mce_event *e,
+static void decode_k8_nb_mc(uint64_t status, char *buf, size_t *len,
                            unsigned *memerr)
 {
-       uint64_t status = e->status;
        unsigned short exterrcode = (status >> 16) & 0x0f;
+       int n;
+       char *p = buf;
 
-       trace_seq_printf(s, "  Northbridge %s\n", nbextendederr[exterrcode]);
+       n = snprintf(buf, *len, "Northbridge %s", nbextendederr[exterrcode]);
+       p += n;
+       *len -= n;
 
+       n = 0;
        switch (exterrcode) {
        case 0:
                *memerr = 1;
-               trace_seq_printf(s, "  ECC syndrome = %x\n",
-                      (uint32_t) (status >> 47) & 0xff);
+               n = snprintf(p, *len, " ECC syndrome = %x",
+                           (uint32_t) (status >> 47) & 0xff);
                break;
        case 8:
                *memerr = 1;
-               trace_seq_printf(s, "  Chipkill ECC syndrome = %x\n",
-                      (uint32_t) ((((status >> 24) & 0xff) << 8) | ((status >> 47) & 0xff)));
+               n = snprintf(p, *len, " Chipkill ECC syndrome = %x",
+                           (uint32_t) ((((status >> 24) & 0xff) << 8) | ((status >> 47) & 0xff)));
                break;
        case 1:
        case 2:
        case 3:
        case 4:
        case 6:
-               trace_seq_printf(s, "  link number = %x\n",
-                      (uint32_t) (status >> 36) & 0xf);
+               n = snprintf(p, *len, " link number = %x\n",
+                            (uint32_t) (status >> 36) & 0xf);
                break;
        }
+       p += n;
+       *len -= n;
 
-       decode_k8_generic_errcode(ras, s, e);
-}
+       if (p != buf) {
+               n = snprintf(p, *len, " ");
+               p += n;
+               *len -= n;
+       }
 
-static void decode_k8_fr_mc(struct ras_events *ras,
-                           struct trace_seq *s, struct mce_event *e)
-{
-       decode_k8_generic_errcode(ras, s, e);
+       decode_k8_generic_errcode(status, p, len);
 }
 
-#if 0
-static void decode_k8_threshold(u64 misc)
+static void decode_k8_threashold(uint64_t misc, char *buf, size_t *len)
 {
-       if (misc & MCI_THRESHOLD_OVER)
-               trace_seq_printf(s, "  Threshold error count overflow\n");
-}
-#endif
+       int n;
+       char *p = buf;
 
-static char *bank_name(uint64_t status, unsigned bank)
-{
-       static char buf[64];
-       char *s = "unknown";
-
-       /* Handle GART errors */
-       if (bank == 4) {
-               unsigned short exterrcode = (status >> 16) & 0x0f;
-               if (exterrcode == 5 && (status & (1ULL << 61))) {
-                       sprintf(buf, "GART error");
-                       return 0;
-               }
+       if (misc & MCI_THRESHOLD_OVER) {
+               n = snprintf(p, *len, "  Threshold error count overflow\n");
+               p += n;
+               *len -= n;
        }
+}
 
-       if (bank < ARRAY_SIZE(k8bank))
-               s = k8bank[bank];
-       else if (bank >= K8_MCE_THRESHOLD_BASE &&
-                bank < K8_MCE_THRESHOLD_TOP)
-               s = k8threshold[bank - K8_MCE_THRESHOLD_BASE];
-       else {
-               sprintf(buf, "bank=%x", bank);
-               return buf;
-       }
-       snprintf(buf, sizeof(buf) - 1, "%s (bank=%d)", s, bank);
-       return buf;
+static void bank_name(struct mce_event *e)
+{
+       char *buf = e->bank_name;
+       char *s;
+
+       if (e->bank < ARRAY_SIZE(k8bank))
+               s = k8bank[e->bank];
+       else if (e->bank >= K8_MCE_THRESHOLD_BASE &&
+                e->bank < K8_MCE_THRESHOLD_TOP)
+               s = k8threshold[e->bank - K8_MCE_THRESHOLD_BASE];
+       else
+               return;         /* Use the generic parser for bank */
+
+       snprintf(buf, sizeof(buf) - 1, "%s (bank=%d)", s, e->bank);
 }
 
-void dump_amd_k8_event(struct ras_events *ras,
-                      struct trace_seq *s, struct mce_event *e)
+int parse_amd_k8_event(struct ras_events *ras, struct mce_event *e)
 {
        unsigned unknown_bank = 0;
        unsigned ismemerr = 0;
+       char *buf = e->error_msg;
+       size_t len = sizeof(e->error_msg);
+
+       /* Don't handle GART errors */
+       if (e->bank == 4) {
+               unsigned short exterrcode = (e->status >> 16) & 0x0f;
+               if (exterrcode == 5 && (e->status & (1ULL << 61))) {
+                       return -1;
+               }
+       }
 
-       trace_seq_printf(s, "%s ",bank_name(e->status, e->bank));
+       bank_name(e);
 
        switch (e->bank) {
        case 0:
-               decode_k8_dc_mc(ras, s, e);
+               decode_k8_dc_mc(e->status, buf, &len);
                break;
        case 1:
-               decode_k8_ic_mc(ras, s, e);
+               decode_k8_ic_mc(e->status, buf, &len);
                break;
        case 2:
-               decode_k8_bu_mc(ras, s, e);
+               decode_k8_bu_mc(e->status, buf, &len);
                break;
-       case 3:
-               decode_k8_ls_mc(ras, s, e);
+       case 3:         /* LS */
+               decode_k8_generic_errcode(e->status, buf, &len);
                break;
        case 4:
-               decode_k8_nb_mc(ras, s, e, &ismemerr);
+               decode_k8_nb_mc(e->status, buf, &len, &ismemerr);
+               break;
+       case 5:         /* FR */
+               decode_k8_generic_errcode(e->status, buf, &len);
                break;
-       case 5:
-               decode_k8_fr_mc(ras, s, e);
+       case K8_MCE_THRESHOLD_BASE ... K8_MCE_THRESHOLD_TOP:
+               decode_k8_threashold(e->misc, buf, &len);
                break;
        default:
-               trace_seq_printf(s, "Don't know how to decode this bank");
-               unknown_bank = 1;
+               strcpy(e->error_msg, "Don't know how to decode this bank");
        }
-       trace_seq_printf(s, ", mcgcap= %d ", e->mcgcap);
-       trace_seq_printf(s, ", mcgstatus= %d ", e->mcgstatus);
-       trace_seq_printf(s, ", status= %d ", e->status);
-       trace_seq_printf(s, ", addr= %d ", e->addr);
-       trace_seq_printf(s, ", misc= %d ", e->misc);
-       trace_seq_printf(s, ", ip= %d ", e->ip);
-       trace_seq_printf(s, ", tsc= %d ", e->tsc);
-       trace_seq_printf(s, ", walltime= %d ", e->walltime);
-       trace_seq_printf(s, ", cpu= %d ", e->cpu);
-       trace_seq_printf(s, ", cpuid= %d ", e->cpuid);
-       trace_seq_printf(s, ", apicid= %d ", e->apicid);
-       trace_seq_printf(s, ", socketid= %d ", e->socketid);
-       trace_seq_printf(s, ", cs= %d ", e->cs);
-       trace_seq_printf(s, ", cpuvendor= %d", e->cpuvendor);
+
+       /* IP doesn't matter on memory errors */
+       if (ismemerr)
+               e->ip = 0;
+
+       return 0;
 }
index 6b90004c930d60e5af4c5dbb46b238bdf1216363..39b8d7251bd2b502de13b6abd2c134bfd38e2f1a 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
 
-#include <stdio.h>
+#include <string.h>
 
 #include "ras-mce-handler.h"
 
 #define MCE_THERMAL_BANK       (MCE_EXTENDED_BANK + 0)
 #define MCE_TIMEOUT_BANK        (MCE_EXTENDED_BANK + 90)
 
-static char *bank_name(unsigned bank)
+static void bank_name(struct mce_event *e)
 {
-       static char buf[64];
+       char *buf = e->bank_name;
 
-       switch (bank) {
+       switch (e->bank) {
        case MCE_THERMAL_BANK:
-               return "THERMAL EVENT";
+               strcpy(buf, "THERMAL EVENT");
+               break;
        case MCE_TIMEOUT_BANK:
-               return "Timeout waiting for exception on other CPUs";
+               strcpy(buf, "Timeout waiting for exception on other CPUs");
+               break;
        default:
-               sprintf(buf, "bank=%x", bank);
-               return buf;
+               break;
        }
 }
 
-void dump_intel_event(struct ras_events *ras,
-                     struct trace_seq *s, struct mce_event *e)
+int parse_intel_event(struct ras_events *ras, struct mce_event *e)
 {
-       trace_seq_printf(s, "%s ",bank_name(e->bank));
-       trace_seq_printf(s, ", mcgcap= %d ", e->mcgcap);
-       trace_seq_printf(s, ", mcgstatus= %d ", e->mcgstatus);
-       trace_seq_printf(s, ", status= %d ", e->status);
-       trace_seq_printf(s, ", addr= %d ", e->addr);
-       trace_seq_printf(s, ", misc= %d ", e->misc);
-       trace_seq_printf(s, ", ip= %d ", e->ip);
-       trace_seq_printf(s, ", tsc= %d ", e->tsc);
-       trace_seq_printf(s, ", walltime= %d ", e->walltime);
-       trace_seq_printf(s, ", cpu= %d ", e->cpu);
-       trace_seq_printf(s, ", cpuid= %d ", e->cpuid);
-       trace_seq_printf(s, ", apicid= %d ", e->apicid);
-       trace_seq_printf(s, ", socketid= %d ", e->socketid);
-       trace_seq_printf(s, ", cs= %d ", e->cs);
-       trace_seq_printf(s, ", cpuvendor= %d", e->cpuvendor);
+       bank_name(e);
+
+       return 0;
 }
 
index 0543bb6007c939e2b7525555c76d272695de541e..a9d5a3997efc4ed71c8e9bb05d9e81446d47e7a5 100644 (file)
@@ -46,33 +46,6 @@ static const char *aer_errors[32] = {
        [20] = "Unsupported Request",
 };
 
-char *aer_status_msg(char *buf, size_t len, unsigned int status)
-{
-       int i, n;
-       char *p = buf;
-
-       len--;
-
-       for (i = 0; i < 32; i++) {
-               if (status & (1 << i)) {
-                       if (p != buf) {
-                               n = snprintf(p, len, ", ");
-                               len -= n;
-                               p += n;
-                       }
-                       if (!aer_errors[i])
-                               n = snprintf(p, len, "BIT(%d)", i);
-                       else
-                               n = snprintf(p, len, "%s", aer_errors[i]);
-                       len -= n;
-                       p += n;
-               }
-       }
-
-       *p = 0;
-       return buf;
-}
-
 int ras_aer_event_handler(struct trace_seq *s,
                         struct pevent_record *record,
                         struct event_format *event, void *context)
@@ -114,7 +87,8 @@ int ras_aer_event_handler(struct trace_seq *s,
                return -1;
 
        /* Fills the error buffer */
-       ev.msg = aer_status_msg(buf, sizeof(buf), val);
+       bitfield_msg(buf, sizeof(buf), aer_errors, 32, 0, 0, val);
+       ev.msg = buf;
        trace_seq_printf(s, "%s ", ev.msg);
 
        if (pevent_get_field_val(s, event, "severity", record, &val, 1) < 0)
index 79e24229b3646f3bbf3b403dbaa0cd61c4d47fad..a5df82e7ab2f82bf2b550e4d97ae917ef84fe29d 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdint.h>
 #include "libtrace/kbuffer.h"
 #include "ras-mce-handler.h"
 #include "ras-record.h"
@@ -202,39 +203,45 @@ int register_mce_handler(struct ras_events *ras)
  * End of mcelog's code
  */
 
-static void dump_mce_event(struct trace_seq *s, struct mce_event *e)
+unsigned bitfield_msg(char *buf, size_t len, char **bitarray, unsigned array_len,
+                     unsigned bit_offset, unsigned ignore_bits,
+                     uint64_t status)
 {
-       trace_seq_printf(s, "bank=%s ",e->bank);
-       trace_seq_printf(s, ", mcgcap= %d ", e->mcgcap);
-       trace_seq_printf(s, ", mcgstatus= %d ", e->mcgstatus);
-       trace_seq_printf(s, ", status= %d ", e->status);
-       trace_seq_printf(s, ", addr= %d ", e->addr);
-       trace_seq_printf(s, ", misc= %d ", e->misc);
-       trace_seq_printf(s, ", ip= %d ", e->ip);
-       trace_seq_printf(s, ", tsc= %d ", e->tsc);
-       trace_seq_printf(s, ", walltime= %d ", e->walltime);
-       trace_seq_printf(s, ", cpu= %d ", e->cpu);
-       trace_seq_printf(s, ", cpuid= %d ", e->cpuid);
-       trace_seq_printf(s, ", apicid= %d ", e->apicid);
-       trace_seq_printf(s, ", socketid= %d ", e->socketid);
-       trace_seq_printf(s, ", cs= %d ", e->cs);
-       trace_seq_printf(s, ", cpuvendor= %d", e->cpuvendor);
-}
+       int i, n;
+       char *p = buf;
 
+       len--;
 
-int ras_mce_event_handler(struct trace_seq *s,
-                         struct pevent_record *record,
-                         struct event_format *event, void *context)
+       for (i = 0; i < array_len; i++) {
+               if (status & ignore_bits)
+                       continue;
+               if (status & (1 <<  (i + bit_offset))) {
+                       if (p != buf) {
+                               n = snprintf(p, len, ", ");
+                               len -= n;
+                               p += n;
+                       }
+                       if (!bitarray[i])
+                               n = snprintf(p, len, "BIT%d", i + bit_offset);
+                       else
+                               n = snprintf(p, len, "%s", bitarray[i]);
+                       len -= n;
+                       p += n;
+               }
+       }
+
+       *p = 0;
+       return p - buf;
+}
+
+static void report_mce_event(struct ras_events *ras,
+                            struct pevent_record *record,
+                            struct trace_seq *s, struct mce_event *e)
 {
-       int len;
        unsigned long long val;
-       struct ras_events *ras = context;
        time_t now;
        struct tm *tm;
-       struct ras_aer_event ev;
-       char buf[1024];
        struct mce_priv *mce = ras->mce_priv;
-       struct mce_event e;
 
        /*
         * Newer kernels (3.10-rc1 or upper) provide an uptime clock.
@@ -252,11 +259,84 @@ int ras_mce_event_handler(struct trace_seq *s,
 
        tm = localtime(&now);
        if (tm)
-               strftime(ev.timestamp, sizeof(ev.timestamp),
+               strftime(e->timestamp, sizeof(e->timestamp),
                         "%Y-%m-%d %H:%M:%S %z", tm);
-       trace_seq_printf(s, "%s ", ev.timestamp);
+       trace_seq_printf(s, "%s ", e->timestamp);
+
+       if (*e->bank_name)
+               trace_seq_printf(s, "%s", e->bank_name);
+       else
+               trace_seq_printf(s, "bank=%x", e->bank);
+
+       trace_seq_printf(s, ", status= %d ", e->status);
+       if (*e->error_msg)
+               trace_seq_printf(s, ", %s ", e->error_msg);
+
+#if 0
+       /*
+        * While the logic for decoding tsc is there at mcelog, why to
+        * decode/print it, if we already got the uptime from the
+        * tracing event? Let's just discard it for now.
+        */
+       trace_seq_printf(s, ", tsc= %d ", e->tsc);
+       trace_seq_printf(s, ", walltime= %d ", e->walltime);
+#endif
 
        trace_seq_printf(s, "CPU: %s, ", cputype_name[mce->cputype]);
+       trace_seq_printf(s, ", cpu= %d ", e->cpu);
+       trace_seq_printf(s, ", socketid= %d ", e->socketid);
+
+#if 0
+       /*
+        * The CPU vendor is already reported from mce->cputype
+        */
+       trace_seq_printf(s, ", cpuvendor= %d", e->cpuvendor);
+       trace_seq_printf(s, ", cpuid= %d ", e->cpuid);
+#endif
+
+       if (e->ip)
+               trace_seq_printf(s, ", ip= %d%s ",
+                                !(e->mcgstatus & MCG_STATUS_EIPV) ? " (INEXACT)" : "",
+                                e->ip);
+
+       if (e->cs)
+               trace_seq_printf(s, ", cs= %d ", e->cs);
+
+       if (e->status & MCI_STATUS_MISCV)
+               trace_seq_printf(s, ", misc= %d ", e->misc);
+
+       if (e->status & MCI_STATUS_ADDRV)
+               trace_seq_printf(s, ", addr= %d ", e->addr);
+
+       trace_seq_printf(s, ", mcgstatus= %d ", e->mcgstatus);
+
+       if (e->mcgcap)
+               trace_seq_printf(s, ", mcgcap= %d ", e->mcgcap);
+
+       trace_seq_printf(s, ", apicid= %d ", e->apicid);
+
+       /*
+        * FIXME: The original mcelog userspace tool uses DMI to map from
+        * address to DIMM. From the comments there, the code there doesn't
+        * take interleaving sets into account. Also, it is known that
+        * BIOS is generally not reliable enough to associate DIMM labels
+        * with addresses.
+        * As, in thesis, we shouldn't be receiving memory error reports via
+        * MCE, as they should go via EDAC traces, let's not do it.
+        */
+}
+
+int ras_mce_event_handler(struct trace_seq *s,
+                         struct pevent_record *record,
+                         struct event_format *event, void *context)
+{
+       unsigned long long val;
+       struct ras_events *ras = context;
+       struct mce_priv *mce = ras->mce_priv;
+       struct mce_event e;
+       int rc;
+
+       memset(&e, 0, sizeof(e));
 
        /* Parse the MCE error data */
        if (pevent_get_field_val(s, event, "mcgcap", record, &val, 1) < 0)
@@ -307,12 +387,16 @@ int ras_mce_event_handler(struct trace_seq *s,
 
        switch (mce->cputype) {
        case CPU_GENERIC:
-               dump_mce_event(s, &e);
+               break;
        case CPU_K8:
-               dump_amd_k8_event(ras, s, &e);
+               rc = parse_amd_k8_event(ras, &e);
+               break;
        default:                        /* All other CPU types are Intel */
-               dump_intel_event(ras, s, &e);
+               rc = parse_intel_event(ras, &e);
        }
 
-       return 0;
+       if (rc)
+               return rc;
+
+       report_mce_event(ras, record, s, &e);
 }
index 0f5cd1ea51fe2d2de3d1618bb3079780ae995b48..9267681b7ed6471cb352b8fe0766d6fb22e78a88 100644 (file)
@@ -45,6 +45,7 @@ enum cputype {
 };
 
 struct mce_event {
+       /* Unparsed data, obtained directly from MCE tracing */
        uint64_t        mcgcap;
        uint64_t        mcgstatus;
        uint64_t        status;
@@ -60,6 +61,11 @@ struct mce_event {
        uint8_t         cs;
        uint8_t         bank;
        uint8_t         cpuvendor;
+
+       /* Parsed data */
+       char            timestamp[64];
+       char            bank_name[64];
+       char            error_msg[4096];
 };
 
 struct mce_priv {
@@ -72,19 +78,40 @@ struct mce_priv {
        char *processor_flags;
 };
 
+/* register and handling routines */
 int register_mce_handler(struct ras_events *ras);
 int ras_mce_event_handler(struct trace_seq *s,
                          struct pevent_record *record,
                          struct event_format *event, void *context);
 
+/* Ancillary routines */
+
+unsigned bitfield_msg(char *buf, size_t len, char **bitarray, unsigned array_len,
+                     unsigned bit_offset, unsigned ignore_bits,
+                     uint64_t status);
+
 /* Software defined banks */
 #define MCE_EXTENDED_BANK      128
 
+#define MCI_THRESHOLD_OVER  (1ULL<<48)  /* threshold error count overflow */
+
+#define MCI_STATUS_VAL   (1ULL<<63)  /* valid error */
+#define MCI_STATUS_OVER  (1ULL<<62)  /* previous errors lost */
+#define MCI_STATUS_UC    (1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN    (1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59)  /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58)  /* addr reg. valid */
+#define MCI_STATUS_PCC   (1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S    (1ULL<<56)  /* signalled */
+#define MCI_STATUS_AR   (1ULL<<55)  /* action-required */
+
+#define MCG_STATUS_RIPV  (1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV  (1ULL<<1)   /* eip points to correct instruction */
+#define MCG_STATUS_MCIP  (1ULL<<2)   /* machine check in progress */
+
 /* Those functions are defined on per-cpu vendor C files */
-void dump_intel_event(struct ras_events *ras,
-                     struct trace_seq *s, struct mce_event *e);
+int parse_intel_event(struct ras_events *ras, struct mce_event *e);
 
-void dump_amd_k8_event(struct ras_events *ras,
-                      struct trace_seq *s, struct mce_event *e);
+int parse_amd_k8_event(struct ras_events *ras, struct mce_event *e);
 
 #endif