From: Bjorn Helgaas <helgaas@kernel.org>
To: Ajay Agarwal <ajayagarwal@google.com>
Cc: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"David E. Box" <david.e.box@linux.intel.com>,
"Johan Hovold" <johan+linaro@kernel.org>,
"Manivannan Sadhasivam" <manivannan.sadhasivam@linaro.org>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Manu Gautam" <manugautam@google.com>,
"Sajid Dalvi" <sdalvi@google.com>,
"Heiner Kallweit" <hkallweit1@gmail.com>,
"Vidya Sagar" <vidyas@nvidia.com>,
"Shuai Xue" <xueshuai@linux.alibaba.com>,
linux-pci@vger.kernel.org
Subject: Re: [PATCH v3] PCI/ASPM: Disable L1 before disabling L1ss
Date: Tue, 22 Oct 2024 17:30:18 -0500 [thread overview]
Message-ID: <20241022223018.GA893095@bhelgaas> (raw)
In-Reply-To: <20241007032917.872262-1-ajayagarwal@google.com>
On Mon, Oct 07, 2024 at 08:59:17AM +0530, Ajay Agarwal wrote:
> The current sequence in the driver for L1ss update is as follows.
>
> Disable L1ss
> Disable L1
> Enable L1ss as required
> Enable L1 if required
>
> With this sequence, a bus hang is observed during the L1ss
> disable sequence when the RC CPU attempts to clear the RC L1ss
> register after clearing the EP L1ss register. It looks like the
> RC attempts to enter L1ss again and at the same time, access to
> RC L1ss register fails because aux clk is still not active.
>
> PCIe spec r6.2, section 5.5.4, recommends that setting either
> or both of the enable bits for ASPM L1 PM Substates must be done
> while ASPM L1 is disabled. My interpretation here is that
> clearing L1ss should also be done when L1 is disabled. Thereby,
> change the sequence as follows.
>
> Disable L1
> Disable L1ss
> Enable L1ss as required
> Enable L1 if required
>
> Signed-off-by: Ajay Agarwal <ajayagarwal@google.com>
Applied to pci/aspm for v6.13, thank you, Ajay!
> ---
> Changelog since v2:
> - Add the logic in pcie_aspm_cap_init()
>
> Changelog since v1:
> - Move the L1 disable/enable logic to pcie_config_aspm_link()
> - Add detailed comments including spec version and section number
>
> drivers/pci/pcie/aspm.c | 66 +++++++++++++++++++++++++----------------
> 1 file changed, 40 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
> index cee2365e54b8..50997e378631 100644
> --- a/drivers/pci/pcie/aspm.c
> +++ b/drivers/pci/pcie/aspm.c
> @@ -805,6 +805,15 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
> pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
> pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
>
> + /* Make sure L0s/L1 are disabled before updating L1SS config */
> + if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) ||
> + FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) {
> + pcie_capability_write_word(child, PCI_EXP_LNKCTL,
> + child_lnkctl & ~PCI_EXP_LNKCTL_ASPMC);
> + pcie_capability_write_word(parent, PCI_EXP_LNKCTL,
> + parent_lnkctl & ~PCI_EXP_LNKCTL_ASPMC);
> + }
> +
> /*
> * Setup L0s state
> *
> @@ -829,6 +838,13 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
>
> aspm_l1ss_init(link);
>
> + /* Restore L0s/L1 if they were enabled */
> + if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) ||
> + FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) {
> + pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_lnkctl);
> + pcie_capability_write_word(child, PCI_EXP_LNKCTL, child_lnkctl);
> + }
> +
> /* Save default state */
> link->aspm_default = link->aspm_enabled;
>
> @@ -848,17 +864,13 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
> /* Configure the ASPM L1 substates */
> static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
> {
> - u32 val, enable_req;
> + u32 val;
> struct pci_dev *child = link->downstream, *parent = link->pdev;
>
> - enable_req = (link->aspm_enabled ^ state) & state;
> -
> /*
> - * Here are the rules specified in the PCIe spec for enabling L1SS:
> + * Spec r6.2, section 5.5.4, mentions the rules for enabling L1SS:
> * - When enabling L1.x, enable bit at parent first, then at child
> * - When disabling L1.x, disable bit at child first, then at parent
> - * - When enabling ASPM L1.x, need to disable L1
> - * (at child followed by parent).
> * - The ASPM/PCIPM L1.2 must be disabled while programming timing
> * parameters
> *
> @@ -871,16 +883,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
> PCI_L1SS_CTL1_L1SS_MASK, 0);
> pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
> PCI_L1SS_CTL1_L1SS_MASK, 0);
> - /*
> - * If needed, disable L1, and it gets enabled later
> - * in pcie_config_aspm_link().
> - */
> - if (enable_req & (PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2)) {
> - pcie_capability_clear_word(child, PCI_EXP_LNKCTL,
> - PCI_EXP_LNKCTL_ASPM_L1);
> - pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
> - PCI_EXP_LNKCTL_ASPM_L1);
> - }
>
> val = 0;
> if (state & PCIE_LINK_STATE_L1_1)
> @@ -937,21 +939,33 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
> dwstream |= PCI_EXP_LNKCTL_ASPM_L1;
> }
>
> + /*
> + * Spec r6.2, section 5.5.4, recommends that setting either or both of
> + * the enable bits for ASPM L1 PM Substates must be done while ASPM L1
> + * is disabled. So disable L1 here, and it gets enabled later after the
> + * L1ss configuration has been completed.
> + *
> + * Spec r6.2, section 7.5.3.7, mentions that ASPM L1 must be enabled by
> + * software in the Upstream component on a Link prior to enabling ASPM
> + * L1 in the Downstream component on the Link. When disabling L1,
> + * software must disable ASPM L1 in the Downstream component on a Link
> + * prior to disabling ASPM L1 in the Upstream component on that Link.
> + *
> + * Spec doesn't mention L0s.
> + *
> + * Disable L1 and L0s here, and they get enabled later after the L1ss
> + * configuration has been completed.
> + */
> + list_for_each_entry(child, &linkbus->devices, bus_list)
> + pcie_config_aspm_dev(child, 0);
> + pcie_config_aspm_dev(parent, 0);
> +
> if (link->aspm_capable & PCIE_LINK_STATE_L1SS)
> pcie_config_aspm_l1ss(link, state);
>
> - /*
> - * Spec 2.0 suggests all functions should be configured the
> - * same setting for ASPM. Enabling ASPM L1 should be done in
> - * upstream component first and then downstream, and vice
> - * versa for disabling ASPM L1. Spec doesn't mention L0S.
> - */
> - if (state & PCIE_LINK_STATE_L1)
> - pcie_config_aspm_dev(parent, upstream);
> + pcie_config_aspm_dev(parent, upstream);
> list_for_each_entry(child, &linkbus->devices, bus_list)
> pcie_config_aspm_dev(child, dwstream);
> - if (!(state & PCIE_LINK_STATE_L1))
> - pcie_config_aspm_dev(parent, upstream);
>
> link->aspm_enabled = state;
>
> --
> 2.47.0.rc0.187.ge670bccf7e-goog
>
next prev parent reply other threads:[~2024-10-22 22:30 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-07 3:29 [PATCH v3] PCI/ASPM: Disable L1 before disabling L1ss Ajay Agarwal
2024-10-18 15:25 ` Ajay Agarwal
2024-10-22 22:30 ` Bjorn Helgaas [this message]
2025-06-05 11:23 ` Macpaul Lin (林智斌)
2025-06-05 11:27 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241022223018.GA893095@bhelgaas \
--to=helgaas@kernel.org \
--cc=ajayagarwal@google.com \
--cc=bhelgaas@google.com \
--cc=david.e.box@linux.intel.com \
--cc=hkallweit1@gmail.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=johan+linaro@kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=manivannan.sadhasivam@linaro.org \
--cc=manugautam@google.com \
--cc=sdalvi@google.com \
--cc=vidyas@nvidia.com \
--cc=xueshuai@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox