]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
PCI/portdrv: Factor out Interrupt Message Number lookup
authorBjorn Helgaas <bhelgaas@google.com>
Fri, 20 Oct 2017 13:48:06 +0000 (08:48 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 20 Oct 2017 16:08:28 +0000 (11:08 -0500)
Factor out Interrupt Message Number lookup from the MSI/MSI-X interrupt
setup.  One side effect is that we only have to check once to see if we
have enough vectors for all the services.  No functional change intended.

Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
drivers/pci/pcie/portdrv_core.c

index accd16082348df23511a0b9a44c4fae1994501b3..102f5c5fcfe0a95baa5206e12b77ee4410a9c22d 100644 (file)
@@ -43,6 +43,53 @@ static void release_pcie_device(struct device *dev)
        kfree(to_pcie_device(dev));
 }
 
+/*
+ * Fill in *pme, *aer, *dpc with the relevant Interrupt Message Numbers if
+ * services are enabled in "mask".  Return the number of MSI/MSI-X vectors
+ * required to accommodate the largest Message Number.
+ */
+static int pcie_message_numbers(struct pci_dev *dev, int mask,
+                               u32 *pme, u32 *aer, u32 *dpc)
+{
+       u32 nvec = 0, pos, reg32;
+       u16 reg16;
+
+       /*
+        * The Interrupt Message Number indicates which vector is used, i.e.,
+        * the MSI-X table entry or the MSI offset between the base Message
+        * Data and the generated interrupt message.  See PCIe r3.1, sec
+        * 7.8.2, 7.10.10, 7.31.2.
+        */
+
+       if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
+               pcie_capability_read_word(dev, PCI_EXP_FLAGS, &reg16);
+               *pme = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
+               nvec = *pme + 1;
+       }
+
+       if (mask & PCIE_PORT_SERVICE_AER) {
+               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+               if (pos) {
+                       pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS,
+                                             &reg32);
+                       *aer = (reg32 & PCI_ERR_ROOT_AER_IRQ) >> 27;
+                       nvec = max(nvec, *aer + 1);
+               }
+       }
+
+       if (mask & PCIE_PORT_SERVICE_DPC) {
+               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC);
+               if (pos) {
+                       pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP,
+                                            &reg16);
+                       *dpc = reg16 & PCI_EXP_DPC_IRQ;
+                       nvec = max(nvec, *dpc + 1);
+               }
+       }
+
+       return nvec;
+}
+
 /**
  * pcie_port_enable_irq_vec - try to set up MSI-X or MSI as interrupt mode
  * for given port
@@ -54,7 +101,8 @@ static void release_pcie_device(struct device *dev)
  */
 static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
 {
-       int nr_entries, entry, nvec = 0;
+       int nr_entries, nvec;
+       u32 pme = 0, aer = 0, dpc = 0;
 
        /* Allocate the maximum possible number of MSI/MSI-X vectors */
        nr_entries = pci_alloc_irq_vectors(dev, 1, PCIE_PORT_MAX_MSI_ENTRIES,
@@ -62,54 +110,24 @@ static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
        if (nr_entries < 0)
                return nr_entries;
 
-       /*
-        * The Interrupt Message Number indicates which vector is used, i.e.,
-        * the MSI-X table entry or the MSI offset between the base Message
-        * Data and the generated interrupt message.  See PCIe r3.1, sec
-        * 7.8.2, 7.10.10, 7.31.2.
-        */
-       if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
-               u16 reg16;
-
-               pcie_capability_read_word(dev, PCI_EXP_FLAGS, &reg16);
-               entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
-               if (entry >= nr_entries)
-                       goto out_free_irqs;
-
-               /* PME and hotplug share an MSI/MSI-X vector */
-               irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pci_irq_vector(dev, entry);
-               irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pci_irq_vector(dev, entry);
-
-               nvec = max(nvec, entry + 1);
+       /* See how many and which Interrupt Message Numbers we actually use */
+       nvec = pcie_message_numbers(dev, mask, &pme, &aer, &dpc);
+       if (nvec > nr_entries) {
+               pci_free_irq_vectors(dev);
+               return -EIO;
        }
 
-       if (mask & PCIE_PORT_SERVICE_AER) {
-               u32 reg32, pos;
-
-               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
-               entry = (reg32 & PCI_ERR_ROOT_AER_IRQ) >> 27;
-               if (entry >= nr_entries)
-                       goto out_free_irqs;
-
-               irqs[PCIE_PORT_SERVICE_AER_SHIFT] = pci_irq_vector(dev, entry);
-
-               nvec = max(nvec, entry + 1);
+       /* PME and hotplug share an MSI/MSI-X vector */
+       if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
+               irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pci_irq_vector(dev, pme);
+               irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pci_irq_vector(dev, pme);
        }
 
-       if (mask & PCIE_PORT_SERVICE_DPC) {
-               u16 reg16, pos;
-
-               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC);
-               pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP, &reg16);
-               entry = reg16 & PCI_EXP_DPC_IRQ;
-               if (entry >= nr_entries)
-                       goto out_free_irqs;
-
-               irqs[PCIE_PORT_SERVICE_DPC_SHIFT] = pci_irq_vector(dev, entry);
+       if (mask & PCIE_PORT_SERVICE_AER)
+               irqs[PCIE_PORT_SERVICE_AER_SHIFT] = pci_irq_vector(dev, aer);
 
-               nvec = max(nvec, entry + 1);
-       }
+       if (mask & PCIE_PORT_SERVICE_DPC)
+               irqs[PCIE_PORT_SERVICE_DPC_SHIFT] = pci_irq_vector(dev, dpc);
 
        /* If we allocated more than we need, free them and allocate fewer */
        if (nvec != nr_entries) {
@@ -122,10 +140,6 @@ static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
        }
 
        return 0;
-
-out_free_irqs:
-       pci_free_irq_vectors(dev);
-       return -EIO;
 }
 
 /**