diff options
Diffstat (limited to 'arch/mips/vr41xx/common/irq.c')
| -rw-r--r-- | arch/mips/vr41xx/common/irq.c | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c index 43b214d3943..ae0e4ee6c61 100644 --- a/arch/mips/vr41xx/common/irq.c +++ b/arch/mips/vr41xx/common/irq.c @@ -1,7 +1,7 @@ /* * Interrupt handing routines for NEC VR4100 series. * - * Copyright (C) 2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * Copyright (C) 2005-2007 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,24 +19,24 @@ */ #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/irq.h> #include <asm/irq_cpu.h> -#include <asm/system.h> -#include <asm/vr41xx/vr41xx.h> +#include <asm/vr41xx/irq.h> typedef struct irq_cascade { - int (*get_irq)(unsigned int, struct pt_regs *); + int (*get_irq)(unsigned int); } irq_cascade_t; static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned; static struct irqaction cascade_irqaction = { .handler = no_action, - .mask = CPU_MASK_NONE, .name = "cascade", + .flags = IRQF_NO_THREAD, }; -int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *)) +int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int)) { int retval = 0; @@ -59,10 +59,9 @@ int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *) EXPORT_SYMBOL_GPL(cascade_irq); -asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs) +static void irq_dispatch(unsigned int irq) { irq_cascade_t *cascade; - irq_desc_t *desc; if (irq >= NR_IRQS) { atomic_inc(&irq_err_count); @@ -71,24 +70,55 @@ asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs) cascade = irq_cascade + irq; if (cascade->get_irq != NULL) { - unsigned int source_irq = irq; - desc = irq_desc + source_irq; - desc->handler->ack(source_irq); - irq = cascade->get_irq(irq, regs); - if (irq < 0) + struct irq_desc *desc = irq_to_desc(irq); + struct irq_data *idata = irq_desc_get_irq_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + int ret; + + if (chip->irq_mask_ack) + chip->irq_mask_ack(idata); + else { + chip->irq_mask(idata); + chip->irq_ack(idata); + } + ret = cascade->get_irq(irq); + irq = ret; + if (ret < 0) atomic_inc(&irq_err_count); else - irq_dispatch(irq, regs); - desc->handler->end(source_irq); + irq_dispatch(irq); + if (!irqd_irq_disabled(idata) && chip->irq_unmask) + chip->irq_unmask(idata); } else - do_IRQ(irq, regs); + do_IRQ(irq); } -extern asmlinkage void vr41xx_handle_interrupt(void); +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; + + if (pending & CAUSEF_IP7) + do_IRQ(TIMER_IRQ); + else if (pending & 0x7800) { + if (pending & CAUSEF_IP3) + irq_dispatch(INT1_IRQ); + else if (pending & CAUSEF_IP4) + irq_dispatch(INT2_IRQ); + else if (pending & CAUSEF_IP5) + irq_dispatch(INT3_IRQ); + else if (pending & CAUSEF_IP6) + irq_dispatch(INT4_IRQ); + } else if (pending & CAUSEF_IP2) + irq_dispatch(INT0_IRQ); + else if (pending & CAUSEF_IP0) + do_IRQ(MIPS_SOFTINT0_IRQ); + else if (pending & CAUSEF_IP1) + do_IRQ(MIPS_SOFTINT1_IRQ); + else + spurious_interrupt(); +} void __init arch_init_irq(void) { - mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); - - set_except_vector(0, vr41xx_handle_interrupt); + mips_cpu_irq_init(); } |
