[linux-yocto] [PATCH 33/35] arch/arm/mach-axxia: Added support for doorbell interrupts

Daniel Dragomir daniel.dragomir at windriver.com
Thu Nov 13 09:20:00 PST 2014


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