diff options
author | Shuai Xue <xueshuai@linux.alibaba.com> | 2023-04-25 21:23:22 +0800 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2023-06-09 11:49:32 -0700 |
commit | 13e098c3afd6705abd1ff0ba1a3cec6a5486c466 (patch) | |
tree | 73f0500eea8a8fa82345456edeb2c3369367f571 | |
parent | 95b089cf33ae2fac5cd34236cdc4e8fdd69c6dbb (diff) | |
download | ras-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-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | einj.c | 27 | ||||
-rw-r--r-- | einj.h | 7 | ||||
-rw-r--r-- | einj_pcie_err.c | 105 |
5 files changed, 145 insertions, 2 deletions
@@ -1,6 +1,7 @@ *.o cmcistorm einj_mem_uc +einj_pcie_err hornet lmce mca-recover @@ -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 @@ -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); +} @@ -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; +} |