From: SangeethaRao <sangeetha....@lsi.com> Added support for doorbell interrupts for both RootComplex and EndPoint modes.
Signed-off-by: SangeethaRao <sangeetha....@lsi.com> --- arch/arm/mach-axxia/pci.c | 87 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-axxia/pci.c b/arch/arm/mach-axxia/pci.c index c33f1e5..aaa966b 100644 --- a/arch/arm/mach-axxia/pci.c +++ b/arch/arm/mach-axxia/pci.c @@ -77,6 +77,7 @@ #define PCIE_INT1_STATUS (0x11C4) #define PCIE_INT1_ENABLE (0x11C8) #define PCIE_INT1_FORCE (0x11CC) +#define INT1_DOORBELL 0x00000001U #define PCIE_RC_BAR0_SIZE (0x11F4) #define PCIE_MSI0_STATUS (0x1230) #define PCIE_MSI0_ENABLE (0x1234) @@ -398,6 +399,49 @@ static struct pci_ops axxia_pciex_pci_ops = { .write = arm_pciex_axxia_write_config, }; +/* RootComplex Doorbell Handler */ +void doorbell_rc_handler() +{ + pr_info("doorbell_rc_handler\n"); +} +EXPORT_SYMBOL(doorbell_rc_handler); + +/* EndPoint Doorbell Handler */ +void doorbell_ep_handler() +{ + pr_info("doorbell_ep_handler\n"); +} +EXPORT_SYMBOL(doorbell_ep_handler); + +/* + * pcie_doorbell_isr + * + * This ISR is for doorbell interrupts for + * Endpoint mode which has a dedicated IRQ line + */ +static irqreturn_t +pcie_doorbell_isr(int irq, void *arg) +{ + struct axxia_pciex_port *port = arg; + void __iomem *mbase = port->regs; + u32 intr1_status; + irqreturn_t retval = IRQ_HANDLED; + + /* read the PEI interrupt status register */ + intr1_status = readl(mbase + PCIE_INT1_STATUS); + + if (intr1_status & INT1_DOORBELL) { + pr_info("PCIE%d: Doorbell interrupt\n", + port->index); + doorbell_ep_handler(); + /* clear the doorbell status */ + writel(intr1_status, port->regs + PCIE_INT1_STATUS); + } + + return retval; +} + + /* * pcie_legacy_isr * @@ -413,11 +457,12 @@ pcie_legacy_isr(int irq, void *arg) { struct axxia_pciex_port *port = arg; void __iomem *mbase = port->regs; - u32 intr_status; + u32 intr_status, intr1_status; irqreturn_t retval = IRQ_HANDLED; /* read the PEI interrupt status register */ intr_status = readl(mbase + PCIE_INT0_STATUS); + intr1_status = readl(mbase + PCIE_INT1_STATUS); /* check if this is a PCIe message not from an external device */ if (intr_status & INT0_ERROR) { @@ -471,6 +516,14 @@ pcie_legacy_isr(int irq, void *arg) retval = IRQ_NONE; } + if (intr1_status & INT1_DOORBELL) { + pr_info("PCIE%d: Doorbell interrupt\n", + port->index); + doorbell_rc_handler(); + /* clear the doorbell status */ + writel(intr1_status, port->regs + PCIE_INT1_STATUS); + } + /* * We clear all the interrupts in the PEI status, even though * interrupts from external devices have not yet been handled. @@ -478,7 +531,6 @@ pcie_legacy_isr(int irq, void *arg) * re-enabled until all external handlers have been called. */ writel(intr_status, mbase + PCIE_INT0_STATUS); - return retval; } @@ -636,9 +688,34 @@ static int axxia_pcie_setup(int portno, struct pci_sys_data *sys) /* make sure the ACP device is configured as PCI Root Complex */ if ((pci_status & 0x18) != 0x18) { + /* Endpoint */ pr_err("PCIE%d: Device is not Root Complex\n", port->index); + if (sys->domain == 0) { + /* PEI0 */ + err = request_irq(port->irq[0]+3, pcie_doorbell_isr, + IRQF_SHARED, "pcie_db", port); + if (err) { + pr_err("PCIE%d: Failed to request IRQ#%d (%d)\n", + sys->domain, port->irq[0], err); + release_resource(&sys->io_res); + goto fail; + } + } else if (sys->domain == 1) { + /* PEI1 */ + err = request_irq(port->irq[0]+2, pcie_doorbell_isr, + IRQF_SHARED, "pcie_db", port); + if (err) { + pr_err("PCIE%d: Failed to request IRQ#%d (%d)\n", + sys->domain, port->irq[0], err); + release_resource(&sys->io_res); + goto fail; + } + } + /* Enable doorbell interrupts */ + writel(INT1_DOORBELL, + port->regs + PCIE_INT1_ENABLE); release_resource(&sys->io_res); - goto fail; + return; } /* Make sure the link is up */ @@ -714,6 +791,10 @@ static int axxia_pcie_setup(int portno, struct pci_sys_data *sys) writel(INT0_MSI | INT0_INT_ASSERTED | INT0_ERROR, port->regs + PCIE_INT0_ENABLE); + /* Enable doorbell interrupts */ + writel(INT1_DOORBELL, + port->regs + PCIE_INT1_ENABLE); + /* Enable all MSI interrupt groups */ writel(0xFFFF, port->regs + PCIE_MSI0_ENABLE); /* Enable all lines in all subgroups */ -- 1.8.1.4 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto