diff options
author | Maciej W. Rozycki <macro@orcam.me.uk> | 2023-06-11 19:19:53 +0200 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2023-06-20 17:58:53 +0200 |
commit | 680e9c47a2293bcc6a67a6f13f3b23d4c456885b (patch) | |
tree | 8b1d935d9aa4958b68acfccee32fa6aaaf1d8075 | |
parent | PCI: Export pcie_retrain_link() for use outside ASPM (diff) | |
download | linux-680e9c47a2293bcc6a67a6f13f3b23d4c456885b.tar.xz linux-680e9c47a2293bcc6a67a6f13f3b23d4c456885b.zip |
PCI: Add support for polling DLLLA to pcie_retrain_link()
Let the caller of pcie_retrain_link() specify whether they want to use the
LT bit or the DLLLA bit of the Link Status Register to determine if link
training has completed. It is up to the caller to verify whether the use
of the DLLLA bit, the implementation of which is optional, is valid for the
device requested.
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2306110310540.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 | 28 | ||||
-rw-r--r-- | drivers/pci/pci.h | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 2 |
3 files changed, 22 insertions, 10 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 47ceb8567b2b..d576f7fa86cd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4857,35 +4857,47 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe) } /** - * pcie_wait_for_link_status - Wait for link training end + * pcie_wait_for_link_status - Wait for link status change * @pdev: Device whose link to wait for. + * @use_lt: Use the LT bit if TRUE, or the DLLLA bit if FALSE. + * @active: Waiting for active or inactive? * - * Return TRUE if successful, or FALSE if training has not completed - * within PCIE_LINK_RETRAIN_TIMEOUT_MS milliseconds. + * Return TRUE if successful, or FALSE if status has not changed within + * PCIE_LINK_RETRAIN_TIMEOUT_MS milliseconds. */ -static bool pcie_wait_for_link_status(struct pci_dev *pdev) +static bool pcie_wait_for_link_status(struct pci_dev *pdev, + bool use_lt, bool active) { + u16 lnksta_mask, lnksta_match; unsigned long end_jiffies; u16 lnksta; + lnksta_mask = use_lt ? PCI_EXP_LNKSTA_LT : PCI_EXP_LNKSTA_DLLLA; + lnksta_match = active ? lnksta_mask : 0; + 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)) + if ((lnksta & lnksta_mask) == lnksta_match) break; msleep(1); } while (time_before(jiffies, end_jiffies)); - return !(lnksta & PCI_EXP_LNKSTA_LT); + return (lnksta & lnksta_mask) == lnksta_match; } /** * pcie_retrain_link - Request a link retrain and wait for it to complete * @pdev: Device whose link to retrain. + * @use_lt: Use the LT bit if TRUE, or the DLLLA bit if FALSE, for status. + * + * Retrain completion status is retrieved from the Link Status Register + * according to @use_lt. It is not verified whether the use of the DLLLA + * bit is valid. * * 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) +bool pcie_retrain_link(struct pci_dev *pdev, bool use_lt) { u16 lnkctl; @@ -4902,7 +4914,7 @@ bool pcie_retrain_link(struct pci_dev *pdev) pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl); } - return pcie_wait_for_link_status(pdev); + return pcie_wait_for_link_status(pdev, use_lt, !use_lt); } /** diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 0d9671b20d17..6c257acbae90 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -565,7 +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); +bool pcie_retrain_link(struct pci_dev *pdev, bool use_lt); #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 0c5d392dc793..99b8badddea5 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -257,7 +257,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) reg16 &= ~PCI_EXP_LNKCTL_CCC; pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); - if (pcie_retrain_link(link->pdev)) + if (pcie_retrain_link(link->pdev, true)) return; /* Training failed. Restore common clock configurations */ |