All of lore.kernel.org
 help / color / mirror / Atom feed
* [V2,2/2] rasdaemon: add support for ARM events
@ 2017-06-02 21:40 Tyler Baicar
  0 siblings, 0 replies; only message in thread
From: Tyler Baicar @ 2017-06-02 21:40 UTC (permalink / raw)
  To: mchehab, linux-edac, astone, fu.wei, shiju.jose; +Cc: Tyler Baicar

Add support to handle the ARM kernel trace events
which cover RAS ARM processor errors.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
---
 Makefile.am       |  3 ++
 configure.ac      |  9 ++++++
 ras-arm-handler.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ras-arm-handler.h | 31 +++++++++++++++++++
 ras-events.c      | 15 ++++++++++
 ras-record.c      | 52 ++++++++++++++++++++++++++++++++
 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 1bc25e4..83868e2 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 2adb798..648a3ac 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..fb825c3
--- /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\n", ev.affinity);
+
+	if (pevent_get_field_val(s, event, "mpidr", record, &val, 1) < 0)
+		return -1;
+	ev.mpidr = val;
+	trace_seq_printf(s, "MPIDR: 0x%llx\n", (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, "MIDR: 0x%llx\n", (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, "running_state: %d\n", 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, "psci_state: %d\n", 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_record(ras, &ev);
+#endif
+
+	return 0;
+}
diff --git a/ras-arm-handler.h b/ras-arm-handler.h
new file mode 100644
index 0000000..9196617
--- /dev/null
+++ b/ras-arm-handler.h
@@ -0,0 +1,31 @@
+/*
+ * 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"
+
+static char *arm_error_type_strs[] = {
+	"cache error",
+	"TLB error",
+	"bus error",
+	"micro-architectural error",
+};
+
+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..5dfa00f 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" },
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 3e508a5..af656b2 100644
--- a/ras-report.c
+++ b/ras-report.c
@@ -230,6 +230,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%llx\n",     \
+						"midr=0x%llx\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;
@@ -255,6 +282,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;
 	}
@@ -427,6 +457,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
 

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2017-06-02 21:40 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-02 21:40 [V2,2/2] rasdaemon: add support for ARM events Tyler Baicar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.