Skip site navigation (1)Skip section navigation (2)
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>