[PATCH V3 5/5] PCI: pciehp: Clear stale 14-Bit Tag Requester Enable on hot add
Vidya Sagar <[email protected]>
| Newsgroups | org.kernel.vger.linux-pci,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
pci_bridge_refresh_14bit_tag() runs from pci_bridge_wait_for_secondary_bus() and from __pcie_update_link_speed(), which between them cover every reset and every link mode change the core observes. A hot swap that changes the mode of the link reaches neither in time. Take a Downstream Port without DPC. A card whose link runs in Flit Mode is pulled out and one that trains in Non-Flit Mode is plugged in. Nothing is reset, so pci_bridge_wait_for_secondary_bus() never runs, and the new card has no saved state, so pci_restore_state() does not run on it either. pciehp does reach __pcie_update_link_speed() from pciehp_check_link_status(), but only after pci_bus_check_dev() has polled the new card's Vendor ID for up to a second in 20 ms steps. The Port is the requester for every one of those reads and still has 14-Bit Tag Requester Enable set, so the card's completions cannot be matched, each read times out and returns all ones, and the slot is reported as empty. The card never enumerates. Refresh the Port's 14-Bit Tag Requester Enable in pciehp_check_link_status() once pcie_wait_for_link() has confirmed Data Link Layer Link Active, and before the first config read to the card. LNKSTA2.Flit_Mode is valid at that point because the link has finished training. The subordinate bus holds no devices yet, so the subtree walk in the helper is a no-op, which is what we want: the new card comes out of reset with its own 14-Bit Tag Requester Enable clear and is configured during enumeration. Signed-off-by: Vidya Sagar <[email protected]> --- V3: * New patch in this series drivers/pci/hotplug/pciehp_hpc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 4c62140a3cb4..95f9d5abdec2 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -302,6 +302,14 @@ int pciehp_check_link_status(struct controller *ctrl) if (ctrl->inband_presence_disabled) pcie_wait_for_presence(pdev); + /* + * The link is up, but a newly inserted card may have trained it in a + * different mode than the card that was removed left it in. Drop a + * now stale 14-Bit Tag Requester Enable on the Port before the first + * config read below, which the Port issues as the requester. + */ + pci_bridge_refresh_14bit_tag(pdev); + found = pci_bus_check_dev(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0)); -- 2.43.0