Skip to content

Commit e231b96

Browse files
author
CKI KWF Bot
committed
Merge: PCI/ASPM: Disable L1 before disabling L1 PM Substates
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7278 JIRA: https://issues.redhat.com/browse/RHEL-102694 ## Summary of Changes The following series updates PCI/ASPM code. Signed-off-by: Marcin Juszkiewicz <mjuszkiewicz@redhat.com> Approved-by: John W. Linville <linville@redhat.com> Approved-by: Myron Stowe <mstowe@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents 0f49aec + 4d87a6e commit e231b96

File tree

1 file changed

+90
-55
lines changed

1 file changed

+90
-55
lines changed

drivers/pci/pcie/aspm.c

Lines changed: 90 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,44 @@ void pci_configure_aspm_l1ss(struct pci_dev *pdev)
8181

8282
void pci_save_aspm_l1ss_state(struct pci_dev *pdev)
8383
{
84+
struct pci_dev *parent = pdev->bus->self;
8485
struct pci_cap_saved_state *save_state;
85-
u16 l1ss = pdev->l1ss;
8686
u32 *cap;
8787

88+
/*
89+
* If this is a Downstream Port, we never restore the L1SS state
90+
* directly; we only restore it when we restore the state of the
91+
* Upstream Port below it.
92+
*/
93+
if (pcie_downstream_port(pdev) || !parent)
94+
return;
95+
96+
if (!pdev->l1ss || !parent->l1ss)
97+
return;
98+
8899
/*
89100
* Save L1 substate configuration. The ASPM L0s/L1 configuration
90101
* in PCI_EXP_LNKCTL_ASPMC is saved by pci_save_pcie_state().
91102
*/
92-
if (!l1ss)
103+
save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
104+
if (!save_state)
93105
return;
94106

95-
save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
107+
cap = &save_state->cap.data[0];
108+
pci_read_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL2, cap++);
109+
pci_read_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, cap++);
110+
111+
/*
112+
* Save parent's L1 substate configuration so we have it for
113+
* pci_restore_aspm_l1ss_state(pdev) to restore.
114+
*/
115+
save_state = pci_find_saved_ext_cap(parent, PCI_EXT_CAP_ID_L1SS);
96116
if (!save_state)
97117
return;
98118

99119
cap = &save_state->cap.data[0];
100-
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL2, cap++);
101-
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, cap++);
120+
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, cap++);
121+
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, cap++);
102122
}
103123

104124
void pci_restore_aspm_l1ss_state(struct pci_dev *pdev)
@@ -805,6 +825,15 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
805825
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
806826
pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
807827

828+
/* Disable L0s/L1 before updating L1SS config */
829+
if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) ||
830+
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) {
831+
pcie_capability_write_word(child, PCI_EXP_LNKCTL,
832+
child_lnkctl & ~PCI_EXP_LNKCTL_ASPMC);
833+
pcie_capability_write_word(parent, PCI_EXP_LNKCTL,
834+
parent_lnkctl & ~PCI_EXP_LNKCTL_ASPMC);
835+
}
836+
808837
/*
809838
* Setup L0s state
810839
*
@@ -829,6 +858,13 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
829858

830859
aspm_l1ss_init(link);
831860

861+
/* Restore L0s/L1 if they were enabled */
862+
if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) ||
863+
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) {
864+
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_lnkctl);
865+
pcie_capability_write_word(child, PCI_EXP_LNKCTL, child_lnkctl);
866+
}
867+
832868
/* Save default state */
833869
link->aspm_default = link->aspm_enabled;
834870

@@ -845,52 +881,35 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
845881
}
846882
}
847883

848-
/* Configure the ASPM L1 substates */
884+
/* Configure the ASPM L1 substates. Caller must disable L1 first. */
849885
static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
850886
{
851-
u32 val, enable_req;
887+
u32 val;
852888
struct pci_dev *child = link->downstream, *parent = link->pdev;
853889

854-
enable_req = (link->aspm_enabled ^ state) & state;
890+
val = 0;
891+
if (state & PCIE_LINK_STATE_L1_1)
892+
val |= PCI_L1SS_CTL1_ASPM_L1_1;
893+
if (state & PCIE_LINK_STATE_L1_2)
894+
val |= PCI_L1SS_CTL1_ASPM_L1_2;
895+
if (state & PCIE_LINK_STATE_L1_1_PCIPM)
896+
val |= PCI_L1SS_CTL1_PCIPM_L1_1;
897+
if (state & PCIE_LINK_STATE_L1_2_PCIPM)
898+
val |= PCI_L1SS_CTL1_PCIPM_L1_2;
855899

856900
/*
857-
* Here are the rules specified in the PCIe spec for enabling L1SS:
858-
* - When enabling L1.x, enable bit at parent first, then at child
859-
* - When disabling L1.x, disable bit at child first, then at parent
860-
* - When enabling ASPM L1.x, need to disable L1
861-
* (at child followed by parent).
862-
* - The ASPM/PCIPM L1.2 must be disabled while programming timing
901+
* PCIe r6.2, sec 5.5.4, rules for enabling L1 PM Substates:
902+
* - Clear L1.x enable bits at child first, then at parent
903+
* - Set L1.x enable bits at parent first, then at child
904+
* - ASPM/PCIPM L1.2 must be disabled while programming timing
863905
* parameters
864-
*
865-
* To keep it simple, disable all L1SS bits first, and later enable
866-
* what is needed.
867906
*/
868907

869908
/* Disable all L1 substates */
870909
pci_clear_and_set_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
871910
PCI_L1SS_CTL1_L1SS_MASK, 0);
872911
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
873912
PCI_L1SS_CTL1_L1SS_MASK, 0);
874-
/*
875-
* If needed, disable L1, and it gets enabled later
876-
* in pcie_config_aspm_link().
877-
*/
878-
if (enable_req & (PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2)) {
879-
pcie_capability_clear_word(child, PCI_EXP_LNKCTL,
880-
PCI_EXP_LNKCTL_ASPM_L1);
881-
pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
882-
PCI_EXP_LNKCTL_ASPM_L1);
883-
}
884-
885-
val = 0;
886-
if (state & PCIE_LINK_STATE_L1_1)
887-
val |= PCI_L1SS_CTL1_ASPM_L1_1;
888-
if (state & PCIE_LINK_STATE_L1_2)
889-
val |= PCI_L1SS_CTL1_ASPM_L1_2;
890-
if (state & PCIE_LINK_STATE_L1_1_PCIPM)
891-
val |= PCI_L1SS_CTL1_PCIPM_L1_1;
892-
if (state & PCIE_LINK_STATE_L1_2_PCIPM)
893-
val |= PCI_L1SS_CTL1_PCIPM_L1_2;
894913

895914
/* Enable what we need to enable */
896915
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
@@ -937,21 +956,30 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
937956
dwstream |= PCI_EXP_LNKCTL_ASPM_L1;
938957
}
939958

959+
/*
960+
* Per PCIe r6.2, sec 5.5.4, setting either or both of the enable
961+
* bits for ASPM L1 PM Substates must be done while ASPM L1 is
962+
* disabled. Disable L1 here and apply new configuration after L1SS
963+
* configuration has been completed.
964+
*
965+
* Per sec 7.5.3.7, when disabling ASPM L1, software must disable
966+
* it in the Downstream component prior to disabling it in the
967+
* Upstream component, and ASPM L1 must be enabled in the Upstream
968+
* component prior to enabling it in the Downstream component.
969+
*
970+
* Sec 7.5.3.7 also recommends programming the same ASPM Control
971+
* value for all functions of a multi-function device.
972+
*/
973+
list_for_each_entry(child, &linkbus->devices, bus_list)
974+
pcie_config_aspm_dev(child, 0);
975+
pcie_config_aspm_dev(parent, 0);
976+
940977
if (link->aspm_capable & PCIE_LINK_STATE_L1SS)
941978
pcie_config_aspm_l1ss(link, state);
942979

943-
/*
944-
* Spec 2.0 suggests all functions should be configured the
945-
* same setting for ASPM. Enabling ASPM L1 should be done in
946-
* upstream component first and then downstream, and vice
947-
* versa for disabling ASPM L1. Spec doesn't mention L0S.
948-
*/
949-
if (state & PCIE_LINK_STATE_L1)
950-
pcie_config_aspm_dev(parent, upstream);
980+
pcie_config_aspm_dev(parent, upstream);
951981
list_for_each_entry(child, &linkbus->devices, bus_list)
952982
pcie_config_aspm_dev(child, dwstream);
953-
if (!(state & PCIE_LINK_STATE_L1))
954-
pcie_config_aspm_dev(parent, upstream);
955983

956984
link->aspm_enabled = state;
957985

@@ -1242,16 +1270,16 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
12421270
parent_link = link->parent;
12431271

12441272
/*
1245-
* link->downstream is a pointer to the pci_dev of function 0. If
1246-
* we remove that function, the pci_dev is about to be deallocated,
1247-
* so we can't use link->downstream again. Free the link state to
1248-
* avoid this.
1273+
* Free the parent link state, no later than function 0 (i.e.
1274+
* link->downstream) being removed.
12491275
*
1250-
* If we're removing a non-0 function, it's possible we could
1251-
* retain the link state, but PCIe r6.0, sec 7.5.3.7, recommends
1252-
* programming the same ASPM Control value for all functions of
1253-
* multi-function devices, so disable ASPM for all of them.
1276+
* Do not free the link state any earlier. If function 0 is a
1277+
* switch upstream port, this link state is parent_link to all
1278+
* subordinate ones.
12541279
*/
1280+
if (pdev != link->downstream)
1281+
goto out;
1282+
12551283
pcie_config_aspm_link(link, 0);
12561284
list_del(&link->sibling);
12571285
free_link_state(link);
@@ -1262,6 +1290,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
12621290
pcie_config_aspm_path(parent_link);
12631291
}
12641292

1293+
out:
12651294
mutex_unlock(&aspm_lock);
12661295
up_read(&pci_bus_sem);
12671296
}
@@ -1442,6 +1471,9 @@ static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked)
14421471
* touch the LNKCTL register. Also note that this does not enable states
14431472
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
14441473
*
1474+
* Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per
1475+
* PCIe r6.0, sec 5.5.4.
1476+
*
14451477
* @pdev: PCI device
14461478
* @state: Mask of ASPM link states to enable
14471479
*/
@@ -1458,6 +1490,9 @@ EXPORT_SYMBOL(pci_enable_link_state);
14581490
* can't touch the LNKCTL register. Also note that this does not enable states
14591491
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
14601492
*
1493+
* Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per
1494+
* PCIe r6.0, sec 5.5.4.
1495+
*
14611496
* @pdev: PCI device
14621497
* @state: Mask of ASPM link states to enable
14631498
*

0 commit comments

Comments
 (0)