Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 14 Aug 2014 12:08:30 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-hackers@freebsd.org
Cc:        Chris Torek <torek@torek.net>
Subject:   Re: PCIe AER
Message-ID:  <201408141208.30208.jhb@freebsd.org>
In-Reply-To: <201408122328.s7CNSGoC077640@elf.torek.net>
References:  <201408122328.s7CNSGoC077640@elf.torek.net>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tuesday, August 12, 2014 7:28:16 pm Chris Torek wrote:
> Is there any sort of overall plan for advanced error reporting
> on PCIe?
> 
> I may need to implement something along these lines soon, at least
> for detection (not necessarily correction just yet).

As Konstantin noted, there is nothing planned.  There is the '-e' flag for 
pciconf, and I have a hack to allow pciconf to clear errors via a '-C' flag.  
I believe at least NetApp has their own internal AER support, but my 
understanding is that it is very grotty and not really suitable for 
upstreaming.

Index: err.c
===================================================================
--- err.c	(revision 270540)
+++ err.c	(working copy)
@@ -171,3 +171,36 @@
 	mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_COR_STATUS, 4);
 	print_bits("Corrected", aer_cor, mask);
 }
+
+void
+clear_errors(int fd, struct pci_conf *p)
+{
+	uint16_t sta, aer;
+	uint8_t pcie;
+
+	/* Clear standard PCI errors. */
+	sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
+	if ((sta & PCI_ERRORS) != 0)
+		write_config(fd, &p->pc_sel, PCIR_STATUS, 2,
+		    sta & ~PCI_ERRORS);
+
+	/* See if this is a PCI-express device. */
+	pcie = pci_find_cap(fd, p, PCIY_EXPRESS);
+	if (pcie == 0)
+		return;
+
+	/* Clear PCI-e errors. */
+	sta = read_config(fd, &p->pc_sel, pcie + PCIER_DEVICE_STA, 2);
+	if ((sta & PCIE_ERRORS) != 0)
+		write_config(fd, &p->pc_sel, pcie + PCIER_DEVICE_STA, 2,
+		    sta & PCIE_ERRORS);
+
+	/* See if this device supports AER. */
+	aer = pcie_find_cap(fd, p, PCIZ_AER);
+	if (aer == 0)
+		return;
+
+	/* Clear AER errors. */
+	write_config(fd, &p->pc_sel, aer + PCIR_AER_UC_STATUS, 4, 0xffffffff);
+	write_config(fd, &p->pc_sel, aer + PCIR_AER_COR_STATUS, 4, 0xffffffff);
+}
Index: pciconf.c
===================================================================
--- pciconf.c	(revision 270540)
+++ pciconf.c	(working copy)
@@ -80,6 +81,7 @@
 static void readit(const char *, const char *, int);
 static void writeit(const char *, const char *, const char *, int);
 static void chkattached(const char *);
+static void clearerrs(const char *);
 
 static int exitstatus = 0;
 
@@ -88,7 +90,8 @@
 {
 	fprintf(stderr, "%s\n%s\n%s\n%s\n",
 		"usage: pciconf -l [-bcevV] [device]",
 		"       pciconf -a device",
+		"       pciconf -C device",
 		"       pciconf -r [-b | -h] device addr[:addr2]",
 		"       pciconf -w [-b | -h] device addr value");
 	exit (1);
@@ -98,14 +102,14 @@
 main(int argc, char **argv)
 {
 	int c;
-	int listmode, readmode, writemode, attachedmode;
+	int listmode, readmode, writemode, attachedmode, clearmode;
 	int bars, caps, errors, verbose, vpd;
 	int byte, isshort;
 
-	listmode = readmode = writemode = attachedmode = 0;
+	listmode = readmode = writemode = attachedmode = clearmode = 0;
 	bars = caps = errors = verbose = vpd = byte = isshort = 0;
 
-	while ((c = getopt(argc, argv, "abcehlrwvV")) != -1) {
+	while ((c = getopt(argc, argv, "abcCehlrwvV")) != -1) {
 		switch(c) {
 		case 'a':
 			attachedmode = 1;
@@ -116,6 +120,10 @@
 			byte = 1;
 			break;
 
+		case 'C':
+			clearmode = 1;
+			break;
+
 		case 'c':
 			caps = 1;
 			break;
@@ -160,6 +172,7 @@
 	if ((listmode && optind >= argc + 1)
 	    || (writemode && optind + 3 != argc)
 	    || (readmode && optind + 2 != argc)
+	    || (clearmode && optind + 1 != argc)
 	    || (attachedmode && optind + 1 != argc))
 		usage();
 
@@ -174,6 +188,8 @@
 	} else if (writemode) {
 		writeit(argv[optind], argv[optind + 1], argv[optind + 2],
 		    byte ? 1 : isshort ? 2 : 4);
+	} else if (clearmode) {
+		clearerrs(argv[optind]);
 	} else {
 		usage();
 	}
@@ -642,6 +663,20 @@
 	return (pi.pi_data);
 }
 
+void
+write_config(int fd, struct pcisel *sel, long reg, int width, uint32_t value)
+{
+	struct pci_io pi;
+
+	pi.pi_sel = *sel;
+	pi.pi_reg = reg;
+	pi.pi_width = width;
+	pi.pi_data = value;
+
+	if (ioctl(fd, PCIOCWRITE, &pi) < 0)
+		err(1, "ioctl(PCIOCWRITE)");
+}
+
 static struct pcisel
 getdevice(const char *name)
 {
@@ -792,19 +827,18 @@
 writeit(const char *name, const char *reg, const char *data, int width)
 {
 	int fd;
-	struct pci_io pi;
+	struct pcisel sel;
+	u_long r, value;
 
-	pi.pi_sel = getsel(name);
-	pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */
-	pi.pi_width = width;
-	pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */
+	sel = getsel(name);
+	r = strtoul(reg, (char **)0, 0); /* XXX error check */
+	value = strtoul(data, (char **)0, 0); /* XXX error check */
 
 	fd = open(_PATH_DEVPCI, O_RDWR, 0);
 	if (fd < 0)
 		err(1, "%s", _PATH_DEVPCI);
 
-	if (ioctl(fd, PCIOCWRITE, &pi) < 0)
-		err(1, "ioctl(PCIOCWRITE)");
+	write_config(fd, &sel, r, width, value);
 }
 
 static void
@@ -825,3 +859,33 @@
 	exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */
 	printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached");
 }
+
+static void
+clearerrs(const char *name)
+{
+	int fd;
+	struct pci_conf_io pc;
+	struct pci_conf conf[1];
+	struct pci_match_conf patterns[1];
+
+	fd = open(_PATH_DEVPCI, O_RDWR, 0);
+	if (fd < 0)
+		err(1, "%s", _PATH_DEVPCI);
+
+	bzero(&pc, sizeof(struct pci_conf_io));
+	pc.match_buf_len = sizeof(conf);
+	pc.matches = conf;
+	bzero(&patterns, sizeof(patterns));
+	patterns[0].pc_sel = getsel(name);
+	patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS |
+	    PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
+	pc.num_patterns = 1;
+	pc.pat_buf_len = sizeof(patterns);
+	pc.patterns = patterns;
+
+	if (ioctl(fd, PCIOCGETCONF, &pc) == -1)
+		err(1, "ioctl(PCIOCGETCONF)");
+
+	clear_errors(fd, conf);
+	close(fd);
+}
Index: pciconf.h
===================================================================
--- pciconf.h	(revision 270540)
+++ pciconf.h	(working copy)
@@ -33,11 +33,14 @@
 #ifndef __PCICONF_H__
 #define	__PCICONF_H__
 
+void	clear_errors(int fd, struct pci_conf *p);
 void	list_caps(int fd, struct pci_conf *p);
 void	list_errors(int fd, struct pci_conf *p);
 void	list_slot(struct pci_conf *p);
 uint8_t	pci_find_cap(int fd, struct pci_conf *p, uint8_t id);
 uint16_t pcie_find_cap(int fd, struct pci_conf *p, uint16_t id);
 uint32_t read_config(int fd, struct pcisel *sel, long reg, int width);
+void	write_config(int fd, struct pcisel *sel, long reg, int width,
+	    uint32_t value);
 
 #endif

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408141208.30208.jhb>