Index: linux-irq-work/arch/powerpc/platforms/cell/interrupt.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/cell/interrupt.c	2006-07-03 09:50:28.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/cell/interrupt.c	2006-07-03 10:02:44.000000000 +1000
@@ -1,6 +1,9 @@
 /*
  * Cell Internal Interrupt Controller
  *
+ * Copyright (C) 2006 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *                    IBM, Corp.
+ *
  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
  *
  * Author: Arnd Bergmann <arndb@de.ibm.com>
@@ -25,11 +28,13 @@
 #include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/types.h>
+#include <linux/ioport.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/ptrace.h>
+#include <asm/machdep.h>
 
 #include "interrupt.h"
 #include "cbe_regs.h"
@@ -39,9 +44,25 @@
 	u8 target_id;
 	u8 eoi_stack[16];
 	int eoi_ptr;
+	struct irq_host *host;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
+#define IIC_NODE_COUNT	2
+static struct irq_host *iic_hosts[IIC_NODE_COUNT];
+
+/* Convert between "pending" bits and hw irq number */
+static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
+{
+	unsigned char unit = bits.source & 0xf;
+
+	if (bits.flags & CBE_IIC_IRQ_IPI)
+		return IIC_IRQ_IPI0 | (bits.prio >> 4);
+	else if (bits.class <= 3)
+		return (bits.class << 4) | unit;
+	else
+		return IIC_IRQ_INVALID;
+}
 
 static void iic_mask(unsigned int irq)
 {
@@ -65,197 +86,21 @@
 	.eoi = iic_eoi,
 };
 
-/* XXX All of this has to be reworked completely. We need to assign a real
- * interrupt numbers to the external interrupts and remove all the hard coded
- * interrupt maps (rely on the device-tree whenever possible).
- *
- * Basically, my scheme is to define the "pendings" bits to be the HW interrupt
- * number (ignoring the data and flags here). That means we can sort-of split
- * external sources based on priority, and we can use request_irq() on pretty
- * much anything.
- *
- * For spider or axon, they have their own interrupt space. spider will just have
- * local "hardward" interrupts 0...xx * node stride. The node stride is not
- * necessary (separate interrupt chips will have separate HW number space), but
- * will allow to be compatible with existing device-trees.
- *
- * All of thise little world will get a standard remapping scheme to map those HW
- * numbers into the linux flat irq number space.
-*/
-static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
-{
-	int irq;
-	unsigned char node, unit;
-
-	node = pending.source >> 4;
-	unit = pending.source & 0xf;
-	irq = -1;
-
-	/*
-	 * This mapping is specific to the Cell Broadband
-	 * Engine. We might need to get the numbers
-	 * from the device tree to support future CPUs.
-	 */
-	switch (unit) {
-	case 0x00:
-	case 0x0b:
-		/*
-		 * One of these units can be connected
-		 * to an external interrupt controller.
-		 */
-		if (pending.class != 2)
-			break;
-		/* TODO: We might want to silently ignore cascade interrupts
-		 * when no cascade handler exist yet
-		 */
-		irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
-		break;
-	case 0x01 ... 0x04:
-	case 0x07 ... 0x0a:
-		/*
-		 * These units are connected to the SPEs
-		 */
-		if (pending.class > 2)
-			break;
-		irq = IIC_SPE_OFFSET
-			+ pending.class * IIC_CLASS_STRIDE
-			+ node * IIC_NODE_STRIDE
-			+ unit;
-		break;
-	}
-	if (irq == -1)
-		printk(KERN_WARNING "Unexpected interrupt class %02x, "
-			"source %02x, prio %02x, cpu %02x\n", pending.class,
-			pending.source, pending.prio, smp_processor_id());
-	return irq;
-}
-
 /* Get an IRQ number from the pending state register of the IIC */
-int iic_get_irq(struct pt_regs *regs)
+static unsigned int iic_get_irq(struct pt_regs *regs)
 {
-	struct iic *iic;
-	int irq;
-	struct cbe_iic_pending_bits pending;
-
-	iic = &__get_cpu_var(iic);
-	*(unsigned long *) &pending = 
-		in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
-	iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
-	BUG_ON(iic->eoi_ptr > 15);
-
-	irq = -1;
-	if (pending.flags & CBE_IIC_IRQ_VALID) {
-		if (pending.flags & CBE_IIC_IRQ_IPI) {
-			irq = IIC_IPI_OFFSET + (pending.prio >> 4);
-/*
-			if (irq > 0x80)
-				printk(KERN_WARNING "Unexpected IPI prio %02x"
-					"on CPU %02x\n", pending.prio,
-							smp_processor_id());
-*/
-		} else {
-			irq = iic_external_get_irq(pending);
-		}
-	}
-	return irq;
-}
-
-/* hardcoded part to be compatible with older firmware */
-
-static int __init setup_iic_hardcoded(void)
-{
-	struct device_node *np;
-	int nodeid, cpu;
-	unsigned long regs;
-	struct iic *iic;
+  	struct cbe_iic_pending_bits pending;
+ 	struct iic *iic;
 
-	for_each_possible_cpu(cpu) {
-		iic = &per_cpu(iic, cpu);
-		nodeid = cpu/2;
-
-		for (np = of_find_node_by_type(NULL, "cpu");
-		     np;
-		     np = of_find_node_by_type(np, "cpu")) {
-			if (nodeid == *(int *)get_property(np, "node-id", NULL))
-				break;
-			}
-
-		if (!np) {
-			printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
-			iic->regs = NULL;
-			iic->target_id = 0xff;
-			return -ENODEV;
-			}
-
-		regs = *(long *)get_property(np, "iic", NULL);
-
-		/* hack until we have decided on the devtree info */
-		regs += 0x400;
-		if (cpu & 1)
-			regs += 0x20;
-
-		printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
-		iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
-		iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
-		iic->eoi_stack[0] = 0xff;
-	}
-
-	return 0;
-}
-
-static int __init setup_iic(void)
-{
-	struct device_node *dn;
-	unsigned long *regs;
-	char *compatible;
- 	unsigned *np, found = 0;
-	struct iic *iic = NULL;
-
-	for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
-		compatible = (char *)get_property(dn, "compatible", NULL);
-
-		if (!compatible) {
-			printk(KERN_WARNING "no compatible property found !\n");
-			continue;
-		}
-
- 		if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller"))
- 			regs = (unsigned long *)get_property(dn,"reg", NULL);
- 		else
-			continue;
-
- 		if (!regs)
- 			printk(KERN_WARNING "IIC: no reg property\n");
-
- 		np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL);
-
- 		if (!np) {
-			printk(KERN_WARNING "IIC: CPU association not found\n");
-			iic->regs = NULL;
-			iic->target_id = 0xff;
-			return -ENODEV;
-		}
-
- 		iic = &per_cpu(iic, np[0]);
- 		iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
-		iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
-		iic->eoi_stack[0] = 0xff;
- 		printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
-
- 		iic = &per_cpu(iic, np[1]);
- 		iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
-		iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
-		iic->eoi_stack[0] = 0xff;
-
- 		printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
-
-		found++;
-  	}
-
-	if (found)
-		return 0;
-	else
-		return -ENODEV;
+ 	iic = &__get_cpu_var(iic);
+ 	*(unsigned long *) &pending =
+ 		in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
+ 	iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
+ 	BUG_ON(iic->eoi_ptr > 15);
+	if (pending.flags & CBE_IIC_IRQ_VALID)
+		return irq_linear_revmap(iic->host,
+ 					 iic_pending_to_hwnum(pending));
+	return NO_IRQ;
 }
 
 #ifdef CONFIG_SMP
@@ -263,12 +108,12 @@
 /* Use the highest interrupt priorities for IPI */
 static inline int iic_ipi_to_irq(int ipi)
 {
-	return IIC_IPI_OFFSET + IIC_NUM_IPIS - 1 - ipi;
+	return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi;
 }
 
 static inline int iic_irq_to_ipi(int irq)
 {
-	return IIC_NUM_IPIS - 1 - (irq - IIC_IPI_OFFSET);
+	return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0);
 }
 
 void iic_setup_cpu(void)
@@ -287,22 +132,51 @@
 }
 EXPORT_SYMBOL_GPL(iic_get_target_id);
 
+struct irq_host *iic_get_irq_host(int node)
+{
+	if (node < 0 || node >= IIC_NODE_COUNT)
+		return NULL;
+	return iic_hosts[node];
+}
+EXPORT_SYMBOL_GPL(iic_get_irq_host);
+
+
 static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
-	smp_message_recv(iic_irq_to_ipi(irq), regs);
+	int ipi = (int)(long)dev_id;
+
+	smp_message_recv(ipi, regs);
+
 	return IRQ_HANDLED;
 }
 
 static void iic_request_ipi(int ipi, const char *name)
 {
-	int irq;
-
-	irq = iic_ipi_to_irq(ipi);
+	int node, virq;
 
-	/* IPIs are marked IRQF_DISABLED as they must run with irqs
-	 * disabled */
- 	set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
-	request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
+	for (node = 0; node < IIC_NODE_COUNT; node++) {
+		char *rname;
+		if (iic_hosts[node] == NULL)
+			continue;
+		virq = irq_create_mapping(iic_hosts[node],
+					  iic_ipi_to_irq(ipi), 0);
+		if (virq == NO_IRQ) {
+			printk(KERN_ERR
+			       "iic: failed to map IPI %s on node %d\n",
+			       name, node);
+			continue;
+		}
+		rname = kzalloc(strlen(name) + 16, GFP_KERNEL);
+		if (rname)
+			sprintf(rname, "%s node %d", name, node);
+		else
+			rname = (char *)name;
+		if (request_irq(virq, iic_ipi_action, IRQF_DISABLED,
+				rname, (void *)(long)ipi))
+			printk(KERN_ERR
+			       "iic: failed to request IPI %s on node %d\n",
+			       name, node);
+	}
 }
 
 void iic_request_IPIs(void)
@@ -313,41 +187,119 @@
 	iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug");
 #endif /* CONFIG_DEBUGGER */
 }
+
 #endif /* CONFIG_SMP */
 
-static void __init iic_setup_builtin_handlers(void)
+
+static int iic_host_match(struct irq_host *h, struct device_node *node)
 {
-	int be, isrc;
+	return h->host_data != NULL && node == h->host_data;
+}
+
+static int iic_host_map(struct irq_host *h, unsigned int virq,
+			irq_hw_number_t hw, unsigned int flags)
+{
+	if (hw < IIC_IRQ_IPI0)
+		set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
+	else
+		set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq);
+	return 0;
+}
+
+static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
+			   u32 *intspec, unsigned int intsize,
+			   irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+
+{
+	/* Currently, we don't translate anything. That needs to be fixed as
+	 * we get better defined device-trees. iic interrupts have to be
+	 * explicitely mapped by whoever needs them
+	 */
+	return -ENODEV;
+}
 
-	/* XXX FIXME: Assume two threads per BE are present */
-	for (be=0; be < num_present_cpus() / 2; be++) {
-		int irq;
-
-		/* setup SPE chip and handlers */
-		for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
-			irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
-			set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
+static struct irq_host_ops iic_host_ops = {
+	.match = iic_host_match,
+	.map = iic_host_map,
+	.xlate = iic_host_xlate,
+};
+
+static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
+				struct irq_host *host)
+{
+	/* XXX FIXME: should locate the linux CPU number from the HW cpu
+	 * number properly. We are lucky for now
+	 */
+	struct iic *iic = &per_cpu(iic, hw_cpu);
+
+	iic->regs = ioremap(addr, sizeof(struct cbe_iic_thread_regs));
+	BUG_ON(iic->regs == NULL);
+
+	iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe);
+	iic->eoi_stack[0] = 0xff;
+	iic->host = host;
+	out_be64(&iic->regs->prio, 0);
+
+	printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n",
+	       hw_cpu, addr, iic->regs, iic->target_id);
+}
+
+static int __init setup_iic(void)
+{
+	struct device_node *dn;
+	struct resource r0, r1;
+	struct irq_host *host;
+	int found = 0;
+ 	u32 *np;
+
+	for (dn = NULL;
+	     (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
+		if (!device_is_compatible(dn,
+				     "IBM,CBEA-Internal-Interrupt-Controller"))
+			continue;
+ 		np = (u32 *)get_property(dn, "ibm,interrupt-server-ranges",
+					 NULL);
+ 		if (np == NULL) {
+			printk(KERN_WARNING "IIC: CPU association not found\n");
+			of_node_put(dn);
+			return -ENODEV;
+		}
+		if (of_address_to_resource(dn, 0, &r0) ||
+		    of_address_to_resource(dn, 1, &r1)) {
+			printk(KERN_WARNING "IIC: Can't resolve addresses\n");
+			of_node_put(dn);
+			return -ENODEV;
+		}
+		host = NULL;
+		if (found < IIC_NODE_COUNT) {
+			host = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
+					      IIC_SOURCE_COUNT,
+					      &iic_host_ops,
+					      IIC_IRQ_INVALID);
+			iic_hosts[found] = host;
+			BUG_ON(iic_hosts[found] == NULL);
+			iic_hosts[found]->host_data = of_node_get(dn);
+			found++;
 		}
-		/* setup cascade chip */
-		irq = IIC_EXT_CASCADE + be * IIC_NODE_STRIDE;
-		set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
+		init_one_iic(np[0], r0.start, host);
+		init_one_iic(np[1], r1.start, host);
 	}
+
+	if (found)
+		return 0;
+	else
+		return -ENODEV;
 }
 
 void __init iic_init_IRQ(void)
 {
-	int cpu, irq_offset;
-	struct iic *iic;
-
+	/* Discover and initialize iics */
 	if (setup_iic() < 0)
-		setup_iic_hardcoded();
+		panic("IIC: Failed to initialize !\n");
 
-	irq_offset = 0;
-	for_each_possible_cpu(cpu) {
-		iic = &per_cpu(iic, cpu);
-		if (iic->regs)
-			out_be64(&iic->regs->prio, 0xff);
-	}
-	iic_setup_builtin_handlers();
+	/* Set master interrupt handling function */
+	ppc_md.get_irq = iic_get_irq;
 
+	/* Enable on current CPU */
+	iic_setup_cpu();
 }
Index: linux-irq-work/arch/powerpc/platforms/cell/interrupt.h
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/cell/interrupt.h	2006-07-03 09:49:35.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/cell/interrupt.h	2006-07-03 10:00:08.000000000 +1000
@@ -37,23 +37,22 @@
  */
 
 enum {
-	IIC_EXT_OFFSET   = 0x00, /* Start of south bridge IRQs */
-	IIC_EXT_CASCADE  = 0x20, /* There is no interrupt 32 on spider */
-	IIC_NUM_EXT      = 0x40, /* Number of south bridge IRQs */
-	IIC_SPE_OFFSET   = 0x40, /* Start of SPE interrupts */
-	IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class    */
-	IIC_IPI_OFFSET   = 0x70, /* Start of IPI IRQs */
-	IIC_NUM_IPIS     = 0x10, /* IRQs reserved for IPI */
-	IIC_NODE_STRIDE  = 0x80, /* Total IRQs per node   */
+	IIC_IRQ_INVALID		= 0xff,
+	IIC_IRQ_MAX		= 0x3f,
+	IIC_IRQ_EXT_IOIF0	= 0x20,
+	IIC_IRQ_EXT_IOIF1	= 0x2b,
+	IIC_IRQ_IPI0		= 0x40,
+	IIC_NUM_IPIS    	= 0x10, /* IRQs reserved for IPI */
+	IIC_SOURCE_COUNT	= 0x50,
 };
 
 extern void iic_init_IRQ(void);
-extern int  iic_get_irq(struct pt_regs *regs);
 extern void iic_cause_IPI(int cpu, int mesg);
 extern void iic_request_IPIs(void);
 extern void iic_setup_cpu(void);
 
 extern u8 iic_get_target_id(int cpu);
+extern struct irq_host *iic_get_irq_host(int node);
 
 extern void spider_init_IRQ(void);
 
Index: linux-irq-work/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/cell/setup.c	2006-07-03 09:50:34.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/cell/setup.c	2006-07-03 10:00:08.000000000 +1000
@@ -80,6 +80,14 @@
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
+static void __init cell_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+
+	for_each_pci_dev(dev)
+		pci_read_irq_line(dev);
+}
+
 static void __init cell_init_irq(void)
 {
 	iic_init_IRQ();
@@ -130,8 +138,6 @@
 
 	cell_init_iommu();
 
-	ppc64_interrupt_controller = IC_CELL_PIC;
-
 	DBG(" <- cell_init_early()\n");
 }
 
@@ -178,8 +184,7 @@
 	.check_legacy_ioport	= cell_check_legacy_ioport,
 	.progress		= cell_progress,
 	.init_IRQ       	= cell_init_irq,
-	.get_irq        	= iic_get_irq,
-
+	.pcibios_fixup		= cell_pcibios_fixup,
 #ifdef CONFIG_KEXEC
 	.machine_kexec		= default_machine_kexec,
 	.machine_kexec_prepare	= default_machine_kexec_prepare,
Index: linux-irq-work/arch/powerpc/platforms/cell/spider-pic.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/cell/spider-pic.c	2006-07-03 09:49:35.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/cell/spider-pic.c	2006-07-03 10:00:08.000000000 +1000
@@ -22,6 +22,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/ioport.h>
 
 #include <asm/pgtable.h>
 #include <asm/prom.h>
@@ -56,58 +57,67 @@
 	REISWAITEN	= 0x508, /* Reissue Wait Control*/
 };
 
-static void __iomem *spider_pics[4];
-
-static void __iomem *spider_get_pic(int irq)
-{
-	int node = irq / IIC_NODE_STRIDE;
-	irq %= IIC_NODE_STRIDE;
-
-	if (irq >= IIC_EXT_OFFSET &&
-	    irq < IIC_EXT_OFFSET + IIC_NUM_EXT &&
-	    spider_pics)
-		return spider_pics[node];
-	return NULL;
-}
+#define SPIDER_CHIP_COUNT	4
+#define SPIDER_SRC_COUNT	64
+#define SPIDER_IRQ_INVALID	63
+
+struct spider_pic {
+	struct irq_host		*host;
+	struct device_node	*of_node;
+	void __iomem		*regs;
+	unsigned int		node_id;
+};
+static struct spider_pic spider_pics[SPIDER_CHIP_COUNT];
 
-static int spider_get_nr(unsigned int irq)
+static struct spider_pic *spider_virq_to_pic(unsigned int virq)
 {
-	return (irq % IIC_NODE_STRIDE) - IIC_EXT_OFFSET;
+	return irq_map[virq].host->host_data;
 }
 
-static void __iomem *spider_get_irq_config(int irq)
+static void __iomem *spider_get_irq_config(struct spider_pic *pic,
+					   unsigned int src)
 {
-	void __iomem *pic;
-	pic = spider_get_pic(irq);
-	return pic + TIR_CFGA + 8 * spider_get_nr(irq);
+	return pic->regs + TIR_CFGA + 8 * src;
 }
 
-static void spider_unmask_irq(unsigned int irq)
+static void spider_unmask_irq(unsigned int virq)
 {
-	int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
-	void __iomem *cfg = spider_get_irq_config(irq);
-	irq = spider_get_nr(irq);
+	struct spider_pic *pic = spider_virq_to_pic(virq);
+	void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
 
-	/* FIXME: Most of that is configuration and has nothing to do with enabling/disable,
-	 * besides, it's also partially bogus.
+	/* We use no locking as we should be covered by the descriptor lock
+	 * for access to invidual source configuration registers
 	 */
-	out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
-	out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
+	out_be32(cfg, in_be32(cfg) | 0x30000000u);
 }
 
-static void spider_mask_irq(unsigned int irq)
+static void spider_mask_irq(unsigned int virq)
 {
-	void __iomem *cfg = spider_get_irq_config(irq);
-	irq = spider_get_nr(irq);
+	struct spider_pic *pic = spider_virq_to_pic(virq);
+	void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
 
+	/* We use no locking as we should be covered by the descriptor lock
+	 * for access to invidual source configuration registers
+	 */
 	out_be32(cfg, in_be32(cfg) & ~0x30000000u);
 }
 
-static void spider_ack_irq(unsigned int irq)
+static void spider_ack_irq(unsigned int virq)
 {
-	/* Should reset edge detection logic but we don't configure any edge interrupt
-	 * at the moment.
+	struct spider_pic *pic = spider_virq_to_pic(virq);
+	unsigned int src = irq_map[virq].hwirq;
+
+	/* Reset edge detection logic if necessary
 	 */
+	if (get_irq_desc(virq)->status & IRQ_LEVEL)
+		return;
+
+	/* Only interrupts 47 to 50 can be set to edge */
+	if (src < 47 || src > 50)
+		return;
+
+	/* Perform the clear of the edge logic */
+	out_be32(pic->regs + TIR_EDC, 0x100 | (src & 0xf));
 }
 
 static struct irq_chip spider_pic = {
@@ -117,102 +127,243 @@
 	.ack = spider_ack_irq,
 };
 
-static int spider_get_irq(int node)
+static int spider_host_match(struct irq_host *h, struct device_node *node)
+{
+	struct spider_pic *pic = h->host_data;
+	return node == pic->of_node;
+}
+
+static int spider_host_map(struct irq_host *h, unsigned int virq,
+			irq_hw_number_t hw, unsigned int flags)
 {
-	unsigned long cs;
-	void __iomem *regs = spider_pics[node];
+	unsigned int sense = flags & IRQ_TYPE_SENSE_MASK;
+	struct spider_pic *pic = h->host_data;
+	void __iomem *cfg = spider_get_irq_config(pic, hw);
+	int level = 0;
+	u32 ic;
+
+	/* Note that only level high is supported for most interrupts */
+	if (sense != IRQ_TYPE_NONE && sense != IRQ_TYPE_LEVEL_HIGH &&
+	    (hw < 47 || hw > 50))
+		return -EINVAL;
+
+	/* Decode sense type */
+	switch(sense) {
+	case IRQ_TYPE_EDGE_RISING:
+		ic = 0x3;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		ic = 0x2;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		ic = 0x0;
+		level = 1;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+	case IRQ_TYPE_NONE:
+		ic = 0x1;
+		level = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
 
-	cs = in_be32(regs + TIR_CS) >> 24;
+	/* Configure the source. One gross hack that was there before and
+	 * that I've kept around is the priority to the BE which I set to
+	 * be the same as the interrupt source number. I don't know wether
+	 * that's supposed to make any kind of sense however, we'll have to
+	 * decide that, but for now, I'm not changing the behaviour.
+	 */
+	out_be32(cfg, (ic << 24) | (0x7 << 16) | (pic->node_id << 4) | 0xe);
+	out_be32(cfg + 4, (0x2 << 16) | (hw & 0xff));
 
-	if (cs == 63)
-		return -1;
-	else
-		return cs;
+	if (level)
+		get_irq_desc(virq)->status |= IRQ_LEVEL;
+	set_irq_chip_and_handler(virq, &spider_pic, handle_level_irq);
+	return 0;
+}
+
+static int spider_host_xlate(struct irq_host *h, struct device_node *ct,
+			   u32 *intspec, unsigned int intsize,
+			   irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+
+{
+	/* Spider interrupts have 2 cells, first is the interrupt source,
+	 * second, well, I don't know for sure yet ... We mask the top bits
+	 * because old device-trees encode a node number in there
+	 */
+	*out_hwirq = intspec[0] & 0x3f;
+	*out_flags = IRQ_TYPE_LEVEL_HIGH;
+	return 0;
 }
 
+static struct irq_host_ops spider_host_ops = {
+	.match = spider_host_match,
+	.map = spider_host_map,
+	.xlate = spider_host_xlate,
+};
+
 static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
 			       struct pt_regs *regs)
 {
-	int node = (int)(long)desc->handler_data;
-	int cascade_irq;
+	struct spider_pic *pic = desc->handler_data;
+	unsigned int cs, virq;
 
-	cascade_irq = spider_get_irq(node);
-	generic_handle_irq(cascade_irq, regs);
+	cs = in_be32(pic->regs + TIR_CS) >> 24;
+	if (cs == SPIDER_IRQ_INVALID)
+		virq = NO_IRQ;
+	else
+		virq = irq_linear_revmap(pic->host, cs);
+	if (virq != NO_IRQ)
+		generic_handle_irq(virq, regs);
 	desc->chip->eoi(irq);
 }
 
-/* hardcoded part to be compatible with older firmware */
+/* For hooking up the cascace we have a problem. Our device-tree is
+ * crap and we don't know on which BE iic interrupt we are hooked on at
+ * least not the "standard" way. We can reconstitute it based on two
+ * informations though: which BE node we are connected to and wether
+ * we are connected to IOIF0 or IOIF1. Right now, we really only care
+ * about the IBM cell blade and we know that its firmware gives us an
+ * interrupt-map property which is pretty strange.
+ */
+static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
+{
+	unsigned int virq;
+	u32 *imap, *tmp;
+	int imaplen, intsize, unit;
+	struct device_node *iic;
+	struct irq_host *iic_host;
+
+#if 0 /* Enable that when we have a way to retreive the node as well */
+	/* First, we check wether we have a real "interrupts" in the device
+	 * tree in case the device-tree is ever fixed
+	 */
+	struct of_irq oirq;
+	if (of_irq_map_one(pic->of_node, 0, &oirq) == 0) {
+		virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+					     oirq.size);
+		goto bail;
+	}
+#endif
+
+	/* Now do the horrible hacks */
+	tmp = (u32 *)get_property(pic->of_node, "#interrupt-cells", NULL);
+	if (tmp == NULL)
+		return NO_IRQ;
+	intsize = *tmp;
+	imap = (u32 *)get_property(pic->of_node, "interrupt-map", &imaplen);
+	if (imap == NULL || imaplen < (intsize + 1))
+		return NO_IRQ;
+	iic = of_find_node_by_phandle(imap[intsize]);
+	if (iic == NULL)
+		return NO_IRQ;
+	imap += intsize + 1;
+	tmp = (u32 *)get_property(iic, "#interrupt-cells", NULL);
+	if (tmp == NULL)
+		return NO_IRQ;
+	intsize = *tmp;
+	/* Assume unit is last entry of interrupt specifier */
+	unit = imap[intsize - 1];
+	/* Ok, we have a unit, now let's try to get the node */
+	tmp = (u32 *)get_property(iic, "ibm,interrupt-server-ranges", NULL);
+	if (tmp == NULL) {
+		of_node_put(iic);
+		return NO_IRQ;
+	}
+	/* ugly as hell but works for now */
+	pic->node_id = (*tmp) >> 1;
+	of_node_put(iic);
+
+	/* Ok, now let's get cracking. You may ask me why I just didn't match
+	 * the iic host from the iic OF node, but that way I'm still compatible
+	 * with really really old old firmwares for which we don't have a node
+	 */
+	iic_host = iic_get_irq_host(pic->node_id);
+	if (iic_host == NULL)
+		return NO_IRQ;
+	/* Manufacture an IIC interrupt number of class 2 */
+	virq = irq_create_mapping(iic_host, 0x20 | unit, 0);
+	if (virq == NO_IRQ)
+		printk(KERN_ERR "spider_pic: failed to map cascade !");
+	return virq;
+}
+
 
-static void __init spider_init_one(int node, unsigned long addr)
+static void __init spider_init_one(struct device_node *of_node, int chip,
+				   unsigned long addr)
 {
-	int n, irq;
+	struct spider_pic *pic = &spider_pics[chip];
+	int i, virq;
 
-	spider_pics[node] = ioremap(addr, 0x800);
-	if (spider_pics[node] == NULL)
+	/* Map registers */
+	pic->regs = ioremap(addr, 0x1000);
+	if (pic->regs == NULL)
 		panic("spider_pic: can't map registers !");
 
-	printk(KERN_INFO "spider_pic: mapped for node %d, addr: 0x%lx mapped to %p\n",
-	       node, addr, spider_pics[node]);
-
-	for (n = 0; n < IIC_NUM_EXT; n++) {
-		if (n == IIC_EXT_CASCADE)
-			continue;
-		irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-		set_irq_chip_and_handler(irq, &spider_pic, handle_level_irq);
-		get_irq_desc(irq)->status |= IRQ_LEVEL;
+	/* Allocate a host */
+	pic->host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, SPIDER_SRC_COUNT,
+				   &spider_host_ops, SPIDER_IRQ_INVALID);
+	if (pic->host == NULL)
+		panic("spider_pic: can't allocate irq host !");
+	pic->host->host_data = pic;
+
+	/* Fill out other bits */
+	pic->of_node = of_node_get(of_node);
+
+	/* Go through all sources and disable them */
+	for (i = 0; i < SPIDER_SRC_COUNT; i++) {
+		void __iomem *cfg = pic->regs + TIR_CFGA + 8 * i;
+		out_be32(cfg, in_be32(cfg) & ~0x30000000u);
 	}
 
 	/* do not mask any interrupts because of level */
-	out_be32(spider_pics[node] + TIR_MSK, 0x0);
-
-	/* disable edge detection clear */
-	/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
+	out_be32(pic->regs + TIR_MSK, 0x0);
 
 	/* enable interrupt packets to be output */
-	out_be32(spider_pics[node] + TIR_PIEN,
-		 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
+	out_be32(pic->regs + TIR_PIEN, in_be32(pic->regs + TIR_PIEN) | 0x1);
+
+	/* Hook up the cascade interrupt to the iic and nodeid */
+	virq = spider_find_cascade_and_node(pic);
+	if (virq == NO_IRQ)
+		return;
+	set_irq_data(virq, pic);
+	set_irq_chained_handler(virq, spider_irq_cascade);
 
-	/* Hook up cascade */
-	irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
-	set_irq_data(irq, (void *)(long)node);
-	set_irq_chained_handler(irq, spider_irq_cascade);
+	printk(KERN_INFO "spider_pic: node %d, addr: 0x%lx %s\n",
+	       pic->node_id, addr, of_node->full_name);
 
 	/* Enable the interrupt detection enable bit. Do this last! */
-	out_be32(spider_pics[node] + TIR_DEN,
-		 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+	out_be32(pic->regs + TIR_DEN, in_be32(pic->regs + TIR_DEN) | 0x1);
 }
 
 void __init spider_init_IRQ(void)
 {
-	unsigned long *spider_reg;
+	struct resource r;
 	struct device_node *dn;
-	char *compatible;
-	int node = 0;
+	int chip = 0;
 
-	/* XXX node numbers are totally bogus. We _hope_ we get the device nodes in the right
-	 * order here but that's definitely not guaranteed, we need to get the node from the
-	 * device tree instead. There is currently no proper property for it (but our whole
-	 * device-tree is bogus anyway) so all we can do is pray or maybe test the address
-	 * and deduce the node-id
+	/* XXX node numbers are totally bogus. We _hope_ we get the device
+	 * nodes in the right order here but that's definitely not guaranteed,
+	 * we need to get the node from the device tree instead.
+	 * There is currently no proper property for it (but our whole
+	 * device-tree is bogus anyway) so all we can do is pray or maybe test
+	 * the address and deduce the node-id
 	 */
-	for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
-		compatible = (char *)get_property(dn, "compatible", NULL);
-
-		if (!compatible)
-			continue;
-
- 		if (strstr(compatible, "CBEA,platform-spider-pic"))
-			spider_reg = (unsigned long *)get_property(dn, "reg", NULL);
-		else if (strstr(compatible, "sti,platform-spider-pic") && (node < 2)) {
-			static long hard_coded_pics[] = { 0x24000008000, 0x34000008000 };
-			spider_reg = &hard_coded_pics[node];
+	for (dn = NULL;
+	     (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
+		if (device_is_compatible(dn, "CBEA,platform-spider-pic")) {
+			if (of_address_to_resource(dn, 0, &r)) {
+				printk(KERN_WARNING "spider-pic: Failed\n");
+				continue;
+			}
+		} else if (device_is_compatible(dn, "sti,platform-spider-pic")
+			   && (chip < 2)) {
+			static long hard_coded_pics[] =
+				{ 0x24000008000, 0x34000008000 };
+			r.start = hard_coded_pics[chip];
 		} else
 			continue;
-
-		if (spider_reg == NULL)
-			printk(KERN_ERR "spider_pic: No address for node %d\n", node);
-
-		spider_init_one(node, *spider_reg);
-		node++;
+		spider_init_one(dn, chip++, r.start);
 	}
 }
Index: linux-irq-work/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/kernel/pci_64.c	2006-07-03 09:50:39.000000000 +1000
+++ linux-irq-work/arch/powerpc/kernel/pci_64.c	2006-07-03 10:00:08.000000000 +1000
@@ -398,6 +398,7 @@
 	} else {
 		dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
 		dev->rom_base_reg = PCI_ROM_ADDRESS;
+		/* Maybe do a default OF mapping here */
 		dev->irq = NO_IRQ;
 	}
 
Index: linux-irq-work/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-irq-work.orig/arch/powerpc/platforms/cell/spu_base.c	2006-07-03 09:45:12.000000000 +1000
+++ linux-irq-work/arch/powerpc/platforms/cell/spu_base.c	2006-07-03 10:00:08.000000000 +1000
@@ -559,17 +559,38 @@
 	iounmap((u8 __iomem *)spu->local_store);
 }
 
+/* This function shall be abstracted for HV platforms */
+static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
+{
+	struct irq_host *host;
+	unsigned int isrc;
+	u32 *tmp;
+
+	host = iic_get_irq_host(spu->node);
+	if (host == NULL)
+		return -ENODEV;
+
+	/* Get the interrupt source from the device-tree */
+	tmp = (u32 *)get_property(np, "isrc", NULL);
+	if (!tmp)
+		return -ENODEV;
+	spu->isrc = isrc = tmp[0];
+
+	/* Now map interrupts of all 3 classes */
+	spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc, 0);
+	spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc, 0);
+	spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc, 0);
+
+	/* Right now, we only fail if class 2 failed */
+	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
+}
+
 static int __init spu_map_device(struct spu *spu, struct device_node *node)
 {
 	char *prop;
 	int ret;
 
 	ret = -ENODEV;
-	prop = get_property(node, "isrc", NULL);
-	if (!prop)
-		goto out;
-	spu->isrc = *(unsigned int *)prop;
-
 	spu->name = get_property(node, "name", NULL);
 	if (!spu->name)
 		goto out;
@@ -636,7 +657,8 @@
 		return ret;
 	}
 
-	sysdev_create_file(&spu->sysdev, &attr_isrc);
+	if (spu->isrc != 0)
+		sysdev_create_file(&spu->sysdev, &attr_isrc);
 	sysfs_add_device_to_node(&spu->sysdev, spu->nid);
 
 	return 0;
@@ -668,6 +690,9 @@
 	spu->nid = of_node_to_nid(spe);
 	if (spu->nid == -1)
 		spu->nid = 0;
+	ret = spu_map_interrupts(spu, spe);
+	if (ret)
+		goto out_unmap;
 	spin_lock_init(&spu->register_lock);
 	spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
 	spu_mfc_sr1_set(spu, 0x33);
Index: linux-irq-work/include/asm-powerpc/spu.h
===================================================================
--- linux-irq-work.orig/include/asm-powerpc/spu.h	2006-06-24 10:54:38.000000000 +1000
+++ linux-irq-work/include/asm-powerpc/spu.h	2006-07-03 10:00:08.000000000 +1000
@@ -117,6 +117,7 @@
 	struct list_head sched_list;
 	int number;
 	int nid;
+	unsigned int irqs[3];
 	u32 isrc;
 	u32 node;
 	u64 flags;
