Commit 37edd87e authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Bjorn Helgaas
Browse files

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: default avatarMaciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 33a176ab
Loading
Loading
Loading
Loading
+49 −0
Original line number Diff line number Diff line
@@ -4856,6 +4856,55 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
	return pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
}

/**
 * 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
+1 −0
Original line number Diff line number Diff line
@@ -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);
+0 −42
Original line number Diff line number Diff line
@@ -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