From 00456b35a527ee308c3a545624ef19b4ff71c8ac Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Wed, 18 May 2016 09:04:19 -0500 Subject: [PATCH 01/23] PCI: Add function 1 DMA alias quirk for Marvell 88SE9182 Add function 1 DMA alias quirk for Marvell 88SE9182. We found this quirk reported in the same thread as other Marvell devices, but no patch resulted: https://bugzilla.kernel.org/show_bug.cgi?id=42679#c78 Signed-off-by: Steven Graham Signed-off-by: Aaron Sierra Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ee72ebe18f4b..42366a11d798 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3711,6 +3711,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172, /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c59 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x917a, quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c78 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9182, + quirk_dma_func1_alias); /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0, quirk_dma_func1_alias); From 386ed2ab85cf1c618e5797a66154a41908ed6aeb Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Fri, 10 Jun 2016 19:05:09 -0500 Subject: [PATCH 02/23] PCI: Fix comment typo Fix typo. Signed-off-by: Andrea Gelmini Signed-off-by: Bjorn Helgaas --- arch/x86/pci/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 8196054fedb0..7b6a9d14c8c0 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -133,7 +133,7 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev) if (pci_probe & PCI_NOASSIGN_BARS) { /* * If the BIOS did not assign the BAR, zero out the - * resource so the kernel doesn't attmept to assign + * resource so the kernel doesn't attempt to assign * it later on in pci_assign_unassigned_resources */ for (bar = 0; bar <= PCI_STD_RESOURCE_END; bar++) { From 92a1fe2e82d7beb2a65118833db44541663d09c7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 22 May 2016 11:06:12 +0200 Subject: [PATCH 03/23] MAINTAINERS: Add file patterns for PCI device tree bindings Submitters of device tree binding documentation may forget to CC the subsystem maintainer if this is missing. Signed-off-by: Geert Uytterhoeven Signed-off-by: Bjorn Helgaas --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ed42cb65a19b..2eea84d1d53d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8678,6 +8678,7 @@ L: linux-pci@vger.kernel.org Q: http://patchwork.ozlabs.org/project/linux-pci/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git S: Supported +F: Documentation/devicetree/bindings/pci/ F: Documentation/PCI/ F: drivers/pci/ F: include/linux/pci* From a6c1c6f3547b6c4cbd4a30d67a968ee1519a8ffd Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 24 May 2016 17:32:10 +0800 Subject: [PATCH 04/23] PCI/ASPM: Remove redundant check of pcie_set_clkpm Without supporting clock PM capable, if we want to disable clkpm, we don't need this extra check as it must already be zero for the enable argument. And it's the same for enabling clkpm here. So let's remove this check. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 2dfe7fdb77e7..0ec649d961d7 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -139,7 +139,7 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) static void pcie_set_clkpm(struct pcie_link_state *link, int enable) { /* Don't enable Clock PM if the link is not Clock PM capable */ - if (!link->clkpm_capable && enable) + if (!link->clkpm_capable) enable = 0; /* Need nothing if the specified equals to current state */ if (link->clkpm_enabled == enable) From 9ac0108c2bac3f1d0255f64fb89fc27e71131b24 Mon Sep 17 00:00:00 2001 From: Chris Blake Date: Mon, 30 May 2016 07:26:37 -0500 Subject: [PATCH 05/23] PCI: Mark Atheros AR9485 and QCA9882 to avoid bus reset Similar to the AR93xx series, the AR94xx and the Qualcomm QCA988x also have the same quirk for the Bus Reset. Fixes: c3e59ee4e766 ("PCI: Mark Atheros AR93xx to avoid bus reset") Signed-off-by: Chris Blake Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.14+ --- drivers/pci/quirks.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 42366a11d798..98b0af0fcc81 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3189,13 +3189,15 @@ static void quirk_no_bus_reset(struct pci_dev *dev) } /* - * Atheros AR93xx chips do not behave after a bus reset. The device will - * throw a Link Down error on AER-capable systems and regardless of AER, - * config space of the device is never accessible again and typically - * causes the system to hang or reset when access is attempted. + * Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset. + * The device will throw a Link Down error on AER-capable systems and + * regardless of AER, config space of the device is never accessible again + * and typically causes the system to hang or reset when access is attempted. * http://www.spinics.net/lists/linux-pci/msg34797.html */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset); static void quirk_no_pm_reset(struct pci_dev *dev) { From 21751a9a4ed4219c11e4073afecb9a876d1107ea Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 9 Jun 2016 11:42:13 +0100 Subject: [PATCH 06/23] PCI: Make bus_attr_resource_alignment static The symbol bus_attr_resource_alignment is not exported or declared elsewhere, so make it static to fix the following warning: drivers/pci/pci.c:4900:1: warning: symbol 'bus_attr_resource_alignment' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c8b4dbdd1bdd..9add28516a66 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4897,7 +4897,7 @@ static ssize_t pci_resource_alignment_store(struct bus_type *bus, return pci_set_resource_alignment_param(buf, count); } -BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show, +static BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show, pci_resource_alignment_store); static int __init pci_resource_alignment_sysfs_init(void) From 9661e783d830699a65f7d42e4b4a76e6923089eb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 7 Jun 2016 20:48:33 +0300 Subject: [PATCH 07/23] PCI / PM: Enforce type casting for pci_power_t When casting variables of type pci_power_t, a static analysis tool complains: include/linux/pci.h:119:37: warning: cast from restricted pci_power_t Enforce type casting to make the static analyzer happy. Signed-off-by: Andy Shevchenko Signed-off-by: Bjorn Helgaas --- include/linux/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index b67e4df20801..8d748345b158 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -116,7 +116,7 @@ extern const char *pci_power_names[]; static inline const char *pci_power_name(pci_power_t state) { - return pci_power_names[1 + (int) state]; + return pci_power_names[1 + (__force int) state]; } #define PCI_PM_D2_DELAY 200 From 43f7f88b9362e1f26603b45932069bbd6e15a1e1 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 2 Jun 2016 11:17:11 +0300 Subject: [PATCH 08/23] PCI: Don't clear d3cold_allowed for PCIe ports The PCI core skips bridges and ports when the system is suspended. The PCI core checks return value of pci_has_subordinate() in pci_pm_suspend_noirq() to skip all devices where it is non-zero (which means PCI bridges and PCIe ports). Since PCIe ports are never suspended in the first place, there is no need to set d3cold_allowed for them. Tested-by: Lukas Wunner Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pcie/portdrv_pci.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index be35da2e105e..6c6bb03392ea 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -134,11 +134,6 @@ static int pcie_portdrv_probe(struct pci_dev *dev, return status; pci_save_state(dev); - /* - * D3cold may not work properly on some PCIe port, so disable - * it by default. - */ - dev->d3cold_allowed = false; return 0; } From 9d26d3a8f1b0c442339a235f9508bdad8af91043 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 2 Jun 2016 11:17:12 +0300 Subject: [PATCH 09/23] PCI: Put PCIe ports into D3 during suspend Currently the Linux PCI core does not touch power state of PCI bridges and PCIe ports when system suspend is entered. Leaving them in D0 consumes power unnecessarily and may prevent the CPU from entering deeper C-states. With recent PCIe hardware we can power down the ports to save power given that we take into account few restrictions: - The PCIe port hardware is recent enough, starting from 2015. - Devices connected to PCIe ports are effectively in D3cold once the port is transitioned to D3 (the config space is not accessible anymore and the link may be powered down). - Devices behind the PCIe port need to be allowed to transition to D3cold and back. There is a way both drivers and userspace can forbid this. - If the device behind the PCIe port is capable of waking the system it needs to be able to do so from D3cold. This patch adds a new flag to struct pci_device called 'bridge_d3'. This flag is set and cleared by the PCI core whenever there is a change in power management state of any of the devices behind the PCIe port. When system later on is suspended we only need to check this flag and if it is true transition the port to D3 otherwise we leave it in D0. Also provide override mechanism via command line parameter "pcie_port_pm=[off|force]" that can be used to disable or enable the feature regardless of the BIOS manufacturing date. Tested-by: Lukas Wunner Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 4 + drivers/pci/bus.c | 1 + drivers/pci/pci-driver.c | 5 +- drivers/pci/pci-sysfs.c | 5 + drivers/pci/pci.c | 175 ++++++++++++++++++++++++++++ drivers/pci/pci.h | 11 ++ drivers/pci/remove.c | 2 + drivers/usb/host/xhci-pci.c | 2 +- include/linux/pci.h | 3 + 9 files changed, 203 insertions(+), 5 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 82b42c958d1c..86edee4cedd4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3047,6 +3047,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe ports driver. + pcie_port_pm= [PCIE] PCIe port power management handling: + off Disable power management of all PCIe ports + force Forcibly enable power management of all PCIe ports + pcie_pme= [PCIE,PM] Native PCIe PME signaling options: nomsi Do not use MSI for native PCIe PME signaling (this makes all PCIe root ports use INTx for all services). diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index dd7cdbee8029..28731360b457 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -291,6 +291,7 @@ void pci_bus_add_device(struct pci_dev *dev) pci_fixup_device(pci_fixup_final, dev); pci_create_sysfs_dev_files(dev); pci_proc_attach_device(dev); + pci_bridge_d3_device_changed(dev); dev->match_driver = true; retval = device_attach(&dev->dev); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d7ffd66814bb..e39a67c8ef39 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -777,7 +777,7 @@ static int pci_pm_suspend_noirq(struct device *dev) if (!pci_dev->state_saved) { pci_save_state(pci_dev); - if (!pci_has_subordinate(pci_dev)) + if (pci_power_manageable(pci_dev)) pci_prepare_to_sleep(pci_dev); } @@ -1144,7 +1144,6 @@ static int pci_pm_runtime_suspend(struct device *dev) return -ENOSYS; pci_dev->state_saved = false; - pci_dev->no_d3cold = false; error = pm->runtime_suspend(dev); if (error) { /* @@ -1161,8 +1160,6 @@ static int pci_pm_runtime_suspend(struct device *dev) return error; } - if (!pci_dev->d3cold_allowed) - pci_dev->no_d3cold = true; pci_fixup_device(pci_fixup_suspend, pci_dev); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index d319a9ca9b7b..bcd10c795284 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -406,6 +406,11 @@ static ssize_t d3cold_allowed_store(struct device *dev, return -EINVAL; pdev->d3cold_allowed = !!val; + if (pdev->d3cold_allowed) + pci_d3cold_enable(pdev); + else + pci_d3cold_disable(pdev); + pm_runtime_resume(dev); return count; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c8b4dbdd1bdd..9ff7183e25a2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,21 @@ unsigned int pcibios_max_latency = 255; /* If set, the PCIe ARI capability will not be used. */ static bool pcie_ari_disabled; +/* Disable bridge_d3 for all PCIe ports */ +static bool pci_bridge_d3_disable; +/* Force bridge_d3 for all PCIe ports */ +static bool pci_bridge_d3_force; + +static int __init pcie_port_pm_setup(char *str) +{ + if (!strcmp(str, "off")) + pci_bridge_d3_disable = true; + else if (!strcmp(str, "force")) + pci_bridge_d3_force = true; + return 1; +} +__setup("pcie_port_pm=", pcie_port_pm_setup); + /** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search @@ -2155,6 +2171,164 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev) pm_runtime_put_sync(parent); } +/** + * pci_bridge_d3_possible - Is it possible to put the bridge into D3 + * @bridge: Bridge to check + * + * This function checks if it is possible to move the bridge to D3. + * Currently we only allow D3 for recent enough PCIe ports. + */ +static bool pci_bridge_d3_possible(struct pci_dev *bridge) +{ + unsigned int year; + + if (!pci_is_pcie(bridge)) + return false; + + switch (pci_pcie_type(bridge)) { + case PCI_EXP_TYPE_ROOT_PORT: + case PCI_EXP_TYPE_UPSTREAM: + case PCI_EXP_TYPE_DOWNSTREAM: + if (pci_bridge_d3_disable) + return false; + if (pci_bridge_d3_force) + return true; + + /* + * It should be safe to put PCIe ports from 2015 or newer + * to D3. + */ + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && + year >= 2015) { + return true; + } + break; + } + + return false; +} + +static int pci_dev_check_d3cold(struct pci_dev *dev, void *data) +{ + bool *d3cold_ok = data; + bool no_d3cold; + + /* + * The device needs to be allowed to go D3cold and if it is wake + * capable to do so from D3cold. + */ + no_d3cold = dev->no_d3cold || !dev->d3cold_allowed || + (device_may_wakeup(&dev->dev) && !pci_pme_capable(dev, PCI_D3cold)) || + !pci_power_manageable(dev); + + *d3cold_ok = !no_d3cold; + + return no_d3cold; +} + +/* + * pci_bridge_d3_update - Update bridge D3 capabilities + * @dev: PCI device which is changed + * @remove: Is the device being removed + * + * Update upstream bridge PM capabilities accordingly depending on if the + * device PM configuration was changed or the device is being removed. The + * change is also propagated upstream. + */ +static void pci_bridge_d3_update(struct pci_dev *dev, bool remove) +{ + struct pci_dev *bridge; + bool d3cold_ok = true; + + bridge = pci_upstream_bridge(dev); + if (!bridge || !pci_bridge_d3_possible(bridge)) + return; + + pci_dev_get(bridge); + /* + * If the device is removed we do not care about its D3cold + * capabilities. + */ + if (!remove) + pci_dev_check_d3cold(dev, &d3cold_ok); + + if (d3cold_ok) { + /* + * We need to go through all children to find out if all of + * them can still go to D3cold. + */ + pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold, + &d3cold_ok); + } + + if (bridge->bridge_d3 != d3cold_ok) { + bridge->bridge_d3 = d3cold_ok; + /* Propagate change to upstream bridges */ + pci_bridge_d3_update(bridge, false); + } + + pci_dev_put(bridge); +} + +/** + * pci_bridge_d3_device_changed - Update bridge D3 capabilities on change + * @dev: PCI device that was changed + * + * If a device is added or its PM configuration, such as is it allowed to + * enter D3cold, is changed this function updates upstream bridge PM + * capabilities accordingly. + */ +void pci_bridge_d3_device_changed(struct pci_dev *dev) +{ + pci_bridge_d3_update(dev, false); +} + +/** + * pci_bridge_d3_device_removed - Update bridge D3 capabilities on remove + * @dev: PCI device being removed + * + * Function updates upstream bridge PM capabilities based on other devices + * still left on the bus. + */ +void pci_bridge_d3_device_removed(struct pci_dev *dev) +{ + pci_bridge_d3_update(dev, true); +} + +/** + * pci_d3cold_enable - Enable D3cold for device + * @dev: PCI device to handle + * + * This function can be used in drivers to enable D3cold from the device + * they handle. It also updates upstream PCI bridge PM capabilities + * accordingly. + */ +void pci_d3cold_enable(struct pci_dev *dev) +{ + if (dev->no_d3cold) { + dev->no_d3cold = false; + pci_bridge_d3_device_changed(dev); + } +} +EXPORT_SYMBOL_GPL(pci_d3cold_enable); + +/** + * pci_d3cold_disable - Disable D3cold for device + * @dev: PCI device to handle + * + * This function can be used in drivers to disable D3cold from the device + * they handle. It also updates upstream PCI bridge PM capabilities + * accordingly. + */ +void pci_d3cold_disable(struct pci_dev *dev) +{ + if (!dev->no_d3cold) { + dev->no_d3cold = true; + pci_bridge_d3_device_changed(dev); + } +} +EXPORT_SYMBOL_GPL(pci_d3cold_disable); + /** * pci_pm_init - Initialize PM functions of given PCI device * @dev: PCI device to handle. @@ -2189,6 +2363,7 @@ void pci_pm_init(struct pci_dev *dev) dev->pm_cap = pm; dev->d3_delay = PCI_PM_D3_WAIT; dev->d3cold_delay = PCI_PM_D3COLD_WAIT; + dev->bridge_d3 = pci_bridge_d3_possible(dev); dev->d3cold_allowed = true; dev->d1_support = false; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a814bbb80fcb..9730c474b016 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -82,6 +82,8 @@ void pci_pm_init(struct pci_dev *dev); void pci_ea_init(struct pci_dev *dev); void pci_allocate_cap_save_buffers(struct pci_dev *dev); void pci_free_cap_save_buffers(struct pci_dev *dev); +void pci_bridge_d3_device_changed(struct pci_dev *dev); +void pci_bridge_d3_device_removed(struct pci_dev *dev); static inline void pci_wakeup_event(struct pci_dev *dev) { @@ -94,6 +96,15 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev) return !!(pci_dev->subordinate); } +static inline bool pci_power_manageable(struct pci_dev *pci_dev) +{ + /* + * Currently we allow normal PCI devices and PCI bridges transition + * into D3 if their bridge_d3 is set. + */ + return !pci_has_subordinate(pci_dev) || pci_dev->bridge_d3; +} + struct pci_vpd_ops { ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 8982026637d5..d1ef7acf6930 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -96,6 +96,8 @@ static void pci_remove_bus_device(struct pci_dev *dev) dev->subordinate = NULL; } + pci_bridge_d3_device_removed(dev); + pci_destroy_dev(dev); } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 48672fac7ff3..ac352fe391f4 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -382,7 +382,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) * need to have the registers polled during D3, so avoid D3cold. */ if (xhci->quirks & XHCI_COMP_MODE_QUIRK) - pdev->no_d3cold = true; + pci_d3cold_disable(pdev); if (xhci->quirks & XHCI_PME_STUCK_QUIRK) xhci_pme_quirk(hcd); diff --git a/include/linux/pci.h b/include/linux/pci.h index 8d748345b158..8597b423cb63 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -294,6 +294,7 @@ struct pci_dev { unsigned int d2_support:1; /* Low power state D2 is supported */ unsigned int no_d1d2:1; /* D1 and D2 are forbidden */ unsigned int no_d3cold:1; /* D3cold is forbidden */ + unsigned int bridge_d3:1; /* Allow D3 for bridge */ unsigned int d3cold_allowed:1; /* D3cold is allowed by user */ unsigned int mmio_always_on:1; /* disallow turning off io/mem decoding during bar sizing */ @@ -1083,6 +1084,8 @@ int pci_back_from_sleep(struct pci_dev *dev); bool pci_dev_run_wake(struct pci_dev *dev); bool pci_check_pme_status(struct pci_dev *dev); void pci_pme_wakeup_bus(struct pci_bus *bus); +void pci_d3cold_enable(struct pci_dev *dev); +void pci_d3cold_disable(struct pci_dev *dev); static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) From d963f6512e15fb2c0a9e9770078e2206f55c2f7a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 2 Jun 2016 11:17:13 +0300 Subject: [PATCH 10/23] PCI: Power on bridges before scanning new devices When a PCI device is removed through sysfs interface, the upstream bridge (PCIe port) can be runtime suspended if it was the last device on that bus. Now, if the bridge is in D3 we cannot find devices below the bridge anymore. For example following fails to find the removed device again: # echo 1 > /sys/bus/pci/devices/0000:00:01.0/0000:01:00.0/remove # echo 1 > /sys/bus/pci/devices/0000:00:01.0/rescan Where 0000:00:01.0 is the bridge device. In order to be able to rescan devices below the bridge add pm_runtime_get_sync()/pm_runtime_put() calls to pci_scan_bridge(). This should keep bridges powered on while their children devices are being scanned. Reported-by: Peter Wu Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/probe.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8e3ef720997d..11a802daf242 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ @@ -832,6 +833,12 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) u8 primary, secondary, subordinate; int broken = 0; + /* + * Make sure the bridge is powered on to be able to access config + * space of devices below it. + */ + pm_runtime_get_sync(&dev->dev); + pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); primary = buses & 0xFF; secondary = (buses >> 8) & 0xFF; @@ -1012,6 +1019,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) out: pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl); + pm_runtime_put(&dev->dev); + return max; } EXPORT_SYMBOL(pci_scan_bridge); From 16468c783cb4cf72475dcda23fabecb4a4bb0e17 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 2 Jun 2016 11:17:14 +0300 Subject: [PATCH 11/23] ACPI / hotplug / PCI: Runtime resume bridge before rescan If a PCI bridge (or PCIe port) that is runtime suspended gets an ACPI hotplug event, such as BUS_CHECK we need to make sure it is resumed before devices below the bridge are re-scanned. Otherwise the devices behind the port are not accessible and will be treated as hot-unplugged. To fix this, resume PCI bridges from runtime suspend while rescanning. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index fa49f9143b80..6a33ddcfa20b 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -675,6 +675,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) if (bridge->is_going_away) return; + pm_runtime_get_sync(&bridge->pci_dev->dev); + list_for_each_entry(slot, &bridge->slots, node) { struct pci_bus *bus = slot->bus; struct pci_dev *dev, *tmp; @@ -694,6 +696,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) disable_slot(slot); } } + + pm_runtime_put(&bridge->pci_dev->dev); } /* From 006d44e49a259b39947366728d65a873a19aadc0 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 2 Jun 2016 11:17:15 +0300 Subject: [PATCH 12/23] PCI: Add runtime PM support for PCIe ports Add back runtime PM support for PCIe ports that was removed by fe9a743a2601 ("PCI/PM: Drop unused runtime PM support code for PCIe ports"). We cannot enable it automatically for all ports since there have been problems previously [1]. In summary suspended PCIe ports were not able to deal with ACPI-based hotplug reliably. One reason why this might happen is the fact that when a PCIe port is powered down, config space access to the devices behind the port is not possible. If the BIOS hotplug SMI handler assumes the port is always in D0 it will not be able to find the hotplugged devices. To be on the safe side only enable runtime PM if the port does not claim to support hotplug. For PCIe ports not using hotplug, we enable and allow runtime PM automatically. Since 'bridge_d3' can be changed any time we check this in driver ->runtime_idle() and ->runtime_suspend() and only allow runtime suspend if the flag is still set. Use autosuspend with default of 100ms idle time to prevent the port from repeatedly suspending and resuming on continuous configuration space access of devices behind the port. The actual power transition to D3 and back is handled in the PCI core. Idea to automatically unblock (allow) runtime PM for PCIe ports came from Dave Airlie. [1] https://bugzilla.kernel.org/show_bug.cgi?id=53811 This includes a fix for lockdep issue reported by Valdis Kletnieks. Tested-by: Lukas Wunner Signed-off-by: Lukas Wunner Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pcie/portdrv_core.c | 3 ++ drivers/pci/pcie/portdrv_pci.c | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 32d4d0a3d20e..e9270b4026f3 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -342,6 +343,8 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq) return retval; } + pm_runtime_no_callbacks(device); + return 0; } diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 6c6bb03392ea..70d7ad8c6d17 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -93,6 +93,26 @@ static int pcie_port_resume_noirq(struct device *dev) return 0; } +static int pcie_port_runtime_suspend(struct device *dev) +{ + return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY; +} + +static int pcie_port_runtime_resume(struct device *dev) +{ + return 0; +} + +static int pcie_port_runtime_idle(struct device *dev) +{ + /* + * Assume the PCI core has set bridge_d3 whenever it thinks the port + * should be good to go to D3. Everything else, including moving + * the port to D3, is handled by the PCI core. + */ + return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY; +} + static const struct dev_pm_ops pcie_portdrv_pm_ops = { .suspend = pcie_port_device_suspend, .resume = pcie_port_device_resume, @@ -101,6 +121,9 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = { .poweroff = pcie_port_device_suspend, .restore = pcie_port_device_resume, .resume_noirq = pcie_port_resume_noirq, + .runtime_suspend = pcie_port_runtime_suspend, + .runtime_resume = pcie_port_runtime_resume, + .runtime_idle = pcie_port_runtime_idle, }; #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) @@ -134,11 +157,39 @@ static int pcie_portdrv_probe(struct pci_dev *dev, return status; pci_save_state(dev); + + /* + * Prevent runtime PM if the port is advertising support for PCIe + * hotplug. Otherwise the BIOS hotplug SMI code might not be able + * to enumerate devices behind this port properly (the port is + * powered down preventing all config space accesses to the + * subordinate devices). We can't be sure for native PCIe hotplug + * either so prevent that as well. + */ + if (!dev->is_hotplug_bridge) { + /* + * Keep the port resumed 100ms to make sure things like + * config space accesses from userspace (lspci) will not + * cause the port to repeatedly suspend and resume. + */ + pm_runtime_set_autosuspend_delay(&dev->dev, 100); + pm_runtime_use_autosuspend(&dev->dev); + pm_runtime_mark_last_busy(&dev->dev); + pm_runtime_put_autosuspend(&dev->dev); + pm_runtime_allow(&dev->dev); + } + return 0; } static void pcie_portdrv_remove(struct pci_dev *dev) { + if (!dev->is_hotplug_bridge) { + pm_runtime_forbid(&dev->dev); + pm_runtime_get_noresume(&dev->dev); + pm_runtime_dont_use_autosuspend(&dev->dev); + } + pcie_port_device_remove(dev); } From 3ee803641e76bea76ec730c80dcc64739a9919ff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 15 Jun 2016 15:47:33 -0500 Subject: [PATCH 13/23] PCI/MSI: irqchip: Fix PCI_MSI dependencies The PCI_MSI symbol is used inconsistently throughout the tree, with some drivers using 'select' and others using 'depends on', or using conditional selects. This keeps causing problems; the latest one is a result of ARCH_ALPINE using a 'select' statement to enable its platform-specific MSI driver without enabling MSI: warning: (ARCH_ALPINE) selects ALPINE_MSI which has unmet direct dependencies (PCI && PCI_MSI) drivers/irqchip/irq-alpine-msi.c:104:15: error: variable 'alpine_msix_domain_info' has initializer but incomplete type static struct msi_domain_info alpine_msix_domain_info = { ^~~~~~~~~~~~~~~ drivers/irqchip/irq-alpine-msi.c:105:2: error: unknown field 'flags' specified in initializer .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | ^ drivers/irqchip/irq-alpine-msi.c:105:11: error: 'MSI_FLAG_USE_DEF_DOM_OPS' undeclared here (not in a function) .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | ^~~~~~~~~~~~~~~~~~~~~~~~ There is little reason to enable PCI support for a platform that uses MSI but then leave MSI disabled at compile time. Select PCI_MSI from irqchips that implement MSI, and make PCI host bridges that use MSI on ARM depend on PCI_MSI_IRQ_DOMAIN. For all three architectures that support PCI_MSI_IRQ_DOMAIN (ARM, ARM64, X86), enable it by default whenever MSI is enabled. [bhelgaas: changelog, omit crypto config change] Suggested-by: Marc Zyngier Signed-off-by: Arnd Bergmann Signed-off-by: Bjorn Helgaas Acked-by: Marc Zyngier --- arch/arm/Kconfig | 2 +- arch/arm64/Kconfig | 4 ++-- drivers/irqchip/Kconfig | 18 ++++++++---------- drivers/pci/Kconfig | 2 +- drivers/pci/host/Kconfig | 29 +++++++++++++++++++---------- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 90542db1220d..354c167a2b42 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -715,7 +715,7 @@ config ARCH_VIRT depends on ARCH_MULTI_V7 select ARM_AMBA select ARM_GIC - select ARM_GIC_V2M if PCI_MSI + select ARM_GIC_V2M if PCI select ARM_GIC_V3 select ARM_PSCI select HAVE_ARM_ARCH_TIMER diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 5a0a691d4220..70ee71fda467 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -20,9 +20,9 @@ config ARM64 select ARM_ARCH_TIMER select ARM_GIC select AUDIT_ARCH_COMPAT_GENERIC - select ARM_GIC_V2M if PCI_MSI + select ARM_GIC_V2M if PCI select ARM_GIC_V3 - select ARM_GIC_V3_ITS if PCI_MSI + select ARM_GIC_V3_ITS if PCI select ARM_PSCI_FW select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index fa33c50b0e5a..11ecb6cfb2e5 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -15,9 +15,9 @@ config ARM_GIC_MAX_NR config ARM_GIC_V2M bool - depends on ARM_GIC - depends on PCI && PCI_MSI - select PCI_MSI_IRQ_DOMAIN + depends on PCI + select ARM_GIC + select PCI_MSI config GIC_NON_BANKED bool @@ -31,7 +31,8 @@ config ARM_GIC_V3 config ARM_GIC_V3_ITS bool - select PCI_MSI_IRQ_DOMAIN + depends on PCI + depends on PCI_MSI config ARM_NVIC bool @@ -56,13 +57,13 @@ config ARM_VIC_NR config ARMADA_370_XP_IRQ bool select GENERIC_IRQ_CHIP - select PCI_MSI_IRQ_DOMAIN if PCI_MSI + select PCI_MSI if PCI config ALPINE_MSI bool - depends on PCI && PCI_MSI + depends on PCI + select PCI_MSI select GENERIC_IRQ_CHIP - select PCI_MSI_IRQ_DOMAIN config ATMEL_AIC_IRQ bool @@ -111,7 +112,6 @@ config HISILICON_IRQ_MBIGEN bool select ARM_GIC_V3 select ARM_GIC_V3_ITS - select GENERIC_MSI_IRQ_DOMAIN config IMGPDC_IRQ bool @@ -244,12 +244,10 @@ config IRQ_MXS config MVEBU_ODMI bool - select GENERIC_MSI_IRQ_DOMAIN config LS_SCFG_MSI def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE depends on PCI && PCI_MSI - select PCI_MSI_IRQ_DOMAIN config PARTITION_PERCPU bool diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 56389be5d08b..67f9916ff14d 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -25,7 +25,7 @@ config PCI_MSI If you don't know what to do here, say Y. config PCI_MSI_IRQ_DOMAIN - bool + def_bool ARM || ARM64 || X86 depends on PCI_MSI select GENERIC_MSI_IRQ_DOMAIN diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 5d2374e4ee7f..80cfe2f0a580 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -3,8 +3,9 @@ menu "PCI host controller drivers" config PCI_DRA7XX bool "TI DRA7xx PCIe controller" - select PCIE_DW depends on OF && HAS_IOMEM && TI_PIPE3 + depends on PCI_MSI_IRQ_DOMAIN + select PCIE_DW help Enables support for the PCIe controller in the DRA7xx SoC. There are two instances of PCIe controller in DRA7xx. This controller can @@ -20,7 +21,7 @@ config PCI_MVEBU config PCIE_XILINX_NWL bool "NWL PCIe Core" depends on ARCH_ZYNQMP - select PCI_MSI_IRQ_DOMAIN if PCI_MSI + depends on PCI_MSI_IRQ_DOMAIN help Say 'Y' here if you want kernel support for Xilinx NWL PCIe controller. The controller can act as Root Port @@ -29,6 +30,7 @@ config PCIE_XILINX_NWL config PCIE_DW_PLAT bool "Platform bus based DesignWare PCIe Controller" + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW ---help--- This selects the DesignWare PCIe controller support. Select this if @@ -40,16 +42,19 @@ config PCIE_DW_PLAT config PCIE_DW bool + depends on PCI_MSI_IRQ_DOMAIN config PCI_EXYNOS bool "Samsung Exynos PCIe controller" depends on SOC_EXYNOS5440 + depends on PCI_MSI_IRQ_DOMAIN select PCIEPORTBUS select PCIE_DW config PCI_IMX6 bool "Freescale i.MX6 PCIe controller" depends on SOC_IMX6Q + depends on PCI_MSI_IRQ_DOMAIN select PCIEPORTBUS select PCIE_DW @@ -72,8 +77,7 @@ config PCI_RCAR_GEN2 config PCIE_RCAR bool "Renesas R-Car PCIe controller" depends on ARCH_RENESAS || (ARM && COMPILE_TEST) - select PCI_MSI - select PCI_MSI_IRQ_DOMAIN + depends on PCI_MSI_IRQ_DOMAIN help Say Y here if you want PCIe controller support on R-Car SoCs. @@ -92,6 +96,7 @@ config PCI_HOST_GENERIC config PCIE_SPEAR13XX bool "STMicroelectronics SPEAr PCIe controller" depends on ARCH_SPEAR13XX + depends on PCI_MSI_IRQ_DOMAIN select PCIEPORTBUS select PCIE_DW help @@ -100,6 +105,7 @@ config PCIE_SPEAR13XX config PCI_KEYSTONE bool "TI Keystone PCIe controller" depends on ARCH_KEYSTONE + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW select PCIEPORTBUS help @@ -120,7 +126,6 @@ config PCI_XGENE depends on ARCH_XGENE depends on OF select PCIEPORTBUS - select PCI_MSI_IRQ_DOMAIN if PCI_MSI help Say Y here if you want internal PCI support on APM X-Gene SoC. There are 5 internal PCIe ports available. Each port is GEN3 capable @@ -128,7 +133,8 @@ config PCI_XGENE config PCI_XGENE_MSI bool "X-Gene v1 PCIe MSI feature" - depends on PCI_XGENE && PCI_MSI + depends on PCI_XGENE + depends on PCI_MSI_IRQ_DOMAIN default y help Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC. @@ -137,6 +143,7 @@ config PCI_XGENE_MSI config PCI_LAYERSCAPE bool "Freescale Layerscape PCIe controller" depends on OF && (ARM || ARCH_LAYERSCAPE) + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW select MFD_SYSCON help @@ -177,8 +184,7 @@ config PCIE_IPROC_BCMA config PCIE_IPROC_MSI bool "Broadcom iProc PCIe MSI support" depends on PCIE_IPROC_PLATFORM || PCIE_IPROC_BCMA - depends on PCI_MSI - select PCI_MSI_IRQ_DOMAIN + depends on PCI_MSI_IRQ_DOMAIN default ARCH_BCM_IPROC help Say Y here if you want to enable MSI support for Broadcom's iProc @@ -195,8 +201,8 @@ config PCIE_ALTERA config PCIE_ALTERA_MSI bool "Altera PCIe MSI feature" - depends on PCIE_ALTERA && PCI_MSI - select PCI_MSI_IRQ_DOMAIN + depends on PCIE_ALTERA + depends on PCI_MSI_IRQ_DOMAIN help Say Y here if you want PCIe MSI support for the Altera FPGA. This MSI driver supports Altera MSI to GIC controller IP. @@ -204,6 +210,7 @@ config PCIE_ALTERA_MSI config PCI_HISI depends on OF && ARM64 bool "HiSilicon Hip05 and Hip06 SoCs PCIe controllers" + depends on PCI_MSI_IRQ_DOMAIN select PCIEPORTBUS select PCIE_DW help @@ -213,6 +220,7 @@ config PCI_HISI config PCIE_QCOM bool "Qualcomm PCIe controller" depends on ARCH_QCOM && OF + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW select PCIEPORTBUS help @@ -237,6 +245,7 @@ config PCI_HOST_THUNDER_ECAM config PCIE_ARMADA_8K bool "Marvell Armada-8K PCIe controller" depends on ARCH_MVEBU + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW select PCIEPORTBUS help From 224abb67e6eb5ac062de9239163136d5ec3155c8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 17 Jun 2016 15:23:52 -0500 Subject: [PATCH 14/23] PCI: Document connection between pci_power_t and hardware PM capability The dev.pme_support field, pci_pm_init(), pci_pme_capable(), and pci_raw_set_power_state() depend on the fact that the pci_power_t values (PCI_D0, PCI_D1, etc.) match the definition of the Capabilities PME_Support and the Control/Status PowerState fields in the Power Management capability (see PCI Bus Power Management spec r1.2, sec 3.2.3). Add a note to this effect at the pci_power_t typedef. Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko Reviewed-by: Mika Westerberg --- include/linux/pci.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index 8597b423cb63..0a1a9e30359c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -101,6 +101,10 @@ enum { DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES, }; +/* + * pci_power_t values must match the bits in the Capabilities PME_Support + * and Control/Status PowerState fields in the Power Management capability. + */ typedef int __bitwise pci_power_t; #define PCI_D0 ((pci_power_t __force) 0) From ed91de7e14fb20b7db9981ab2a34f6d114bf50a0 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 13 May 2016 13:15:31 +0200 Subject: [PATCH 15/23] PCI: pciehp: Ignore interrupts during D3cold If a hotplug port is suspended to D3cold, its slot status register cannot be read. If that hotplug port happens to share its IRQ with other devices, whenever an interrupt occurs for one of these devices, pciehp logs a "no response from device" message and tries to read the PCI_EXP_SLTSTA register, even though we know that will fail. Ignore interrupts while we're in D3cold. [bhelgaas: changelog] Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp_hpc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 5c24e938042f..08e84d61874e 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -546,6 +546,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) u8 present; bool link; + /* Interrupts cannot originate from a controller that's asleep */ + if (pdev->current_state == PCI_D3cold) + return IRQ_NONE; + /* * In order to guarantee that all interrupt events are * serviced, we need to re-inspect Slot Status register after From 733f3d1339f91d893584b2afcea18b34148ca125 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 6 Jun 2016 16:06:07 +0300 Subject: [PATCH 16/23] PCI: Convert Downstream Port Containment driver to use devm_* functions Use the device resource management (devm) interfaces so we don't need to explicitly release resources on failure paths or when the driver is removed. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Keith Busch --- drivers/pci/pcie/pcie-dpc.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c index ab552f1bc08f..79e371d4f7e6 100644 --- a/drivers/pci/pcie/pcie-dpc.c +++ b/drivers/pci/pcie/pcie-dpc.c @@ -89,7 +89,7 @@ static int dpc_probe(struct pcie_device *dev) int status; u16 ctl, cap; - dpc = kzalloc(sizeof(*dpc), GFP_KERNEL); + dpc = devm_kzalloc(&dev->device, sizeof(*dpc), GFP_KERNEL); if (!dpc) return -ENOMEM; @@ -98,11 +98,12 @@ static int dpc_probe(struct pcie_device *dev) INIT_WORK(&dpc->work, interrupt_event_handler); set_service_data(dev, dpc); - status = request_irq(dev->irq, dpc_irq, IRQF_SHARED, "pcie-dpc", dpc); + status = devm_request_irq(&dev->device, dev->irq, dpc_irq, IRQF_SHARED, + "pcie-dpc", dpc); if (status) { dev_warn(&dev->device, "request IRQ%d failed: %d\n", dev->irq, status); - goto out; + return status; } pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); @@ -117,9 +118,6 @@ static int dpc_probe(struct pcie_device *dev) FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), (cap >> 8) & 0xf, FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE)); return status; - out: - kfree(dpc); - return status; } static void dpc_remove(struct pcie_device *dev) @@ -131,9 +129,6 @@ static void dpc_remove(struct pcie_device *dev) pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl); ctl &= ~(PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN); pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); - - free_irq(dev->irq, dpc); - kfree(dpc); } static struct pcie_port_service_driver dpcdriver = { From 14a16d57eaeca38b5de9f9e13eff58c887b3a2e1 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 6 Jun 2016 16:06:08 +0300 Subject: [PATCH 17/23] PCI: Fix whitespace in struct dpc_dev Remove unnecessary spaces before tabs. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Keith Busch --- drivers/pci/pcie/pcie-dpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c index 79e371d4f7e6..fcd19430d41e 100644 --- a/drivers/pci/pcie/pcie-dpc.c +++ b/drivers/pci/pcie/pcie-dpc.c @@ -15,8 +15,8 @@ struct dpc_dev { struct pcie_device *dev; - struct work_struct work; - int cap_pos; + struct work_struct work; + int cap_pos; }; static void dpc_wait_link_inactive(struct pci_dev *pdev) From 2a2aca316aedae815cc3d7e9ba0b30ec5d8a5edf Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 17 Jun 2016 16:05:13 +0100 Subject: [PATCH 18/23] PCI: Include for isa_dma_bridge_buggy At least on arm, does not get included when building drivers/pci/pci.o. This causes the following build warning which can be fixed by including : drivers/pci/pci.c:37:5: warning: symbol 'isa_dma_bridge_buggy' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 9add28516a66..86b538d6a2a5 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "pci.h" From db83f87b7312a58e5cab347f2c6869b0fea3f3a1 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 18 Jul 2016 08:32:45 -0600 Subject: [PATCH 19/23] PCI: Add DMA alias quirk for Adaptec 3805 Add a DMA alias quirk for the Adaptec 3805, just like the 3405 quirk added in commit d3d2ab43ddae ("PCI: Add DMA alias quirk for Adaptec 3405"). Link: https://www.redhat.com/archives/vfio-users/2016-July/msg00046.html Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 98b0af0fcc81..b69321c0c5d6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3752,6 +3752,9 @@ static const struct pci_device_id fixed_dma_alias_tbl[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285, PCI_VENDOR_ID_ADAPTEC2, 0x02bb), /* Adaptec 3405 */ .driver_data = PCI_DEVFN(1, 0) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285, + PCI_VENDOR_ID_ADAPTEC2, 0x02bc), /* Adaptec 3805 */ + .driver_data = PCI_DEVFN(1, 0) }, { 0 } }; From 7e16fd6df178d3395d32c7d325df69062ea6e024 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 6 Jul 2016 10:06:00 -0600 Subject: [PATCH 20/23] PCI: Bind DPC to Root Ports as well as Downstream Ports PCIe port type values are not flags, so OR'ing them is not correct. Previously the result was equivalent to PCIe Downstream Ports, so we were missing binding to DPC-capable Root Ports. Change the type to 'any' so we can bind to both port types. While this will cause the code to check Upstream Ports, the driver won't claim them since they are not DPC-capable. Reported-by: Alexander Antonov Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas CC: Mika Westerberg --- drivers/pci/pcie/pcie-dpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c index fcd19430d41e..250f87861786 100644 --- a/drivers/pci/pcie/pcie-dpc.c +++ b/drivers/pci/pcie/pcie-dpc.c @@ -133,7 +133,7 @@ static void dpc_remove(struct pcie_device *dev) static struct pcie_port_service_driver dpcdriver = { .name = "dpc", - .port_type = PCI_EXP_TYPE_ROOT_PORT | PCI_EXP_TYPE_DOWNSTREAM, + .port_type = PCIE_ANY_PORT, .service = PCIE_PORT_SERVICE_DPC, .probe = dpc_probe, .remove = dpc_remove, From a4959d8c1eaa4893b3f72d505e977ae53bce2f03 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 6 Jul 2016 10:06:01 -0600 Subject: [PATCH 21/23] PCI: Remove DPC tristate module option Change the Downstream Port Containment config type from tristate to bool. The driver doesn't automatically load based on any rules, so it needs to be built-in in order to bind to devices it needs to drive. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/Kconfig | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 22ca6412bd15..7fcea75afa4c 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -83,7 +83,7 @@ config PCIE_PME depends on PCIEPORTBUS && PM config PCIE_DPC - tristate "PCIe Downstream Port Containment support" + bool "PCIe Downstream Port Containment support" depends on PCIEPORTBUS default n help @@ -92,6 +92,3 @@ config PCIE_DPC will be handled by the DPC driver. If your system doesn't have this capability or you do not want to use this feature, it is safe to answer N. - - To compile this driver as a module, choose M here: the module - will be called pcie-dpc. From e16b46605960bd071a3e26f316e0bb600ae91e37 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 21 Jul 2016 21:40:28 -0600 Subject: [PATCH 22/23] PCI: Allow additional bus numbers for hotplug bridges A user may hot add a switch requiring more than one bus to enumerate. This previously required a system reboot if BIOS did not sufficiently pad the bus resource, which they frequently don't do. Add a kernel parameter so a user can specify the minimum number of bus numbers to reserve for a hotplug bridge's subordinate buses so rebooting won't be necessary. The default is 1, which is equivalent to previous behavior. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- Documentation/kernel-parameters.txt | 3 +++ drivers/pci/pci.c | 8 ++++++++ drivers/pci/probe.c | 9 +++++++++ include/linux/pci.h | 1 + 4 files changed, 21 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 82b42c958d1c..487e799b1da2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3016,6 +3016,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. hpmemsize=nn[KMG] The fixed amount of bus space which is reserved for hotplug bridge's memory window. Default size is 2 megabytes. + hpbussize=nn The minimum amount of additional bus numbers + reserved for buses below a hotplug bridge. + Default is 1. realloc= Enable/disable reallocating PCI bridge resources if allocations done by BIOS are too small to accommodate resources required by all child diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c8b4dbdd1bdd..f18ea90cf91a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -81,6 +81,9 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; +#define DEFAULT_HOTPLUG_BUS_SIZE 1 +unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE; + enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT; /* @@ -5021,6 +5024,11 @@ static int __init pci_setup(char *str) pci_hotplug_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "hpmemsize=", 10)) { pci_hotplug_mem_size = memparse(str + 10, &str); + } else if (!strncmp(str, "hpbussize=", 10)) { + pci_hotplug_bus_size = + simple_strtoul(str + 10, &str, 0); + if (pci_hotplug_bus_size > 0xff) + pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE; } else if (!strncmp(str, "pcie_bus_tune_off", 17)) { pcie_bus_config = PCIE_BUS_TUNE_OFF; } else if (!strncmp(str, "pcie_bus_safe", 13)) { diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8e3ef720997d..f680099c110d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2076,6 +2076,15 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus) max = pci_scan_bridge(bus, dev, max, pass); } + /* + * Make sure a hotplug bridge has at least the minimum requested + * number of buses. + */ + if (bus->self && bus->self->is_hotplug_bridge && pci_hotplug_bus_size) { + if (max - bus->busn_res.start < pci_hotplug_bus_size - 1) + max = bus->busn_res.start + pci_hotplug_bus_size - 1; + } + /* * We've scanned the bus and so we know all about what's on * the other side of any bridges that may be on this bus plus diff --git a/include/linux/pci.h b/include/linux/pci.h index b67e4df20801..0c283254111d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1706,6 +1706,7 @@ extern u8 pci_cache_line_size; extern unsigned long pci_hotplug_io_size; extern unsigned long pci_hotplug_mem_size; +extern unsigned long pci_hotplug_bus_size; /* Architecture-specific versions may override these (weak) */ void pcibios_disable_device(struct pci_dev *dev); From 9fad4012db45c975321cdb9d8b7bdc21a8d59000 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 28 Jul 2016 18:13:56 +0100 Subject: [PATCH 23/23] PCI: Add ACS quirk for Solarflare SFC9220 The Solarflare SFC9220 apparently lacks an ACS capability, but does not perform peer-to-peer between functions. Add a quirk so we know about this isolation. [bhelgaas: changelog] Signed-off-by: Edward Cree Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b69321c0c5d6..37ff0158e45f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4095,6 +4095,7 @@ static const struct pci_dev_acs_enabled { { PCI_VENDOR_ID_AMD, 0x7809, pci_quirk_amd_sb_acs }, { PCI_VENDOR_ID_SOLARFLARE, 0x0903, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_SOLARFLARE, 0x0923, pci_quirk_mf_endpoint_acs }, + { PCI_VENDOR_ID_SOLARFLARE, 0x0A03, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_INTEL, 0x10C6, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_INTEL, 0x10DB, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_INTEL, 0x10DD, pci_quirk_mf_endpoint_acs },