summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/pcie-mediatek.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:55:52 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:55:52 +0200
commit93467b31bec6da512b51544e5e4584f2745e995e (patch)
tree2ea2be38c5e4dc9aafffbbc0db5aae0f6513a1d9 /drivers/pci/controller/pcie-mediatek.c
parent8ca1f4c6fb1462ee120730ea75c19da10d2f2d6f (diff)
parent7a5cef0db4795d9d453a12e0f61b5b7634fc4d40 (diff)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/pci/controller/pcie-mediatek.c')
-rw-r--r--drivers/pci/controller/pcie-mediatek.c63
1 files changed, 40 insertions, 23 deletions
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 75722524fe74..907ae4285ecb 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -529,23 +529,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
}
-static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+static void mtk_pcie_irq_teardown_port(struct mtk_pcie_port *port)
{
- struct mtk_pcie_port *port, *tmp;
+ irq_set_chained_handler_and_data(port->irq, NULL, NULL);
- list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
- irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+ if (port->irq_domain)
+ irq_domain_remove(port->irq_domain);
- if (port->irq_domain)
- irq_domain_remove(port->irq_domain);
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ if (port->inner_domain)
+ irq_domain_remove(port->inner_domain);
+ }
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- if (port->inner_domain)
- irq_domain_remove(port->inner_domain);
- }
+ irq_dispose_mapping(port->irq);
+}
- irq_dispose_mapping(port->irq);
- }
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+ struct mtk_pcie_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+ mtk_pcie_irq_teardown_port(port);
}
static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
@@ -865,7 +869,7 @@ static int mtk_pcie_startup_port_an7583(struct mtk_pcie_port *port)
return mtk_pcie_startup_port_v2(port);
}
-static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
+static int mtk_pcie_enable_port(struct mtk_pcie_port *port)
{
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
@@ -874,7 +878,7 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
err = clk_prepare_enable(port->sys_ck);
if (err) {
dev_err(dev, "failed to enable sys_ck%d clock\n", port->slot);
- goto err_sys_clk;
+ return err;
}
err = clk_prepare_enable(port->ahb_ck);
@@ -922,11 +926,15 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
goto err_phy_on;
}
- if (!pcie->soc->startup(port))
- return;
+ err = pcie->soc->startup(port);
+ if (err) {
+ dev_info(dev, "Port%d link down\n", port->slot);
+ goto err_soc_startup;
+ }
- dev_info(dev, "Port%d link down\n", port->slot);
+ return 0;
+err_soc_startup:
phy_power_off(port->phy);
err_phy_on:
phy_exit(port->phy);
@@ -942,8 +950,8 @@ err_aux_clk:
clk_disable_unprepare(port->ahb_ck);
err_ahb_clk:
clk_disable_unprepare(port->sys_ck);
-err_sys_clk:
- mtk_pcie_port_free(port);
+
+ return err;
}
static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
@@ -1109,8 +1117,13 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
return err;
/* enable each port, and then check link status */
- list_for_each_entry_safe(port, tmp, &pcie->ports, list)
- mtk_pcie_enable_port(port);
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ err = mtk_pcie_enable_port(port);
+ if (err) {
+ mtk_pcie_irq_teardown_port(port);
+ mtk_pcie_port_free(port);
+ }
+ }
/* power down PCIe subsys if slots are all empty (link down) */
if (list_empty(&pcie->ports))
@@ -1209,14 +1222,18 @@ static int mtk_pcie_resume_noirq(struct device *dev)
{
struct mtk_pcie *pcie = dev_get_drvdata(dev);
struct mtk_pcie_port *port, *tmp;
+ int err;
if (list_empty(&pcie->ports))
return 0;
clk_prepare_enable(pcie->free_ck);
- list_for_each_entry_safe(port, tmp, &pcie->ports, list)
- mtk_pcie_enable_port(port);
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ err = mtk_pcie_enable_port(port);
+ if (err)
+ mtk_pcie_port_free(port);
+ }
/* In case of EP was removed while system suspend. */
if (list_empty(&pcie->ports))