MSI: Factorize common code in pci_msi_supported()
authorBrice Goglin <brice@myri.com>
Thu, 31 Aug 2006 05:55:07 +0000 (01:55 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 27 Sep 2006 00:43:52 +0000 (17:43 -0700)
pci_enable_msi() and pci_enable_msix() use the same code to detect
whether MSI might be enabled on this device. Factorize this code in
pci_msi_supported(). And improve the documentation about the fact
that only the root chipset must support MSI, but it is hard to
find the root bus so we check all parent busses MSI flags.

Signed-off-by: Brice Goglin <brice@myri.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/msi.c

index a83c1f5735d69bc05418e5963dbbcbc975a06a11..008235947aa41248d221817e23731f4de7cf626f 100644 (file)
@@ -900,6 +900,33 @@ static int msix_capability_init(struct pci_dev *dev,
        return 0;
 }
 
+/**
+ * pci_msi_supported - check whether MSI may be enabled on device
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * MSI must be globally enabled and supported by the device and its root
+ * bus. But, the root bus is not easy to find since some architectures
+ * have virtual busses on top of the PCI hierarchy (for instance the
+ * hypertransport bus), while the actual bus where MSI must be supported
+ * is below. So we test the MSI flag on all parent busses and assume
+ * that no quirk will ever set the NO_MSI flag on a non-root bus.
+ **/
+static
+int pci_msi_supported(struct pci_dev * dev)
+{
+       struct pci_bus *bus;
+
+       if (!pci_msi_enable || !dev || dev->no_msi)
+               return -EINVAL;
+
+       /* check MSI flags of all parent busses */
+       for (bus = dev->bus; bus; bus = bus->parent)
+               if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+                       return -EINVAL;
+
+       return 0;
+}
+
 /**
  * pci_enable_msi - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
@@ -912,19 +939,11 @@ static int msix_capability_init(struct pci_dev *dev,
  **/
 int pci_enable_msi(struct pci_dev* dev)
 {
-       struct pci_bus *bus;
-       int pos, temp, status = -EINVAL;
+       int pos, temp, status;
        u16 control;
 
-       if (!pci_msi_enable || !dev)
-               return status;
-
-       if (dev->no_msi)
-               return status;
-
-       for (bus = dev->bus; bus; bus = bus->parent)
-               if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
-                       return -EINVAL;
+       if (pci_msi_supported(dev) < 0)
+               return -EINVAL;
 
        temp = dev->irq;
 
@@ -1134,22 +1153,14 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
  **/
 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 {
-       struct pci_bus *bus;
        int status, pos, nr_entries, free_vectors;
        int i, j, temp;
        u16 control;
        unsigned long flags;
 
-       if (!pci_msi_enable || !dev || !entries)
+       if (!entries || pci_msi_supported(dev) < 0)
                return -EINVAL;
 
-       if (dev->no_msi)
-               return -EINVAL;
-
-       for (bus = dev->bus; bus; bus = bus->parent)
-               if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
-                       return -EINVAL;
-
        status = msi_init();
        if (status < 0)
                return status;