From 0f4bd8014db515999493baaa75d506cc8026c462 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 9 Nov 2017 14:15:08 +0300 Subject: PCI: hotplug: Drop checking of PCI_BRIDGE_CONTROL in *_unconfigure_device() When removing a bridge, pciehp_unconfigure_device() reads the PCI_BRIDGE_CONTROL byte. If this is a surprise hot-unplug, the device is already gone and the read returns ~0, which pciehp_unconfigure_device() interprets as having PCI_BRIDGE_CTL_VGA set. This results in failure of the remove operation: pciehp 0000:00:1c.0:pcie004: Slot(0): Link Down pciehp 0000:00:1c.0:pcie004: Slot(0): Card present pciehp 0000:00:1c.0:pcie004: Cannot remove display device 0000:01:00.0 Because of this the hierarchy is left untouched preventing further hotplug operations. Now, it is not clear why the check is there in the first place and why we would like to prevent removing a bridge if it has PCI_BRIDGE_CTL_VGA set. In case of PCIe surprise hot-unplug, it would not even be possible to prevent the removal. Given this and the issue described above, I think it makes sense to drop the whole PCI_BRIDGE_CONTROL check from pciehp_unconfigure_device(). While there do the same for shpchp_configure_device() based on the same reasoning and the fact that the same bug might trigger in standard PCI hotplug as well. Signed-off-by: Mika Westerberg [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp_pci.c | 12 ------------ drivers/pci/hotplug/shpchp_pci.c | 12 ------------ 2 files changed, 24 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 2a1ca020cf5a..acc360d1a1fb 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -79,7 +79,6 @@ int pciehp_configure_device(struct slot *p_slot) int pciehp_unconfigure_device(struct slot *p_slot) { int rc = 0; - u8 bctl = 0; u8 presence = 0; struct pci_dev *dev, *temp; struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate; @@ -101,17 +100,6 @@ int pciehp_unconfigure_device(struct slot *p_slot) list_for_each_entry_safe_reverse(dev, temp, &parent->devices, bus_list) { pci_dev_get(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { - pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - ctrl_err(ctrl, - "Cannot remove display device %s\n", - pci_name(dev)); - pci_dev_put(dev); - rc = -EINVAL; - break; - } - } if (!presence) { pci_dev_set_disconnected(dev, NULL); if (pci_has_subordinate(dev)) diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index ea63db58b4b1..79f1682c858e 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -78,7 +78,6 @@ int shpchp_configure_device(struct slot *p_slot) int shpchp_unconfigure_device(struct slot *p_slot) { int rc = 0; - u8 bctl = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; struct pci_dev *dev, *temp; struct controller *ctrl = p_slot->ctrl; @@ -93,17 +92,6 @@ int shpchp_unconfigure_device(struct slot *p_slot) continue; pci_dev_get(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - ctrl_err(ctrl, - "Cannot remove display device %s\n", - pci_name(dev)); - pci_dev_put(dev); - rc = -EINVAL; - break; - } - } pci_stop_and_remove_bus_device(dev); pci_dev_put(dev); } -- cgit v1.2.3 From 493fb50e958c1c6deef7feff0b8c3855def78d75 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 17 Jan 2018 16:48:39 +0100 Subject: PCI: pciehp: Assume NoCompl+ for Thunderbolt ports Certain Thunderbolt 1 controllers claim to support Command Completed events (value of 0b in the No Command Completed Support field of the Slot Capabilities register) but in reality they neither set the Command Completed bit in the Slot Status register nor signal a Command Completed interrupt: 8086:1513 CV82524 [Light Ridge 4C 2010] 8086:151a DSL2310 [Eagle Ridge 2C 2011] 8086:151b CVL2510 [Light Peak 2C 2010] 8086:1547 DSL3510 [Cactus Ridge 4C 2012] 8086:1548 DSL3310 [Cactus Ridge 2C 2012] 8086:1549 DSL2210 [Port Ridge 1C 2011] All known newer chips (Redwood Ridge and onwards) set No Command Completed Support, indicating that they do not support Command Completed events. The user-visible impact is that after unplugging such a device, 2 seconds elapse until pciehp is unbound. That's because on ->remove, pcie_write_cmd() is called via pcie_disable_notification() and every call to pcie_write_cmd() takes 2 seconds (1 second for each invocation of pcie_wait_cmd()): [ 337.942727] pciehp 0000:0a:00.0:pcie204: Timeout on hotplug command 0x1038 (issued 21176 msec ago) [ 340.014735] pciehp 0000:0a:00.0:pcie204: Timeout on hotplug command 0x0000 (issued 2072 msec ago) That by itself has always been unpleasant, but the situation has become worse with commit cc27b735ad3a ("PCI/portdrv: Turn off PCIe services during shutdown"): Now pciehp is unbound on ->shutdown. Because Thunderbolt controllers typically have 4 hotplug ports, every reboot and shutdown is now delayed by 8 seconds, plus another 2 seconds for every attached Thunderbolt 1 device. Thunderbolt hotplug slots are not physical slots that one inserts cards into, but rather logical hotplug slots implemented in silicon. Devices appear beyond those logical slots once a PCI tunnel is established on top of the Thunderbolt Converged I/O switch. One would expect commands written to the Slot Control register to be executed immediately by the silicon, so for simplicity we always assume NoCompl+ for Thunderbolt ports. Fixes: cc27b735ad3a ("PCI/portdrv: Turn off PCIe services during shutdown") Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Mika Westerberg Cc: stable@vger.kernel.org # v4.12+ Cc: Sinan Kaya Cc: Yehezkel Bernat Cc: Michael Jamet Cc: Andreas Noever --- drivers/pci/hotplug/pciehp_hpc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 7bab0606f1a9..a89d8b990228 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -848,6 +848,13 @@ struct controller *pcie_init(struct pcie_device *dev) if (pdev->hotplug_user_indicators) slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP); + /* + * We assume no Thunderbolt controllers support Command Complete events, + * but some controllers falsely claim they do. + */ + if (pdev->is_thunderbolt) + slot_cap |= PCI_EXP_SLTCAP_NCCS; + ctrl->slot_cap = slot_cap; mutex_init(&ctrl->ctrl_lock); init_waitqueue_head(&ctrl->queue); -- cgit v1.2.3