public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	patches@lists.linux.dev, Ajay Agarwal <ajayagarwal@google.com>,
	Bjorn Helgaas <bhelgaas@google.com>,
	Johnny-CC Chang <Johnny-CC.Chang@mediatek.com>,
	Macpaul Lin <macpaul.lin@mediatek.com>
Subject: [PATCH 6.12 11/24] PCI/ASPM: Disable L1 before disabling L1 PM Substates
Date: Sat,  7 Jun 2025 12:07:42 +0200	[thread overview]
Message-ID: <20250607100718.348292137@linuxfoundation.org> (raw)
In-Reply-To: <20250607100717.910797456@linuxfoundation.org>

6.12-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Ajay Agarwal <ajayagarwal@google.com>

commit 7447990137bf06b2aeecad9c6081e01a9f47f2aa upstream.

PCIe r6.2, sec 5.5.4, requires that:

  If setting either or both of the enable bits for ASPM L1 PM Substates,
  both ports must be configured as described in this section while ASPM L1
  is disabled.

Previously, pcie_config_aspm_l1ss() assumed that "setting enable bits"
meant "setting them to 1", and it configured L1SS as follows:

  - Clear L1SS enable bits
  - Disable L1
  - Configure L1SS enable bits as required
  - Enable L1 if required

With this sequence, when disabling L1SS on an ARM A-core with a Synopsys
DesignWare PCIe core, the CPU occasionally hangs when reading
PCI_L1SS_CTL1, leading to a reboot when the CPU watchdog expires.

Move the L1 disable to the caller (pcie_config_aspm_link(), where L1 was
already enabled) so L1 is always disabled while updating the L1SS bits:

  - Disable L1
  - Clear L1SS enable bits
  - Configure L1SS enable bits as required
  - Enable L1 if required

Change pcie_aspm_cap_init() similarly.

Link: https://lore.kernel.org/r/20241007032917.872262-1-ajayagarwal@google.com
Signed-off-by: Ajay Agarwal <ajayagarwal@google.com>
[bhelgaas: comments, commit log, compute L1SS setting before config access]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Johnny-CC Chang <Johnny-CC.Chang@mediatek.com>
Signed-off-by: Macpaul Lin <macpaul.lin@mediatek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/pci/pcie/aspm.c |   92 ++++++++++++++++++++++++++----------------------
 1 file changed, 50 insertions(+), 42 deletions(-)

--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -805,6 +805,15 @@ static void pcie_aspm_cap_init(struct pc
 	pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
 	pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
 
+	/* Disable L0s/L1 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 pc
 
 	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;
 
@@ -845,25 +861,28 @@ static void pcie_aspm_cap_init(struct pc
 	}
 }
 
-/* Configure the ASPM L1 substates */
+/* Configure the ASPM L1 substates. Caller must disable L1 first. */
 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;
+	val = 0;
+	if (state & PCIE_LINK_STATE_L1_1)
+		val |= PCI_L1SS_CTL1_ASPM_L1_1;
+	if (state & PCIE_LINK_STATE_L1_2)
+		val |= PCI_L1SS_CTL1_ASPM_L1_2;
+	if (state & PCIE_LINK_STATE_L1_1_PCIPM)
+		val |= PCI_L1SS_CTL1_PCIPM_L1_1;
+	if (state & PCIE_LINK_STATE_L1_2_PCIPM)
+		val |= PCI_L1SS_CTL1_PCIPM_L1_2;
 
 	/*
-	 * Here are the rules specified in the PCIe spec 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
+	 * PCIe r6.2, sec 5.5.4, rules for enabling L1 PM Substates:
+	 * - Clear L1.x enable bits at child first, then at parent
+	 * - Set L1.x enable bits at parent first, then at child
+	 * - ASPM/PCIPM L1.2 must be disabled while programming timing
 	 *   parameters
-	 *
-	 * To keep it simple, disable all L1SS bits first, and later enable
-	 * what is needed.
 	 */
 
 	/* Disable all L1 substates */
@@ -871,26 +890,6 @@ static void pcie_config_aspm_l1ss(struct
 				       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)
-		val |= PCI_L1SS_CTL1_ASPM_L1_1;
-	if (state & PCIE_LINK_STATE_L1_2)
-		val |= PCI_L1SS_CTL1_ASPM_L1_2;
-	if (state & PCIE_LINK_STATE_L1_1_PCIPM)
-		val |= PCI_L1SS_CTL1_PCIPM_L1_1;
-	if (state & PCIE_LINK_STATE_L1_2_PCIPM)
-		val |= PCI_L1SS_CTL1_PCIPM_L1_2;
 
 	/* Enable what we need to enable */
 	pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
@@ -937,21 +936,30 @@ static void pcie_config_aspm_link(struct
 		dwstream |= PCI_EXP_LNKCTL_ASPM_L1;
 	}
 
+	/*
+	 * Per PCIe r6.2, sec 5.5.4, setting either or both of the enable
+	 * bits for ASPM L1 PM Substates must be done while ASPM L1 is
+	 * disabled. Disable L1 here and apply new configuration after L1SS
+	 * configuration has been completed.
+	 *
+	 * Per sec 7.5.3.7, when disabling ASPM L1, software must disable
+	 * it in the Downstream component prior to disabling it in the
+	 * Upstream component, and ASPM L1 must be enabled in the Upstream
+	 * component prior to enabling it in the Downstream component.
+	 *
+	 * Sec 7.5.3.7 also recommends programming the same ASPM Control
+	 * value for all functions of a multi-function device.
+	 */
+	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;
 



  parent reply	other threads:[~2025-06-07 10:09 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-07 10:07 [PATCH 6.12 00/24] 6.12.33-rc1 review Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 01/24] tracing: Fix compilation warning on arm32 Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 02/24] f2fs: fix to avoid accessing uninitialized curseg Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 03/24] pinctrl: armada-37xx: use correct OUTPUT_VAL register for GPIOs > 31 Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 04/24] pinctrl: armada-37xx: set GPIO output value before setting direction Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 05/24] acpi-cpufreq: Fix nominal_freq units to KHz in get_max_boost_ratio() Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 06/24] Documentation: ACPI: Use all-string data node references Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 07/24] rtc: Make rtc_time64_to_tm() support dates before 1970 Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 08/24] rtc: Fix offset calculation for .start_secs < 0 Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 09/24] accel/ivpu: Add initial Panther Lake support Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 10/24] accel/ivpu: Update power island delays Greg Kroah-Hartman
2025-06-07 10:07 ` Greg Kroah-Hartman [this message]
2025-06-07 10:07 ` [PATCH 6.12 12/24] block: fix adding folio to bio Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 13/24] Revert "cpufreq: tegra186: Share policy per cluster" Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 14/24] usb: quirks: Add NO_LPM quirk for SanDisk Extreme 55AE Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 15/24] usb: storage: Ignore UAS driver for SanDisk 3.2 Gen2 storage device Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 16/24] USB: serial: pl2303: add new chip PL2303GC-Q20 and PL2303GT-2AB Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 17/24] usb: typec: ucsi: fix Clang -Wsign-conversion warning Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 18/24] Bluetooth: hci_qca: move the SoC type check to the right place Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 19/24] serial: jsm: fix NPE during jsm_uart_port_init Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 20/24] usb: usbtmc: Fix timeout value in get_stb Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 21/24] thunderbolt: Do not double dequeue a configuration request Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 22/24] dt-bindings: usb: cypress,hx3: Add support for all variants Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 23/24] dt-bindings: phy: imx8mq-usb: fix fsl,phy-tx-vboost-level-microvolt property Greg Kroah-Hartman
2025-06-07 10:07 ` [PATCH 6.12 24/24] Revert "drm/amd/display: more liberal vmin/vmax update for freesync" Greg Kroah-Hartman
2025-06-07 15:07 ` [PATCH 6.12 00/24] 6.12.33-rc1 review Markus Reichelt
2025-06-07 15:49 ` Florian Fainelli
2025-06-08  5:50 ` Ron Economos
2025-06-08  6:41 ` Naresh Kamboju
2025-06-08 15:38 ` Peter Schneider
2025-06-08 17:53 ` Pavel Machek
2025-06-08 22:23 ` Mark Brown
2025-06-09 12:48 ` Jon Hunter

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=20250607100718.348292137@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=Johnny-CC.Chang@mediatek.com \
    --cc=ajayagarwal@google.com \
    --cc=bhelgaas@google.com \
    --cc=macpaul.lin@mediatek.com \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    /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