#include <xen/softirq.h>
#include <xen/time.h>
#include <xen/pci.h>
+#include <xen/pci_ids.h>
#include <xen/pci_regs.h>
#include <xen/keyhandler.h>
#include <asm/msi.h>
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) !=
+ PCI_VENDOR_ID_INTEL )
+ return;
+
+ switch ( pci_conf_read16(seg, bus, dev, func, PCI_DEVICE_ID) )
{
+ case 0x342e: /* Tylersburg chipset (Nehalem / Westmere systems) */
+ case 0x3c28: /* Sandybridge */
val = pci_conf_read32(seg, bus, dev, func, 0x1AC);
pci_conf_write32(seg, bus, dev, func, 0x1AC, val | (1 << 31));
+ break;
+
+ /* Tylersburg (EP)/Boxboro (MP) chipsets (NHM-EP/EX, WSM-EP/EX) */
+ case 0x3400 ... 0x3407: /* host bridges */
+ case 0x3408 ... 0x3411: case 0x3420 ... 0x3421: /* root ports */
+ /* JasperForest (Intel Xeon Processor C5500/C3500 */
+ case 0x3700 ... 0x370f: /* host bridges */
+ case 0x3720 ... 0x3724: /* root ports */
+ /* Sandybridge-EP (Romley) */
+ case 0x3c00: /* host bridge */
+ case 0x3c01 ... 0x3c0b: /* root ports */
+ 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;
}
}
/**
* 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);
*/
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 )
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);
#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
#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 */
#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
*