* [PATCH 0/3] PCI: dwc: Avoid full EP cleanup on PERST#
@ 2026-09-23 7:25 Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 1/3] PCI: dwc: Add Endpoint reinit helper Manikanta Maddireddy
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Manikanta Maddireddy @ 2026-09-23 7:25 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczynski, Bjorn Helgaas, linux-pci
Cc: Rob Herring, Thierry Reding, Jonathan Hunter, Vidya Sagar,
Niklas Cassel, linux-kernel, linux-tegra, Manikanta Maddireddy
This series avoids tearing down and reallocating DWC Endpoint software
resources on every PERST# assertion while still restoring reset-lost
hardware state on the following PERST# deassert.
The current Tegra194/234 Endpoint flow can run the full DWC EP
cleanup/init sequence for each PERST# cycle. That is heavier than needed
for a link reset and can repeatedly free/reallocate devres/dmam-backed
resources that are intended to live for the driver lifetime. It also risks
stale software users running after the host removes the link.
Patch 1 adds a common DWC EP reinit helper that preserves software
resources and reinitializes only reset-lost registers when resources
already exist. Patch 2 switches Tegra194/234 Endpoint PERST# deassert to
that helper. Patch 3 sends the software-only endpoint linkdown
notification on PERST# assert so EPF drivers stop outstanding work without
touching hardware after REFCLK may be gone.
The series keeps hardware-register cleanup in the PERST# deassert path
where REFCLK and resets are available.
Manikanta Maddireddy (3):
PCI: dwc: Add Endpoint reinit helper
PCI: tegra194: Avoid full Endpoint reinit on PERST#
PCI: tegra194: Notify Endpoint functions on PERST# assert
.../pci/controller/dwc/pcie-designware-ep.c | 152 +++++++++++++-----
drivers/pci/controller/dwc/pcie-designware.h | 13 ++
drivers/pci/controller/dwc/pcie-tegra194.c | 8 +-
3 files changed, 129 insertions(+), 44 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/3] PCI: dwc: Add Endpoint reinit helper
2026-09-23 7:25 [PATCH 0/3] PCI: dwc: Avoid full EP cleanup on PERST# Manikanta Maddireddy
@ 2026-09-23 7:25 ` Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 2/3] PCI: tegra194: Avoid full Endpoint reinit on PERST# Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 3/3] PCI: tegra194: Notify Endpoint functions on PERST# assert Manikanta Maddireddy
2 siblings, 0 replies; 4+ messages in thread
From: Manikanta Maddireddy @ 2026-09-23 7:25 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczynski, Bjorn Helgaas, linux-pci
Cc: Rob Herring, Thierry Reding, Jonathan Hunter, Vidya Sagar,
Niklas Cassel, linux-kernel, linux-tegra, Manikanta Maddireddy
Endpoint controllers can receive a fundamental reset while software
resources such as eDMA, debugfs and function state must live for the
controller lifetime.
Track whether DWC Endpoint resources are initialized and add helpers
that perform full initialization once, then reinitialize only reset-lost
registers on later fundamental reset cycles.
A fundamental reset also clears outbound iATU programming. Clear the
cached outbound window map, outbound address array and MSI iATU cache
before reinitializing registers so stale software state cannot hide a
window that was reset by hardware.
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
.../pci/controller/dwc/pcie-designware-ep.c | 152 +++++++++++++-----
drivers/pci/controller/dwc/pcie-designware.h | 13 ++
2 files changed, 124 insertions(+), 41 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index de8ee3db4360..7ba40220b821 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -1155,6 +1155,28 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_msix_irq);
+static void dw_pcie_ep_clear_msi_iatu(struct dw_pcie_ep *ep)
+{
+ ep->msi_iatu_mapped = false;
+ ep->msi_iatu_mapped_offset = 0;
+ ep->msi_msg_addr = 0;
+ ep->msi_map_size = 0;
+}
+
+static void dw_pcie_ep_clear_outbound_atus(struct dw_pcie_ep *ep)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+ if (ep->ob_window_map)
+ bitmap_zero(ep->ob_window_map, pci->num_ob_windows);
+
+ if (ep->outbound_addr)
+ memset(ep->outbound_addr, 0,
+ pci->num_ob_windows * sizeof(*ep->outbound_addr));
+
+ dw_pcie_ep_clear_msi_iatu(ep);
+}
+
/**
* dw_pcie_ep_cleanup - Cleanup DWC EP resources after fundamental reset
* @ep: DWC EP device
@@ -1169,11 +1191,12 @@ void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep)
if (ep->msi_iatu_mapped) {
dw_pcie_ep_unmap_addr(ep->epc, 0, 0, ep->msi_mem_phys);
- ep->msi_iatu_mapped = false;
+ dw_pcie_ep_clear_msi_iatu(ep);
}
dwc_pcie_debugfs_deinit(pci);
dw_pcie_edma_remove(pci);
+ ep->resources_initialized = false;
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_cleanup);
@@ -1307,6 +1330,89 @@ static void dw_pcie_ep_disable_bars(struct dw_pcie_ep *ep)
}
}
+static void dw_pcie_ep_init_ptm(struct dw_pcie_ep *ep)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ u32 ptm_cap_base, reg;
+
+ /*
+ * PCIe r6.0, section 7.9.15 states that for endpoints that support
+ * PTM, this capability structure is required in exactly one
+ * function, which controls the PTM behavior of all PTM capable
+ * functions. This indicates the PTM capability structure
+ * represents controller-level registers rather than per-function
+ * registers.
+ *
+ * Therefore, PTM capability registers are configured using the
+ * standard DBI accessors, instead of func_no indexed per-function
+ * accessors.
+ */
+ ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
+
+ /*
+ * 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);
+ }
+}
+
+/**
+ * dw_pcie_ep_reinit_registers - Reinitialize DWC EP reset-lost registers
+ * @ep: DWC EP device
+ *
+ * Reinitialize the EP registers lost after a fundamental reset without
+ * reallocating EP resources that live until dw_pcie_ep_deinit(). The
+ * caller must only use this after hardware has reset the iATU; this
+ * helper invalidates software iATU state but does not disable live
+ * windows.
+ */
+int dw_pcie_ep_reinit_registers(struct dw_pcie_ep *ep)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ int ret;
+
+ dw_pcie_ep_clear_outbound_atus(ep);
+
+ if (ep->ops->init) {
+ ret = ep->ops->init(ep);
+ if (ret)
+ return ret;
+ }
+
+ dw_pcie_ep_disable_bars(ep);
+ dw_pcie_ep_init_ptm(ep);
+ dw_pcie_ep_init_non_sticky_registers(pci);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_pcie_ep_reinit_registers);
+
+/**
+ * dw_pcie_ep_init_or_reinit_registers - Initialize or reinitialize DWC EP
+ * @ep: DWC EP device
+ *
+ * Initialize DWC EP resources on first use. If resources are already
+ * initialized, reinitialize only the reset-lost registers.
+ */
+int dw_pcie_ep_init_or_reinit_registers(struct dw_pcie_ep *ep)
+{
+ if (ep->resources_initialized)
+ return dw_pcie_ep_reinit_registers(ep);
+
+ return dw_pcie_ep_init_registers(ep);
+}
+EXPORT_SYMBOL_GPL(dw_pcie_ep_init_or_reinit_registers);
+
/**
* dw_pcie_ep_init_registers - Initialize DWC EP specific registers
* @ep: DWC EP device
@@ -1321,7 +1427,6 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
struct dw_pcie_ep_func *ep_func;
struct device *dev = pci->dev;
struct pci_epc *epc = ep->epc;
- u32 ptm_cap_base, reg;
u8 hdr_type;
u8 func_no;
void *addr;
@@ -1386,47 +1491,12 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
list_add_tail(&ep_func->list, &ep->func_list);
}
- if (ep->ops->init) {
- ret = ep->ops->init(ep);
- if (ret)
- goto err_remove_edma;
- }
-
- dw_pcie_ep_disable_bars(ep);
-
- /*
- * PCIe r6.0, section 7.9.15 states that for endpoints that support
- * PTM, this capability structure is required in exactly one
- * function, which controls the PTM behavior of all PTM capable
- * functions. This indicates the PTM capability structure
- * represents controller-level registers rather than per-function
- * registers.
- *
- * Therefore, PTM capability registers are configured using the
- * standard DBI accessors, instead of func_no indexed per-function
- * accessors.
- */
- ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM);
-
- /*
- * 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);
- }
-
- dw_pcie_ep_init_non_sticky_registers(pci);
+ ret = dw_pcie_ep_reinit_registers(ep);
+ if (ret)
+ goto err_remove_edma;
dwc_pcie_debugfs_init(pci, DW_PCIE_EP_TYPE);
+ ep->resources_initialized = true;
return 0;
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 4d55339750f0..ae442de396ff 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -511,6 +511,7 @@ struct dw_pcie_ep {
unsigned long *ob_window_map;
void __iomem *msi_mem;
phys_addr_t msi_mem_phys;
+ bool resources_initialized;
/* MSI outbound iATU state */
bool msi_iatu_mapped;
@@ -922,6 +923,8 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep);
void dw_pcie_ep_linkdown(struct dw_pcie_ep *ep);
int dw_pcie_ep_init(struct dw_pcie_ep *ep);
int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep);
+int dw_pcie_ep_reinit_registers(struct dw_pcie_ep *ep);
+int dw_pcie_ep_init_or_reinit_registers(struct dw_pcie_ep *ep);
void dw_pcie_ep_deinit(struct dw_pcie_ep *ep);
void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep);
int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no);
@@ -953,6 +956,16 @@ static inline int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
return 0;
}
+static inline int dw_pcie_ep_reinit_registers(struct dw_pcie_ep *ep)
+{
+ return 0;
+}
+
+static inline int dw_pcie_ep_init_or_reinit_registers(struct dw_pcie_ep *ep)
+{
+ return 0;
+}
+
static inline void dw_pcie_ep_deinit(struct dw_pcie_ep *ep)
{
}
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/3] PCI: tegra194: Avoid full Endpoint reinit on PERST#
2026-09-23 7:25 [PATCH 0/3] PCI: dwc: Avoid full EP cleanup on PERST# Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 1/3] PCI: dwc: Add Endpoint reinit helper Manikanta Maddireddy
@ 2026-09-23 7:25 ` Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 3/3] PCI: tegra194: Notify Endpoint functions on PERST# assert Manikanta Maddireddy
2 siblings, 0 replies; 4+ messages in thread
From: Manikanta Maddireddy @ 2026-09-23 7:25 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczynski, Bjorn Helgaas, linux-pci
Cc: Rob Herring, Thierry Reding, Jonathan Hunter, Vidya Sagar,
Niklas Cassel, linux-kernel, linux-tegra, Manikanta Maddireddy
Tegra194 and Tegra234 Endpoint mode receive PERST# as a fundamental
reset. Controller registers are lost across that reset, but DWC
Endpoint resources live for the controller lifetime.
Use the DWC init-or-reinit helper for Tegra PERST# deassertions so only
reset-lost registers are restored after the first initialization. Keep
the EPF deinit notification in the deassert path where refclk and core
reset are available.
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
drivers/pci/controller/dwc/pcie-tegra194.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 513299541f18..dd3f4c30ba52 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1914,7 +1914,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
/* Perform cleanup that requires refclk and core reset deasserted */
pci_epc_deinit_notify(pcie->pci.ep.epc);
- dw_pcie_ep_cleanup(&pcie->pci.ep);
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
val &= ~PORT_LOGIC_SPEED_CHANGE;
@@ -1958,7 +1957,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
val = (upper_32_bits(ep->msi_mem_phys) & MSIX_ADDR_MATCH_HIGH_OFF_MASK);
dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_HIGH_OFF, val);
- ret = dw_pcie_ep_init_registers(ep);
+ ret = dw_pcie_ep_init_or_reinit_registers(ep);
if (ret) {
dev_err(dev, "Failed to complete initialization: %d\n", ret);
goto fail_init_complete;
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 3/3] PCI: tegra194: Notify Endpoint functions on PERST# assert
2026-09-23 7:25 [PATCH 0/3] PCI: dwc: Avoid full EP cleanup on PERST# Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 1/3] PCI: dwc: Add Endpoint reinit helper Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 2/3] PCI: tegra194: Avoid full Endpoint reinit on PERST# Manikanta Maddireddy
@ 2026-09-23 7:25 ` Manikanta Maddireddy
2 siblings, 0 replies; 4+ messages in thread
From: Manikanta Maddireddy @ 2026-09-23 7:25 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczynski, Bjorn Helgaas, linux-pci
Cc: Rob Herring, Thierry Reding, Jonathan Hunter, Vidya Sagar,
Niklas Cassel, linux-kernel, linux-tegra, Manikanta Maddireddy
Tegra Endpoint mode powers the controller down when the host asserts
PERST#. EPF drivers must be told about link down before that happens,
otherwise remove while PERST# is asserted can free EPC resources while
EPF work is still active.
Use pci_epc_linkdown() directly in the PERST# assert path. It is a
software-only EPF notification and avoids dw_pcie_ep_linkdown(), which
reinitializes non-sticky DWC registers and touches DBI while the host
REFCLK may be disappearing.
Keep pci_epc_deinit_notify() in the PERST# deassert path, after core
reset is deasserted, because EPF deinit callbacks can clear BARs and
therefore need register access. If remove runs while the controller is
already powered down, pex_ep_event_pex_rst_assert() returns because
ep_state is disabled; that is safe because the link-down notification
was sent at the earlier PERST# assert.
The final dw_pcie_ep_deinit() does not require Tegra register access
today: Tegra uses its own MSI-X address-match window instead of the
DWC MSI iATU, and the supported DTs do not register a DWC eDMA device.
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
drivers/pci/controller/dwc/pcie-tegra194.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index dd3f4c30ba52..3e9d46850a78 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1724,6 +1724,7 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie)
{
+ struct dw_pcie_ep *ep = &pcie->pci.ep;
u32 val;
int ret;
@@ -1745,6 +1746,8 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie)
if (ret)
dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret);
+ pci_epc_linkdown(ep->epc);
+
/*
* Deassert LTSSM state to stop the state toggling between
* Polling and Detect.
@@ -1913,7 +1916,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
}
/* Perform cleanup that requires refclk and core reset deasserted */
- pci_epc_deinit_notify(pcie->pci.ep.epc);
+ pci_epc_deinit_notify(ep->epc);
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
val &= ~PORT_LOGIC_SPEED_CHANGE;
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-23 7:26 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 7:25 [PATCH 0/3] PCI: dwc: Avoid full EP cleanup on PERST# Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 1/3] PCI: dwc: Add Endpoint reinit helper Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 2/3] PCI: tegra194: Avoid full Endpoint reinit on PERST# Manikanta Maddireddy
2026-09-23 7:25 ` [PATCH 3/3] PCI: tegra194: Notify Endpoint functions on PERST# assert Manikanta Maddireddy
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®