From: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
To: "Jingoo Han" <jingoohan1@gmail.com>,
"Manivannan Sadhasivam" <mani@kernel.org>,
"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Bjorn Helgaas" <bhelgaas@google.com>
Cc: konrad.dybcio@oss.qualcomm.com, linux-pci@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
Subject: [PATCH v7 2/3] PCI: dwc: Force L2 link entry on shutdown/reboot without D3cold check
Date: Thu, 29 Oct 2026 09:49:28 +0530 [thread overview]
Message-ID: <20261029-shutdown-v7-2-3fd7a76a6991@oss.qualcomm.com> (raw)
In-Reply-To: <20261029-shutdown-v7-0-3fd7a76a6991@oss.qualcomm.com>
dw_pcie_suspend_noirq() normally calls pci_host_common_d3cold_possible()
to check whether every downstream endpoint can be put into D3cold before
bothering to move the link to L2. If no endpoint supports it, the
function returns early and leaves the link up.
Querying D3cold support during shutdown is actively harmful, not just
slow: pci_host_common_d3cold_possible() requires every active endpoint
to already be in PCI_D3hot, and returns false otherwise. If any endpoint
is still in D0 -- which is common, since endpoint drivers aren't
guaranteed to have suspended by the time the host's shutdown path runs
the check fails and dw_pcie_suspend_noirq() returns early without ever
moving the link to L2, leaving it up right up to the point where the
system cuts power/clocks to the controller.
Add a force parameter to dw_pcie_suspend_noirq() that callers set
explicitly to force this behavior, still call
pci_host_common_d3cold_possible() unconditionally, since it's also how
pme_capable gets set, but ignore its return value and force L2 entry
regardless when force is set.
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/pci/controller/dwc/pci-imx6.c | 2 +-
drivers/pci/controller/dwc/pci-layerscape.c | 2 +-
drivers/pci/controller/dwc/pcie-designware-host.c | 9 ++++-----
drivers/pci/controller/dwc/pcie-designware.h | 4 ++--
drivers/pci/controller/dwc/pcie-eswin.c | 2 +-
drivers/pci/controller/dwc/pcie-nxp-s32g.c | 2 +-
drivers/pci/controller/dwc/pcie-qcom.c | 2 +-
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +-
drivers/pci/controller/dwc/pcie-stm32.c | 2 +-
drivers/pci/controller/dwc/pcie-ultrarisc.c | 2 +-
10 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 83fbd998551d..1f2b942e8423 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -1788,7 +1788,7 @@ static int imx_pcie_suspend_noirq(struct device *dev)
imx_pcie_assert_perst(imx_pcie, true);
imx_pcie->drvdata->enable_ref_clk(imx_pcie, false);
} else {
- return dw_pcie_suspend_noirq(imx_pcie->pci);
+ return dw_pcie_suspend_noirq(imx_pcie->pci, false);
}
return 0;
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
index 7f37a0537159..bfed194834d4 100644
--- a/drivers/pci/controller/dwc/pci-layerscape.c
+++ b/drivers/pci/controller/dwc/pci-layerscape.c
@@ -382,7 +382,7 @@ static int ls_pcie_suspend_noirq(struct device *dev)
if (!pcie->drvdata->pm_support)
return 0;
- return dw_pcie_suspend_noirq(pcie->pci);
+ return dw_pcie_suspend_noirq(pcie->pci, false);
}
static int ls_pcie_resume_noirq(struct device *dev)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 869a39107a81..e4d47999613c 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -1235,23 +1235,22 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
return 0;
}
-int dw_pcie_suspend_noirq(struct dw_pcie *pci)
+int dw_pcie_suspend_noirq(struct dw_pcie *pci, bool force)
{
- bool d3cold, pme_capable = false;
+ bool d3cold_possible, pme_capable = false;
int ret = 0;
u32 val;
if (!dw_pcie_link_up(pci))
goto stop_link;
- d3cold = pci_host_common_d3cold_possible(pci->pp.bridge, &pme_capable);
-
/*
* Enter L2 if D3cold is possible, or if the platform loses RC power
* during suspend (in which case L2 entry is required to notify
* endpoints before power loss, regardless of D3cold support).
*/
- if (!d3cold && !pci->pp.suspend_poweroff)
+ d3cold_possible = pci_host_common_d3cold_possible(pci->pp.bridge, &pme_capable);
+ if (!d3cold_possible && !force && !pci->pp.suspend_poweroff)
return 0;
if (pci->pp.ops->pme_turn_off) {
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 6d788aa00011..4905932cfaf9 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -861,7 +861,7 @@ static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci)
const char *dw_pcie_ltssm_status_string(enum dw_pcie_ltssm ltssm);
#ifdef CONFIG_PCIE_DW_HOST
-int dw_pcie_suspend_noirq(struct dw_pcie *pci);
+int dw_pcie_suspend_noirq(struct dw_pcie *pci, bool force);
int dw_pcie_resume_noirq(struct dw_pcie *pci);
void dw_handle_msi_irq(struct dw_pcie_rp *pp);
void dw_pcie_msi_init(struct dw_pcie_rp *pp);
@@ -874,7 +874,7 @@ int dw_pcie_allocate_msi_domains(struct dw_pcie_rp *pp);
void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn,
int where);
#else
-static inline int dw_pcie_suspend_noirq(struct dw_pcie *pci)
+static inline int dw_pcie_suspend_noirq(struct dw_pcie *pci, bool force)
{
return 0;
}
diff --git a/drivers/pci/controller/dwc/pcie-eswin.c b/drivers/pci/controller/dwc/pcie-eswin.c
index 1bb44696057e..21d077172724 100644
--- a/drivers/pci/controller/dwc/pcie-eswin.c
+++ b/drivers/pci/controller/dwc/pcie-eswin.c
@@ -367,7 +367,7 @@ static int eswin_pcie_suspend_noirq(struct device *dev)
{
struct eswin_pcie *pcie = dev_get_drvdata(dev);
- return dw_pcie_suspend_noirq(&pcie->pci);
+ return dw_pcie_suspend_noirq(&pcie->pci, false);
}
static int eswin_pcie_resume_noirq(struct device *dev)
diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
index 386e44dd0477..cb9cc9327d85 100644
--- a/drivers/pci/controller/dwc/pcie-nxp-s32g.c
+++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
@@ -365,7 +365,7 @@ static int s32g_pcie_suspend_noirq(struct device *dev)
struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
struct dw_pcie *pci = &s32g_pp->pci;
- return dw_pcie_suspend_noirq(pci);
+ return dw_pcie_suspend_noirq(pci, false);
}
static int s32g_pcie_resume_noirq(struct device *dev)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index d903f10211c2..a7835e8a51e0 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -2464,7 +2464,7 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
if (!pcie)
return 0;
- ret = dw_pcie_suspend_noirq(pcie->pci);
+ ret = dw_pcie_suspend_noirq(pcie->pci, false);
if (ret)
return ret;
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index fceecbd16355..045d33ac61ea 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -1071,7 +1071,7 @@ static int rcar_gen4_pcie_suspend_noirq(struct device *dev)
if (rcar->drvdata->mode != DW_PCIE_RC_TYPE)
return 0;
- return dw_pcie_suspend_noirq(&rcar->dw);
+ return dw_pcie_suspend_noirq(&rcar->dw, false);
}
static int rcar_gen4_pcie_resume_noirq(struct device *dev)
diff --git a/drivers/pci/controller/dwc/pcie-stm32.c b/drivers/pci/controller/dwc/pcie-stm32.c
index 349618ea5b9c..7b3a8c1b04a4 100644
--- a/drivers/pci/controller/dwc/pcie-stm32.c
+++ b/drivers/pci/controller/dwc/pcie-stm32.c
@@ -78,7 +78,7 @@ static int stm32_pcie_suspend_noirq(struct device *dev)
struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
int ret;
- ret = dw_pcie_suspend_noirq(&stm32_pcie->pci);
+ ret = dw_pcie_suspend_noirq(&stm32_pcie->pci, false);
if (ret)
return ret;
diff --git a/drivers/pci/controller/dwc/pcie-ultrarisc.c b/drivers/pci/controller/dwc/pcie-ultrarisc.c
index 523f454c6c52..59341682213c 100644
--- a/drivers/pci/controller/dwc/pcie-ultrarisc.c
+++ b/drivers/pci/controller/dwc/pcie-ultrarisc.c
@@ -193,7 +193,7 @@ static int ultrarisc_pcie_suspend_noirq(struct device *dev)
if (pci->suspended)
return 0;
- ret = dw_pcie_suspend_noirq(pci);
+ ret = dw_pcie_suspend_noirq(pci, false);
if (ret)
return ret;
--
2.34.1
next prev parent reply other threads:[~2026-10-29 4:19 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 4:19 [PATCH v7 0/3] PCI: qcom: Implement shutdown() to avoid SMMU/NoC errors on reboot Krishna Chaitanya Chundru
2026-10-29 4:19 ` [PATCH v7 1/3] PCI: host-common: Fix early bus-walk exit in d3cold_possible() Krishna Chaitanya Chundru
2026-10-29 4:19 ` Krishna Chaitanya Chundru [this message]
2026-10-29 4:19 ` [PATCH v7 3/3] PCI: qcom: Implement shutdown() callback Krishna Chaitanya Chundru
2026-10-30 11:26 ` kernel test robot
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=20261029-shutdown-v7-2-3fd7a76a6991@oss.qualcomm.com \
--to=krishna.chundru@oss.qualcomm.com \
--cc=bhelgaas@google.com \
--cc=jingoohan1@gmail.com \
--cc=konrad.dybcio@oss.qualcomm.com \
--cc=kwilczynski@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mani@kernel.org \
--cc=robh@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
all inboxes | Powered by JetHome®