diff options
Diffstat (limited to 'drivers/pci/pcie/portdrv_core.c')
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 42 |
1 files changed, 26 insertions, 16 deletions
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index bf851da97947..5c25761cd05e 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -206,19 +206,20 @@ legacy_irq: */ static int get_port_device_capability(struct pci_dev *dev) { + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); + bool native; int services = 0; - int cap_mask = 0; - cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP; - if (pci_aer_available()) - cap_mask |= PCIE_PORT_SERVICE_AER | PCIE_PORT_SERVICE_DPC; - - if (pcie_ports_auto) - pcie_port_platform_notify(dev, &cap_mask); + /* + * If the user specified "pcie_ports=native", use the PCIe services + * regardless of whether the platform has given us permission. On + * ACPI systems, this means we ignore _OSC. + */ + native = !pcie_ports_auto; - /* Hot-Plug Capable */ - if ((cap_mask & PCIE_PORT_SERVICE_HP) && dev->is_hotplug_bridge) { + if (dev->is_hotplug_bridge && (native || host->native_hotplug)) { services |= PCIE_PORT_SERVICE_HP; + /* * Disable hot-plug interrupts in case they have been enabled * by the BIOS and the hot-plug service driver is not loaded. @@ -226,20 +227,27 @@ static int get_port_device_capability(struct pci_dev *dev) pcie_capability_clear_word(dev, PCI_EXP_SLTCTL, PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE); } - /* AER capable */ - if ((cap_mask & PCIE_PORT_SERVICE_AER) - && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) { + + if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR) && + pci_aer_available() && (native || host->native_aer)) { services |= PCIE_PORT_SERVICE_AER; + /* * Disable AER on this port in case it's been enabled by the * BIOS (the AER service driver will enable it when necessary). */ pci_disable_pcie_error_reporting(dev); } - /* Root ports are capable of generating PME too */ - if ((cap_mask & PCIE_PORT_SERVICE_PME) - && pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) { + + /* + * Root ports are capable of generating PME too. Root Complex + * Event Collectors can also generate PMEs, but we don't handle + * those yet. + */ + if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT && + (native || host->native_pme)) { services |= PCIE_PORT_SERVICE_PME; + /* * Disable PME interrupt on this port in case it's been enabled * by the BIOS (the PME service driver will enable it when @@ -247,7 +255,9 @@ static int get_port_device_capability(struct pci_dev *dev) */ pcie_pme_interrupt_enable(dev, false); } - if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC)) + + if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC) && + pci_aer_available()) services |= PCIE_PORT_SERVICE_DPC; return services; |