@@ -278,6 +278,8 @@ struct advk_pcie {
} wins[OB_WIN_COUNT];
u8 wins_count;
int irq;
+ struct irq_domain *emul_irq_domain;
+ struct irq_chip emul_irq_chip;
struct irq_domain *irq_domain;
struct irq_chip irq_chip;
raw_spinlock_t irq_lock;
@@ -1450,6 +1452,40 @@ static void advk_pcie_remove_irq_domain(struct advk_pcie *pcie)
irq_domain_remove(pcie->irq_domain);
}
+static int advk_pcie_emul_irq_map(struct irq_domain *h,
+ unsigned int virq, irq_hw_number_t hwirq)
+{
+ struct advk_pcie *pcie = h->host_data;
+
+ irq_set_chip_and_handler(virq, &pcie->emul_irq_chip, handle_simple_irq);
+ irq_set_chip_data(virq, pcie);
+
+ return 0;
+}
+
+static const struct irq_domain_ops advk_pcie_emul_irq_domain_ops = {
+ .map = advk_pcie_emul_irq_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static int advk_pcie_init_emul_irq_domain(struct advk_pcie *pcie)
+{
+ pcie->emul_irq_chip.name = "advk-EMU";
+ pcie->emul_irq_domain = irq_domain_add_linear(NULL, 1,
+ &advk_pcie_emul_irq_domain_ops, pcie);
+ if (!pcie->emul_irq_domain) {
+ dev_err(&pcie->pdev->dev, "Failed to add emul IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void advk_pcie_remove_emul_irq_domain(struct advk_pcie *pcie)
+{
+ irq_domain_remove(pcie->emul_irq_domain);
+}
+
static void advk_pcie_handle_pme(struct advk_pcie *pcie)
{
u32 requester = advk_readl(pcie, PCIE_MSG_LOG_REG) >> 16;
@@ -1469,7 +1505,7 @@ static void advk_pcie_handle_pme(struct advk_pcie *pcie)
* Aardvark HW returns zero for PCI_EXP_FLAGS_IRQ, so use PCIe interrupt 0.
*/
if (le16_to_cpu(pcie->bridge.pcie_conf.rootctl) & PCI_EXP_RTCTL_PMEIE) {
- if (generic_handle_domain_irq(pcie->irq_domain, 0) == -EINVAL)
+ if (generic_handle_domain_irq(pcie->emul_irq_domain, 0) == -EINVAL)
dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
}
}
@@ -1523,7 +1559,7 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
* Aardvark HW returns zero for PCI_ERR_ROOT_AER_IRQ, so use
* PCIe interrupt 0
*/
- if (generic_handle_domain_irq(pcie->irq_domain, 0) == -EINVAL)
+ if (generic_handle_domain_irq(pcie->emul_irq_domain, 0) == -EINVAL)
dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
}
@@ -1565,6 +1601,21 @@ static void advk_pcie_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+static int advk_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct advk_pcie *pcie = dev->bus->sysdata;
+
+ /*
+ * Emulated root bridge has its own emulated irq chip and irq domain.
+ * Argument pin is the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) and
+ * hwirq for irq_create_mapping() is indexed from zero.
+ */
+ if (pci_is_root_bus(dev->bus))
+ return irq_create_mapping(pcie->emul_irq_domain, pin - 1);
+ else
+ return of_irq_parse_and_map_pci(dev, slot, pin);
+}
+
static void advk_pcie_disable_phy(struct advk_pcie *pcie)
{
phy_power_off(pcie->phy);
@@ -1766,14 +1817,24 @@ static int advk_pcie_probe(struct platform_device *pdev)
return ret;
}
+ ret = advk_pcie_init_emul_irq_domain(pcie);
+ if (ret) {
+ dev_err(dev, "Failed to initialize irq\n");
+ advk_pcie_remove_msi_irq_domain(pcie);
+ advk_pcie_remove_irq_domain(pcie);
+ return ret;
+ }
+
irq_set_chained_handler_and_data(pcie->irq, advk_pcie_irq_handler, pcie);
bridge->sysdata = pcie;
bridge->ops = &advk_pcie_ops;
+ bridge->map_irq = advk_pcie_map_irq;
ret = pci_host_probe(bridge);
if (ret < 0) {
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+ advk_pcie_remove_emul_irq_domain(pcie);
advk_pcie_remove_msi_irq_domain(pcie);
advk_pcie_remove_irq_domain(pcie);
return ret;
@@ -1825,6 +1886,7 @@ static int advk_pcie_remove(struct platform_device *pdev)
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
/* Remove IRQ domains */
+ advk_pcie_remove_emul_irq_domain(pcie);
advk_pcie_remove_msi_irq_domain(pcie);
advk_pcie_remove_irq_domain(pcie);