diff options
-rw-r--r-- | arch/powerpc/kernel/irq.c | 30 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc_64.S | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 111 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.h | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/setup.c | 12 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spider-pic.c | 173 | ||||
-rw-r--r-- | arch/powerpc/platforms/chrp/setup.c | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/irq.c | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pic.c | 170 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 26 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 443 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.h | 17 | ||||
-rw-r--r-- | arch/powerpc/sysdev/i8259.c | 30 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 193 | ||||
-rw-r--r-- | include/asm-powerpc/i8259.h | 3 | ||||
-rw-r--r-- | include/asm-powerpc/irq.h | 8 | ||||
-rw-r--r-- | include/asm-powerpc/mpic.h | 25 |
17 files changed, 673 insertions, 616 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 525baab45d2..91248559099 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 0c3c70d115c..bfb407fc1aa 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 22da1335445..97936f547f1 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 799f77d98f9..c74515aeb63 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 01ec39431fb..70a4e903f7e 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 7c3a0b6d34f..98425acb6cd 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 1f1771b212b..a5dffc8d93a 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 f70e820e730..7fb6a08786c 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 c9b09a9e605..58a4c7b90b8 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: Sys |