]> git.itanic.dy.fi Git - linux-stable/commitdiff
PCI: Make link retraining use RMW accessors for changing LNKCTL
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Mon, 17 Jul 2023 12:04:54 +0000 (15:04 +0300)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 10 Aug 2023 16:13:22 +0000 (11:13 -0500)
Don't assume that the device is fully under the control of PCI core.  Use
RMW capability accessors in link retraining which do proper locking to
avoid losing concurrent updates to the register values.

Suggested-by: Lukas Wunner <lukas@wunner.de>
Fixes: 4ec73791a64b ("PCI: Work around Pericom PCIe-to-PCI bridge Retrain Link erratum")
Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support")
Link: https://lore.kernel.org/r/20230717120503.15276-3-ilpo.jarvinen@linux.intel.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: "Rafael J. Wysocki" <rafael@kernel.org>
drivers/pci/pci.c

index 60230da957e0c4b1d4481a191dfa709600f2b48b..f7315b13bb8269c0252c5881531b44c50b3287af 100644 (file)
@@ -4927,7 +4927,6 @@ static int pcie_wait_for_link_status(struct pci_dev *pdev,
 int pcie_retrain_link(struct pci_dev *pdev, bool use_lt)
 {
        int rc;
-       u16 lnkctl;
 
        /*
         * Ensure the updated LNKCTL parameters are used during link
@@ -4939,17 +4938,14 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt)
        if (rc)
                return rc;
 
-       pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnkctl);
-       lnkctl |= PCI_EXP_LNKCTL_RL;
-       pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl);
+       pcie_capability_set_word(pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RL);
        if (pdev->clear_retrain_link) {
                /*
                 * Due to an erratum in some devices the Retrain Link bit
                 * needs to be cleared again manually to allow the link
                 * training to succeed.
                 */
-               lnkctl &= ~PCI_EXP_LNKCTL_RL;
-               pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl);
+               pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RL);
        }
 
        return pcie_wait_for_link_status(pdev, use_lt, !use_lt);