Skip to contentSkip to conversation

powerpc: add cascade support to xilinx intc controller

PATCH In review Grant Likely 2 participants 2 messages Aug 25, 2009 – Aug 27, 2009

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 powerpc: add cascade support to xilinx intc controller

From: Grant Likely <[email protected]>

This patch allows the Xilinx intc interrupt controller to be cascaded instead of being the master irqhost. Useful when attaching an FPGA to an SoC that has its own interrupt controller.

---

 arch/powerpc/include/asm/xilinx_intc.h |    1 +
 arch/powerpc/sysdev/Kconfig            |    4 ++
 arch/powerpc/sysdev/Makefile           |    2 +
 arch/powerpc/sysdev/xilinx_intc.c      |   61 ++++++++++++++++++++++++++++++--
 4 files changed, 64 insertions(+), 4 deletions(-)
arch/powerpc/include/asm/xilinx_intc.h +1 -0
index 343612f..47ef6bd 100644
@@ -13,6 +13,7 @@
 
 #ifdef __KERNEL__
 
+extern int xilinx_intc_cascade_setup(struct device_node *cascade_node);
 extern void __init xilinx_intc_init_tree(void);
 extern unsigned int xilinx_intc_get_irq(void);
 
arch/powerpc/sysdev/Kconfig +4 -0
index 3965828..d78f2da 100644
@@ -12,3 +12,7 @@ config PPC_MSI_BITMAP
 	depends on PCI_MSI
 	default y if MPIC
 	default y if FSL_PCI
+
+config XILINX_INTC
+	bool
+	default y if XILINX_VIRTEX
arch/powerpc/sysdev/Makefile +1 -1
index 9d4b174..1cf11b6 100644
@@ -35,7 +35,7 @@ obj-$(CONFIG_PPC_I8259)		+= i8259.o
 obj-$(CONFIG_IPIC)		+= ipic.o
 obj-$(CONFIG_4xx)		+= uic.o
 obj-$(CONFIG_4xx_SOC)		+= ppc4xx_soc.o
-obj-$(CONFIG_XILINX_VIRTEX)	+= xilinx_intc.o
+obj-$(CONFIG_XILINX_INTC)	+= xilinx_intc.o
 obj-$(CONFIG_XILINX_PCI)	+= xilinx_pci.o
 obj-$(CONFIG_OF_RTC)		+= of_rtc.o
 ifeq ($(CONFIG_PCI),y)
arch/powerpc/sysdev/xilinx_intc.c +58 -3

79 lines not on this page · raw message

#1 lore raw
Quoted 5 lines · Grant Likely

From: Grant Likely <[email protected]>

This patch allows the Xilinx intc interrupt controller to be cascaded instead of being the master irqhost. Useful when attaching an FPGA to an SoC that has its own interrupt controller.

Something doesn't look quite right ...

Quoted 5 lines

/*
+ * Cascaded Xilinx interrupt controller
+ */

arch/powerpc/sysdev/xilinx_intc.c +2 -0
+static void xilinx_intc_cascade(unsigned int virq, struct irq_desc *desc)
+{

arch/powerpc/sysdev/xilinx_intc.c static void __init xilinx_i8259_setup_cascade(void) · line 291

Quoted 10 lines
arch/powerpc/sysdev/xilinx_intc.c +10 -0
+	struct irq_host *cascade_irqhost = get_irq_data(virq);
+	void *regs = cascade_irqhost->host_data;
+	unsigned int cascade_virq;
+
+	pr_debug("%s(virq=%i) irq_host=%p\n", __func__, virq, cascade_irqhost);
+	cascade_virq = irq_linear_revmap(cascade_irqhost,
+					 in_be32(regs + XINTC_IVR));
+	if (cascade_virq)
+		generic_handle_irq(cascade_virq);
+}

The cascade handler generally has to be part of the -host- controller or the platform code (we should try maybe to invent a way to make that more transparent but today it's not) because it may need to do special things to ack the interrupt on the host controller.

For example, if I have an MPIC based setup with a cascaded xilinx FPGA, I want to use something that does the EOI right on the MPIC. In fact, it's -almost- like what we need to do for a cascade, is to find a way to stick a get_irq() function pointer somewhere in the irq-desc for the cascaded interrupt, and have in the -host- a generic cascade handler.

Also, you seem to be trying to do the revmap of the child interrupt using the parent host.. .that doesn't make sense. Each PIC has it's own revmap and the child PIC uses it's own revmap as well.

The rest of the code seems to entertain a similar confusion...

Cheers,
Ben.

Quoted 44 lines
arch/powerpc/sysdev/xilinx_intc.c +41 -0
+/**
+ * xilinx_intc_cascade_setup - Add a xilinx intc device as a cascaded controller
+ * @cascade_node: device node for xilinx intc controller.
+ */
+int xilinx_intc_cascade_setup(struct device_node *cascade_node)
+{
+	struct irq_host *cascade_irqhost;
+	int cascade_virq;
+
+	if (!cascade_node) {
+		pr_err("%s(): cannot find xilinx intc node\n", __func__);
+		return -ENODEV;
+	}
+
+	/* Make sure this is a xilinx intc device */
+	if (!of_match_node(xilinx_intc_match, cascade_node)) {
+		pr_err("%s(): %s is not compatible\n",
+			__func__, cascade_node->name);
+		return -EINVAL;
+	}
+
+	/* Map a VIRQ for the cascaded handler */
+	cascade_virq = irq_of_parse_and_map(cascade_node, 0);
+	if (!cascade_virq) {
+		pr_err("%s(): error mapping cascade interrupt\n", __func__);
+		return -ENODEV;
+	}
+
+	/* Set up the irqhost and register it */
+	cascade_irqhost = xilinx_intc_init(cascade_node);
+	set_irq_data(cascade_virq, cascade_irqhost);
+	set_irq_chained_handler(cascade_virq, xilinx_intc_cascade);
+
+	pr_debug("%s(): cascading virq %i to irq_host %p\n",
+		 __func__, cascade_virq, cascade_irqhost);
+
+	return 0;
+}
+EXPORT_SYMBOL(xilinx_intc_cascade_setup);
+
+/*
  * Initialize master Xilinx interrupt controller
  */
 void __init xilinx_intc_init_tree(void)