Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f5a70f1 authored by Oza Pawandeep's avatar Oza Pawandeep Committed by Bjorn Helgaas
Browse files

PCI: Add generic pcie_wait_for_link() interface



Clients such as hotplug and Downstream Port Containment (DPC) both need to
wait until a link becomes active or inactive.

Add a generic pcie_wait_link_active() interface and use it instead of
duplicating the code.

Signed-off-by: default avatarOza Pawandeep <poza@codeaurora.org>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarKeith Busch <keith.busch@intel.com>
parent 2af8641b
Loading
Loading
Loading
Loading
+3 −17
Original line number Diff line number Diff line
@@ -231,25 +231,11 @@ bool pciehp_check_link_active(struct controller *ctrl)
	return ret;
}

static void __pcie_wait_link_active(struct controller *ctrl, bool active)
{
	int timeout = 1000;

	if (pciehp_check_link_active(ctrl) == active)
		return;
	while (timeout > 0) {
		msleep(10);
		timeout -= 10;
		if (pciehp_check_link_active(ctrl) == active)
			return;
	}
	ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
			active ? "set" : "cleared");
}

static void pcie_wait_link_active(struct controller *ctrl)
{
	__pcie_wait_link_active(ctrl, true);
	struct pci_dev *pdev = ctrl_dev(ctrl);

	pcie_wait_for_link(pdev, true);
}

static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
+29 −0
Original line number Diff line number Diff line
@@ -4138,6 +4138,35 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)

	return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
}
/**
 * pcie_wait_for_link - Wait until link is active or inactive
 * @pdev: Bridge device
 * @active: waiting for active or inactive?
 *
 * Use this to wait till link becomes active or inactive.
 */
bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
{
	int timeout = 1000;
	bool ret;
	u16 lnk_status;

	for (;;) {
		pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
		ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
		if (ret == active)
			return true;
		if (timeout <= 0)
			break;
		msleep(10);
		timeout -= 10;
	}

	pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
		 active ? "set" : "cleared");

	return false;
}

void pci_reset_secondary_bus(struct pci_dev *dev)
{
+1 −0
Original line number Diff line number Diff line
@@ -353,6 +353,7 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,

void pci_enable_acs(struct pci_dev *dev);

bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
#ifdef CONFIG_PCIEASPM
void pcie_aspm_init_link_state(struct pci_dev *pdev);
void pcie_aspm_exit_link_state(struct pci_dev *pdev);
+1 −11
Original line number Diff line number Diff line
@@ -68,19 +68,9 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)

static void dpc_wait_link_inactive(struct dpc_dev *dpc)
{
	unsigned long timeout = jiffies + HZ;
	struct pci_dev *pdev = dpc->dev->port;
	struct device *dev = &dpc->dev->device;
	u16 lnk_status;

	pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
	while (lnk_status & PCI_EXP_LNKSTA_DLLLA &&
					!time_after(jiffies, timeout)) {
		msleep(10);
		pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
	}
	if (lnk_status & PCI_EXP_LNKSTA_DLLLA)
		dev_warn(dev, "Link state not disabled for DPC event\n");
	pcie_wait_for_link(pdev, false);
}

static void dpc_work(struct work_struct *work)