You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
489 lines
14 KiB
489 lines
14 KiB
From 5662e5376adcc45da43d7818c8ac1882883c18ac Mon Sep 17 00:00:00 2001 |
|
From: Tyler Baicar <tbaicar@codeaurora.org> |
|
Date: Tue, 12 Sep 2017 14:58:25 -0600 |
|
Subject: [PATCH 1/2] rasdaemon: add support for ARM events |
|
|
|
Add support to handle the ARM kernel trace events |
|
which cover RAS ARM processor errors. |
|
|
|
[V4]: fix arm_event_tab usage |
|
|
|
Change-Id: Ife99c97042498d5fad4d9b8e873ecfba6a47947d |
|
Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org> |
|
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com> |
|
--- |
|
Makefile.am | 3 ++ |
|
configure.ac | 9 ++++++ |
|
ras-arm-handler.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
ras-arm-handler.h | 24 +++++++++++++++ |
|
ras-events.c | 15 ++++++++++ |
|
ras-record.c | 59 ++++++++++++++++++++++++++++++++++++ |
|
ras-record.h | 16 ++++++++++ |
|
ras-report.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ |
|
ras-report.h | 5 +++- |
|
9 files changed, 295 insertions(+), 1 deletion(-) |
|
create mode 100644 ras-arm-handler.c |
|
create mode 100644 ras-arm-handler.h |
|
|
|
diff --git a/Makefile.am b/Makefile.am |
|
index 2500772..4aa5543 100644 |
|
--- a/Makefile.am |
|
+++ b/Makefile.am |
|
@@ -27,6 +27,9 @@ endif |
|
if WITH_NON_STANDARD |
|
rasdaemon_SOURCES += ras-non-standard-handler.c |
|
endif |
|
+if WITH_ARM |
|
+ rasdaemon_SOURCES += ras-arm-handler.c |
|
+endif |
|
if WITH_MCE |
|
rasdaemon_SOURCES += ras-mce-handler.c mce-intel.c mce-amd-k8.c \ |
|
mce-intel-p4-p6.c mce-intel-nehalem.c \ |
|
diff --git a/configure.ac b/configure.ac |
|
index ecd4b2f..14fc2f2 100644 |
|
--- a/configure.ac |
|
+++ b/configure.ac |
|
@@ -53,6 +53,15 @@ AS_IF([test "x$enable_non_standard" = "xyes"], [ |
|
]) |
|
AM_CONDITIONAL([WITH_NON_STANDARD], [test x$enable_non_standard = xyes]) |
|
|
|
+AC_ARG_ENABLE([arm], |
|
+ AS_HELP_STRING([--enable-arm], [enable ARM events (currently experimental)])) |
|
+ |
|
+AS_IF([test "x$enable_arm" = "xyes"], [ |
|
+ AC_DEFINE(HAVE_ARM,1,"have ARM events collect") |
|
+ AC_SUBST([WITH_ARM]) |
|
+]) |
|
+AM_CONDITIONAL([WITH_ARM], [test x$enable_arm = xyes]) |
|
+ |
|
AC_ARG_ENABLE([mce], |
|
AS_HELP_STRING([--enable-mce], [enable MCE events (currently experimental)])) |
|
|
|
diff --git a/ras-arm-handler.c b/ras-arm-handler.c |
|
new file mode 100644 |
|
index 0000000..a76470d |
|
--- /dev/null |
|
+++ b/ras-arm-handler.c |
|
@@ -0,0 +1,90 @@ |
|
+/* |
|
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved. |
|
+ * |
|
+ * This program is free software; you can redistribute it and/or modify |
|
+ * it under the terms of the GNU General Public License version 2 and |
|
+ * only version 2 as published by the Free Software Foundation. |
|
+ |
|
+ * This program is distributed in the hope that it will be useful, |
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
+ * GNU General Public License for more details. |
|
+ */ |
|
+ |
|
+#include <stdio.h> |
|
+#include <stdlib.h> |
|
+#include <string.h> |
|
+#include <unistd.h> |
|
+#include "libtrace/kbuffer.h" |
|
+#include "ras-arm-handler.h" |
|
+#include "ras-record.h" |
|
+#include "ras-logger.h" |
|
+#include "ras-report.h" |
|
+ |
|
+int ras_arm_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; |
|
+ time_t now; |
|
+ struct tm *tm; |
|
+ struct ras_arm_event ev; |
|
+ |
|
+ /* |
|
+ * Newer kernels (3.10-rc1 or upper) provide an uptime clock. |
|
+ * On previous kernels, the way to properly generate an event would |
|
+ * be to inject a fake one, measure its timestamp and diff it against |
|
+ * gettimeofday. We won't do it here. Instead, let's use uptime, |
|
+ * falling-back to the event report's time, if "uptime" clock is |
|
+ * not available (legacy kernels). |
|
+ */ |
|
+ |
|
+ if (ras->use_uptime) |
|
+ now = record->ts/user_hz + ras->uptime_diff; |
|
+ else |
|
+ now = time(NULL); |
|
+ |
|
+ tm = localtime(&now); |
|
+ if (tm) |
|
+ strftime(ev.timestamp, sizeof(ev.timestamp), |
|
+ "%Y-%m-%d %H:%M:%S %z", tm); |
|
+ trace_seq_printf(s, "%s\n", ev.timestamp); |
|
+ |
|
+ if (pevent_get_field_val(s, event, "affinity", record, &val, 1) < 0) |
|
+ return -1; |
|
+ ev.affinity = val; |
|
+ trace_seq_printf(s, " affinity: %d", ev.affinity); |
|
+ |
|
+ if (pevent_get_field_val(s, event, "mpidr", record, &val, 1) < 0) |
|
+ return -1; |
|
+ ev.mpidr = val; |
|
+ trace_seq_printf(s, "\n MPIDR: 0x%llx", (unsigned long long)ev.mpidr); |
|
+ |
|
+ if (pevent_get_field_val(s, event, "midr", record, &val, 1) < 0) |
|
+ return -1; |
|
+ ev.midr = val; |
|
+ trace_seq_printf(s, "\n MIDR: 0x%llx", (unsigned long long)ev.midr); |
|
+ |
|
+ if (pevent_get_field_val(s, event, "running_state", record, &val, 1) < 0) |
|
+ return -1; |
|
+ ev.running_state = val; |
|
+ trace_seq_printf(s, "\n running_state: %d", ev.running_state); |
|
+ |
|
+ if (pevent_get_field_val(s, event, "psci_state", record, &val, 1) < 0) |
|
+ return -1; |
|
+ ev.psci_state = val; |
|
+ trace_seq_printf(s, "\n psci_state: %d", ev.psci_state); |
|
+ |
|
+ /* Insert data into the SGBD */ |
|
+#ifdef HAVE_SQLITE3 |
|
+ ras_store_arm_record(ras, &ev); |
|
+#endif |
|
+ |
|
+#ifdef HAVE_ABRT_REPORT |
|
+ /* Report event to ABRT */ |
|
+ ras_report_arm_event(ras, &ev); |
|
+#endif |
|
+ |
|
+ return 0; |
|
+} |
|
diff --git a/ras-arm-handler.h b/ras-arm-handler.h |
|
new file mode 100644 |
|
index 0000000..eae10ec |
|
--- /dev/null |
|
+++ b/ras-arm-handler.h |
|
@@ -0,0 +1,24 @@ |
|
+/* |
|
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved. |
|
+ * |
|
+ * This program is free software; you can redistribute it and/or modify |
|
+ * it under the terms of the GNU General Public License version 2 and |
|
+ * only version 2 as published by the Free Software Foundation. |
|
+ |
|
+ * This program is distributed in the hope that it will be useful, |
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
+ * GNU General Public License for more details. |
|
+ */ |
|
+ |
|
+#ifndef __RAS_ARM_HANDLER_H |
|
+#define __RAS_ARM_HANDLER_H |
|
+ |
|
+#include "ras-events.h" |
|
+#include "libtrace/event-parse.h" |
|
+ |
|
+int ras_arm_event_handler(struct trace_seq *s, |
|
+ struct pevent_record *record, |
|
+ struct event_format *event, void *context); |
|
+ |
|
+#endif |
|
diff --git a/ras-events.c b/ras-events.c |
|
index 96aa6f1..812d712 100644 |
|
--- a/ras-events.c |
|
+++ b/ras-events.c |
|
@@ -30,6 +30,7 @@ |
|
#include "ras-mc-handler.h" |
|
#include "ras-aer-handler.h" |
|
#include "ras-non-standard-handler.h" |
|
+#include "ras-arm-handler.h" |
|
#include "ras-mce-handler.h" |
|
#include "ras-extlog-handler.h" |
|
#include "ras-record.h" |
|
@@ -213,6 +214,10 @@ int toggle_ras_mc_event(int enable) |
|
rc |= __toggle_ras_mc_event(ras, "ras", "non_standard_event", enable); |
|
#endif |
|
|
|
+#ifdef HAVE_ARM |
|
+ rc |= __toggle_ras_mc_event(ras, "ras", "arm_event", enable); |
|
+#endif |
|
+ |
|
free_ras: |
|
free(ras); |
|
return rc; |
|
@@ -691,6 +696,16 @@ int handle_ras_events(int record_events) |
|
"ras", "non_standard_event"); |
|
#endif |
|
|
|
+#ifdef HAVE_ARM |
|
+ rc = add_event_handler(ras, pevent, page_size, "ras", "arm_event", |
|
+ ras_arm_event_handler); |
|
+ if (!rc) |
|
+ num_events++; |
|
+ else |
|
+ log(ALL, LOG_ERR, "Can't get traces from %s:%s\n", |
|
+ "ras", "arm_event"); |
|
+#endif |
|
+ |
|
cpus = get_num_cpus(ras); |
|
|
|
#ifdef HAVE_MCE |
|
diff --git a/ras-record.c b/ras-record.c |
|
index 357ab61..c3644cb 100644 |
|
--- a/ras-record.c |
|
+++ b/ras-record.c |
|
@@ -209,6 +209,58 @@ int ras_store_non_standard_record(struct ras_events *ras, struct ras_non_standar |
|
} |
|
#endif |
|
|
|
+/* |
|
+ * Table and functions to handle ras:arm |
|
+ */ |
|
+ |
|
+#ifdef HAVE_ARM |
|
+static const struct db_fields arm_event_fields[] = { |
|
+ { .name="id", .type="INTEGER PRIMARY KEY" }, |
|
+ { .name="timestamp", .type="TEXT" }, |
|
+ { .name="error_count", .type="INTEGER" }, |
|
+ { .name="affinity", .type="INTEGER" }, |
|
+ { .name="mpidr", .type="INTEGER" }, |
|
+ { .name="running_state", .type="INTEGER" }, |
|
+ { .name="psci_state", .type="INTEGER" }, |
|
+}; |
|
+ |
|
+static const struct db_table_descriptor arm_event_tab = { |
|
+ .name = "arm_event", |
|
+ .fields = arm_event_fields, |
|
+ .num_fields = ARRAY_SIZE(arm_event_fields), |
|
+}; |
|
+ |
|
+int ras_store_arm_record(struct ras_events *ras, struct ras_arm_event *ev) |
|
+{ |
|
+ int rc; |
|
+ struct sqlite3_priv *priv = ras->db_priv; |
|
+ |
|
+ if (!priv || !priv->stmt_arm_record) |
|
+ return 0; |
|
+ log(TERM, LOG_INFO, "arm_event store: %p\n", priv->stmt_arm_record); |
|
+ |
|
+ sqlite3_bind_text (priv->stmt_arm_record, 1, ev->timestamp, -1, NULL); |
|
+ sqlite3_bind_int (priv->stmt_arm_record, 2, ev->error_count); |
|
+ sqlite3_bind_int (priv->stmt_arm_record, 3, ev->affinity); |
|
+ sqlite3_bind_int (priv->stmt_arm_record, 4, ev->mpidr); |
|
+ sqlite3_bind_int (priv->stmt_arm_record, 5, ev->running_state); |
|
+ sqlite3_bind_int (priv->stmt_arm_record, 6, ev->psci_state); |
|
+ |
|
+ rc = sqlite3_step(priv->stmt_arm_record); |
|
+ if (rc != SQLITE_OK && rc != SQLITE_DONE) |
|
+ log(TERM, LOG_ERR, |
|
+ "Failed to do arm_event step on sqlite: error = %d\n", rc); |
|
+ rc = sqlite3_reset(priv->stmt_arm_record); |
|
+ if (rc != SQLITE_OK && rc != SQLITE_DONE) |
|
+ log(TERM, LOG_ERR, |
|
+ "Failed reset arm_event on sqlite: error = %d\n", |
|
+ rc); |
|
+ log(TERM, LOG_INFO, "register inserted at db\n"); |
|
+ |
|
+ return rc; |
|
+} |
|
+#endif |
|
+ |
|
#ifdef HAVE_EXTLOG |
|
static const struct db_fields extlog_event_fields[] = { |
|
{ .name="id", .type="INTEGER PRIMARY KEY" }, |
|
@@ -509,6 +561,13 @@ int ras_mc_event_opendb(unsigned cpu, struct ras_events *ras) |
|
&non_standard_event_tab); |
|
#endif |
|
|
|
+#ifdef HAVE_ARM |
|
+ rc = ras_mc_create_table(priv, &arm_event_tab); |
|
+ if (rc == SQLITE_OK) |
|
+ rc = ras_mc_prepare_stmt(priv, &priv->stmt_arm_record, |
|
+ &arm_event_tab); |
|
+#endif |
|
+ |
|
ras->db_priv = priv; |
|
return 0; |
|
} |
|
diff --git a/ras-record.h b/ras-record.h |
|
index 473ae40..12c2218 100644 |
|
--- a/ras-record.h |
|
+++ b/ras-record.h |
|
@@ -65,10 +65,21 @@ struct ras_non_standard_event { |
|
uint32_t length; |
|
}; |
|
|
|
+struct ras_arm_event { |
|
+ char timestamp[64]; |
|
+ int32_t error_count; |
|
+ int8_t affinity; |
|
+ int64_t mpidr; |
|
+ int64_t midr; |
|
+ int32_t running_state; |
|
+ int32_t psci_state; |
|
+}; |
|
+ |
|
struct ras_mc_event; |
|
struct ras_aer_event; |
|
struct ras_extlog_event; |
|
struct ras_non_standard_event; |
|
+struct ras_arm_event; |
|
struct mce_event; |
|
|
|
#ifdef HAVE_SQLITE3 |
|
@@ -90,6 +101,9 @@ struct sqlite3_priv { |
|
#ifdef HAVE_NON_STANDARD |
|
sqlite3_stmt *stmt_non_standard_record; |
|
#endif |
|
+#ifdef HAVE_ARM |
|
+ sqlite3_stmt *stmt_arm_record; |
|
+#endif |
|
}; |
|
|
|
int ras_mc_event_opendb(unsigned cpu, struct ras_events *ras); |
|
@@ -98,6 +112,7 @@ int ras_store_aer_event(struct ras_events *ras, struct ras_aer_event *ev); |
|
int ras_store_mce_record(struct ras_events *ras, struct mce_event *ev); |
|
int ras_store_extlog_mem_record(struct ras_events *ras, struct ras_extlog_event *ev); |
|
int ras_store_non_standard_record(struct ras_events *ras, struct ras_non_standard_event *ev); |
|
+int ras_store_arm_record(struct ras_events *ras, struct ras_arm_event *ev); |
|
|
|
#else |
|
static inline int ras_mc_event_opendb(unsigned cpu, struct ras_events *ras) { return 0; }; |
|
@@ -106,6 +121,7 @@ static inline int ras_store_aer_event(struct ras_events *ras, struct ras_aer_eve |
|
static inline int ras_store_mce_record(struct ras_events *ras, struct mce_event *ev) { return 0; }; |
|
static inline int ras_store_extlog_mem_record(struct ras_events *ras, struct ras_extlog_event *ev) { return 0; }; |
|
static inline int ras_store_non_standard_record(struct ras_events *ras, struct ras_non_standard_event *ev) { return 0; }; |
|
+static inline int ras_store_arm_record(struct ras_events *ras, struct ras_arm_event *ev) { return 0; }; |
|
|
|
#endif |
|
|
|
diff --git a/ras-report.c b/ras-report.c |
|
index 1eb9f79..d4beee0 100644 |
|
--- a/ras-report.c |
|
+++ b/ras-report.c |
|
@@ -228,6 +228,33 @@ static int set_non_standard_event_backtrace(char *buf, struct ras_non_standard_e |
|
return 0; |
|
} |
|
|
|
+static int set_arm_event_backtrace(char *buf, struct ras_arm_event *ev){ |
|
+ char bt_buf[MAX_BACKTRACE_SIZE]; |
|
+ |
|
+ if(!buf || !ev) |
|
+ return -1; |
|
+ |
|
+ sprintf(bt_buf, "BACKTRACE=" \ |
|
+ "timestamp=%s\n" \ |
|
+ "error_count=%d\n" \ |
|
+ "affinity=%d\n" \ |
|
+ "mpidr=0x%lx\n" \ |
|
+ "midr=0x%lx\n" \ |
|
+ "running_state=%d\n" \ |
|
+ "psci_state=%d\n", \ |
|
+ ev->timestamp, \ |
|
+ ev->error_count, \ |
|
+ ev->affinity, \ |
|
+ ev->mpidr, \ |
|
+ ev->midr, \ |
|
+ ev->running_state, \ |
|
+ ev->psci_state); |
|
+ |
|
+ strcat(buf, bt_buf); |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
static int commit_report_backtrace(int sockfd, int type, void *ev){ |
|
char buf[MAX_BACKTRACE_SIZE]; |
|
char *pbuf = buf; |
|
@@ -253,6 +280,9 @@ static int commit_report_backtrace(int sockfd, int type, void *ev){ |
|
case NON_STANDARD_EVENT: |
|
rc = set_non_standard_event_backtrace(buf, (struct ras_non_standard_event *)ev); |
|
break; |
|
+ case ARM_EVENT: |
|
+ rc = set_arm_event_backtrace(buf, (struct ras_arm_event *)ev); |
|
+ break; |
|
default: |
|
return -1; |
|
} |
|
@@ -425,6 +455,51 @@ non_standard_fail: |
|
return rc; |
|
} |
|
|
|
+int ras_report_arm_event(struct ras_events *ras, struct ras_arm_event *ev){ |
|
+ char buf[MAX_MESSAGE_SIZE]; |
|
+ int sockfd = 0; |
|
+ int rc = -1; |
|
+ |
|
+ memset(buf, 0, sizeof(buf)); |
|
+ |
|
+ sockfd = setup_report_socket(); |
|
+ if(sockfd < 0){ |
|
+ return rc; |
|
+ } |
|
+ |
|
+ rc = commit_report_basic(sockfd); |
|
+ if(rc < 0){ |
|
+ goto arm_fail; |
|
+ } |
|
+ |
|
+ rc = commit_report_backtrace(sockfd, ARM_EVENT, ev); |
|
+ if(rc < 0){ |
|
+ goto arm_fail; |
|
+ } |
|
+ |
|
+ sprintf(buf, "ANALYZER=%s", "rasdaemon-arm"); |
|
+ rc = write(sockfd, buf, strlen(buf) + 1); |
|
+ if(rc < strlen(buf) + 1){ |
|
+ goto arm_fail; |
|
+ } |
|
+ |
|
+ sprintf(buf, "REASON=%s", "ARM CPU report problem"); |
|
+ rc = write(sockfd, buf, strlen(buf) + 1); |
|
+ if(rc < strlen(buf) + 1){ |
|
+ goto arm_fail; |
|
+ } |
|
+ |
|
+ rc = 0; |
|
+ |
|
+arm_fail: |
|
+ |
|
+ if(sockfd > 0){ |
|
+ close(sockfd); |
|
+ } |
|
+ |
|
+ return rc; |
|
+} |
|
+ |
|
int ras_report_mce_event(struct ras_events *ras, struct mce_event *ev){ |
|
char buf[MAX_MESSAGE_SIZE]; |
|
int sockfd = 0; |
|
diff --git a/ras-report.h b/ras-report.h |
|
index c2fcf42..6c466f5 100644 |
|
--- a/ras-report.h |
|
+++ b/ras-report.h |
|
@@ -33,7 +33,8 @@ enum { |
|
MC_EVENT, |
|
MCE_EVENT, |
|
AER_EVENT, |
|
- NON_STANDARD_EVENT |
|
+ NON_STANDARD_EVENT, |
|
+ ARM_EVENT |
|
}; |
|
|
|
#ifdef HAVE_ABRT_REPORT |
|
@@ -42,6 +43,7 @@ int ras_report_mc_event(struct ras_events *ras, struct ras_mc_event *ev); |
|
int ras_report_aer_event(struct ras_events *ras, struct ras_aer_event *ev); |
|
int ras_report_mce_event(struct ras_events *ras, struct mce_event *ev); |
|
int ras_report_non_standard_event(struct ras_events *ras, struct ras_non_standard_event *ev); |
|
+int ras_report_arm_event(struct ras_events *ras, struct ras_arm_event *ev); |
|
|
|
#else |
|
|
|
@@ -49,6 +51,7 @@ static inline int ras_report_mc_event(struct ras_events *ras, struct ras_mc_even |
|
static inline int ras_report_aer_event(struct ras_events *ras, struct ras_aer_event *ev) { return 0; }; |
|
static inline int ras_report_mce_event(struct ras_events *ras, struct mce_event *ev) { return 0; }; |
|
static inline int ras_report_non_standard_event(struct ras_events *ras, struct ras_non_standard_event *ev) { return 0; }; |
|
+static inline int ras_report_arm_event(struct ras_events *ras, struct ras_arm_event *ev) { return 0; }; |
|
|
|
#endif |
|
|
|
-- |
|
1.8.3.1 |
|
|
|
|