PCI/portdrv: Do not setup up IRQs if there are no users
authorJan Kiszka <jan.kiszka@siemens.com>
Mon, 30 Aug 2021 08:08:10 +0000 (10:08 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 20 Sep 2021 20:09:14 +0000 (15:09 -0500)
Avoid registering service IRQs if there is no service that offers them
or no driver to register a handler against them. This saves IRQ vectors
when they are limited (e.g. on x86) and also avoids that spurious events
could hit a missing handler. Such spurious events need to be generated
by the Jailhouse hypervisor for active MSI vectors when enabling or
disabling itself.

Link: https://lore.kernel.org/r/8f9a13ac-8ab1-15ac-06cb-c131b488a36f@siemens.com
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/pcie/portdrv_core.c

index 3ee63968deaa5880dc700feb3d17b338a8557e68..bf5440c3ca8a90c2ffaa2c739797034fdd2eaf20 100644 (file)
@@ -166,9 +166,6 @@ static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
 {
        int ret, i;
 
-       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
-               irqs[i] = -1;
-
        /*
         * If we support PME but can't use MSI/MSI-X for it, we have to
         * fall back to INTx or other interrupts, e.g., a system shared
@@ -317,8 +314,10 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
  */
 int pcie_port_device_register(struct pci_dev *dev)
 {
-       int status, capabilities, i, nr_service;
-       int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
+       int status, capabilities, irq_services, i, nr_service;
+       int irqs[PCIE_PORT_DEVICE_MAXSERVICES] = {
+               [0 ... PCIE_PORT_DEVICE_MAXSERVICES-1] = -1
+       };
 
        /* Enable PCI Express port device */
        status = pci_enable_device(dev);
@@ -331,18 +330,32 @@ int pcie_port_device_register(struct pci_dev *dev)
                return 0;
 
        pci_set_master(dev);
-       /*
-        * Initialize service irqs. Don't use service devices that
-        * require interrupts if there is no way to generate them.
-        * However, some drivers may have a polling mode (e.g. pciehp_poll_mode)
-        * that can be used in the absence of irqs.  Allow them to determine
-        * if that is to be used.
-        */
-       status = pcie_init_service_irqs(dev, irqs, capabilities);
-       if (status) {
-               capabilities &= PCIE_PORT_SERVICE_HP;
-               if (!capabilities)
-                       goto error_disable;
+
+       irq_services = 0;
+       if (IS_ENABLED(CONFIG_PCIE_PME))
+               irq_services |= PCIE_PORT_SERVICE_PME;
+       if (IS_ENABLED(CONFIG_PCIEAER))
+               irq_services |= PCIE_PORT_SERVICE_AER;
+       if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
+               irq_services |= PCIE_PORT_SERVICE_HP;
+       if (IS_ENABLED(CONFIG_PCIE_DPC))
+               irq_services |= PCIE_PORT_SERVICE_DPC;
+       irq_services &= capabilities;
+
+       if (irq_services) {
+               /*
+                * Initialize service IRQs. Don't use service devices that
+                * require interrupts if there is no way to generate them.
+                * However, some drivers may have a polling mode (e.g.
+                * pciehp_poll_mode) that can be used in the absence of IRQs.
+                * Allow them to determine if that is to be used.
+                */
+               status = pcie_init_service_irqs(dev, irqs, irq_services);
+               if (status) {
+                       irq_services &= PCIE_PORT_SERVICE_HP;
+                       if (!irq_services)
+                               goto error_disable;
+               }
        }
 
        /* Allocate child services if any */