@@ -193,6 +193,7 @@ struct advk_msi_range {
struct advk_pcie {
struct platform_device *pdev;
void __iomem *base;
+ int irq;
struct irq_domain *irq_domain;
struct irq_chip irq_chip;
struct irq_domain *msi_domain;
@@ -1283,21 +1284,24 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
}
}
-static irqreturn_t advk_pcie_irq_handler(int irq, void *arg)
+static void advk_pcie_irq_handler(struct irq_desc *desc)
{
- struct advk_pcie *pcie = arg;
- u32 status;
+ struct advk_pcie *pcie = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 val, mask, status;
- status = advk_readl(pcie, HOST_CTRL_INT_STATUS_REG);
- if (!(status & PCIE_IRQ_CORE_INT))
- return IRQ_NONE;
+ chained_irq_enter(chip, desc);
- advk_pcie_handle_int(pcie);
+ val = advk_readl(pcie, HOST_CTRL_INT_STATUS_REG);
+ mask = advk_readl(pcie, HOST_CTRL_INT_MASK_REG);
+ status = val & ((~mask) & PCIE_IRQ_ALL_MASK);
- /* Clear interrupt */
- advk_writel(pcie, PCIE_IRQ_CORE_INT, HOST_CTRL_INT_STATUS_REG);
+ if (status & PCIE_IRQ_CORE_INT) {
+ advk_pcie_handle_int(pcie);
+ advk_writel(pcie, PCIE_IRQ_CORE_INT, HOST_CTRL_INT_STATUS_REG);
+ }
- return IRQ_HANDLED;
+ chained_irq_exit(chip, desc);
}
static void __maybe_unused advk_pcie_disable_phy(struct advk_pcie *pcie)
@@ -1363,7 +1367,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct advk_pcie *pcie;
struct pci_host_bridge *bridge;
- int ret, irq;
+ int ret;
bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct advk_pcie));
if (!bridge)
@@ -1377,17 +1381,9 @@ static int advk_pcie_probe(struct platform_device *pdev)
if (IS_ERR(pcie->base))
return PTR_ERR(pcie->base);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- ret = devm_request_irq(dev, irq, advk_pcie_irq_handler,
- IRQF_SHARED | IRQF_NO_THREAD, "advk-pcie",
- pcie);
- if (ret) {
- dev_err(dev, "Failed to register interrupt\n");
- return ret;
- }
+ pcie->irq = platform_get_irq(pdev, 0);
+ if (pcie->irq < 0)
+ return pcie->irq;
pcie->reset_gpio = devm_gpiod_get_from_of_node(dev, dev->of_node,
"reset-gpios", 0,
@@ -1436,6 +1432,8 @@ static int advk_pcie_probe(struct platform_device *pdev)
return ret;
}
+ irq_set_chained_handler_and_data(pcie->irq, advk_pcie_irq_handler, pcie);
+
bridge->sysdata = pcie;
bridge->ops = &advk_pcie_ops;
@@ -1443,6 +1441,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
if (ret < 0) {
advk_pcie_remove_msi_irq_domain(pcie);
advk_pcie_remove_irq_domain(pcie);
+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
return ret;
}
@@ -1491,6 +1490,8 @@ static int advk_pcie_remove(struct platform_device *pdev)
advk_pcie_remove_msi_irq_domain(pcie);
advk_pcie_remove_irq_domain(pcie);
+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+
/* Free config space for emulated root bridge */
pci_bridge_emul_cleanup(&pcie->bridge);