[POWERPC] Cell interrupt rework
This patch reworks the cell iic interrupt handling so that:
- Node ID is back in the interrupt number (only one IRQ host is created
for all nodes). This allows interrupts from sources on another node to
be routed non-locally. This will allow possibly one day to fix maxcpus=1
or 2 and still get interrupts from devices on BE 1. (A bit more fixing
is needed for that) and it will allow us to implement actual affinity
control of external interrupts.
- Added handling of the IO exceptions interrupts (badly named, but I
re-used the name initially used by STI). Those are the interrupts
exposed by IIC_ISR and IIC_IRR, such as the IOC translation exception,
performance monitor, etc... Those get their special numbers in the IRQ
number space and are internally implemented as a cascade on unit 0xe,
class 1 of each node.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 0f5c8eb..f786803 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -568,24 +568,23 @@
/* 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;
const u32 *tmp;
- host = iic_get_irq_host(spu->node);
- if (host == NULL)
- return -ENODEV;
-
- /* Get the interrupt source from the device-tree */
+ /* Get the interrupt source unit from the device-tree */
tmp = get_property(np, "isrc", NULL);
if (!tmp)
return -ENODEV;
- spu->isrc = isrc = tmp[0];
+ isrc = tmp[0];
+
+ /* Add the node number */
+ isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
+ spu->isrc = isrc;
/* Now map interrupts of all 3 classes */
- spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc);
- spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc);
- spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc);
+ spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
+ spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
+ spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
/* Right now, we only fail if class 2 failed */
return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;