summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/pcie-altera.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/controller/pcie-altera.c')
-rw-r--r--drivers/pci/controller/pcie-altera.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c
index 3dbb7adc421c..76f3823d9613 100644
--- a/drivers/pci/controller/pcie-altera.c
+++ b/drivers/pci/controller/pcie-altera.c
@@ -864,11 +864,25 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
return 0;
}
+static void altera_pcie_disable_irq(struct altera_pcie *pcie)
+{
+ if (pcie->pcie_data->version == ALTERA_PCIE_V1 ||
+ pcie->pcie_data->version == ALTERA_PCIE_V2) {
+ /* Disable all P2A interrupts */
+ cra_writel(pcie, 0, P2A_INT_ENABLE);
+ } else if (pcie->pcie_data->version == ALTERA_PCIE_V3) {
+ /* Disable port-level interrupts (CFG_AER, etc.) */
+ writel(0, pcie->hip_base +
+ pcie->pcie_data->port_conf_offset +
+ pcie->pcie_data->port_irq_enable_offset);
+ }
+}
+
static void altera_pcie_irq_teardown(struct altera_pcie *pcie)
{
+ altera_pcie_disable_irq(pcie);
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
irq_domain_remove(pcie->irq_domain);
- irq_dispose_mapping(pcie->irq);
}
static int altera_pcie_parse_dt(struct altera_pcie *pcie)
@@ -891,7 +905,6 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
if (pcie->irq < 0)
return pcie->irq;
- irq_set_chained_handler_and_data(pcie->irq, pcie->pcie_data->ops->rp_isr, pcie);
return 0;
}
@@ -1020,6 +1033,14 @@ static int altera_pcie_probe(struct platform_device *pdev)
return ret;
}
+ /*
+ * The chained handler uses pcie->irq_domain, so set it only after the
+ * INTx domain has been created.
+ */
+ irq_set_chained_handler_and_data(pcie->irq,
+ pcie->pcie_data->ops->rp_isr,
+ pcie);
+
if (pcie->pcie_data->version == ALTERA_PCIE_V1 ||
pcie->pcie_data->version == ALTERA_PCIE_V2) {
/* clear all interrupts */
@@ -1037,7 +1058,16 @@ static int altera_pcie_probe(struct platform_device *pdev)
bridge->busnr = pcie->root_bus_nr;
bridge->ops = &altera_pcie_ops;
- return pci_host_probe(bridge);
+ ret = pci_host_probe(bridge);
+ if (ret)
+ goto err_teardown_irq;
+
+ return 0;
+
+err_teardown_irq:
+ altera_pcie_irq_teardown(pcie);
+
+ return ret;
}
static void altera_pcie_remove(struct platform_device *pdev)