[PATCH v2] PCI: keystone: fix endpoint teardown on remove
From: Guangshuo Li
Date: Mon Sep 21 2026 - 11:46:40 EST
ks_pcie_probe() initializes the DesignWare PCIe endpoint with
dw_pcie_ep_init() and notifies the endpoint framework after the
endpoint registers have been initialized. However, the remove path
does not perform the corresponding endpoint teardown.
This leaves the EPC initialization state and resources allocated by
the DesignWare endpoint core active after the driver is removed.
Make dw_pcie_ep_deinit() notify the endpoint framework when endpoint
initialization has completed, so controller drivers do not need to
duplicate the notification before endpoint teardown. Keep the
notification conditional since dw_pcie_ep_deinit() is also used on
error paths before pci_epc_init_notify() has been called.
Remove the now redundant explicit notification from the STM32 endpoint
driver.
Cache the controller mode in struct keystone_pcie and use it during
removal to deinitialize the endpoint before runtime PM and the PHYs are
disabled.
Fixes: 23284ad677a9 ("PCI: keystone: Add support for PCIe EP in AM654x Platforms")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
v2:
- Cache the PCIe mode in struct keystone_pcie instead of looking up the
match data again during removal.
- Move pci_epc_deinit_notify() into dw_pcie_ep_deinit() to avoid
duplicating the notification in controller drivers.
- Remove the now redundant explicit deinit notification from the STM32
endpoint driver.
drivers/pci/controller/dwc/pci-keystone.c | 6 ++++++
drivers/pci/controller/dwc/pcie-designware-ep.c | 3 +++
drivers/pci/controller/dwc/pcie-stm32-ep.c | 1 -
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 602516239a57..59f7b2e152a2 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -121,6 +121,7 @@ struct ks_pcie_of_data {
struct keystone_pcie {
struct dw_pcie *pci;
+ enum dw_pcie_device_mode mode;
/* PCI Device ID */
u32 device_id;
int intx_host_irqs[PCI_NUM_INTX];
@@ -1226,6 +1227,7 @@ static int ks_pcie_probe(struct platform_device *pdev)
ks_pcie->np = np;
ks_pcie->pci = pci;
+ ks_pcie->mode = mode;
ks_pcie->link = link;
ks_pcie->num_lanes = num_lanes;
ks_pcie->phy = phy;
@@ -1349,9 +1351,13 @@ static void ks_pcie_remove(struct platform_device *pdev)
{
struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
struct device_link **link = ks_pcie->link;
+ struct dw_pcie *pci = ks_pcie->pci;
int num_lanes = ks_pcie->num_lanes;
struct device *dev = &pdev->dev;
+ if (ks_pcie->mode == DW_PCIE_EP_TYPE)
+ dw_pcie_ep_deinit(&pci->ep);
+
pm_runtime_put(dev);
pm_runtime_disable(dev);
ks_pcie_disable_phy(ks_pcie);
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index de8ee3db4360..b785e098f759 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -1188,6 +1188,9 @@ void dw_pcie_ep_deinit(struct dw_pcie_ep *ep)
{
struct pci_epc *epc = ep->epc;
+ if (epc->init_complete)
+ pci_epc_deinit_notify(epc);
+
dw_pcie_ep_cleanup(ep);
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
diff --git a/drivers/pci/controller/dwc/pcie-stm32-ep.c b/drivers/pci/controller/dwc/pcie-stm32-ep.c
index a7988dff1045..1cb31bd76da5 100644
--- a/drivers/pci/controller/dwc/pcie-stm32-ep.c
+++ b/drivers/pci/controller/dwc/pcie-stm32-ep.c
@@ -304,7 +304,6 @@ static void stm32_pcie_remove(struct platform_device *pdev)
dw_pcie_stop_link(pci);
- pci_epc_deinit_notify(ep->epc);
dw_pcie_ep_deinit(ep);
stm32_pcie_disable_resources(stm32_pcie);
--
2.43.0