From a50edf37d58993983ec90dc5aab8ca6d2b8ff10b Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Tue, 4 Jul 2017 20:39:08 -0400 Subject: [PATCH] pci: do not enable extended tags on pre-dated(v1.x) systems Signed-off-by: Sinan Kaya --- drivers/pci/probe.c | 52 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index dfc9a27..c67af22 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1663,21 +1663,58 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) */ } -static void pci_configure_extended_tags(struct pci_dev *dev) +static bool pcie_bus_exttags_supported(struct pci_bus *bus) +{ + bool exttags_supported = true; + struct pci_dev *bridge; + int rc; + u16 flags; + + bridge = bus->self; + while (bridge) { + if (pci_is_pcie(bridge)) { + rc = pcie_capability_read_word(bridge, PCI_EXP_FLAGS, + &flags); + if (!rc && ((flags & PCI_EXP_FLAGS_VERS) < 2)) { + exttags_supported = false; + break; + } + } + if (!bridge->bus->parent) + break; + bridge = bridge->bus->parent->self; + } + + return exttags_supported; +} + +static int pcie_bus_configure_exttags(struct pci_dev *dev, void *data) { u32 dev_cap; int ret; + bool supported; if (!pci_is_pcie(dev)) - return; + return 0; ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &dev_cap); if (ret) - return; + return 0; - if (dev_cap & PCI_EXP_DEVCAP_EXT_TAG) - pcie_capability_set_word(dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_EXT_TAG); + if (dev_cap & PCI_EXP_DEVCAP_EXT_TAG) { + supported = pcie_bus_exttags_supported(dev->bus); + + if (supported) { + dev_info(&dev->dev, "setting extended tags capability\n"); + pcie_capability_set_word(dev, PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_EXT_TAG); + } else { + dev_info(&dev->dev, "clearing extended tags capability\n"); + pcie_capability_clear_word(dev, PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_EXT_TAG); + } + } + return 0; } static void pci_configure_device(struct pci_dev *dev) @@ -1686,7 +1723,6 @@ static void pci_configure_device(struct pci_dev *dev) int ret; pci_configure_mps(dev); - pci_configure_extended_tags(dev); memset(&hpp, 0, sizeof(hpp)); ret = pci_get_hp_params(dev, &hpp); @@ -2231,6 +2267,8 @@ void pcie_bus_configure_settings(struct pci_bus *bus) pcie_bus_configure_set(bus->self, &smpss); pci_walk_bus(bus, pcie_bus_configure_set, &smpss); + + pci_walk_bus(bus, pcie_bus_configure_exttags, NULL); } EXPORT_SYMBOL_GPL(pcie_bus_configure_settings); -- 1.9.1