Skip to content

Commit 815bc31

Browse files
paliLorenzo Pieralisi
authored andcommitted
PCI: aardvark: Use separate INTA interrupt for emulated root bridge
Emulated root bridge currently provides only one Legacy INTA interrupt which is used for reporting PCIe PME and ERR events and handled by kernel PCIe PME and AER drivers. Aardvark HW reports these PME and ERR events separately, so there is no need to mix real INTA interrupt and emulated INTA interrupt for PCIe PME and AER drivers. Register a new advk-RP (as in Root Port) irq chip and a new irq domain for emulated root bridge and use this new separate irq domain for providing INTA interrupt from emulated root bridge for PME and ERR events. The real INTA interrupt from real devices is now separate. A custom map_irq callback function on PCI host bridge structure is used to allocate IRQ mapping for emulated root bridge from new irq domain. Original callback of_irq_parse_and_map_pci() is used for all other devices as before. Link: https://lore.kernel.org/r/20220110015018.26359-19-kabel@kernel.org Signed-off-by: Pali Rohár <pali@kernel.org> Signed-off-by: Marek Behún <kabel@kernel.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
1 parent 273ddd8 commit 815bc31

1 file changed

Lines changed: 67 additions & 2 deletions

File tree

drivers/pci/controller/pci-aardvark.c

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ struct advk_pcie {
273273
} wins[OB_WIN_COUNT];
274274
u8 wins_count;
275275
int irq;
276+
struct irq_domain *rp_irq_domain;
276277
struct irq_domain *irq_domain;
277278
struct irq_chip irq_chip;
278279
raw_spinlock_t irq_lock;
@@ -1434,6 +1435,44 @@ static void advk_pcie_remove_irq_domain(struct advk_pcie *pcie)
14341435
irq_domain_remove(pcie->irq_domain);
14351436
}
14361437

1438+
static struct irq_chip advk_rp_irq_chip = {
1439+
.name = "advk-RP",
1440+
};
1441+
1442+
static int advk_pcie_rp_irq_map(struct irq_domain *h,
1443+
unsigned int virq, irq_hw_number_t hwirq)
1444+
{
1445+
struct advk_pcie *pcie = h->host_data;
1446+
1447+
irq_set_chip_and_handler(virq, &advk_rp_irq_chip, handle_simple_irq);
1448+
irq_set_chip_data(virq, pcie);
1449+
1450+
return 0;
1451+
}
1452+
1453+
static const struct irq_domain_ops advk_pcie_rp_irq_domain_ops = {
1454+
.map = advk_pcie_rp_irq_map,
1455+
.xlate = irq_domain_xlate_onecell,
1456+
};
1457+
1458+
static int advk_pcie_init_rp_irq_domain(struct advk_pcie *pcie)
1459+
{
1460+
pcie->rp_irq_domain = irq_domain_add_linear(NULL, 1,
1461+
&advk_pcie_rp_irq_domain_ops,
1462+
pcie);
1463+
if (!pcie->rp_irq_domain) {
1464+
dev_err(&pcie->pdev->dev, "Failed to add Root Port IRQ domain\n");
1465+
return -ENOMEM;
1466+
}
1467+
1468+
return 0;
1469+
}
1470+
1471+
static void advk_pcie_remove_rp_irq_domain(struct advk_pcie *pcie)
1472+
{
1473+
irq_domain_remove(pcie->rp_irq_domain);
1474+
}
1475+
14371476
static void advk_pcie_handle_pme(struct advk_pcie *pcie)
14381477
{
14391478
u32 requester = advk_readl(pcie, PCIE_MSG_LOG_REG) >> 16;
@@ -1455,7 +1494,7 @@ static void advk_pcie_handle_pme(struct advk_pcie *pcie)
14551494
if (!(le16_to_cpu(pcie->bridge.pcie_conf.rootctl) & PCI_EXP_RTCTL_PMEIE))
14561495
return;
14571496

1458-
if (generic_handle_domain_irq(pcie->irq_domain, 0) == -EINVAL)
1497+
if (generic_handle_domain_irq(pcie->rp_irq_domain, 0) == -EINVAL)
14591498
dev_err_ratelimited(&pcie->pdev->dev, "unhandled PME IRQ\n");
14601499
}
14611500
}
@@ -1507,7 +1546,7 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
15071546
* Aardvark HW returns zero for PCI_ERR_ROOT_AER_IRQ, so use
15081547
* PCIe interrupt 0
15091548
*/
1510-
if (generic_handle_domain_irq(pcie->irq_domain, 0) == -EINVAL)
1549+
if (generic_handle_domain_irq(pcie->rp_irq_domain, 0) == -EINVAL)
15111550
dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
15121551
}
15131552

@@ -1551,6 +1590,21 @@ static void advk_pcie_irq_handler(struct irq_desc *desc)
15511590
chained_irq_exit(chip, desc);
15521591
}
15531592

1593+
static int advk_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
1594+
{
1595+
struct advk_pcie *pcie = dev->bus->sysdata;
1596+
1597+
/*
1598+
* Emulated root bridge has its own emulated irq chip and irq domain.
1599+
* Argument pin is the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) and
1600+
* hwirq for irq_create_mapping() is indexed from zero.
1601+
*/
1602+
if (pci_is_root_bus(dev->bus))
1603+
return irq_create_mapping(pcie->rp_irq_domain, pin - 1);
1604+
else
1605+
return of_irq_parse_and_map_pci(dev, slot, pin);
1606+
}
1607+
15541608
static void __maybe_unused advk_pcie_disable_phy(struct advk_pcie *pcie)
15551609
{
15561610
phy_power_off(pcie->phy);
@@ -1752,14 +1806,24 @@ static int advk_pcie_probe(struct platform_device *pdev)
17521806
return ret;
17531807
}
17541808

1809+
ret = advk_pcie_init_rp_irq_domain(pcie);
1810+
if (ret) {
1811+
dev_err(dev, "Failed to initialize irq\n");
1812+
advk_pcie_remove_msi_irq_domain(pcie);
1813+
advk_pcie_remove_irq_domain(pcie);
1814+
return ret;
1815+
}
1816+
17551817
irq_set_chained_handler_and_data(pcie->irq, advk_pcie_irq_handler, pcie);
17561818

17571819
bridge->sysdata = pcie;
17581820
bridge->ops = &advk_pcie_ops;
1821+
bridge->map_irq = advk_pcie_map_irq;
17591822

17601823
ret = pci_host_probe(bridge);
17611824
if (ret < 0) {
17621825
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
1826+
advk_pcie_remove_rp_irq_domain(pcie);
17631827
advk_pcie_remove_msi_irq_domain(pcie);
17641828
advk_pcie_remove_irq_domain(pcie);
17651829
return ret;
@@ -1811,6 +1875,7 @@ static int advk_pcie_remove(struct platform_device *pdev)
18111875
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
18121876

18131877
/* Remove IRQ domains */
1878+
advk_pcie_remove_rp_irq_domain(pcie);
18141879
advk_pcie_remove_msi_irq_domain(pcie);
18151880
advk_pcie_remove_irq_domain(pcie);
18161881

0 commit comments

Comments
 (0)