atom feed17 messages in org.freebsd.freebsd-archWhere do MSI quirks belong? [patch]
FromSent OnAttachments
John PolstraNov 20, 2006 4:11 am 
John BaldwinNov 20, 2006 6:45 pm 
John PolstraNov 20, 2006 6:49 pm 
John BaldwinNov 20, 2006 9:07 pm 
Jack VogelNov 20, 2006 11:44 pm 
John PolstraNov 20, 2006 11:59 pm 
Jack VogelNov 21, 2006 12:02 am 
John PolstraNov 21, 2006 12:06 am 
John PolstraDec 10, 2006 4:28 pm 
Andre OppermannDec 11, 2006 2:30 am 
John BaldwinDec 11, 2006 6:57 am 
John PolstraDec 11, 2006 3:24 pm 
John PolstraDec 11, 2006 3:32 pm 
John BaldwinDec 12, 2006 12:21 pm 
John PolstraDec 13, 2006 3:31 pm 
John PolstraDec 13, 2006 5:56 pm 
John BaldwinDec 14, 2006 9:41 am 
Subject:Where do MSI quirks belong? [patch]
From:John Polstra (jd@polstra.com)
Date:Dec 10, 2006 4:28:59 pm
List:org.freebsd.freebsd-arch

On Nov 20, 2006, at 9:42 AM, John Baldwin wrote:

It's going to be a function of the chipset, as something in the chipset (presumably a Host -> PCI bridge) has to listen for writes to 0xfeeXXXXXX and convert them into APIC messages. There are two ways I planned on doing this:

1) Allow PCI-PCI bridges to be blacklisted, and the pcib_alloc_msi [x]() methods would compare the bridge's device id against a blacklist. This can matter if you have virtual PCI-PCI bridges that really a HT -> PCI bridge or the like.

2) Blacklist chipsets in the x86 MD code based on the device ID of the first Host -> PCI bridge at device 0.0.0.

I have implemented both of these checks, except that I put #2 into the MI code since I couldn't find any reason to make it x86- specific. Here's the patch. Does it look OK to you? It works fine here.

John

Index: pci.c =================================================================== RCS file: /home/ncvs/src/sys/dev/pci/pci.c,v retrieving revision 1.324 diff -u -p -u -r1.324 pci.c --- pci.c 21 Nov 2006 05:46:09 -0000 1.324 +++ pci.c 11 Dec 2006 00:16:59 -0000 @@ -175,6 +175,24 @@ struct pci_quirk pci_quirks[] = { { 0 } }; +/* MSI device quirks. */ +struct msi_device_quirk { + uint32_t devid; /* Vendor/device ID */ + int flags; /* MSI quirk flags */ +}; + +#define MSI_QUIRK_NO_MSI 0x01 +#define MSI_QUIRK_NO_MSIX 0x02 + +struct msi_device_quirk msi_device_quirks[] = { + /* + * MSI doesn't work with the Intel E7501 chipset, at least on + * the Tyan 2721 motherboard. + */ + { 0x254c8086, MSI_QUIRK_NO_MSI | MSI_QUIRK_NO_MSIX }, + { 0 } +}; + /* map register information */ #define PCI_MAPMEM 0x01 /* memory map */ #define PCI_MAPMEMP 0x02 /* prefetchable memory map */ @@ -1116,6 +1134,43 @@ pci_resume_msi(device_t dev) } /* + * Return the MSI quirks associated with a specific device, typically + * a host-PCI or PCI-PCI bridge. + */ +static int +pci_get_msi_device_quirks(device_t dev) +{ + uint32_t devid; + int i; + + devid = pci_get_device(dev) << 16 | pci_get_vendor(dev); + for (i = 0; msi_device_quirks[i].devid != 0; i++) + if (msi_device_quirks[i].devid == devid) + return (msi_device_quirks[i].flags); + return (0); +} + +/* + * Return the systemwide MSI quirks. 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_get_msi_global_quirks(void) +{ + device_t dev; + int quirks; + + quirks = 0; + dev = pci_find_bsf(0, 0, 0); + if (dev != NULL) + quirks |= pci_get_msi_device_quirks(dev); + return (quirks); +} + +/* * 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. @@ -1126,7 +1181,7 @@ pci_alloc_msi_method(device_t dev, devic struct pci_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; struct resource_list_entry *rle; - int actual, error, i, irqs[32]; + int actual, error, i, irqs[32], quirks; uint16_t ctrl; /* Don't let count == 0 get us into trouble. */ @@ -1138,13 +1193,23 @@ pci_alloc_msi_method(device_t dev, devic if (rle != NULL && rle->res != NULL) return (ENXIO); + /* + * Check for MSI quirks that affect the whole system, and those + * that are specific to the device's parent bridge. + */ + quirks = pci_get_msi_global_quirks() | + pci_get_msi_device_quirks(device_get_parent(dev)); + /* Try MSI-X first. */ - error = pci_alloc_msix(dev, child, count); - if (error != ENODEV) - return (error); + if (!(quirks & MSI_QUIRK_NO_MSIX)) { + error = pci_alloc_msix(dev, child, count); + if (error != ENODEV) + return (error); + } /* MSI capability present? */ - if (cfg->msi.msi_location == 0 || !pci_do_msi) + if (cfg->msi.msi_location == 0 || !pci_do_msi || + (quirks & MSI_QUIRK_NO_MSI)) return (ENODEV); /* Already have allocated messages? */