summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/pcie-mediatek.c
diff options
context:
space:
mode:
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 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))