diff options
author | Maciej W. Rozycki <macro@orcam.me.uk> | 2023-06-11 18:19:41 +0100 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2023-06-20 10:58:53 -0500 |
commit | 37edd87eb621a96d33ee4eefe4b54cfc5a7e03df (patch) | |
tree | 39f140cd556bd47729cc22fcb51871dd2f1c47c0 | |
parent | 33a176abcc4cd4ed3d65512ed96d7b73f2565ed7 (diff) | |
download | linux-37edd87eb621a96d33ee4eefe4b54cfc5a7e03df.tar.gz linux-37edd87eb621a96d33ee4eefe4b54cfc5a7e03df.tar.bz2 linux-37edd87eb621a96d33ee4eefe4b54cfc5a7e03df.zip |
PCI: Export pcie_retrain_link() for use outside ASPM
Export pcie_retrain_link() for link retrain needs outside ASPM. Struct
pcie_link_state is local to ASPM and only used by pcie_retrain_link() to
get at the associated PCI device, so change the operand and adjust the lone
call site accordingly. Document the interface. No functional change at
this point.
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2306110229010.64925@angie.orcam.me.uk
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r-- | drivers/pci/pci.c | 49 | ||||
-rw-r--r-- | drivers/pci/pci.h | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 42 |
3 files changed, 50 insertions, 42 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 71645d568986..47ceb8567b2b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4857,6 +4857,55 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe) } /** + * pcie_wait_for_link_status - Wait for link training end + * @pdev: Device whose link to wait for. + * + * Return TRUE if successful, or FALSE if training has not completed + * within PCIE_LINK_RETRAIN_TIMEOUT_MS milliseconds. + */ +static bool pcie_wait_for_link_status(struct pci_dev *pdev) +{ + unsigned long end_jiffies; + u16 lnksta; + + end_jiffies = jiffies + msecs_to_jiffies(PCIE_LINK_RETRAIN_TIMEOUT_MS); + do { + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnksta); + if (!(lnksta & PCI_EXP_LNKSTA_LT)) + break; + msleep(1); + } while (time_before(jiffies, end_jiffies)); + return !(lnksta & PCI_EXP_LNKSTA_LT); +} + +/** + * pcie_retrain_link - Request a link retrain and wait for it to complete + * @pdev: Device whose link to retrain. + * + * Return TRUE if successful, or FALSE if training has not completed + * within PCIE_LINK_RETRAIN_TIMEOUT_MS milliseconds. + */ +bool pcie_retrain_link(struct pci_dev *pdev) +{ + u16 lnkctl; + + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnkctl); + lnkctl |= PCI_EXP_LNKCTL_RL; + pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl); + 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); + } + + return pcie_wait_for_link_status(pdev); +} + +/** * pcie_wait_for_link_delay - Wait until link is active or inactive * @pdev: Bridge device * @active: waiting for active or inactive? diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d5fe253114f2..0d9671b20d17 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -565,6 +565,7 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev, pci_ers_result_t (*reset_subordinates)(struct pci_dev *pdev)); bool pcie_wait_for_link(struct pci_dev *pdev, bool active); +bool pcie_retrain_link(struct pci_dev *pdev); #ifdef CONFIG_PCIEASPM void pcie_aspm_init_link_state(struct pci_dev *pdev); void pcie_aspm_exit_link_state(struct pci_dev *pdev); diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 721e5c787cf3..0c5d392dc793 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -191,48 +191,6 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) link->clkpm_disable = blacklist ? 1 : 0; } -/** - * pcie_wait_for_link_status - Wait for link training end - * @pdev: Device whose link to wait for. - * - * Return TRUE if successful, or FALSE if training has not completed - * within PCIE_LINK_RETRAIN_TIMEOUT_MS milliseconds. - */ -static bool pcie_wait_for_link_status(struct pci_dev *pdev) -{ - unsigned long end_jiffies; - u16 lnksta; - - end_jiffies = jiffies + msecs_to_jiffies(PCIE_LINK_RETRAIN_TIMEOUT_MS); - do { - pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnksta); - if (!(lnksta & PCI_EXP_LNKSTA_LT)) - break; - msleep(1); - } while (time_before(jiffies, end_jiffies)); - return !(lnksta & PCI_EXP_LNKSTA_LT); -} - -static bool pcie_retrain_link(struct pci_dev *pdev) -{ - u16 lnkctl; - - pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnkctl); - lnkctl |= PCI_EXP_LNKCTL_RL; - pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl); - 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); - } - - return pcie_wait_for_link_status(pdev); -} - /* * pcie_aspm_configure_common_clock: check if the 2 ends of a link * could use common clock. If they are, configure them to use the |