--- //depot/projects/smpng/sys/dev/pci/pci.c 2006/12/12 19:41:57 +++ //depot/user/jhb/msi/dev/pci/pci.c 2006/12/12 19:59:13 @@ -165,6 +165,7 @@ uint32_t devid; /* Vendor/device of the card */ int type; #define PCI_QUIRK_MAP_REG 1 /* PCI map register in weird place */ +#define PCI_QUIRK_DISABLE_MSI 2 /* MSI/MSI-X doesn't work */ int arg1; int arg2; }; @@ -176,6 +177,24 @@ /* As does the Serverworks OSB4 (the SMBus mapping register) */ { 0x02001166, PCI_QUIRK_MAP_REG, 0x90, 0 }, + /* + * MSI doesn't work with the Intel E7500 chipset, at least on + * the XXXX system. + */ + { 0x25408086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + + /* + * MSI doesn't work with the Intel E7501 chipset, at least on + * the Tyan 2721 motherboard. + */ + { 0x254c8086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + + /* + * MSI doesn't work with devices behind the AMD 8131 HT-PCIX + * bridge. + */ + { 0x74501022, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0 } }; @@ -224,6 +243,11 @@ SYSCTL_INT(_hw_pci, OID_AUTO, enable_msix, CTLFLAG_RW, &pci_do_msix, 1, "Enable support for MSI-X interrupts"); +static int pci_honor_msi_blacklist = 1; +TUNABLE_INT("hw.pci.honor_msi_blacklist", &pci_honor_msi_blacklist); +SYSCTL_INT(_hw_pci, OID_AUTO, honor_msi_blacklist, CTLFLAG_RD, + &pci_honor_msi_blacklist, 1, "Honor chipset blacklist for MSI"); + /* Find a device_t by bus/slot/function */ device_t @@ -1195,6 +1225,47 @@ } /* + * Returns true if the specified device is blacklisted because MSI + * doesn't work. + */ +int +pci_msi_device_blacklisted(device_t dev) +{ + struct pci_quirk *q; + + if (!pci_honor_msi_blacklist) + return (0); + + for (q = &pci_quirks[0]; q->devid; q++) { + if (q->devid == pci_get_devid(dev) && + q->type == PCI_QUIRK_DISABLE_MSI) + return (1); + } + return (0); +} + +/* + * Determine if MSI is blacklisted globally on this sytem. Currently, + * we just check for blacklisted chipsets as represented by the + * host-PCI bridge at device 0:0:0. In the future, it may become + * necessary to check other system attributes, such as the kenv values + * that give the motherboard manufacturer and model number. + */ +static int +pci_msi_blacklisted(void) +{ + device_t dev; + + if (!pci_honor_msi_blacklist) + return (0); + + dev = pci_find_bsf(0, 0, 0); + if (dev != NULL) + return (pci_msi_device_blacklisted(dev)); + return (0); +} + +/* * Attempt to allocate *count MSI messages. The actual number allocated is * returned in *count. After this function returns, each message will be * available to the driver as SYS_RES_IRQ resources starting at a rid 1. @@ -1217,6 +1288,10 @@ if (rle != NULL && rle->res != NULL) return (ENXIO); + /* If MSI is blacklisted for this system, fail. */ + if (pci_msi_blacklisted()) + return (ENXIO); + /* Try MSI-X first. */ error = pci_alloc_msix(dev, child, count); if (error != ENODEV) --- //depot/projects/smpng/sys/dev/pci/pci_pci.c 2006/11/13 22:08:01 +++ //depot/user/jhb/msi/dev/pci/pci_pci.c 2006/12/12 17:52:17 @@ -240,6 +240,9 @@ } } + if (pci_msi_device_blacklisted(dev)) + sc->flags |= PCIB_DISABLE_MSI; + /* * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, @@ -547,8 +550,11 @@ int pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) { + struct pcib_softc *sc = device_get_softc(dev); device_t bus; + if (sc->flags & PCIB_DISABLE_MSI) + return (ENXIO); bus = device_get_parent(pcib); return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, irqs)); @@ -568,8 +574,11 @@ int pcib_alloc_msix(device_t pcib, device_t dev, int index, int *irq) { + struct pcib_softc *sc = device_get_softc(dev); device_t bus; + if (sc->flags & PCIB_DISABLE_MSI) + return (ENXIO); bus = device_get_parent(pcib); return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, index, irq)); } --- //depot/projects/smpng/sys/dev/pci/pcib_private.h 2006/11/13 22:08:01 +++ //depot/user/jhb/msi/dev/pci/pcib_private.h 2006/11/29 21:34:00 @@ -46,6 +46,7 @@ device_t dev; uint32_t flags; /* flags */ #define PCIB_SUBTRACTIVE 0x1 +#define PCIB_DISABLE_MSI 0x2 uint16_t command; /* command register */ uint8_t secbus; /* secondary bus number */ uint8_t subbus; /* subordinate bus number */ --- //depot/projects/smpng/sys/dev/pci/pcivar.h 2006/11/15 21:39:52 +++ //depot/user/jhb/msi/dev/pci/pcivar.h 2006/12/12 17:52:17 @@ -417,6 +417,7 @@ void pci_mask_msix(device_t dev, u_int index); int pci_pending_msix(device_t dev, u_int index); void pci_unmask_msix(device_t dev, u_int index); +int pci_msi_device_blacklisted(device_t dev); #endif /* _SYS_BUS_H_ */