summaryrefslogtreecommitdiff
path: root/drivers/pci/pcie
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r--drivers/pci/pcie/aspm.c67
1 files changed, 25 insertions, 42 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 68a4d4b15f9..694ba565775 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -370,56 +370,39 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
}
}
-static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev,
- unsigned int state)
+/**
+ * __pcie_aspm_check_state_one - check latency for endpoint device.
+ * @endpoint: pointer to the struct pci_dev of endpoint device
+ *
+ * TBD: The latency from the endpoint to root complex vary per switch's
+ * upstream link state above the device. Here we just do a simple check
+ * which assumes all links above the device can be in L1 state, that
+ * is we just consider the worst case. If switch's upstream link can't
+ * be put into L0S/L1, then our check is too strictly.
+ */
+static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state)
{
- struct pci_dev *parent_dev, *tmp_dev;
- unsigned int l1_latency = 0;
- struct pcie_link_state *link_state;
+ u32 l1_switch_latency = 0;
struct aspm_latency *acceptable;
+ struct pcie_link_state *link;
- parent_dev = pdev->bus->self;
- link_state = parent_dev->link_state;
- state &= link_state->aspm_support;
- if (state == 0)
- return 0;
- acceptable = &link_state->acceptable[PCI_FUNC(pdev->devfn)];
+ link = endpoint->bus->self->link_state;
+ state &= link->aspm_support;
+ acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)];
- /*
- * Check latency for endpoint device.
- * TBD: The latency from the endpoint to root complex vary per
- * switch's upstream link state above the device. Here we just do a
- * simple check which assumes all links above the device can be in L1
- * state, that is we just consider the worst case. If switch's upstream
- * link can't be put into L0S/L1, then our check is too strictly.
- */
- tmp_dev = pdev;
- while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
- parent_dev = tmp_dev->bus->self;
- link_state = parent_dev->link_state;
+ while (link && state) {
if ((state & PCIE_LINK_STATE_L0S) &&
- (link_state->latency.l0s > acceptable->l0s))
+ (link->latency.l0s > acceptable->l0s))
state &= ~PCIE_LINK_STATE_L0S;
-
if ((state & PCIE_LINK_STATE_L1) &&
- (link_state->latency.l1 + l1_latency > acceptable->l1))
+ (link->latency.l1 + l1_switch_latency > acceptable->l1))
state &= ~PCIE_LINK_STATE_L1;
-
- if (!parent_dev->bus->self) /* parent_dev is a root port */
- break;
- else {
- /*
- * parent_dev is the downstream port of a switch, make
- * tmp_dev the upstream port of the switch
- */
- tmp_dev = parent_dev->bus->self;
- /*
- * every switch on the path to root complex need 1 more
- * microsecond for L1. Spec doesn't mention L0S.
- */
- if (state & PCIE_LINK_STATE_L1)
- l1_latency += 1000;
- }
+ link = link->parent;
+ /*
+ * Every switch on the path to root complex need 1
+ * more microsecond for L1. Spec doesn't mention L0s.
+ */
+ l1_switch_latency += 1000;
}
return state;
}