From owner-freebsd-arch@FreeBSD.ORG Mon Dec 11 00:29:16 2006 Return-Path: X-Original-To: freebsd-arch@freebsd.org Delivered-To: freebsd-arch@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id CD2DC16A40F; Mon, 11 Dec 2006 00:29:16 +0000 (UTC) (envelope-from jdp@polstra.com) Received: from blake.polstra.com (blake.polstra.com [64.81.189.66]) by mx1.FreeBSD.org (Postfix) with ESMTP id 5AE4B43C9D; Mon, 11 Dec 2006 00:27:57 +0000 (GMT) (envelope-from jdp@polstra.com) Received: from [127.0.0.1] (adsl-sj-9-245.rockisland.net [64.119.9.245]) by blake.polstra.com (8.13.8/8.13.8) with ESMTP id kBB0T6KC094486 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sun, 10 Dec 2006 16:29:07 -0800 (PST) (envelope-from jdp@polstra.com) In-Reply-To: <200611201242.58088.jhb@freebsd.org> References: <200611201242.58088.jhb@freebsd.org> Mime-Version: 1.0 (Apple Message framework v752.3) Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed Message-Id: <095D8C4E-5C80-451A-8DF9-C3B307A0F603@polstra.com> Content-Transfer-Encoding: 7bit From: John Polstra Date: Sun, 10 Dec 2006 16:29:00 -0800 To: John Baldwin X-Mailer: Apple Mail (2.752.3) Cc: freebsd-arch@freebsd.org Subject: Re: Where do MSI quirks belong? [patch] X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Dec 2006 00:29:17 -0000 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? */