aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2009-04-28 15:27:27 +0800
committerHuang Ying <ying.huang@intel.com>2009-04-28 15:27:27 +0800
commit7603e362d152dbe3d3917e81371ebd42aa65a582 (patch)
tree0c9d6cc0f60d0c70a03883fa7021a43df3f9f58d
downloadaer-inject-7603e362d152dbe3d3917e81371ebd42aa65a582.tar.gz
Initial commit
-rw-r--r--Makefile34
-rw-r--r--README39
-rw-r--r--SPEC52
-rw-r--r--aer-inject.c37
-rw-r--r--aer.h43
-rw-r--r--aer.lex126
-rw-r--r--aer.y91
-rw-r--r--test/aer14
-rw-r--r--util.c34
-rw-r--r--util.h19
10 files changed, 479 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..700c821
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+CFLAGS := -g -Wall
+LDFLAGS += -lpthread
+
+OBJ := aer-inject.o util.o aer.tab.o lex.yy.o
+GENSRC := aer.tab.c aer.tab.h lex.yy.c
+SRC := aer-inject.c util.c
+CLEAN := ${OBJ} ${GENSRC} aer-inject .gdb_history .depend
+DISTCLEAN := .depend .gdb_history
+
+.PHONY: clean depend
+
+aer-inject: ${OBJ}
+
+lex.yy.c: aer.lex aer.tab.h
+ flex aer.lex
+
+aer.tab.c aer.tab.h: aer.y
+ bison -d aer.y
+
+clean:
+ rm -f ${CLEAN}
+
+distclean: clean
+ rm -f ${DISTCLEAN} *~
+
+depend: .depend
+
+.depend: ${SRC} ${GENSRC}
+ ${CC} -MM -DDEPS_RUN -I. ${SRC} ${GENSRC} > .depend.X && \
+ mv .depend.X .depend
+
+Makefile: .depend
+
+include .depend
diff --git a/README b/README
new file mode 100644
index 0000000..44195f8
--- /dev/null
+++ b/README
@@ -0,0 +1,39 @@
+aer-inject allows to inject PCIE AER errors on the software level into
+a running Linux kernel. This is intended for validation of the PCIE
+driver error recovery handler and PCIE AER core handler.
+
+Syntax:
+
+aer-inject aer-file
+
+See SPEC for the input language
+
+Some simple tests are in test/*.
+
+Requires a new Linux kernel with PCIE AER error injection patches.
+The PCIE AER error injection patches are currently available from
+git://git.kernel.org/pub/scm/linux/kernel/git/xxx.git
+
+
+Authors:
+
+Huang Ying <ying.huang@intel.com>
+
+Basic design, some code and document are based on Andi Kleen's
+mce-inject.
+
+Copyright 2009 by Intel Corporation
+ aer-inject is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2.
+
+ aer-inject 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.
+
+ You should find a copy of v2 of the GNU General Public License
+ somewhere on your Linux system; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+
diff --git a/SPEC b/SPEC
new file mode 100644
index 0000000..00bade3
--- /dev/null
+++ b/SPEC
@@ -0,0 +1,52 @@
+
+aer-inject allows to inject PCIE AER errors in a running kernel.
+
+Has to run as root. /dev/aer_inject has to exist.
+
+aer-inject aer-file
+aer-inject < aer-file
+
+Requires a kernel with PCIE AER error injection support. The injection
+only happens on the software level and does not simulate full PCIE AER
+handling on the platform level.
+
+The PCIE AER error to be injected are described in an input language
+which reflects PCIE AER related registers quite straighforward.
+
+See the PCI Express Base Specification section 7.10 for details on
+PCIE AER related registers.
+
+The keywords are case-insensitive
+
+The error always starts with:
+
+AER
+
+The description of error follows:
+
+BUS number DEV number FN number
+
+These specify the PCI device or port via PCI bus number, dev number
+and function number
+
+COR_STATUS {RCVR|BAD_TLP|BAD_DLLP|REP_ROLL|REP_TIMER|number}
+
+UNCOR_STATUS {TRAIN|DLP|POISON_TLP|FCP|COMP_TIME|COMP_ABORT|UNX_COMP|
+ RX_OVER|MALF_TLP|ECRC|UNSUP|number}
+
+HEADER_LOG number number number number
+
+These specify the corrected and uncorrected error types to be
+injected and corresponding TLP header log.
+
+multiple fields can be on a line.
+
+number can be hex/octal/decimal in the usual C format.
+
+Multiple errors can be in a single file, each new one starts with
+"AER".
+
+For all missing fields reasonable default values are filled in
+(hopefully).
+
+Comments start with # until the end of the line.
diff --git a/aer-inject.c b/aer-inject.c
new file mode 100644
index 0000000..1bcfc54
--- /dev/null
+++ b/aer-inject.c
@@ -0,0 +1,37 @@
+/*
+ * Inject PCIE AER error into Linux kernel for testing
+ *
+ * Copyright 2009 Intel Corporation.
+ * Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "aer.h"
+#include "util.h"
+
+#define AER_DEV "/dev/aer_inject"
+
+void init_aer(struct aer_error_inj *aerr)
+{
+ memset(aerr, 0, sizeof(struct aer_error_inj));
+}
+
+void submit_aer(struct aer_error_inj *err)
+{
+ int fd, ret;
+
+ fd = open(AER_DEV, O_WRONLY);
+ ERROR_EXIT_ON(fd <= 0, "Failed to open device file: %s", AER_DEV);
+ ret = write(fd, err, sizeof(struct aer_error_inj));
+ ERROR_EXIT_ON(ret != sizeof(struct aer_error_inj), "Failed to write");
+ close(fd);
+}
diff --git a/aer.h b/aer.h
new file mode 100644
index 0000000..2061a93
--- /dev/null
+++ b/aer.h
@@ -0,0 +1,43 @@
+#ifndef AER_H
+#define AER_H
+
+struct aer_error_inj
+{
+ int8_t bus;
+ int8_t dev;
+ int8_t fn;
+ int32_t uncor_status;
+ int32_t cor_status;
+ int32_t header_log0;
+ int32_t header_log1;
+ int32_t header_log2;
+ int32_t header_log3;
+};
+
+#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */
+#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */
+#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */
+#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */
+#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */
+#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */
+#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */
+#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */
+#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */
+#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */
+#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */
+#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */
+#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */
+#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */
+#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */
+#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */
+
+extern void init_aer(struct aer_error_inj *err);
+extern void submit_aer(struct aer_error_inj *err);
+
+extern char *filename;
+extern int yylineno;
+extern void yyerror(char const *msg, ...);
+extern int yylex(void);
+extern int yyparse(void);
+
+#endif
diff --git a/aer.lex b/aer.lex
new file mode 100644
index 0000000..b3c6a30
--- /dev/null
+++ b/aer.lex
@@ -0,0 +1,126 @@
+/*
+ * Scanner for the PCIE-AER grammar.
+ *
+ * Copyright (c) 2009 by Intel Corp.
+ * Author: Huang Ying <ying.huang@intel.com>
+ *
+ * Based on mce.lex of mce-inject, which is written by Andi Kleen
+ * <andi.kleen@intel.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+
+%{
+#define _GNU_SOURCE 1
+#include <stdlib.h>
+#include <string.h>
+
+#include "aer.h"
+#include "aer.tab.h"
+#include "util.h"
+
+int yylineno;
+
+static int lookup_symbol(const char *);
+%}
+
+%option nounput
+
+%%
+
+#.*\n /* comment */;
+\n ++yylineno;
+0x[0-9a-fA-F]+ |
+0[0-7]+ |
+[0-9]+ yylval = strtoull(yytext, NULL, 0); return NUMBER;
+[:{}<>] return yytext[0];
+[_a-zA-Z][_a-zA-Z0-9]* return lookup_symbol(yytext);
+[ \t]+ /* white space */;
+. yyerror("Unrecognized character '%s'", yytext);
+
+%%
+
+/* Keyword handling */
+
+static struct key {
+ const char *name;
+ int tok;
+ int32_t val;
+} keys[] = {
+#define KEY(x) { #x, x }
+#define KEYVAL(x,v) { #x, x, v }
+ KEY(AER),
+ KEY(BUS),
+ KEY(DEV),
+ KEY(FN),
+ KEY(UNCOR_STATUS),
+ KEY(COR_STATUS),
+ KEY(HEADER_LOG),
+ KEYVAL(TRAIN,PCI_ERR_UNC_TRAIN),
+ KEYVAL(DLP, PCI_ERR_UNC_DLP),
+ KEYVAL(POISON_TLP, PCI_ERR_UNC_POISON_TLP),
+ KEYVAL(FCP, PCI_ERR_UNC_FCP),
+ KEYVAL(COMP_TIME, PCI_ERR_UNC_COMP_TIME),
+ KEYVAL(COMP_ABORT, PCI_ERR_UNC_COMP_ABORT),
+ KEYVAL(UNX_COMP, PCI_ERR_UNC_UNX_COMP),
+ KEYVAL(RX_OVER, PCI_ERR_UNC_RX_OVER),
+ KEYVAL(MALF_TLP, PCI_ERR_UNC_MALF_TLP),
+ KEYVAL(ECRC, PCI_ERR_UNC_ECRC),
+ KEYVAL(UNSUP, PCI_ERR_UNC_UNSUP),
+ KEYVAL(RCVR, PCI_ERR_COR_RCVR),
+ KEYVAL(BAD_TLP, PCI_ERR_COR_BAD_TLP),
+ KEYVAL(BAD_DLLP, PCI_ERR_COR_BAD_DLLP),
+ KEYVAL(REP_ROLL, PCI_ERR_COR_REP_ROLL),
+ KEYVAL(REP_TIMER, PCI_ERR_COR_REP_TIMER),
+};
+
+static int cmp_key(const void *av, const void *bv)
+{
+ const struct key *a = av;
+ const struct key *b = bv;
+ return strcasecmp(a->name, b->name);
+}
+
+static int lookup_symbol(const char *name)
+{
+ struct key *k;
+ struct key key;
+ key.name = name;
+ k = bsearch(&key, keys, ARRAY_SIZE(keys), sizeof(struct key), cmp_key);
+ if (k != NULL) {
+ yylval = k->val;
+ return k->tok;
+ }
+ return SYMBOL;
+}
+
+static void init_lex(void)
+{
+ qsort(keys, ARRAY_SIZE(keys), sizeof(struct key), cmp_key);
+}
+
+static char **argv;
+char *filename = "<stdin>";
+
+int yywrap(void)
+{
+ if (*argv == NULL)
+ return 1;
+ filename = *argv;
+ yyin = fopen(filename, "r");
+ ERROR_EXIT_ON(!yyin, "Can not open: %s", filename);
+ argv++;
+ return 0;
+}
+
+int main(int ac, char **av)
+{
+ init_lex();
+ argv = ++av;
+ if (*argv)
+ yywrap();
+ return yyparse();
+}
diff --git a/aer.y b/aer.y
new file mode 100644
index 0000000..80b002e
--- /dev/null
+++ b/aer.y
@@ -0,0 +1,91 @@
+/*
+ * Grammar for the PCIE-AER injection.
+ *
+ * Copyright (c) 2009 by Intel Corp.
+ * Author: Huang Ying <ying.huang@intel.com>
+ *
+ * Based on mce.y of mce-inject, which is written by Andi Kleen
+ * <andi.kleen@intel.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+
+%{
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "aer.h"
+
+static struct aer_error_inj aerr;
+
+static void init(void);
+
+%}
+
+%token AER BUS DEV FN UNCOR_STATUS COR_STATUS HEADER_LOG
+%token TRAIN DLP POISON_TLP FCP COMP_TIME COMP_ABORT UNX_COMP RX_OVER MALF_TLP
+%token ECRC UNSUP
+%token RCVR BAD_TLP BAD_DLLP REP_ROLL REP_TIMER
+%token NUMBER SYMBOL
+
+%%
+
+input: /* empty */
+ | input aer_start aer { submit_aer(&aerr); }
+ ;
+
+aer_start: AER { init(); }
+ ;
+
+aer: aer_term
+ | aer aer_term
+ ;
+
+aer_term: UNCOR_STATUS uncor_status_list { aerr.uncor_status = $2; }
+ | COR_STATUS cor_status_list { aerr.cor_status = $2; }
+ | BUS NUMBER DEV NUMBER FN NUMBER { aerr.bus = $2;
+ aerr.dev = $4;
+ aerr.fn = $6; }
+ | HEADER_LOG NUMBER NUMBER NUMBER NUMBER { aerr.header_log0 = $2;
+ aerr.header_log1 = $3;
+ aerr.header_log2 = $4;
+ aerr.header_log3 = $5; }
+ ;
+
+uncor_status_list: /* empty */ { $$ = 0; }
+ | uncor_status_list uncor_status { $$ = $1 | $2; }
+ ;
+
+uncor_status: TRAIN | DLP | POISON_TLP | FCP | COMP_TIME | COMP_ABORT
+ | UNX_COMP | RX_OVER | MALF_TLP | ECRC | UNSUP | NUMBER
+ ;
+
+cor_status_list: /* empty */ { $$ = 0; }
+ | cor_status_list cor_status { $$ = $1 | $2; }
+ ;
+
+cor_status: RCVR | BAD_TLP | BAD_DLLP | REP_ROLL | REP_TIMER | NUMBER
+ ;
+
+%%
+
+static void init(void)
+{
+ init_aer(&aerr);
+}
+
+void yyerror(char const *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ fprintf(stderr, "%s:%d: ", filename, yylineno);
+ vfprintf(stderr, msg, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+ exit(1);
+}
diff --git a/test/aer1 b/test/aer1
new file mode 100644
index 0000000..c960175
--- /dev/null
+++ b/test/aer1
@@ -0,0 +1,4 @@
+AER
+BUS 0 DEV 0 FN 2
+COR_STATUS BAD_TLP
+HEADER_LOG 0 1 2 3
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..b5d80da
--- /dev/null
+++ b/util.c
@@ -0,0 +1,34 @@
+/*
+ * Some utility functions
+ *
+ * Copyright (C) Intel Corp., 2009
+ * Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+void error_exit(char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "Error: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ if (errno)
+ fprintf(stderr, ", %s\n", strerror(errno));
+ else
+ fprintf(stderr, "\n");
+ exit(-1);
+}
+
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..9ed7cd9
--- /dev/null
+++ b/util.h
@@ -0,0 +1,19 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+void error_exit(char *fmt, ...);
+
+#define ERROR_EXIT(fmt, x...) \
+ do { \
+ error_exit(fmt, ## x); \
+ } while (0)
+
+#define ERROR_EXIT_ON(check, fmt, x...) \
+ do { \
+ if (check) \
+ error_exit(fmt, ## x); \
+ } while (0)
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x)))
+
+#endif