Date: Sun, 10 Dec 2006 16:29:00 -0800 From: John Polstra <jdp@polstra.com> To: John Baldwin <jhb@freebsd.org> Cc: freebsd-arch@freebsd.org Subject: Re: Where do MSI quirks belong? [patch] Message-ID: <095D8C4E-5C80-451A-8DF9-C3B307A0F603@polstra.com> In-Reply-To: <200611201242.58088.jhb@freebsd.org> References: <XFMail.20061119201122.jdp@polstra.com> <200611201242.58088.jhb@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
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? */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?095D8C4E-5C80-451A-8DF9-C3B307A0F603>