@@ -419,8 +419,10 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link,
*/
if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
link->aspm_support |= ASPM_STATE_L0S;
- if (dwreg.enabled & PCIE_LINK_STATE_L0S)
+ if (dwreg.enabled & PCIE_LINK_STATE_L0S) {
link->aspm_enabled |= ASPM_STATE_L0S_UP;
+ link->aspm_default |= ASPM_STATE_L0S_UP;
+ }
if (upreg.enabled & PCIE_LINK_STATE_L0S)
link->aspm_enabled |= ASPM_STATE_L0S_DW;
link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
@@ -434,9 +436,6 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link,
link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
- /* Save default state */
- link->aspm_default = link->aspm_enabled;
-
/* Setup initial capable state. Will be updated later */
link->aspm_capable = link->aspm_support;
}
@@ -579,6 +578,7 @@ int pci_aspm_init(struct pci_dev *pdev)
{
int ret;
struct pcie_link_state *link;
+ struct aspm_register_info upreg;
if (!aspm_support_enabled)
return 0;
@@ -601,6 +601,13 @@ int pci_aspm_init(struct pci_dev *pdev)
ret = -ENOMEM;
goto unlock;
}
+
+ pcie_get_aspm_reg(pdev, &upreg);
+ if (upreg.enabled & PCIE_LINK_STATE_L0S)
+ link->aspm_default |= ASPM_STATE_L0S_DW;
+ if (upreg.enabled & PCIE_LINK_STATE_L1)
+ link->aspm_default |= ASPM_STATE_L1;
+
} else {
WARN_ON(!pdev->bus);
if (!pdev->bus) {
@@ -748,10 +755,12 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
/* All functions are removed, so just disable ASPM for the link */
pcie_config_aspm_link(link, 0);
- list_del(&link->sibling);
- list_del(&link->link);
- /* Clock PM is for endpoint device */
- free_link_state(link);
+ if (pdev->has_secondary_link) {
+ list_del(&link->sibling);
+ list_del(&link->link);
+ /* Clock PM is for endpoint device */
+ free_link_state(link);
+ }
/* Recheck latencies and configure upstream links */
if (parent_link) {
For endpoints, change pcie_aspm_exit_link_state() so it cleans up the device's own state and disables ASPM if necessary, but doesn't remove the parent's link_state. For bridges, change pcie_aspm_exit_link_state() so it frees the bridge's own link_state. Signed-off-by: Sinan Kaya <okaya@codeaurora.org> --- drivers/pci/pcie/aspm.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)