diff options
Diffstat (limited to 'drivers/pci/controller/pcie-mediatek.c')
| -rw-r--r-- | drivers/pci/controller/pcie-mediatek.c | 63 |
1 files changed, 40 insertions, 23 deletions
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index e0bf667c2b4c..d779baf1ae6d 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -519,23 +519,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, @@ -823,7 +827,7 @@ static int mtk_pcie_startup_port(struct mtk_pcie_port *port) return 0; } -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; @@ -832,7 +836,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); @@ -880,11 +884,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); @@ -900,8 +908,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, @@ -1067,8 +1075,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)) @@ -1167,14 +1180,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)) |
