--- a/xen/drivers/passthrough/vtd/quirks.c +++ b/xen/drivers/passthrough/vtd/quirks.c @@ -390,12 +390,62 @@ void __init pci_vtd_quirk(struct pci_dev int bus = pdev->bus; int dev = PCI_SLOT(pdev->devfn); int func = PCI_FUNC(pdev->devfn); - int id, val; + int pos; + u32 val; - id = pci_conf_read32(seg, bus, dev, func, 0); - if ( id == 0x342e8086 || id == 0x3c288086 ) + if ( pci_conf_read16(seg, bus, dev, func, PCI_VENDOR_ID) != 0x8086 ) + return; + + switch ( pci_conf_read16(seg, bus, dev, func, PCI_DEVICE_ID) ) { + case 0x342e: + case 0x3c28: val = pci_conf_read32(seg, bus, dev, func, 0x1AC); pci_conf_write32(seg, bus, dev, func, 0x1AC, val | (1 << 31)); + break; + + case 0x3400 ... 0x3411: case 0x3420: + case 0x3c00 ... 0x3c0b: + case 0x3700 ... 0x3707: case 0x3720: + case 0x0e00: case 0x0e01: case 0x0e04 ... 0x0e0b: + pos = pci_find_ext_capability(seg, bus, pdev->devfn, + PCI_EXT_CAP_ID_ERR); + if ( !pos ) + { + pos = pci_find_ext_capability(seg, bus, pdev->devfn, + PCI_EXT_CAP_ID_VNDR); + while ( pos ) + { + val = pci_conf_read32(seg, bus, dev, func, pos + PCI_VNDR_HEADER); + if ( PCI_VNDR_HEADER_ID(val) == 4 && PCI_VNDR_HEADER_REV(val) == 1 ) + { + pos += PCI_VNDR_HEADER; + break; + } + pos = pci_find_next_ext_capability(seg, bus, pdev->devfn, pos, + PCI_EXT_CAP_ID_VNDR); + } + } + if ( !pos ) + { + printk(XENLOG_WARNING "%04x:%02x:%02x.%u without AER capability?\n", + seg, bus, dev, func); + break; + } + + val = pci_conf_read32(seg, bus, dev, func, pos + PCI_ERR_UNCOR_MASK); + pci_conf_write32(seg, bus, dev, func, pos + PCI_ERR_UNCOR_MASK, + val | PCI_ERR_UNC_UNSUP); + val = pci_conf_read32(seg, bus, dev, func, pos + PCI_ERR_COR_MASK); + pci_conf_write32(seg, bus, dev, func, pos + PCI_ERR_COR_MASK, + val | PCI_ERR_COR_ADV_NFAT); + + /* XPUNCERRMSK Send Completion with Unsupported Request */ + val = pci_conf_read32(seg, bus, dev, func, 0x20c); + pci_conf_write32(seg, bus, dev, func, 0x20c, val | (1 << 4)); + + printk(XENLOG_INFO "Masked UR signaling on %04x:%02x:%02x.%u\n", + seg, bus, dev, func); + break; } } --- a/xen/drivers/pci/pci.c +++ b/xen/drivers/pci/pci.c @@ -66,23 +66,33 @@ int pci_find_next_cap(u16 seg, u8 bus, u /** * pci_find_ext_capability - Find an extended capability - * @dev: PCI device to query + * @seg/@bus/@devfn: PCI device to query * @cap: capability code * * Returns the address of the requested extended capability structure * within the device's PCI configuration space or 0 if the device does - * not support it. Possible values for @cap: - * - * %PCI_EXT_CAP_ID_ERR Advanced Error Reporting - * %PCI_EXT_CAP_ID_VC Virtual Channel - * %PCI_EXT_CAP_ID_DSN Device Serial Number - * %PCI_EXT_CAP_ID_PWR Power Budgeting + * not support it. */ int pci_find_ext_capability(int seg, int bus, int devfn, int cap) { + return pci_find_next_ext_capability(seg, bus, devfn, 0, cap); +} + +/** + * pci_find_next_ext_capability - Find another extended capability + * @seg/@bus/@devfn: PCI device to query + * @pos: starting position + * @cap: capability code + * + * Returns the address of the requested extended capability structure + * within the device's PCI configuration space or 0 if the device does + * not support it. + */ +int pci_find_next_ext_capability(int seg, int bus, int devfn, int start, int cap) +{ u32 header; int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */ - int pos = 0x100; + int pos = max(start, 0x100); header = pci_conf_read32(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos); @@ -92,9 +102,10 @@ int pci_find_ext_capability(int seg, int */ if ( (header == 0) || (header == -1) ) return 0; + ASSERT(start != pos || PCI_EXT_CAP_ID(header) == cap); while ( ttl-- > 0 ) { - if ( PCI_EXT_CAP_ID(header) == cap ) + if ( PCI_EXT_CAP_ID(header) == cap && pos != start ) return pos; pos = PCI_EXT_CAP_NEXT(header); if ( pos < 0x100 ) --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -140,6 +140,7 @@ int pci_mmcfg_write(unsigned int seg, un int pci_find_cap_offset(u16 seg, u8 bus, u8 dev, u8 func, u8 cap); int pci_find_next_cap(u16 seg, u8 bus, unsigned int devfn, u8 pos, int cap); int pci_find_ext_capability(int seg, int bus, int devfn, int cap); +int pci_find_next_ext_capability(int seg, int bus, int devfn, int pos, int cap); const char *parse_pci(const char *, unsigned int *seg, unsigned int *bus, unsigned int *dev, unsigned int *func); --- a/xen/include/xen/pci_regs.h +++ b/xen/include/xen/pci_regs.h @@ -431,6 +431,7 @@ #define PCI_EXT_CAP_ID_VC 2 #define PCI_EXT_CAP_ID_DSN 3 #define PCI_EXT_CAP_ID_PWR 4 +#define PCI_EXT_CAP_ID_VNDR 11 #define PCI_EXT_CAP_ID_ACS 13 #define PCI_EXT_CAP_ID_ARI 14 #define PCI_EXT_CAP_ID_ATS 15 @@ -459,6 +460,7 @@ #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 */ +#define PCI_ERR_COR_ADV_NFAT 0x00002000 /* Advisory Non-Fatal */ #define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ /* Same bits as above */ #define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ @@ -510,6 +512,12 @@ #define PCI_PWR_CAP 12 /* Capability */ #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ +/* Vendor-Specific (VSEC, PCI_EXT_CAP_ID_VNDR) */ +#define PCI_VNDR_HEADER 4 /* Vendor-Specific Header */ +#define PCI_VNDR_HEADER_ID(x) ((x) & 0xffff) +#define PCI_VNDR_HEADER_REV(x) (((x) >> 16) & 0xf) +#define PCI_VNDR_HEADER_LEN(x) (((x) >> 20) & 0xfff) + /* * Hypertransport sub capability types *