aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShuai Xue <xueshuai@linux.alibaba.com>2023-04-25 21:23:22 +0800
committerTony Luck <tony.luck@intel.com>2023-06-09 11:49:32 -0700
commit13e098c3afd6705abd1ff0ba1a3cec6a5486c466 (patch)
tree73f0500eea8a8fa82345456edeb2c3369367f571
parent95b089cf33ae2fac5cd34236cdc4e8fdd69c6dbb (diff)
downloadras-tools-13e098c3afd6705abd1ff0ba1a3cec6a5486c466.tar.gz
einj_pcie_err: support PCIe error injection through EINJ
Support PCIe error injection, e.g. fatal error, through APEI EINJ interface. Tested on ARM platform (Alibaba Yitian 710) and X86 platform (Intel Sapphire Rapids). Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r--.gitignore1
-rw-r--r--Makefile7
-rw-r--r--einj.c27
-rw-r--r--einj.h7
-rw-r--r--einj_pcie_err.c105
5 files changed, 145 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index d0eb8d3..0f1b6b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
*.o
cmcistorm
einj_mem_uc
+einj_pcie_err
hornet
lmce
mca-recover
diff --git a/Makefile b/Makefile
index 0d18223..3abe9ac 100644
--- a/Makefile
+++ b/Makefile
@@ -2,10 +2,10 @@
CFLAGS = -O
-all: mca-recover vtop cmcistorm hornet einj_mem_uc lmce rep_ce_page memattr victim
+all: mca-recover vtop cmcistorm hornet einj_mem_uc lmce rep_ce_page memattr victim einj_pcie_err
clean:
- rm -f *.o mca-recover vtop cmcistorm hornet einj_mem_uc lmce rep_ce_page memattr victim
+ rm -f *.o mca-recover vtop cmcistorm hornet einj_mem_uc lmce rep_ce_page memattr victim einj_pcie_err
mca-recover: mca-recover.o proc_pagemap.o
cc -o mca-recover $(CFLAGS) mca-recover.o proc_pagemap.o
@@ -33,3 +33,6 @@ memattr: memattr.o einj.o
victim: victim.c
cc -o victim $(CFLAGS) victim.c
+
+einj_pcie_err: einj_pcie_err.o einj.o
+ cc -o einj_pcie_err einj_pcie_err.o einj.o
diff --git a/einj.c b/einj.c
index d411570..c157a53 100644
--- a/einj.c
+++ b/einj.c
@@ -7,6 +7,22 @@
#include "einj.h"
+struct error_type error_types[] = {
+ { 0x00000001, "Processor Correctable",},
+ { 0x00000002, "Processor Uncorrectable non-fatal",},
+ { 0x00000004, "Processor Uncorrectable fatal",},
+ { 0x00000008, "Memory Correctable",},
+ { 0x00000010, "Memory Uncorrectable non-fatal",},
+ { 0x00000020, "Memory Uncorrectable fatal",},
+ { 0x00000040, "PCI Express Correctable",},
+ { 0x00000080, "PCI Express Uncorrectable non-fatal",},
+ { 0x00000100, "PCI Express Uncorrectable fatal",},
+ { 0x00000200, "Platform Correctabl",},
+ { 0x00000400, "Platform Uncorrectable non-fatal",},
+ { 0x00000800, "Platform Uncorrectable fatal",},
+ { -1, NULL }
+};
+
int check_errortype_available(char *file, unsigned long long val)
{
FILE *fp;
@@ -98,3 +114,14 @@ void inject_mem_uc(unsigned long long addr, void *vaddr, int notrigger)
wfile(EINJ_NOTRIGGER, notrigger);
wfile(EINJ_DOIT, 1);
}
+
+char *lookup_type_name(unsigned long long type)
+{
+ struct error_type *t;
+
+ for (t = error_types; t->type_name; t++)
+ if (t->type == type)
+ return t->type_name;
+ fprintf(stderr, "%s: unknown type '%x'\n", progname, type);
+ exit(1);
+}
diff --git a/einj.h b/einj.h
index a5c8e9a..d8f8eee 100644
--- a/einj.h
+++ b/einj.h
@@ -39,6 +39,11 @@ extern char *progname;
extern int Sflag;
extern long pagesize;
+struct error_type {
+ int type;
+ char *type_name;
+};
+
int check_errortype_available(char *file, unsigned long long val);
void wfile(char *file, unsigned long long val);
@@ -49,4 +54,6 @@ int is_privileged(void);
void inject_mem_uc(unsigned long long addr, void *vaddr, int notrigger);
+char *lookup_type_name(unsigned long long type);
+
#endif /* EINJ_H */
diff --git a/einj_pcie_err.c b/einj_pcie_err.c
new file mode 100644
index 0000000..782a3db
--- /dev/null
+++ b/einj_pcie_err.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2023 Alibaba Corporation
+ * Authors: Shuai Xue
+ *
+ * This software may be redistributed and/or modified under the terms of
+ * the GNU General Public License ("GPL") version 2 only as published by the
+ * Free Software Foundation.
+ */
+
+#include "einj.h"
+
+char *progname;
+int Sflag;
+long pagesize;
+
+static void check_configuration(void)
+{
+ if (!is_privileged() || !is_einj_support())
+ exit(1);
+}
+
+static void inject_pcie_error(unsigned long long type, int sbdf)
+{
+ wfile(EINJ_ETYPE, type);
+ wfile(EINJ_SBDF, sbdf);
+ wfile(EINJ_FLAGS, 0x4);
+ wfile(EINJ_NOTRIGGER, 0);
+ wfile(EINJ_DOIT, 1);
+}
+
+static int split(char dst[][16], const char *str, const char *spl)
+{
+ int count = 0;
+ char *ret;
+ char *tmp = strdup(str);
+
+ while ((ret = strsep(&tmp, spl))) {
+ if (!(*ret))
+ continue;
+ strcpy(dst[count++], ret);
+ }
+ free(tmp);
+ return count;
+}
+
+static int slot2sbdf(const char *slot)
+{
+ char bdf[3][16];
+ int bus, dev, func, bdf_count;
+
+ /* get bus, device and function */
+ bdf_count = split(bdf, slot, ":.");
+ if (bdf_count != 3) {
+ printf("invalid bdf, please check!\n");
+ return -EINVAL;
+ }
+ sscanf(bdf[0], "%x", &bus);
+ sscanf(bdf[1], "%x", &dev);
+ sscanf(bdf[2], "%x", &func);
+
+ return (bus << 16) | (dev << 11) | (func << 8);
+}
+
+
+static void show_help(void)
+{
+ struct test *t;
+
+ printf("Usage: %s [-s slot][-t type]\n", progname);
+ printf(" e.g. inject non-fatal into rootport\n");
+ printf(" ./einj_pcie_err -s 7b:05.0 -t 0x80\n");
+
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ int rp_sbdf, c;
+ char *bdf, *type_name;
+ unsigned long long type;
+
+ progname = argv[0];
+ check_configuration();
+
+ while ((c = getopt(argc, argv, "s:t:")) != -1)
+ switch (c) {
+ case 's':
+ bdf = strdup(optarg);
+ rp_sbdf = slot2sbdf(optarg);
+ break;
+ case 't':
+ type = strtol(optarg, NULL, 0);
+ type_name = lookup_type_name(type);
+ break;
+ case 'h': case '?':
+ show_help();
+ }
+ printf("Injecting %s into Rootport %s (%x)\n", type_name, bdf, rp_sbdf);
+
+ inject_pcie_error(type, rp_sbdf);
+
+ return 0;
+}