* [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 21:42 [PATCH v2 0/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it Bjorn Helgaas
@ 2025-11-18 21:42 ` Bjorn Helgaas
2025-11-18 22:20 ` Frank Li
` (2 more replies)
2025-11-18 21:42 ` [PATCH v2 2/4] PCI: tegra194: Remove unnecessary L1SS disable code Bjorn Helgaas
` (2 subsequent siblings)
3 siblings, 3 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2025-11-18 21:42 UTC (permalink / raw)
To: Niklas Cassel, Shawn Lin
Cc: Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Heiko Stuebner,
Kever Yang, Simon Xue, Damien Le Moal, Dragan Simic,
FUKAUMI Naoki, Diederik de Haas, Richard Zhu, Frank Li,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
From: Bjorn Helgaas <bhelgaas@google.com>
L1 PM Substates require the CLKREQ# signal and may also require
device-specific support. If CLKREQ# is not supported or driver support is
lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
e.g.,
nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
enable L1.x via sysfs, users may trip over these errors even if L1
Substates haven't been enabled by firmware or the driver.
To prevent such errors, disable advertising the L1 PM Substates unless the
driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
present and any device-specific configuration has been done.
Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
"supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
Based on Niklas's patch:
https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
---
.../pci/controller/dwc/pcie-designware-ep.c | 2 ++
.../pci/controller/dwc/pcie-designware-host.c | 2 ++
drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
drivers/pci/controller/dwc/pcie-designware.h | 2 ++
drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
6 files changed, 35 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 7f2112c2fb21..ad6c0fd67a65 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
if (ep->ops->init)
ep->ops->init(ep);
+ dw_pcie_hide_unsupported_l1ss(pci);
+
ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
/*
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 20c9333bcb1c..7abeb771e32d 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -1060,6 +1060,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+ dw_pcie_hide_unsupported_l1ss(pci);
+
dw_pcie_config_presets(pp);
/*
* If the platform provides its own child bus config accesses, it means
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c644216995f6..6e6a0dac5b53 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -1081,6 +1081,30 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
dw_edma_remove(&pci->edma);
}
+void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
+{
+ u16 l1ss;
+ u32 l1ss_cap;
+
+ if (pci->l1ss_support)
+ return;
+
+ l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
+ if (!l1ss)
+ return;
+
+ /*
+ * Unless the driver claims "l1ss_support", don't advertise L1 PM
+ * Substates because they require CLKREQ# and possibly other
+ * device-specific configuration.
+ */
+ l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
+ l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
+ PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
+ PCI_L1SS_CAP_L1_PM_SS);
+ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
+}
+
void dw_pcie_setup(struct dw_pcie *pci)
{
u32 val;
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index e995f692a1ec..a68eea47d451 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -516,6 +516,7 @@ struct dw_pcie {
int max_link_speed;
u8 n_fts[2];
struct dw_edma_chip edma;
+ bool l1ss_support; /* L1 PM Substates support */
struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS];
struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS];
struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS];
@@ -573,6 +574,7 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type, u64 parent_bus_addr,
u8 bar, size_t size);
void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
+void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci);
void dw_pcie_setup(struct dw_pcie *pci);
void dw_pcie_iatu_detect(struct dw_pcie *pci);
int dw_pcie_edma_detect(struct dw_pcie *pci);
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 805edbbfe7eb..61c2f4e2f74d 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -1067,6 +1067,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
val &= ~REQ_NOT_ENTR_L1;
writel(val, pcie->parf + PARF_PM_CTRL);
+ pci->l1ss_support = true;
+
val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
val |= EN;
writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 10e74458e667..3934757baa30 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -703,6 +703,9 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
val |= (pcie->aspm_pwr_on_t << 19);
dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
+ if (pcie->supports_clkreq)
+ pci->l1ss_support = true;
+
/* Program L0s and L1 entrance latencies */
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 21:42 ` [PATCH v2 1/4] " Bjorn Helgaas
@ 2025-11-18 22:20 ` Frank Li
2025-11-18 22:45 ` Niklas Cassel
2025-11-18 22:34 ` Frank Li
2025-11-20 7:40 ` Manivannan Sadhasivam
2 siblings, 1 reply; 14+ messages in thread
From: Frank Li @ 2025-11-18 22:20 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Niklas Cassel, Shawn Lin, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Heiko Stuebner, Kever Yang, Simon Xue, Damien Le Moal,
Dragan Simic, FUKAUMI Naoki, Diederik de Haas, Richard Zhu,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
On Tue, Nov 18, 2025 at 03:42:15PM -0600, Bjorn Helgaas wrote:
> From: Bjorn Helgaas <bhelgaas@google.com>
>
> L1 PM Substates require the CLKREQ# signal and may also require
> device-specific support. If CLKREQ# is not supported or driver support is
> lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
> e.g.,
>
> nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
>
> If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
> enable L1.x via sysfs, users may trip over these errors even if L1
> Substates haven't been enabled by firmware or the driver.
>
> To prevent such errors, disable advertising the L1 PM Substates unless the
> driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
> present and any device-specific configuration has been done.
>
> Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
> "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
> and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
>
> Based on Niklas's patch:
> https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
>
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> .../pci/controller/dwc/pcie-designware-ep.c | 2 ++
> .../pci/controller/dwc/pcie-designware-host.c | 2 ++
> drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
> drivers/pci/controller/dwc/pcie-designware.h | 2 ++
> drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
> drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
> 6 files changed, 35 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 7f2112c2fb21..ad6c0fd67a65 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
> if (ep->ops->init)
> ep->ops->init(ep);
>
> + dw_pcie_hide_unsupported_l1ss(pci);
> +
Need call dw_pcie_dbi_ro_wr_en(pci) to access PCI_L1SS_CAP.
just ref below code
/*
* PTM responder capability can be disabled only after disabling
* PTM root capability.
*/
if (ptm_cap_base) {
dw_pcie_dbi_ro_wr_en(pci);
reg = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP);
reg &= ~PCI_PTM_CAP_ROOT;
dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, reg);
reg = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP);
reg &= ~(PCI_PTM_CAP_RES | PCI_PTM_GRANULARITY_MASK);
dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, reg);
dw_pcie_dbi_ro_wr_dis(pci);
}
Frank
> ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
>
> /*
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 20c9333bcb1c..7abeb771e32d 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -1060,6 +1060,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
> PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
> dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
>
> + dw_pcie_hide_unsupported_l1ss(pci);
> +
> dw_pcie_config_presets(pp);
> /*
> * If the platform provides its own child bus config accesses, it means
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index c644216995f6..6e6a0dac5b53 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -1081,6 +1081,30 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
> dw_edma_remove(&pci->edma);
> }
>
> +void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
> +{
> + u16 l1ss;
> + u32 l1ss_cap;
> +
> + if (pci->l1ss_support)
> + return;
> +
> + l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
> + if (!l1ss)
> + return;
> +
> + /*
> + * Unless the driver claims "l1ss_support", don't advertise L1 PM
> + * Substates because they require CLKREQ# and possibly other
> + * device-specific configuration.
> + */
> + l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> + l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
> + PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
> + PCI_L1SS_CAP_L1_PM_SS);
> + dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
> +}
> +
> void dw_pcie_setup(struct dw_pcie *pci)
> {
> u32 val;
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index e995f692a1ec..a68eea47d451 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -516,6 +516,7 @@ struct dw_pcie {
> int max_link_speed;
> u8 n_fts[2];
> struct dw_edma_chip edma;
> + bool l1ss_support; /* L1 PM Substates support */
> struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS];
> struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS];
> struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS];
> @@ -573,6 +574,7 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> int type, u64 parent_bus_addr,
> u8 bar, size_t size);
> void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
> +void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci);
> void dw_pcie_setup(struct dw_pcie *pci);
> void dw_pcie_iatu_detect(struct dw_pcie *pci);
> int dw_pcie_edma_detect(struct dw_pcie *pci);
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index 805edbbfe7eb..61c2f4e2f74d 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -1067,6 +1067,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
> val &= ~REQ_NOT_ENTR_L1;
> writel(val, pcie->parf + PARF_PM_CTRL);
>
> + pci->l1ss_support = true;
> +
> val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
> val |= EN;
> writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 10e74458e667..3934757baa30 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -703,6 +703,9 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
> val |= (pcie->aspm_pwr_on_t << 19);
> dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
>
> + if (pcie->supports_clkreq)
> + pci->l1ss_support = true;
> +
> /* Program L0s and L1 entrance latencies */
> val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
> val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 22:20 ` Frank Li
@ 2025-11-18 22:45 ` Niklas Cassel
2025-11-19 0:45 ` Frank Li
0 siblings, 1 reply; 14+ messages in thread
From: Niklas Cassel @ 2025-11-18 22:45 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Helgaas, Shawn Lin, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Heiko Stuebner, Kever Yang, Simon Xue, Damien Le Moal,
Dragan Simic, FUKAUMI Naoki, Diederik de Haas, Richard Zhu,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
Hello Frank,
On Tue, Nov 18, 2025 at 05:20:36PM -0500, Frank Li wrote:
> >
> > + dw_pcie_hide_unsupported_l1ss(pci);
> > +
>
> Need call dw_pcie_dbi_ro_wr_en(pci) to access PCI_L1SS_CAP.
I disagree.
At least when checking two different versions of the databook
(one very old and one more recent), the register fields that we
are touching are all marked as:
Dbi: R/W (sticky)
There are some other register fields in PCI_L1SS_CAP, e.g.
NEXT_OFFSET, CAP_VERSION, and EXTENDED_CAP_ID that are marked as:
Dbi: if (DBI_RO_WR_EN == 1) then R/W(sticky) else R(sticky)
Note: This register field is sticky.
But since we are not touching any of those register fields,
the current code should be good as is.
Perhaps your version of the databook says differently than the
two versions I have, but considering that they seem to have
intentionally made these R/W without the need for DBI_RO_WR_EN,
I don't see a reason why they would want to change it even in
the absolute newest IP version.
Kind regards,
Niklas
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 22:45 ` Niklas Cassel
@ 2025-11-19 0:45 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2025-11-19 0:45 UTC (permalink / raw)
To: Niklas Cassel
Cc: Bjorn Helgaas, Shawn Lin, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Heiko Stuebner, Kever Yang, Simon Xue, Damien Le Moal,
Dragan Simic, FUKAUMI Naoki, Diederik de Haas, Richard Zhu,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
On Tue, Nov 18, 2025 at 11:45:46PM +0100, Niklas Cassel wrote:
> Hello Frank,
>
> On Tue, Nov 18, 2025 at 05:20:36PM -0500, Frank Li wrote:
> > >
> > > + dw_pcie_hide_unsupported_l1ss(pci);
> > > +
> >
> > Need call dw_pcie_dbi_ro_wr_en(pci) to access PCI_L1SS_CAP.
>
> I disagree.
>
> At least when checking two different versions of the databook
> (one very old and one more recent), the register fields that we
> are touching are all marked as:
>
> Dbi: R/W (sticky)
>
Yes, you are right. Sorry for noise.
Frank
>
> There are some other register fields in PCI_L1SS_CAP, e.g.
> NEXT_OFFSET, CAP_VERSION, and EXTENDED_CAP_ID that are marked as:
>
> Dbi: if (DBI_RO_WR_EN == 1) then R/W(sticky) else R(sticky)
> Note: This register field is sticky.
>
>
> But since we are not touching any of those register fields,
> the current code should be good as is.
>
>
> Perhaps your version of the databook says differently than the
> two versions I have, but considering that they seem to have
> intentionally made these R/W without the need for DBI_RO_WR_EN,
> I don't see a reason why they would want to change it even in
> the absolute newest IP version.
>
>
> Kind regards,
> Niklas
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 21:42 ` [PATCH v2 1/4] " Bjorn Helgaas
2025-11-18 22:20 ` Frank Li
@ 2025-11-18 22:34 ` Frank Li
2025-11-19 11:08 ` Niklas Cassel
2025-11-20 7:52 ` Manivannan Sadhasivam
2025-11-20 7:40 ` Manivannan Sadhasivam
2 siblings, 2 replies; 14+ messages in thread
From: Frank Li @ 2025-11-18 22:34 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Niklas Cassel, Shawn Lin, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Heiko Stuebner, Kever Yang, Simon Xue, Damien Le Moal,
Dragan Simic, FUKAUMI Naoki, Diederik de Haas, Richard Zhu,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
On Tue, Nov 18, 2025 at 03:42:15PM -0600, Bjorn Helgaas wrote:
> From: Bjorn Helgaas <bhelgaas@google.com>
>
> L1 PM Substates require the CLKREQ# signal and may also require
> device-specific support. If CLKREQ# is not supported or driver support is
> lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
> e.g.,
>
> nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
>
> If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
> enable L1.x via sysfs, users may trip over these errors even if L1
> Substates haven't been enabled by firmware or the driver.
>
> To prevent such errors, disable advertising the L1 PM Substates unless the
> driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
> present and any device-specific configuration has been done.
>
> Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
> "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
> and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
>
> Based on Niklas's patch:
> https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
>
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> .../pci/controller/dwc/pcie-designware-ep.c | 2 ++
> .../pci/controller/dwc/pcie-designware-host.c | 2 ++
> drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
> drivers/pci/controller/dwc/pcie-designware.h | 2 ++
> drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
> drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
> 6 files changed, 35 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 7f2112c2fb21..ad6c0fd67a65 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
> if (ep->ops->init)
> ep->ops->init(ep);
>
> + dw_pcie_hide_unsupported_l1ss(pci);
> +
And, I don't think EP need clean L1SS CAP flags. If EP don't support L1SS,
it should be force pull down #clkreq.
EP don't know if #clkreq connected in host boards, assume EP with same
software, which can run at two difference host system, one host system
connect #clkreq, the other system have not connect #clkreq.
otherwords, support-clkreq property should be only for RC side. not EP
side. EP side l1ss support should depend on specific epf function and
controller's capablity.
Frank
> ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
>
> /*
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 20c9333bcb1c..7abeb771e32d 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -1060,6 +1060,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
> PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
> dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
>
> + dw_pcie_hide_unsupported_l1ss(pci);
> +
> dw_pcie_config_presets(pp);
> /*
> * If the platform provides its own child bus config accesses, it means
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index c644216995f6..6e6a0dac5b53 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -1081,6 +1081,30 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
> dw_edma_remove(&pci->edma);
> }
>
> +void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
> +{
> + u16 l1ss;
> + u32 l1ss_cap;
> +
> + if (pci->l1ss_support)
> + return;
> +
> + l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
> + if (!l1ss)
> + return;
> +
> + /*
> + * Unless the driver claims "l1ss_support", don't advertise L1 PM
> + * Substates because they require CLKREQ# and possibly other
> + * device-specific configuration.
> + */
> + l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> + l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
> + PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
> + PCI_L1SS_CAP_L1_PM_SS);
> + dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
> +}
> +
> void dw_pcie_setup(struct dw_pcie *pci)
> {
> u32 val;
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index e995f692a1ec..a68eea47d451 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -516,6 +516,7 @@ struct dw_pcie {
> int max_link_speed;
> u8 n_fts[2];
> struct dw_edma_chip edma;
> + bool l1ss_support; /* L1 PM Substates support */
> struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS];
> struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS];
> struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS];
> @@ -573,6 +574,7 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> int type, u64 parent_bus_addr,
> u8 bar, size_t size);
> void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
> +void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci);
> void dw_pcie_setup(struct dw_pcie *pci);
> void dw_pcie_iatu_detect(struct dw_pcie *pci);
> int dw_pcie_edma_detect(struct dw_pcie *pci);
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index 805edbbfe7eb..61c2f4e2f74d 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -1067,6 +1067,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
> val &= ~REQ_NOT_ENTR_L1;
> writel(val, pcie->parf + PARF_PM_CTRL);
>
> + pci->l1ss_support = true;
> +
> val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
> val |= EN;
> writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 10e74458e667..3934757baa30 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -703,6 +703,9 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
> val |= (pcie->aspm_pwr_on_t << 19);
> dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
>
> + if (pcie->supports_clkreq)
> + pci->l1ss_support = true;
> +
> /* Program L0s and L1 entrance latencies */
> val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
> val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 22:34 ` Frank Li
@ 2025-11-19 11:08 ` Niklas Cassel
2025-11-19 15:58 ` Frank Li
2025-11-20 7:52 ` Manivannan Sadhasivam
1 sibling, 1 reply; 14+ messages in thread
From: Niklas Cassel @ 2025-11-19 11:08 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Helgaas, Shawn Lin, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Heiko Stuebner, Kever Yang, Simon Xue, Damien Le Moal,
Dragan Simic, FUKAUMI Naoki, Diederik de Haas, Richard Zhu,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
On Tue, Nov 18, 2025 at 05:34:18PM -0500, Frank Li wrote:
> On Tue, Nov 18, 2025 at 03:42:15PM -0600, Bjorn Helgaas wrote:
> > From: Bjorn Helgaas <bhelgaas@google.com>
> >
> > L1 PM Substates require the CLKREQ# signal and may also require
> > device-specific support. If CLKREQ# is not supported or driver support is
> > lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
> > e.g.,
> >
> > nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
> >
> > If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
> > enable L1.x via sysfs, users may trip over these errors even if L1
> > Substates haven't been enabled by firmware or the driver.
> >
> > To prevent such errors, disable advertising the L1 PM Substates unless the
> > driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
> > present and any device-specific configuration has been done.
> >
> > Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
> > "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
> > and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
> >
> > Based on Niklas's patch:
> > https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
> >
> > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> > ---
> > .../pci/controller/dwc/pcie-designware-ep.c | 2 ++
> > .../pci/controller/dwc/pcie-designware-host.c | 2 ++
> > drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
> > drivers/pci/controller/dwc/pcie-designware.h | 2 ++
> > drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
> > drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
> > 6 files changed, 35 insertions(+)
> >
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > index 7f2112c2fb21..ad6c0fd67a65 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > @@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
> > if (ep->ops->init)
> > ep->ops->init(ep);
> >
> > + dw_pcie_hide_unsupported_l1ss(pci);
> > +
>
> And, I don't think EP need clean L1SS CAP flags. If EP don't support L1SS,
> it should be force pull down #clkreq.
I think the problem is that we cannot force pull down CLKREQ# in a generic
DWC function. That would have to be done in glue driver specific callbacks.
Bjorn, perhaps we should simply drop the dw_pcie_hide_unsupported_l1ss()
call from dw_pcie_ep_init_registers(), and consider hiding L1ss for EPs to
be out of scope for this series.
That way, we could still queue this series up for 6.19.
Thoughts from everyone?
Kind regards,
Niklas
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-19 11:08 ` Niklas Cassel
@ 2025-11-19 15:58 ` Frank Li
2025-11-20 0:53 ` Shawn Lin
0 siblings, 1 reply; 14+ messages in thread
From: Frank Li @ 2025-11-19 15:58 UTC (permalink / raw)
To: Niklas Cassel
Cc: Bjorn Helgaas, Shawn Lin, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Heiko Stuebner, Kever Yang, Simon Xue, Damien Le Moal,
Dragan Simic, FUKAUMI Naoki, Diederik de Haas, Richard Zhu,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
On Wed, Nov 19, 2025 at 12:08:41PM +0100, Niklas Cassel wrote:
> On Tue, Nov 18, 2025 at 05:34:18PM -0500, Frank Li wrote:
> > On Tue, Nov 18, 2025 at 03:42:15PM -0600, Bjorn Helgaas wrote:
> > > From: Bjorn Helgaas <bhelgaas@google.com>
> > >
> > > L1 PM Substates require the CLKREQ# signal and may also require
> > > device-specific support. If CLKREQ# is not supported or driver support is
> > > lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
> > > e.g.,
> > >
> > > nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
> > >
> > > If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
> > > enable L1.x via sysfs, users may trip over these errors even if L1
> > > Substates haven't been enabled by firmware or the driver.
> > >
> > > To prevent such errors, disable advertising the L1 PM Substates unless the
> > > driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
> > > present and any device-specific configuration has been done.
> > >
> > > Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
> > > "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
> > > and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
> > >
> > > Based on Niklas's patch:
> > > https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
> > >
> > > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> > > ---
> > > .../pci/controller/dwc/pcie-designware-ep.c | 2 ++
> > > .../pci/controller/dwc/pcie-designware-host.c | 2 ++
> > > drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
> > > drivers/pci/controller/dwc/pcie-designware.h | 2 ++
> > > drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
> > > drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
> > > 6 files changed, 35 insertions(+)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > index 7f2112c2fb21..ad6c0fd67a65 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > @@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
> > > if (ep->ops->init)
> > > ep->ops->init(ep);
> > >
> > > + dw_pcie_hide_unsupported_l1ss(pci);
> > > +
> >
> > And, I don't think EP need clean L1SS CAP flags. If EP don't support L1SS,
> > it should be force pull down #clkreq.
>
> I think the problem is that we cannot force pull down CLKREQ# in a generic
> DWC function. That would have to be done in glue driver specific callbacks.
>
> Bjorn, perhaps we should simply drop the dw_pcie_hide_unsupported_l1ss()
> call from dw_pcie_ep_init_registers(), and consider hiding L1ss for EPs to
> be out of scope for this series.
Agree, we should consider EP later. When work at EP mode, #clkreq default
it is 0. RC should not turn L1SS if RC don't support. If RC side support,
it should be fine by turing on EP's L1SS because hardware already support
it.
Frank
>
> That way, we could still queue this series up for 6.19.
>
> Thoughts from everyone?
>
>
>
> Kind regards,
> Niklas
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-19 15:58 ` Frank Li
@ 2025-11-20 0:53 ` Shawn Lin
0 siblings, 0 replies; 14+ messages in thread
From: Shawn Lin @ 2025-11-20 0:53 UTC (permalink / raw)
To: Frank Li, Niklas Cassel
Cc: shawn.lin, Bjorn Helgaas, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Heiko Stuebner, Kever Yang, Simon Xue, Damien Le Moal,
Dragan Simic, FUKAUMI Naoki, Diederik de Haas, Richard Zhu,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
在 2025/11/19 星期三 23:58, Frank Li 写道:
> On Wed, Nov 19, 2025 at 12:08:41PM +0100, Niklas Cassel wrote:
>> On Tue, Nov 18, 2025 at 05:34:18PM -0500, Frank Li wrote:
>>> On Tue, Nov 18, 2025 at 03:42:15PM -0600, Bjorn Helgaas wrote:
>>>> From: Bjorn Helgaas <bhelgaas@google.com>
>>>>
>>>> L1 PM Substates require the CLKREQ# signal and may also require
>>>> device-specific support. If CLKREQ# is not supported or driver support is
>>>> lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
>>>> e.g.,
>>>>
>>>> nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
>>>>
>>>> If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
>>>> enable L1.x via sysfs, users may trip over these errors even if L1
>>>> Substates haven't been enabled by firmware or the driver.
>>>>
>>>> To prevent such errors, disable advertising the L1 PM Substates unless the
>>>> driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
>>>> present and any device-specific configuration has been done.
>>>>
>>>> Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
>>>> "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
>>>> and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
>>>>
>>>> Based on Niklas's patch:
>>>> https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
>>>>
>>>> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
>>>> ---
>>>> .../pci/controller/dwc/pcie-designware-ep.c | 2 ++
>>>> .../pci/controller/dwc/pcie-designware-host.c | 2 ++
>>>> drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
>>>> drivers/pci/controller/dwc/pcie-designware.h | 2 ++
>>>> drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
>>>> drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
>>>> 6 files changed, 35 insertions(+)
>>>>
>>>> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
>>>> index 7f2112c2fb21..ad6c0fd67a65 100644
>>>> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
>>>> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
>>>> @@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
>>>> if (ep->ops->init)
>>>> ep->ops->init(ep);
>>>>
>>>> + dw_pcie_hide_unsupported_l1ss(pci);
>>>> +
>>>
>>> And, I don't think EP need clean L1SS CAP flags. If EP don't support L1SS,
>>> it should be force pull down #clkreq.
>>
>> I think the problem is that we cannot force pull down CLKREQ# in a generic
>> DWC function. That would have to be done in glue driver specific callbacks.
>>
>> Bjorn, perhaps we should simply drop the dw_pcie_hide_unsupported_l1ss()
>> call from dw_pcie_ep_init_registers(), and consider hiding L1ss for EPs to
>> be out of scope for this series.
>
>
> Agree, we should consider EP later. When work at EP mode, #clkreq default
> it is 0. RC should not turn L1SS if RC don't support. If RC side support,
> it should be fine by turing on EP's L1SS because hardware already support
> it.
I agree to drop it from dw_pcie_ep_init_registers, and queue it up for
6.19.
Don't get me wrong, but I just need clearly speak out the thought: I
think the idea behind is something like quirk that a variant controller
works on EP mode claiming L1ss available through *CAP* regs but actually
it doesn't. This is nothing related to RC side, even if it pulls down
CLKREQ# to reject negotiation for L1ss, it still looks wrong from lspci
view. So of course, we could leave it to the glue driver to explictly
eliminate L1SS capability later. If they want, just export
dw_pcie_hide_unsupported_l1ss() the call it.
>
> Frank
>
>>
>> That way, we could still queue this series up for 6.19.
>>
>> Thoughts from everyone?
>>
>>
>>
>> Kind regards,
>> Niklas
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 22:34 ` Frank Li
2025-11-19 11:08 ` Niklas Cassel
@ 2025-11-20 7:52 ` Manivannan Sadhasivam
1 sibling, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2025-11-20 7:52 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Helgaas, Niklas Cassel, Shawn Lin, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Heiko Stuebner,
Kever Yang, Simon Xue, Damien Le Moal, Dragan Simic,
FUKAUMI Naoki, Diederik de Haas, Richard Zhu, Lucas Stach,
Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
On Tue, Nov 18, 2025 at 05:34:18PM -0500, Frank Li wrote:
> On Tue, Nov 18, 2025 at 03:42:15PM -0600, Bjorn Helgaas wrote:
> > From: Bjorn Helgaas <bhelgaas@google.com>
> >
> > L1 PM Substates require the CLKREQ# signal and may also require
> > device-specific support. If CLKREQ# is not supported or driver support is
> > lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
> > e.g.,
> >
> > nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
> >
> > If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
> > enable L1.x via sysfs, users may trip over these errors even if L1
> > Substates haven't been enabled by firmware or the driver.
> >
> > To prevent such errors, disable advertising the L1 PM Substates unless the
> > driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
> > present and any device-specific configuration has been done.
> >
> > Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
> > "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
> > and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
> >
> > Based on Niklas's patch:
> > https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
> >
> > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> > ---
> > .../pci/controller/dwc/pcie-designware-ep.c | 2 ++
> > .../pci/controller/dwc/pcie-designware-host.c | 2 ++
> > drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
> > drivers/pci/controller/dwc/pcie-designware.h | 2 ++
> > drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
> > drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
> > 6 files changed, 35 insertions(+)
> >
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > index 7f2112c2fb21..ad6c0fd67a65 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > @@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
> > if (ep->ops->init)
> > ep->ops->init(ep);
> >
> > + dw_pcie_hide_unsupported_l1ss(pci);
> > +
>
> And, I don't think EP need clean L1SS CAP flags. If EP don't support L1SS,
> it should be force pull down #clkreq.
>
> EP don't know if #clkreq connected in host boards, assume EP with same
> software, which can run at two difference host system, one host system
> connect #clkreq, the other system have not connect #clkreq.
>
> otherwords, support-clkreq property should be only for RC side. not EP
> side. EP side l1ss support should depend on specific epf function and
> controller's capablity.
>
'support-clkreq' DT property is only applicable to the RC as per dtschema. So
using it in the EP driver is wrong in the first place. We could add it to the EP
schema, but that should be done first before relying on it in the driver.
Also, I do think that the device capability should accurately reflect whether
L1ss is supported or not and not assume that the EP will pull the CLKREQ# low
when it is not supported. If the L1ss CAP is available on both RC and EP, host
software may enable L1ss and expect it to work.
But enabling/disabling the CAP for EP should be done later based on either the
DT property or controller specific flag.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it
2025-11-18 21:42 ` [PATCH v2 1/4] " Bjorn Helgaas
2025-11-18 22:20 ` Frank Li
2025-11-18 22:34 ` Frank Li
@ 2025-11-20 7:40 ` Manivannan Sadhasivam
2 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2025-11-20 7:40 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Niklas Cassel, Shawn Lin, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Heiko Stuebner,
Kever Yang, Simon Xue, Damien Le Moal, Dragan Simic,
FUKAUMI Naoki, Diederik de Haas, Richard Zhu, Frank Li,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
On Tue, Nov 18, 2025 at 03:42:15PM -0600, Bjorn Helgaas wrote:
> From: Bjorn Helgaas <bhelgaas@google.com>
>
> L1 PM Substates require the CLKREQ# signal and may also require
> device-specific support. If CLKREQ# is not supported or driver support is
> lacking, enabling L1.1 or L1.2 may cause errors when accessing devices,
> e.g.,
>
> nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
>
> If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users
> enable L1.x via sysfs, users may trip over these errors even if L1
> Substates haven't been enabled by firmware or the driver.
>
> To prevent such errors, disable advertising the L1 PM Substates unless the
> driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is
> present and any device-specific configuration has been done.
>
Going by this reasoning, why can't we enable L1 PM Substates for these platforms
by default?
- Mani
> Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the
> "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0,
> and cfg_sc8280xp controllers) so they can continue to use L1 Substates.
>
> Based on Niklas's patch:
> https://patch.msgid.link/20251017163252.598812-2-cassel@kernel.org
>
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> .../pci/controller/dwc/pcie-designware-ep.c | 2 ++
> .../pci/controller/dwc/pcie-designware-host.c | 2 ++
> drivers/pci/controller/dwc/pcie-designware.c | 24 +++++++++++++++++++
> drivers/pci/controller/dwc/pcie-designware.h | 2 ++
> drivers/pci/controller/dwc/pcie-qcom.c | 2 ++
> drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++
> 6 files changed, 35 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 7f2112c2fb21..ad6c0fd67a65 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -966,6 +966,8 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
> if (ep->ops->init)
> ep->ops->init(ep);
>
> + dw_pcie_hide_unsupported_l1ss(pci);
> +
> ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
>
> /*
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 20c9333bcb1c..7abeb771e32d 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -1060,6 +1060,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
> PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
> dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
>
> + dw_pcie_hide_unsupported_l1ss(pci);
> +
> dw_pcie_config_presets(pp);
> /*
> * If the platform provides its own child bus config accesses, it means
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index c644216995f6..6e6a0dac5b53 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -1081,6 +1081,30 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
> dw_edma_remove(&pci->edma);
> }
>
> +void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
> +{
> + u16 l1ss;
> + u32 l1ss_cap;
> +
> + if (pci->l1ss_support)
> + return;
> +
> + l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
> + if (!l1ss)
> + return;
> +
> + /*
> + * Unless the driver claims "l1ss_support", don't advertise L1 PM
> + * Substates because they require CLKREQ# and possibly other
> + * device-specific configuration.
> + */
> + l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> + l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
> + PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
> + PCI_L1SS_CAP_L1_PM_SS);
> + dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
> +}
> +
> void dw_pcie_setup(struct dw_pcie *pci)
> {
> u32 val;
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index e995f692a1ec..a68eea47d451 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -516,6 +516,7 @@ struct dw_pcie {
> int max_link_speed;
> u8 n_fts[2];
> struct dw_edma_chip edma;
> + bool l1ss_support; /* L1 PM Substates support */
> struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS];
> struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS];
> struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS];
> @@ -573,6 +574,7 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> int type, u64 parent_bus_addr,
> u8 bar, size_t size);
> void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
> +void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci);
> void dw_pcie_setup(struct dw_pcie *pci);
> void dw_pcie_iatu_detect(struct dw_pcie *pci);
> int dw_pcie_edma_detect(struct dw_pcie *pci);
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index 805edbbfe7eb..61c2f4e2f74d 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -1067,6 +1067,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
> val &= ~REQ_NOT_ENTR_L1;
> writel(val, pcie->parf + PARF_PM_CTRL);
>
> + pci->l1ss_support = true;
> +
> val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
> val |= EN;
> writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 10e74458e667..3934757baa30 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -703,6 +703,9 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
> val |= (pcie->aspm_pwr_on_t << 19);
> dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
>
> + if (pcie->supports_clkreq)
> + pci->l1ss_support = true;
> +
> /* Program L0s and L1 entrance latencies */
> val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
> val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
> --
> 2.43.0
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 2/4] PCI: tegra194: Remove unnecessary L1SS disable code
2025-11-18 21:42 [PATCH v2 0/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it Bjorn Helgaas
2025-11-18 21:42 ` [PATCH v2 1/4] " Bjorn Helgaas
@ 2025-11-18 21:42 ` Bjorn Helgaas
2025-11-18 21:42 ` [PATCH v2 3/4] PCI: dw-rockchip: Configure L1SS support Bjorn Helgaas
2025-11-18 21:42 ` [PATCH v2 4/4] arm64: dts: rockchip: Add PCIe clkreq stuff for RK3588 EVB1 Bjorn Helgaas
3 siblings, 0 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2025-11-18 21:42 UTC (permalink / raw)
To: Niklas Cassel, Shawn Lin
Cc: Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Heiko Stuebner,
Kever Yang, Simon Xue, Damien Le Moal, Dragan Simic,
FUKAUMI Naoki, Diederik de Haas, Richard Zhu, Frank Li,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
From: Bjorn Helgaas <bhelgaas@google.com>
The DWC core clears the L1 Substates Supported bits unless the driver sets
the "dw_pcie.l1ss_support" flag.
The tegra194 init_host_aspm() sets "dw_pcie.l1ss_support" if the platform
has the "supports-clkreq" DT property. If "supports-clkreq" is absent,
"dw_pcie.l1ss_support" is not set, and the DWC core will clear the L1
Substates Supported bits.
The tegra194 code to clear the L1 Substates Supported bits is unnecessary,
so remove it.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
---
drivers/pci/controller/dwc/pcie-tegra194.c | 45 +++-------------------
1 file changed, 5 insertions(+), 40 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 3934757baa30..0ddeef70726d 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -260,7 +260,6 @@ struct tegra_pcie_dw {
u32 msi_ctrl_int;
u32 num_lanes;
u32 cid;
- u32 cfg_link_cap_l1sub;
u32 ras_des_cap;
u32 pcie_cap_base;
u32 aspm_cmrt;
@@ -475,8 +474,7 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
return IRQ_HANDLED;
/* If EP doesn't advertise L1SS, just return */
- val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
- if (!(val & (PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2)))
+ if (!pci->l1ss_support)
return IRQ_HANDLED;
/* Check if BME is set to '1' */
@@ -608,24 +606,6 @@ static struct pci_ops tegra_pci_ops = {
};
#if defined(CONFIG_PCIEASPM)
-static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
-{
- u32 val;
-
- val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
- val &= ~PCI_L1SS_CAP_ASPM_L1_1;
- dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
-}
-
-static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
-{
- u32 val;
-
- val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
- val &= ~PCI_L1SS_CAP_ASPM_L1_2;
- dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
-}
-
static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
{
u32 val;
@@ -682,10 +662,9 @@ static int aspm_state_cnt(struct seq_file *s, void *data)
static void init_host_aspm(struct tegra_pcie_dw *pcie)
{
struct dw_pcie *pci = &pcie->pci;
- u32 val;
+ u32 l1ss, val;
- val = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
- pcie->cfg_link_cap_l1sub = val + PCI_L1SS_CAP;
+ l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci,
PCI_EXT_CAP_ID_VNDR);
@@ -697,11 +676,11 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val);
/* Program T_cmrt and T_pwr_on values */
- val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
+ val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE);
val |= (pcie->aspm_cmrt << 8);
val |= (pcie->aspm_pwr_on_t << 19);
- dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
+ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
if (pcie->supports_clkreq)
pci->l1ss_support = true;
@@ -729,8 +708,6 @@ static void init_debugfs(struct tegra_pcie_dw *pcie)
aspm_state_cnt);
}
#else
-static inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; }
-static inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; }
static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; }
static inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; }
#endif
@@ -934,12 +911,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
init_host_aspm(pcie);
- /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
- if (!pcie->supports_clkreq) {
- disable_aspm_l11(pcie);
- disable_aspm_l12(pcie);
- }
-
if (!pcie->of_data->has_l1ss_exit_fix) {
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
@@ -1874,12 +1845,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
init_host_aspm(pcie);
- /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
- if (!pcie->supports_clkreq) {
- disable_aspm_l11(pcie);
- disable_aspm_l12(pcie);
- }
-
if (!pcie->of_data->has_l1ss_exit_fix) {
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 3/4] PCI: dw-rockchip: Configure L1SS support
2025-11-18 21:42 [PATCH v2 0/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it Bjorn Helgaas
2025-11-18 21:42 ` [PATCH v2 1/4] " Bjorn Helgaas
2025-11-18 21:42 ` [PATCH v2 2/4] PCI: tegra194: Remove unnecessary L1SS disable code Bjorn Helgaas
@ 2025-11-18 21:42 ` Bjorn Helgaas
2025-11-18 21:42 ` [PATCH v2 4/4] arm64: dts: rockchip: Add PCIe clkreq stuff for RK3588 EVB1 Bjorn Helgaas
3 siblings, 0 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2025-11-18 21:42 UTC (permalink / raw)
To: Niklas Cassel, Shawn Lin
Cc: Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Heiko Stuebner,
Kever Yang, Simon Xue, Damien Le Moal, Dragan Simic,
FUKAUMI Naoki, Diederik de Haas, Richard Zhu, Frank Li,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
From: Shawn Lin <shawn.lin@rock-chips.com>
L1 PM Substates for RC mode require support in the dw-rockchip driver
including proper handling of the CLKREQ# sideband signal. It is mostly
handled by hardware, but software still needs to set the clkreq fields
in the PCIE_CLIENT_POWER_CON register to match the hardware implementation.
For more details, see section '18.6.6.4 L1 Substate' in the RK3568 TRM 1.1
Part 2, or section '11.6.6.4 L1 Substate' in the RK3588 TRM 1.0 Part2.
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
[bhelgaas: set pci->l1ss_support so DWC core preserves L1SS Capability bits;
drop corresponding code here, include updates from
https://lore.kernel.org/r/aRRG8wv13HxOCqgA@ryzen]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/1761187883-150120-1-git-send-email-shawn.lin@rock-chips.com
---
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 3e2752c7dd09..bcd3a28da650 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -62,6 +62,12 @@
/* Interrupt Mask Register Related to Miscellaneous Operation */
#define PCIE_CLIENT_INTR_MASK_MISC 0x24
+/* Power Management Control Register */
+#define PCIE_CLIENT_POWER_CON 0x2c
+#define PCIE_CLKREQ_READY FIELD_PREP_WM16(BIT(0), 1)
+#define PCIE_CLKREQ_NOT_READY FIELD_PREP_WM16(BIT(0), 0)
+#define PCIE_CLKREQ_PULL_DOWN FIELD_PREP_WM16(GENMASK(13, 12), 1)
+
/* Hot Reset Control Register */
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
@@ -85,6 +91,7 @@ struct rockchip_pcie {
struct regulator *vpcie3v3;
struct irq_domain *irq_domain;
const struct rockchip_pcie_of_data *data;
+ bool supports_clkreq;
};
struct rockchip_pcie_of_data {
@@ -200,6 +207,35 @@ static bool rockchip_pcie_link_up(struct dw_pcie *pci)
return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP;
}
+/*
+ * See e.g. section '11.6.6.4 L1 Substate' in the RK3588 TRM V1.0 for the steps
+ * needed to support L1 substates. Currently, just enable L1 substates for RC
+ * mode if CLKREQ# is properly connected and supports-clkreq is present in DT.
+ * For EP mode, there are more things should be done to actually save power in
+ * L1 substates, so disable L1 substates until there is proper support.
+ */
+static void rockchip_pcie_configure_l1ss(struct dw_pcie *pci)
+{
+ struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
+
+ /* Enable L1 substates if CLKREQ# is properly connected */
+ if (rockchip->supports_clkreq) {
+ rockchip_pcie_writel_apb(rockchip, PCIE_CLKREQ_READY,
+ PCIE_CLIENT_POWER_CON);
+ pci->l1ss_support = true;
+ return;
+ }
+
+ /*
+ * Otherwise, assert CLKREQ# unconditionally. Since
+ * pci->l1ss_support is not set, the DWC core will prevent L1
+ * Substates support from being advertised.
+ */
+ rockchip_pcie_writel_apb(rockchip,
+ PCIE_CLKREQ_PULL_DOWN | PCIE_CLKREQ_NOT_READY,
+ PCIE_CLIENT_POWER_CON);
+}
+
static void rockchip_pcie_enable_l0s(struct dw_pcie *pci)
{
u32 cap, lnkcap;
@@ -264,6 +300,7 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
rockchip);
+ rockchip_pcie_configure_l1ss(pci);
rockchip_pcie_enable_l0s(pci);
return 0;
@@ -412,6 +449,9 @@ static int rockchip_pcie_resource_get(struct platform_device *pdev,
return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst),
"failed to get reset lines\n");
+ rockchip->supports_clkreq = of_property_read_bool(pdev->dev.of_node,
+ "supports-clkreq");
+
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v2 4/4] arm64: dts: rockchip: Add PCIe clkreq stuff for RK3588 EVB1
2025-11-18 21:42 [PATCH v2 0/4] PCI: dwc: Advertise L1 PM Substates only if driver requests it Bjorn Helgaas
` (2 preceding siblings ...)
2025-11-18 21:42 ` [PATCH v2 3/4] PCI: dw-rockchip: Configure L1SS support Bjorn Helgaas
@ 2025-11-18 21:42 ` Bjorn Helgaas
3 siblings, 0 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2025-11-18 21:42 UTC (permalink / raw)
To: Niklas Cassel, Shawn Lin
Cc: Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Heiko Stuebner,
Kever Yang, Simon Xue, Damien Le Moal, Dragan Simic,
FUKAUMI Naoki, Diederik de Haas, Richard Zhu, Frank Li,
Lucas Stach, Shawn Guo, Sascha Hauer, Fabio Estevam, Conor Dooley,
Krzysztof Kozlowski, Thierry Reding, Jonathan Hunter, Hans Zhang,
linux-tegra, linux-pci, linux-arm-kernel, linux-rockchip, kernel,
Bjorn Helgaas
From: Shawn Lin <shawn.lin@rock-chips.com>
Add supports-clkreq and pinmux for PCIe ASPM L1 substates.
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Hans Zhang <hans.zhang@cixtech.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/1761187883-150120-2-git-send-email-shawn.lin@rock-chips.com
---
arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts
index ff1ba5ed56ef..c9d284cb738b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts
@@ -522,6 +522,7 @@ &pcie2x1l0 {
pinctrl-names = "default";
pinctrl-0 = <&pcie2_0_rst>, <&pcie2_0_wake>, <&pcie2_0_clkreq>, <&wifi_host_wake_irq>;
reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+ supports-clkreq;
vpcie3v3-supply = <&vcc3v3_wlan>;
status = "okay";
@@ -545,7 +546,8 @@ wifi: wifi@0,0 {
&pcie2x1l1 {
reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
- pinctrl-0 = <&pcie2_1_rst>, <&rtl8111_isolate>;
+ pinctrl-0 = <&pcie2_1_rst>, <&rtl8111_isolate>, <&pcie30x1m1_1_clkreqn>;
+ supports-clkreq;
status = "okay";
};
@@ -555,7 +557,8 @@ &pcie30phy {
&pcie3x4 {
pinctrl-names = "default";
- pinctrl-0 = <&pcie3_reset>;
+ pinctrl-0 = <&pcie3_reset>, <&pcie30x4m1_clkreqn>;
+ supports-clkreq;
reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
vpcie3v3-supply = <&vcc3v3_pcie30>;
status = "okay";
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread