PCIe AER
John Baldwin
jhb at freebsd.org
Thu Aug 14 16:11:41 UTC 2014
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
More information about the freebsd-hackers
mailing list