]> www.infradead.org Git - users/mchehab/edactool.git/commitdiff
edactool: add its own parser for ras:mc_event
authorMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 26 Feb 2013 21:31:28 +0000 (18:31 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 26 Feb 2013 21:43:54 +0000 (18:43 -0300)
The ras:mc_event is too complex for the built-in parser. Adds its
own parser for it, that will produce an output similar to the
in-kernel one.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
edactool.c

index 15da181f5807f14467c5f1f8e0e88f1877dd8b2a..48dc0c1d7716f0884c666d52db5f621e4739158c 100644 (file)
@@ -39,7 +39,7 @@
  * blocks on read(). So, we need to sleep for a while, to avoid spending
  * too much CPU cycles. A fix for it is expected for 3.10.
  */
-#define POLLING_TIME 15
+#define POLLING_TIME 3
 
 #define PAGE_SIZE 0x400
 /* Test for a little-endian machine */
@@ -95,7 +95,118 @@ static int toggle_ras_mc_event(int enable)
 /*
  * Tracing read code
  */
-static void parse_ras_data(struct pevent *pevent, struct kbuffer *kbuf, void *data, unsigned long long time_stamp)
+
+/* Should match the code at Kernel's include/linux/edac.c */
+enum hw_event_mc_err_type {
+       HW_EVENT_ERR_CORRECTED,
+       HW_EVENT_ERR_UNCORRECTED,
+       HW_EVENT_ERR_FATAL,
+       HW_EVENT_ERR_INFO,
+};
+
+static char *mc_event_error_type(unsigned long long err_type)
+{
+       switch (err_type) {
+       case HW_EVENT_ERR_CORRECTED:
+               return "Corrected";
+       case HW_EVENT_ERR_UNCORRECTED:
+               return "Uncorrected";
+       case HW_EVENT_ERR_FATAL:
+               return "Fatal";
+       default:
+       case HW_EVENT_ERR_INFO:
+               return "Info";
+       }
+}
+
+static int ras_mc_event_handler(struct trace_seq *s,
+                               struct pevent_record *record,
+                               struct event_format *event, void *context)
+{
+       int len;
+       unsigned long long cnt, val, top_l, mid_l, low_l;
+       const char *str;
+
+       if (pevent_get_field_val(s,  event, "error_count", record, &cnt, 0) < 0)
+               return -1;
+       trace_seq_printf(s, "%lld ", cnt);
+
+       if (pevent_get_field_val(s, event, "error_type", record, &val, 1) < 0)
+               return -1;
+       trace_seq_puts(s, mc_event_error_type(val));
+       if (cnt > 1)
+               trace_seq_puts(s, " errors:");
+       else
+               trace_seq_puts(s, " error:");
+       str = pevent_get_field_raw(s, event, "msg", record, &len, 1);
+       if (!str)
+               return -1;
+       if (*str) {
+               trace_seq_puts(s, " ");
+               trace_seq_puts(s, str);
+       }
+
+       str = pevent_get_field_raw(s, event, "label", record, &len, 1);
+       if (!str)
+               return -1;
+       if (*str) {
+               trace_seq_puts(s, " on ");
+               trace_seq_puts(s, str);
+       }
+
+       trace_seq_puts(s, "(");
+       if (pevent_get_field_val(s,  event, "mc_index", record, &val, 0) < 0)
+               return -1;
+       trace_seq_printf(s, " mc: %lld", val);
+
+       if (pevent_get_field_val(s,  event, "top_layer", record, &top_l, 0) < 0)
+               return -1;
+       if (pevent_get_field_val(s,  event, "middle_layer", record, &mid_l, 0) < 0)
+               return -1;
+       if (pevent_get_field_val(s,  event, "lower_layer", record, &low_l, 0) < 0)
+               return -1;
+
+       if (top_l >= 0 || mid_l >= 0 || low_l >= 0) {
+               if (low_l >= 0)
+                       trace_seq_printf(s, " location: %lld:%lld:%lld",
+                                       top_l, mid_l, low_l);
+               else if (mid_l >= 0)
+                       trace_seq_printf(s, " location: %lld:%lld",
+                                        top_l, mid_l);
+               else
+                       trace_seq_printf(s, " location: %lld", top_l);
+       }
+
+       if (pevent_get_field_val(s,  event, "address", record, &val, 0) < 0)
+               return -1;
+       if (val)
+               trace_seq_printf(s, " address: 0x%08llx", val);
+
+       if (pevent_get_field_val(s,  event, "grain", record, &val, 0) < 0)
+               return -1;
+       trace_seq_printf(s, " grain: %lld", val);
+
+
+       if (pevent_get_field_val(s,  event, "syndrome", record, &val, 0) < 0)
+               return -1;
+       if (val)
+               trace_seq_printf(s, " syndrome: 0x%08llx", val);
+
+       str = pevent_get_field_raw(s, event, "driver_detail", record, &len, 1);
+       if (!str)
+               return -1;
+       if (*str) {
+               trace_seq_puts(s, " ");
+               trace_seq_puts(s, str);
+       }
+       trace_seq_puts(s, ")");
+
+       return 0;
+}
+
+
+static void parse_ras_data(struct pevent *pevent, struct kbuffer *kbuf,
+                          void *data, unsigned long long time_stamp)
 {
        struct pevent_record record;
        struct trace_seq s;
@@ -113,7 +224,8 @@ static void parse_ras_data(struct pevent *pevent, struct kbuffer *kbuf, void *da
        trace_seq_do_printf(&s);
 }
 
-static int read_ras_event(int fd, struct pevent *pevent, struct kbuffer *kbuf, void *page)
+static int read_ras_event(int fd, struct pevent *pevent, struct kbuffer *kbuf,
+                         void *page)
 {
        unsigned size;
        unsigned long long time_stamp;
@@ -174,7 +286,7 @@ static int handle_ras_events_cpu(struct pevent *pevent, int cpu)
                perror("Can't allocate page");
                return errno;
        }
-
+printf("Endian: %d\n", ENDIAN);
        kbuf = kbuffer_alloc(KBUFFER_LSIZE_8, ENDIAN);
        if (!kbuf) {
                perror("Can't allocate kbuf");
@@ -242,6 +354,9 @@ static int handle_ras_events(void)
                goto free_pevent;
        }
 
+       pevent_register_event_handler(pevent, -1, "ras", "mc_event",
+                                     ras_mc_event_handler, NULL);
+
        rc = pevent_parse_event(pevent, page, size, "ras");
        free(page);
        if (rc)