[PATCH 03/11] PCI: tegra194: Fix Endpoint PERST# IRQ suspend race

From: Manikanta Maddireddy

Date: Wed Sep 23 2026 - 03:27:43 EST


Endpoint mode disables the PERST# IRQ during system suspend when the
link is down. The old code checked ep_state before disabling the IRQ,
so the host could deassert PERST# in that window and the IRQ thread
could move the endpoint to EP_STATE_ENABLED after the suspend check had
already passed.

Disable the PERST# IRQ before checking ep_state and re-enable it
immediately when suspend is rejected. Pair the successful suspend
disable with the normal resume callback, because PM rollback after
another device aborts suspend invokes .resume, not .resume_early.

Wrap the PM ops pointer with pm_sleep_ptr() so the callbacks are used
only when system sleep is enabled.

Fixes: c76f8eae7d46 ("PCI: tegra194: Allow system suspend when the Endpoint link is not up")
Link: https://lore.kernel.org/r/20260324190755.1094879-10-mmaddireddy@xxxxxxxxxx
Signed-off-by: Manikanta Maddireddy <mmaddireddy@xxxxxxxxxx>
---
drivers/pci/controller/dwc/pcie-tegra194.c | 33 ++++++++++++++--------
1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 810695d8e5c8..b91073a6305a 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2374,19 +2374,29 @@ static int tegra_pcie_dw_suspend(struct device *dev)
{
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);

- if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
- if (pcie->ep_state == EP_STATE_ENABLED) {
- dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
- return -EPERM;
- }
-
- disable_irq(pcie->pex_rst_irq);
+ if (pcie->of_data->mode != DW_PCIE_EP_TYPE)
return 0;
+
+ disable_irq(pcie->pex_rst_irq);
+ if (pcie->ep_state == EP_STATE_ENABLED) {
+ enable_irq(pcie->pex_rst_irq);
+ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
+ return -EPERM;
}

return 0;
}

+static int tegra_pcie_dw_resume(struct device *dev)
+{
+ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
+
+ if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
+ enable_irq(pcie->pex_rst_irq);
+
+ return 0;
+}
+
static int tegra_pcie_dw_suspend_late(struct device *dev)
{
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
@@ -2462,10 +2472,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev)
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
u32 val;

- if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
- enable_irq(pcie->pex_rst_irq);
+ if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
return 0;
- }

if (!pcie->link_state)
return 0;
@@ -2569,10 +2577,11 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = {

static const struct dev_pm_ops tegra_pcie_dw_pm_ops = {
.suspend = tegra_pcie_dw_suspend,
+ .resume = tegra_pcie_dw_resume,
.suspend_late = tegra_pcie_dw_suspend_late,
+ .resume_early = tegra_pcie_dw_resume_early,
.suspend_noirq = tegra_pcie_dw_suspend_noirq,
.resume_noirq = tegra_pcie_dw_resume_noirq,
- .resume_early = tegra_pcie_dw_resume_early,
};

static struct platform_driver tegra_pcie_dw_driver = {
@@ -2581,7 +2590,7 @@ static struct platform_driver tegra_pcie_dw_driver = {
.shutdown = tegra_pcie_dw_shutdown,
.driver = {
.name = "tegra194-pcie",
- .pm = &tegra_pcie_dw_pm_ops,
+ .pm = pm_sleep_ptr(&tegra_pcie_dw_pm_ops),
.of_match_table = tegra_pcie_dw_of_match,
},
};
--
2.34.1