From 5352a44a561d708f1a975a90f5ce16a054fe265c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 23 May 2018 17:24:08 -0500 Subject: [PATCH] PCI: pciehp: Make pciehp_is_native() stricter Previously pciehp_is_native() returned true for any PCI device in a hierarchy where _OSC says we can use pciehp. This is incorrect because bridges without PCI_EXP_SLTCAP_HPC capability should be managed by acpiphp instead. Improve pciehp_is_native() to return true only when PCI_EXP_SLTCAP_HPC is set and the pciehp driver is present. In any other case return false to let acpiphp handle those. Suggested-by: Bjorn Helgaas Signed-off-by: Mika Westerberg [bhelgaas: remove NULL pointer check] Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pci-acpi.c | 26 ++++++++++++++------------ drivers/pci/pcie/portdrv.h | 2 -- include/linux/pci.h | 2 ++ include/linux/pci_hotplug.h | 4 ++-- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 1abdbf267c19..52b8434d4d6e 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -370,26 +370,28 @@ EXPORT_SYMBOL_GPL(pci_get_hp_params); /** * pciehp_is_native - Check whether a hotplug port is handled by the OS - * @pdev: Hotplug port to check + * @bridge: Hotplug port to check * - * Walk up from @pdev to the host bridge, obtain its cached _OSC Control Field - * and return the value of the "PCI Express Native Hot Plug control" bit. - * On failure to obtain the _OSC Control Field return %false. + * Returns true if the given @bridge is handled by the native PCIe hotplug + * driver. */ -bool pciehp_is_native(struct pci_dev *pdev) +bool pciehp_is_native(struct pci_dev *bridge) { - struct acpi_pci_root *root; - acpi_handle handle; + const struct pci_host_bridge *host; + u32 slot_cap; - handle = acpi_find_root_bridge_handle(pdev); - if (!handle) + if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) return false; - root = acpi_pci_find_root(handle); - if (!root) + pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap); + if (!(slot_cap & PCI_EXP_SLTCAP_HPC)) return false; - return root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; + if (pcie_ports_native) + return true; + + host = pci_find_host_bridge(bridge->bus); + return host->native_pcie_hotplug; } /** diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index d0c6783dbfe3..aa542dc10d23 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -11,8 +11,6 @@ #include -extern bool pcie_ports_native; - /* Service Type */ #define PCIE_PORT_SERVICE_PME_SHIFT 0 /* Power Management Event */ #define PCIE_PORT_SERVICE_PME (1 << PCIE_PORT_SERVICE_PME_SHIFT) diff --git a/include/linux/pci.h b/include/linux/pci.h index 30ec7e86af55..3f009003706a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1454,8 +1454,10 @@ static inline int pci_irqd_intx_xlate(struct irq_domain *d, #ifdef CONFIG_PCIEPORTBUS extern bool pcie_ports_disabled; +extern bool pcie_ports_native; #else #define pcie_ports_disabled true +#define pcie_ports_native false #endif #ifdef CONFIG_PCIEASPM diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 26213024e81b..3f32575d1ce8 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -162,7 +162,7 @@ struct hotplug_params { #ifdef CONFIG_ACPI #include int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp); -bool pciehp_is_native(struct pci_dev *pdev); +bool pciehp_is_native(struct pci_dev *bridge); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); int acpi_pci_detect_ejectable(acpi_handle handle); @@ -172,6 +172,6 @@ static inline int pci_get_hp_params(struct pci_dev *dev, { return -ENODEV; } -static inline bool pciehp_is_native(struct pci_dev *pdev) { return true; } +static inline bool pciehp_is_native(struct pci_dev *bridge) { return true; } #endif #endif -- GitLab