summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-03 19:32:51 +1000
committerPaul Mackerras <paulus@samba.org>2006-07-03 19:55:12 +1000
commitb9e5b4e6a991a5a6d521f2e20a65835404b4169f (patch)
treea0ac972faae4bf9133f576d842667bb134190341 /arch
parent5a43a066b11ac2fe84cf67307f20b83bea390f83 (diff)
[POWERPC] Use the genirq framework
This adapts the generic powerpc interrupt handling code, and all of the platforms except for the embedded 6xx machines, to use the new genirq framework. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/irq.c30
-rw-r--r--arch/powerpc/kernel/misc_64.S10
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c111
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h4
-rw-r--r--arch/powerpc/platforms/cell/setup.c12
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c173
-rw-r--r--arch/powerpc/platforms/chrp/setup.c17
-rw-r--r--arch/powerpc/platforms/iseries/irq.c17
-rw-r--r--arch/powerpc/platforms/powermac/pic.c170
-rw-r--r--arch/powerpc/platforms/pseries/setup.c26
-rw-r--r--arch/powerpc/platforms/pseries/xics.c443
-rw-r--r--arch/powerpc/platforms/pseries/xics.h17
-rw-r--r--arch/powerpc/sysdev/i8259.c30
-rw-r--r--arch/powerpc/sysdev/mpic.c193
14 files changed, 663 insertions, 590 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 525baab45d2d..91248559099a 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -62,28 +62,27 @@
#endif
int __irq_offset_value;
-#ifdef CONFIG_PPC32
-EXPORT_SYMBOL(__irq_offset_value);
-#endif
-
static int ppc_spurious_interrupts;
#ifdef CONFIG_PPC32
-#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
+EXPORT_SYMBOL(__irq_offset_value);
+atomic_t ppc_n_lost_interrupts;
+#ifndef CONFIG_PPC_MERGE
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
-atomic_t ppc_n_lost_interrupts;
+#endif
#ifdef CONFIG_TAU_INT
extern int tau_initialized;
extern int tau_interrupts(int);
#endif
+#endif /* CONFIG_PPC32 */
#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
extern atomic_t ipi_recv;
extern atomic_t ipi_sent;
#endif
-#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
EXPORT_SYMBOL(irq_desc);
@@ -219,15 +218,19 @@ void do_IRQ(struct pt_regs *regs)
curtp = current_thread_info();
irqtp = hardirq_ctx[smp_processor_id()];
if (curtp != irqtp) {
+ struct irq_desc *desc = irq_desc + irq;
+ void *handler = desc->handle_irq;
+ if (handler == NULL)
+ handler = &__do_IRQ;
irqtp->task = curtp->task;
irqtp->flags = 0;
- call___do_IRQ(irq, regs, irqtp);
+ call_handle_irq(irq, desc, regs, irqtp, handler);
irqtp->task = NULL;
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);
} else
#endif
- __do_IRQ(irq, regs);
+ generic_handle_irq(irq, regs);
} else if (irq != -2)
/* That's not SMP safe ... but who cares ? */
ppc_spurious_interrupts++;
@@ -245,15 +248,6 @@ void do_IRQ(struct pt_regs *regs)
void __init init_IRQ(void)
{
-#ifdef CONFIG_PPC64
- static int once = 0;
-
- if (once)
- return;
-
- once++;
-
-#endif
ppc_md.init_IRQ();
#ifdef CONFIG_PPC64
irq_ctx_init();
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 0c3c70d115c6..bfb407fc1aa1 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -51,12 +51,14 @@ _GLOBAL(call_do_softirq)
mtlr r0
blr
-_GLOBAL(call___do_IRQ)
+_GLOBAL(call_handle_irq)
+ ld r8,0(r7)
mflr r0
std r0,16(r1)
- stdu r1,THREAD_SIZE-112(r5)
- mr r1,r5
- bl .__do_IRQ
+ mtctr r8
+ stdu r1,THREAD_SIZE-112(r6)
+ mr r1,r6
+ bctrl
ld r1,0(r1)
ld r0,16(r1)
mtlr r0
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 22da1335445a..97936f547f19 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -37,64 +37,51 @@
struct iic {
struct cbe_iic_thread_regs __iomem *regs;
u8 target_id;
+ u8 eoi_stack[16];
+ int eoi_ptr;
};
static DEFINE_PER_CPU(struct iic, iic);
-void iic_local_enable(void)
+static void iic_mask(unsigned int irq)
{
- struct iic *iic = &__get_cpu_var(iic);
- u64 tmp;
-
- /*
- * There seems to be a bug that is present in DD2.x CPUs
- * and still only partially fixed in DD3.1.
- * This bug causes a value written to the priority register
- * not to make it there, resulting in a system hang unless we
- * write it again.
- * Masking with 0xf0 is done because the Cell BE does not
- * implement the lower four bits of the interrupt priority,
- * they always read back as zeroes, although future CPUs
- * might implement different bits.
- */
- do {
- out_be64(&iic->regs->prio, 0xff);
- tmp = in_be64(&iic->regs->prio);
- } while ((tmp & 0xf0) != 0xf0);
-}
-
-void iic_local_disable(void)
-{
- out_be64(&__get_cpu_var(iic).regs->prio, 0x0);
-}
-
-static unsigned int iic_startup(unsigned int irq)
-{
- return 0;
-}
-
-static void iic_enable(unsigned int irq)
-{
- iic_local_enable();
}
-static void iic_disable(unsigned int irq)
+static void iic_unmask(unsigned int irq)
{
}
-static void iic_end(unsigned int irq)
+static void iic_eoi(unsigned int irq)
{
- iic_local_enable();
+ struct iic *iic = &__get_cpu_var(iic);
+ out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
+ BUG_ON(iic->eoi_ptr < 0);
}
-static struct hw_interrupt_type iic_pic = {
+static struct irq_chip iic_chip = {
.typename = " CELL-IIC ",
- .startup = iic_startup,
- .enable = iic_enable,
- .disable = iic_disable,
- .end = iic_end,
+ .mask = iic_mask,
+ .unmask = iic_unmask,
+ .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;
@@ -118,9 +105,10 @@ static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
*/
if (pending.class != 2)
break;
- irq = IIC_EXT_OFFSET
- + spider_get_irq(node)
- + node * IIC_NODE_STRIDE;
+ /* 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:
@@ -152,6 +140,8 @@ int iic_get_irq(struct pt_regs *regs)
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) {
@@ -172,7 +162,7 @@ int iic_get_irq(struct pt_regs *regs)
/* hardcoded part to be compatible with older firmware */
-static int setup_iic_hardcoded(void)
+static int __init setup_iic_hardcoded(void)
{
struct device_node *np;
int nodeid, cpu;
@@ -207,12 +197,13 @@ static int setup_iic_hardcoded(void)
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 setup_iic(void)
+static int __init setup_iic(void)
{
struct device_node *dn;
unsigned long *regs;
@@ -248,11 +239,14 @@ static int setup_iic(void)
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++;
@@ -304,10 +298,10 @@ static void iic_request_ipi(int ipi, const char *name)
int irq;
irq = iic_ipi_to_irq(ipi);
+
/* IPIs are marked IRQF_DISABLED as they must run with irqs
* disabled */
- get_irq_desc(irq)->chip = &iic_pic;
- get_irq_desc(irq)->status |= IRQ_PER_CPU;
+ set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
}
@@ -321,20 +315,26 @@ void iic_request_IPIs(void)
}
#endif /* CONFIG_SMP */
-static void iic_setup_spe_handlers(void)
+static void __init iic_setup_builtin_handlers(void)
{
int be, isrc;
- /* Assume two threads per BE are present */
+ /* 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++) {
- int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
- get_irq_desc(irq)->chip = &iic_pic;
+ irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
+ set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
}
+ /* setup cascade chip */
+ irq = IIC_EXT_CASCADE + be * IIC_NODE_STRIDE;
+ set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
}
}
-void iic_init_IRQ(void)
+void __init iic_init_IRQ(void)
{
int cpu, irq_offset;
struct iic *iic;
@@ -348,5 +348,6 @@ void iic_init_IRQ(void)
if (iic->regs)
out_be64(&iic->regs->prio, 0xff);
}
- iic_setup_spe_handlers();
+ iic_setup_builtin_handlers();
+
}
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index 799f77d98f96..c74515aeb630 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -38,6 +38,7 @@
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 */
@@ -51,13 +52,10 @@ 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 void iic_local_enable(void);
-extern void iic_local_disable(void);
extern u8 iic_get_target_id(int cpu);
extern void spider_init_IRQ(void);
-extern int spider_get_irq(int node);
#endif
#endif /* ASM_CELL_PIC_H */
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 01ec39431fb0..70a4e903f7e2 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -80,10 +80,14 @@ static void cell_progress(char *s, unsigned short hex)
printk("*** %04x : %s\n", hex, s ? s : "");
}
+static void __init cell_init_irq(void)
+{
+ iic_init_IRQ();
+ spider_init_IRQ();
+}
+
static void __init cell_setup_arch(void)
{
- ppc_md.init_IRQ = iic_init_IRQ;
- ppc_md.get_irq = iic_get_irq;
#ifdef CONFIG_SPU_BASE
spu_priv1_ops = &spu_priv1_mmio_ops;
#endif
@@ -109,7 +113,6 @@ static void __init cell_setup_arch(void)
/* Find and initialize PCI host bridges */
init_pci_config_tokens();
find_and_init_phbs();
- spider_init_IRQ();
cbe_pervasive_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -174,6 +177,9 @@ define_machine(cell) {
.calibrate_decr = generic_calibrate_decr,
.check_legacy_ioport = cell_check_legacy_ioport,
.progress = cell_progress,
+ .init_IRQ = cell_init_irq,
+ .get_irq = iic_get_irq,
+
#ifdef CONFIG_KEXEC
.machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 7c3a0b6d34fd..98425acb6cda 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -82,17 +82,20 @@ static void __iomem *spider_get_irq_config(int irq)
return pic + TIR_CFGA + 8 * spider_get_nr(irq);
}
-static void spider_enable_irq(unsigned int irq)
+static void spider_unmask_irq(unsigned int irq)
{
int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
void __iomem *cfg = spider_get_irq_config(irq);
irq = spider_get_nr(irq);
+ /* FIXME: Most of that is configuration and has nothing to do with enabling/disable,
+ * besides, it's also partially bogus.
+ */
out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
}
-static void spider_disable_irq(unsigned int irq)
+static void spider_mask_irq(unsigned int irq)
{
void __iomem *cfg = spider_get_irq_config(irq);
irq = spider_get_nr(irq);
@@ -100,39 +103,21 @@ static void spider_disable_irq(unsigned int irq)
out_be32(cfg, in_be32(cfg) & ~0x30000000u);
}
-static unsigned int spider_startup_irq(unsigned int irq)
-{
- spider_enable_irq(irq);
- return 0;
-}
-
-static void spider_shutdown_irq(unsigned int irq)
-{
- spider_disable_irq(irq);
-}
-
-static void spider_end_irq(unsigned int irq)
-{
- spider_enable_irq(irq);
-}
-
static void spider_ack_irq(unsigned int irq)
{
- spider_disable_irq(irq);
- iic_local_enable();
+ /* Should reset edge detection logic but we don't configure any edge interrupt
+ * at the moment.
+ */
}
-static struct hw_interrupt_type spider_pic = {
+static struct irq_chip spider_pic = {
.typename = " SPIDER ",
- .startup = spider_startup_irq,
- .shutdown = spider_shutdown_irq,
- .enable = spider_enable_irq,
- .disable = spider_disable_irq,
+ .unmask = spider_unmask_irq,
+ .mask = spider_mask_irq,
.ack = spider_ack_irq,
- .end = spider_end_irq,
};
-int spider_get_irq(int node)
+static int spider_get_irq(int node)
{
unsigned long cs;
void __iomem *regs = spider_pics[node];
@@ -145,95 +130,89 @@ int spider_get_irq(int node)
return cs;
}
+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;
+
+ cascade_irq = spider_get_irq(node);
+ generic_handle_irq(cascade_irq, regs);
+ desc->chip->eoi(irq);
+}
+
/* hardcoded part to be compatible with older firmware */
-void spider_init_IRQ_hardcoded(void)
+static void __init spider_init_one(int node, unsigned long addr)
{
- int node;
- long spiderpic;
- long pics[] = { 0x24000008000, 0x34000008000 };
- int n;
-
- pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
-
- for (node = 0; node < num_present_cpus()/2; node++) {
- spiderpic = pics[node];
- printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
- spider_pics[node] = ioremap(spiderpic, 0x800);
- for (n = 0; n < IIC_NUM_EXT; n++) {
- int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
- get_irq_desc(irq)->chip = &spider_pic;
- }
-
- /* 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); */
-
- /* enable interrupt packets to be output */
- out_be32(spider_pics[node] + TIR_PIEN,
- in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
-
- /* Enable the interrupt detection enable bit. Do this last! */
- out_be32(spider_pics[node] + TIR_DEN,
- in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+ int n, irq;
+
+ spider_pics[node] = ioremap(addr, 0x800);
+ if (spider_pics[node] == 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;
}
+
+ /* 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); */
+
+ /* enable interrupt packets to be output */
+ out_be32(spider_pics[node] + TIR_PIEN,
+ in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
+
+ /* 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);
+
+ /* Enable the interrupt detection enable bit. Do this last! */
+ out_be32(spider_pics[node] + TIR_DEN,
+ in_be32(spider_pics[node] + TIR_DEN) | 0x1);
}
-void spider_init_IRQ(void)
+void __init spider_init_IRQ(void)
{
- long spider_reg;
+ unsigned long *spider_reg;
struct device_node *dn;
char *compatible;
- int n, node = 0;
-
+ int node = 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
+ */
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 = *(long *)get_property(dn,"reg", NULL);
- else if (strstr(compatible, "sti,platform-spider-pic")) {
- spider_init_IRQ_hardcoded();
- return;
+ 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];
} else
continue;
- if (!spider_reg)
- printk("interrupt controller does not have reg property !\n");
-
- n = prom_n_addr_cells(dn);
-
- if ( n != 2)
- printk("reg property with invalid number of elements \n");
-
- spider_pics[node] = ioremap(spider_reg, 0x800);
-
- printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
- spider_reg, n, spider_pics[node]);
-
- for (n = 0; n < IIC_NUM_EXT; n++) {
- int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
- get_irq_desc(irq)->chip = &spider_pic;
- }
-
- /* 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); */
-
- /* enable interrupt packets to be output */
- out_be32(spider_pics[node] + TIR_PIEN,
- in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
-
- /* Enable the interrupt detection enable bit. Do this last! */
- out_be32(spider_pics[node] + TIR_DEN,
- in_be32(spider_pics[node] + TIR_DEN) | 0x1);
+ if (spider_reg == NULL)
+ printk(KERN_ERR "spider_pic: No address for node %d\n", node);
+ spider_init_one(node, *spider_reg);
node++;
}
}
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 1f1771b212b4..a5dffc8d93a9 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -315,6 +315,21 @@ chrp_event_scan(unsigned long unused)
jiffies + event_scan_interval);
}
+void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc,
+ struct pt_regs *regs)
+{
+ unsigned int max = 100;
+
+ while(max--) {
+ int irq = i8259_irq(regs);
+ if (max == 99)
+ desc->chip->eoi(irq);
+ if (irq < 0)
+ break;
+ generic_handle_irq(irq, regs);
+ };
+}
+
/*
* Finds the open-pic node and sets up the mpic driver.
*/
@@ -402,7 +417,7 @@ static void __init chrp_find_openpic(void)
}
mpic_init(chrp_mpic);
- mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL);
+ set_irq_chained_handler(NUM_ISA_INTERRUPTS, chrp_8259_cascade);
}
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index f70e820e7304..7fb6a08786c0 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -297,13 +297,13 @@ static void iseries_end_IRQ(unsigned int irq)
(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
}
-static hw_irq_controller iSeries_IRQ_handler = {
- .typename = "iSeries irq controller",
- .startup = iseries_startup_IRQ,
- .shutdown = iseries_shutdown_IRQ,
- .enable = iseries_enable_IRQ,
- .disable = iseries_disable_IRQ,
- .end = iseries_end_IRQ
+static struct irq_chip iseries_pic = {
+ .typename = "iSeries irq controller",
+ .startup = iseries_startup_IRQ,
+ .shutdown = iseries_shutdown_IRQ,
+ .unmask = iseries_enable_IRQ,
+ .mask = iseries_disable_IRQ,
+ .eoi = iseries_end_IRQ
};
/*
@@ -322,8 +322,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
+ function;
virtirq = virt_irq_create_mapping(realirq);
-
- irq_desc[virtirq].chip = &iSeries_IRQ_handler;
+ set_irq_chip_and_handler(virtirq, &iseries_pic, handle_fasteoi_irq);
return virtirq;
}
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index c9b09a9e6050..58a4c7b90b8b 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -70,18 +70,19 @@ static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
+static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
+static int pmac_irq_cascade = -1;
-/*
- * Mark an irq as "lost". This is only used on the pmac
- * since it can lose interrupts (see pmac_set_irq_mask).
- * -- Cort
- */
-void __set_lost(unsigned long irq_nr, int nokick)
+static void __pmac_retrigger(unsigned int irq_nr)
{
- if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
+ if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) {
+ __set_bit(irq_nr, ppc_lost_interrupts);
+ irq_nr = pmac_irq_cascade;
+ mb();
+ }
+ if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
atomic_inc(&ppc_n_lost_interrupts);
- if (!nokick)
- set_dec(1);
+ set_dec(1);
}
}
@@ -94,10 +95,10 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
if ((unsigned)irq_nr >= max_irqs)
return;
- clear_bit(irq_nr, ppc_cached_irq_mask);
- if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
- atomic_dec(&ppc_n_lost_interrupts);
spin_lock_irqsave(&pmac_pic_lock, flags);
+ __clear_bit(irq_nr, ppc_cached_irq_mask);
+ if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+ atomic_dec(&ppc_n_lost_interrupts);
out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
out_le32(&pmac_irq_hw[i]->ack, bit);
do {
@@ -109,7 +110,7 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
-static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+static void pmac_ack_irq(unsigned int irq_nr)
{
unsigned long bit = 1UL << (irq_nr & 0x1f);
int i = irq_nr >> 5;
@@ -118,7 +119,22 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
if ((unsigned)irq_nr >= max_irqs)
return;
- spin_lock_irqsave(&pmac_pic_lock, flags);
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+ atomic_dec(&ppc_n_lost_interrupts);
+ out_le32(&pmac_irq_hw[i]->ack, bit);
+ (void)in_le32(&pmac_irq_hw[i]->ack);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+
+ if ((unsigned)irq_nr >= max_irqs)
+ return;
+
/* enable unmasked interrupts */
out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
@@ -135,8 +151,7 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
* the bit in the flag register or request another interrupt.
*/
if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
- __set_lost((ulong)irq_nr, nokicklost);
- spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ __pmac_retrigger(irq_nr);
}
/* When an irq gets requested for the first client, if it's an
@@ -144,62 +159,67 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
*/
static unsigned int pmac_startup_irq(unsigned int irq_nr)
{
+ unsigned long flags;
unsigned long bit = 1UL << (irq_nr & 0x1f);
int i = irq_nr >> 5;
+ spin_lock_irqsave(&pmac_pic_lock, flags);
if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
out_le32(&pmac_irq_hw[i]->ack, bit);
- set_bit(irq_nr, ppc_cached_irq_mask);
- pmac_set_irq_mask(irq_nr, 0);
+ __set_bit(irq_nr, ppc_cached_irq_mask);
+ __pmac_set_irq_mask(irq_nr, 0);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
return 0;
}
static void pmac_mask_irq(unsigned int irq_nr)
{
- clear_bit(irq_nr, ppc_cached_irq_mask);
- pmac_set_irq_mask(irq_nr, 0);
- mb();
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ __clear_bit(irq_nr, ppc_cached_irq_mask);
+ __pmac_set_irq_mask(irq_nr, 0);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
static void pmac_unmask_irq(unsigned int irq_nr)
{
- set_bit(irq_nr, ppc_cached_irq_mask);
- pmac_set_irq_mask(irq_nr, 0);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ __set_bit(irq_nr, ppc_cached_irq_mask);
+ __pmac_set_irq_mask(irq_nr, 0);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
-static void pmac_end_irq(unsigned int irq_nr)
+static int pmac_retrigger(unsigned int irq_nr)
{
- if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
- && irq_desc[irq_nr].action) {
- set_bit(irq_nr, ppc_cached_irq_mask);
- pmac_set_irq_mask(irq_nr, 1);
- }
-}
+ unsigned long flags;
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ __pmac_retrigger(irq_nr);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ return 1;
+}
-struct hw_interrupt_type pmac_pic = {
+static struct irq_chip pmac_pic = {
.typename = " PMAC-PIC ",
.startup = pmac_startup_irq,
- .enable = pmac_unmask_irq,
- .disable = pmac_mask_irq,
- .ack = pmac_mask_and_ack_irq,
- .end = pmac_end_irq,
-};
-
-struct hw_interrupt_type gatwick_pic = {
- .typename = " GATWICK ",
- .startup = pmac_startup_irq,
- .enable = pmac_unmask_irq,
- .disable = pmac_mask_irq,
- .ack = pmac_mask_and_ack_irq,
- .end = pmac_end_irq,
+ .mask = pmac_mask_irq,
+ .ack = pmac_ack_irq,
+ .mask_ack = pmac_mask_and_ack_irq,
+ .unmask = pmac_unmask_irq,
+ .retrigger = pmac_retrigger,
};
static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
{
+ unsigned long flags;
int irq, bits;
+ int rc = IRQ_NONE;
+ spin_lock_irqsave(&pmac_pic_lock, flags);
for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
int i = irq >> 5;
bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
@@ -209,17 +229,20 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
if (bits == 0)
continue;
irq += __ilog2(bits);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
__do_IRQ(irq, regs);
- return IRQ_HANDLED;
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ rc = IRQ_HANDLED;
}
- printk("gatwick irq not from gatwick pic\n");
- return IRQ_NONE;
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
+ return rc;
}
static int pmac_get_irq(struct pt_regs *regs)
{
int irq;
unsigned long bits = 0;
+ unsigned long flags;
#ifdef CONFIG_SMP
void psurge_smp_message_recv(struct pt_regs *);
@@ -230,6 +253,7 @@ static int pmac_get_irq(struct pt_regs *regs)
return -2; /* ignore, already handled */
}
#endif /* CONFIG_SMP */
+ spin_lock_irqsave(&pmac_pic_lock, flags);
for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
int i = irq >> 5;
bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
@@ -241,6 +265,7 @@ static int pmac_get_irq(struct pt_regs *regs)
irq += __ilog2(bits);
break;
}
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
return irq;
}
@@ -389,7 +414,6 @@ static struct irqaction gatwick_cascade_action = {
static void __init pmac_pic_probe_oldstyle(void)
{
int i;
- int irq_cascade = -1;
struct device_node *master = NULL;
struct device_node *slave = NULL;
u8 __iomem *addr;
@@ -443,9 +467,16 @@ static void __init pmac_pic_probe_oldstyle(void)
}
BUG_ON(master == NULL);
- /* Set the handler for the main PIC */
- for ( i = 0; i < max_real_irqs ; i++ )
- irq_desc[i].chip = &pmac_pic;
+ /* Mark level interrupts and set handlers */
+ for (i = 0; i < max_irqs; i++) {
+ int level = !!(level_mask[i >> 5] & (1UL << (i & 0x1f)));
+ if (level)
+ irq_desc[i].status |= IRQ_LEVEL;
+ else
+ irq_desc[i].status |= IRQ_DELAYED_DISABLE;
+ set_irq_chip_and_handler(i, &pmac_pic, level ?
+ handle_level_irq : handle_edge_irq);
+ }
/* Get addresses of first controller if we have a node for it */
BUG_ON(of_address_to_resource(master, 0, &r));
@@ -472,29 +503,22 @@ static void __init pmac_pic_probe_oldstyle(void)
pmac_irq_hw[i++] =
(volatile struct pmac_irq_hw __iomem *)
(addr + 0x10);
- irq_cascade = slave->intrs[0].line;
+ pmac_irq_cascade = slave->intrs[0].line;
printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
" cascade: %d\n", slave->full_name,
- max_irqs - max_real_irqs, irq_cascade);
+ max_irqs - max_real_irqs, pmac_irq_cascade);
}
of_node_put(slave);
- /* disable all interrupts in all controllers */
+ /* Disable all interrupts in all controllers */
for (i = 0; i * 32 < max_irqs; ++i)
out_le32(&pmac_irq_hw[i]->enable, 0);
- /* mark level interrupts */
- for (i = 0; i < max_irqs; i++)
- if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
- irq_desc[i].status = IRQ_LEVEL;
+ /* Hookup cascade irq */
+ if (slave)
+ setup_irq(pmac_irq_cascade, &gatwick_cascade_action);
- /* Setup handlers for secondary controller and hook cascade irq*/
- if (slave) {
- for ( i = max_real_irqs ; i < max_irqs ; i++ )
- irq_desc[i].chip = &gatwick_pic;
- setup_irq(irq_cascade, &gatwick_cascade_action);
- }
printk(KERN_INFO "irq: System has %d possi