diff options
author | Huang Ying <ying.huang@intel.com> | 2009-04-28 15:27:27 +0800 |
---|---|---|
committer | Huang Ying <ying.huang@intel.com> | 2009-04-28 15:27:27 +0800 |
commit | 7603e362d152dbe3d3917e81371ebd42aa65a582 (patch) | |
tree | 0c9d6cc0f60d0c70a03883fa7021a43df3f9f58d | |
download | aer-inject-7603e362d152dbe3d3917e81371ebd42aa65a582.tar.gz |
Initial commit
-rw-r--r-- | Makefile | 34 | ||||
-rw-r--r-- | README | 39 | ||||
-rw-r--r-- | SPEC | 52 | ||||
-rw-r--r-- | aer-inject.c | 37 | ||||
-rw-r--r-- | aer.h | 43 | ||||
-rw-r--r-- | aer.lex | 126 | ||||
-rw-r--r-- | aer.y | 91 | ||||
-rw-r--r-- | test/aer1 | 4 | ||||
-rw-r--r-- | util.c | 34 | ||||
-rw-r--r-- | util.h | 19 |
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 @@ -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 + @@ -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); +} @@ -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 @@ -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(); +} @@ -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 @@ -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); +} + @@ -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 |