[linux-yocto] [PATCH 28/52] arch/arm/mach-axxia: Added support for doorbell interrupts
Daniel Dragomir
daniel.dragomir at windriver.com
Wed Jan 28 09:18:42 PST 2015
From: SangeethaRao <sangeetha.rao at lsi.com>
Added support for doorbell interrupts for both RootComplex
and EndPoint modes.
Signed-off-by: SangeethaRao <sangeetha.rao at 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
More information about the linux-yocto
mailing list