Sophie

Sophie

distrib > CentOS > 5 > x86_64 > by-pkgid > ea32411352494358b8d75a78402a4713 > files > 3635

kernel-2.6.18-238.19.1.el5.centos.plus.src.rpm

From: Andy Gospodarek <gospo@redhat.com>
Date: Tue, 27 Jan 2009 16:38:41 -0500
Subject: [pci] msi: set 'En' bit for devices on HT-based platform
Message-id: 20090127213841.GI22333@gospo.rdu.redhat.com
O-Subject: Re: [RHEL5.4 PATCH] pci: set 'En' bit of MSI Mapping for devices on HT-based nvidia/Ali platforms
Bugzilla: 290701
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>
RH-Acked-by: Brian Maly <bmaly@redhat.com>

There were some reports that interrupts were just not working correctly
with e1000e on a platform with nvidia bridge chips.  There were some
recent patches to e1000/e1000e to address issues where MSI was detected
but not completely functional.  I also got reports that Fedora was
working find on these systems, so I looked around and discovered that we
needed to backport the following upstream commit:

    commit 9dc625e72309e1c919ea3e7f51d0ffca96123787
    Author: Peer Chen <pchen@nvidia.com>
    Date:   Mon Feb 4 23:50:13 2008 -0800

        PCI: quirks: set 'En' bit of MSI Mapping for devices onHT-based nvidia platform

        According to HT spec, to get message interrupt from devices mapped to HT
        interrupt message, the 'En' bit of MSI Mapping capability need to be set.
        The patch do this setting in quirks code for the devices on HT-based nvidia
        platform.

Later the same fix was proposed Ali chipsets as well, so I added this commit:

    commit 439a7733e8fcbaee39979c10246101565834d6b2
    Author: Björn Krombholz <fox.box@gmail.com>
    Date:   Mon May 12 00:24:27 2008 +0200

        PCI: enable nv_msi_ht_cap_quirk for ALi bridges

        This applies the NVidia MSI enabled flag for HT capable devices quirk
        to ALi bridges as well.

The nvidia portion of this patch has been tested by several customers
and will resolve RHBZ 290701.  I have gotten no reports that the Ali
chipset is an issue, but this is a one-liner we should take since we are
adding this fix.

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index ca70481..da65176 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -27,6 +27,69 @@
  * Mark this device with a broken_parity_status, to allow
  * PCI scanning code to "skip" this now blacklisted device.
  */
+/*
+ *  Force enable MSI mapping capability on HT bridges  */
+static inline void ht_enable_msi_mapping(struct pci_dev *dev)
+{
+	int pos, ttl = 48;
+
+	pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+	while (pos && ttl--) {
+		u8 flags;
+
+		if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+					 &flags) == 0) {
+			dev_info(&dev->dev, "Enabling HT MSI Mapping\n");
+
+			pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+					      flags | HT_MSI_FLAGS_ENABLE);
+		}
+		pos = pci_find_next_ht_capability(dev, pos,
+						  HT_CAPTYPE_MSI_MAPPING);
+	}
+}
+
+static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+{
+	struct pci_dev *host_bridge;
+	int pos, ttl = 48;
+
+	/*
+	 * HT MSI mapping should be disabled on devices that are below
+	 * a non-Hypertransport host bridge. Locate the host bridge...
+	 */
+	host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
+	if (host_bridge == NULL) {
+		dev_warn(&dev->dev,
+			 "nv_msi_ht_cap_quirk didn't locate host bridge\n");
+		return;
+	}
+
+	pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE);
+	if (pos != 0) {
+		/* Host bridge is to HT */
+		ht_enable_msi_mapping(dev);
+		return;
+	}
+
+	/* Host bridge is not to HT, disable HT MSI mapping on this device */
+	pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+	while (pos && ttl--) {
+		u8 flags;
+
+		if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+					 &flags) == 0) {
+			dev_info(&dev->dev, "Quirk disabling HT MSI mapping");
+			pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+					      flags & ~HT_MSI_FLAGS_ENABLE);
+		}
+		pos = pci_find_next_ht_capability(dev, pos,
+						  HT_CAPTYPE_MSI_MAPPING);
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+
 static void __devinit quirk_mellanox_tavor(struct pci_dev *dev)
 {
 	dev->broken_parity_status = 1;	/* This device gives false positives */