diff options
| author | Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> | 2026-07-08 16:30:17 +0200 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-09-14 15:53:17 -0500 |
| commit | 4de786a2cfbaac3dde6172a06ca4470cca17c76a (patch) | |
| tree | 7f1272854eaeee1e8229ca6a2ddba89cc61234ec | |
| parent | 0d28ad027806a6787a6c47a91f1afdcd6d8db424 (diff) | |
| download | linux-next-4de786a2cfbaac3dde6172a06ca4470cca17c76a.tar.gz linux-next-4de786a2cfbaac3dde6172a06ca4470cca17c76a.zip | |
PCI/ASPM: Transition the device to D0 (if required) when enabling ASPM link states
Per PCIe spec r6.0, sec 5.5.4:
If setting either or both of the enable bits for PCI-PM L1 PM Substates,
both ports must be configured as described in this section while in D0.
Currently, the callers of pci_enable_link_state_locked() (vmd, pcie-qcom)
transition the device to D0 themselves before enabling the link state. But
this is easy to get wrong and has to be duplicated by every caller.
Move the D0 transition into the shared __pci_enable_link_state() helper so
that all three APIs pci_enable_link_state(), pci_enable_link_state_locked()
and pci_force_enable_link_state() perform it, and only when the PCI-PM L1
PM Substates are getting enabled.
Now that the helper handles the transition, drop the redundant D0
transition from the vmd and pcie-qcom callers.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20260708-pci-aspm-fix-v3-3-6bd72451746e@kernel.org
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-qcom.c | 5 | ||||
| -rw-r--r-- | drivers/pci/controller/vmd.c | 5 | ||||
| -rw-r--r-- | drivers/pci/pcie/aspm.c | 23 |
3 files changed, 17 insertions, 16 deletions
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index b58a607b713f..078b587a605d 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1109,11 +1109,6 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata) { - /* - * Downstream devices need to be in D0 state before enabling PCI PM - * substates. - */ - pci_set_power_state_locked(pdev, PCI_D0); pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL); return 0; diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 241023ecf677..c9a564299e05 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -896,11 +896,6 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) pci_info(pdev, "VMD: Default LTR value set by driver\n"); out_state_change: - /* - * Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per - * PCIe r6.0, sec 5.5.4. - */ - pci_set_power_state_locked(pdev, PCI_D0); pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL); return 0; } diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index a3fd948b66ba..8b579704514f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -1579,6 +1579,17 @@ static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked, return -EPERM; } + /* + * Ensure the device is in D0 before enabling PCI-PM L1 PM Substates, per + * PCIe r6.0, sec 5.5.4. + */ + if (state & PCIE_LINK_STATE_L1_SS_PCIPM) { + if (locked) + pci_set_power_state_locked(pdev, PCI_D0); + else + pci_set_power_state(pdev, PCI_D0); + } + if (!locked) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); @@ -1605,8 +1616,8 @@ static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked, * touch the LNKCTL register. Also note that this does not enable states * disabled by pci_disable_link_state(). Return 0 or a negative errno. * - * Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per - * PCIe r6.0, sec 5.5.4. + * Note: The device will be transitioned to D0 state if the PCI-PM L1 Substates + * are getting enabled. * * @pdev: PCI device * @state: Mask of ASPM link states to enable @@ -1624,8 +1635,8 @@ EXPORT_SYMBOL(pci_enable_link_state); * can't touch the LNKCTL register. Also note that this does not enable states * disabled by pci_disable_link_state(). Return 0 or a negative errno. * - * Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per - * PCIe r6.0, sec 5.5.4. + * Note: The device will be transitioned to D0 state if the PCI-PM L1 Substates + * are getting enabled. * * @pdev: PCI device * @state: Mask of ASPM link states to enable @@ -1655,8 +1666,8 @@ EXPORT_SYMBOL(pci_enable_link_state_locked); * Note that if the BIOS didn't grant ASPM control to the OS, this does nothing * because we can't touch the LNKCTL register. * - * Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per - * PCIe r6.0, sec 5.5.4. + * Note: The device will be transitioned to D0 state if the PCI-PM L1 Substates + * are getting enabled. * * Return: 0 on success, a negative errno otherwise. */ |
