1/* 2 * Interrupt handing routines for NEC VR4100 series. 3 * 4 * Copyright (C) 2005-2007 Yoichi Yuasa <yuasa@linux-mips.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20#include <linux/interrupt.h> 21#include <linux/module.h> 22 23#include <asm/irq_cpu.h> 24#include <asm/system.h> 25#include <asm/vr41xx/irq.h> 26 27typedef struct irq_cascade { 28 int (*get_irq)(unsigned int); 29} irq_cascade_t; 30 31static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned; 32 33static struct irqaction cascade_irqaction = { 34 .handler = no_action, 35 .name = "cascade", 36}; 37 38int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int)) 39{ 40 int retval = 0; 41 42 if (irq >= NR_IRQS) 43 return -EINVAL; 44 45 if (irq_cascade[irq].get_irq != NULL) 46 free_irq(irq, NULL); 47 48 irq_cascade[irq].get_irq = get_irq; 49 50 if (get_irq != NULL) { 51 retval = setup_irq(irq, &cascade_irqaction); 52 if (retval < 0) 53 irq_cascade[irq].get_irq = NULL; 54 } 55 56 return retval; 57} 58 59EXPORT_SYMBOL_GPL(cascade_irq); 60 61static void irq_dispatch(unsigned int irq) 62{ 63 irq_cascade_t *cascade; 64 struct irq_desc *desc; 65 66 if (irq >= NR_IRQS) { 67 atomic_inc(&irq_err_count); 68 return; 69 } 70 71 cascade = irq_cascade + irq; 72 if (cascade->get_irq != NULL) { 73 unsigned int source_irq = irq; 74 int ret; 75 desc = irq_desc + source_irq; 76 if (desc->chip->mask_ack) 77 desc->chip->mask_ack(source_irq); 78 else { 79 desc->chip->mask(source_irq); 80 desc->chip->ack(source_irq); 81 } 82 ret = cascade->get_irq(irq); 83 irq = ret; 84 if (ret < 0) 85 atomic_inc(&irq_err_count); 86 else 87 irq_dispatch(irq); 88 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) 89 desc->chip->unmask(source_irq); 90 } else 91 do_IRQ(irq); 92} 93 94asmlinkage void plat_irq_dispatch(void) 95{ 96 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; 97 98 if (pending & CAUSEF_IP7) 99 do_IRQ(TIMER_IRQ); 100 else if (pending & 0x7800) { 101 if (pending & CAUSEF_IP3) 102 irq_dispatch(INT1_IRQ); 103 else if (pending & CAUSEF_IP4) 104 irq_dispatch(INT2_IRQ); 105 else if (pending & CAUSEF_IP5) 106 irq_dispatch(INT3_IRQ); 107 else if (pending & CAUSEF_IP6) 108 irq_dispatch(INT4_IRQ); 109 } else if (pending & CAUSEF_IP2) 110 irq_dispatch(INT0_IRQ); 111 else if (pending & CAUSEF_IP0) 112 do_IRQ(MIPS_SOFTINT0_IRQ); 113 else if (pending & CAUSEF_IP1) 114 do_IRQ(MIPS_SOFTINT1_IRQ); 115 else 116 spurious_interrupt(); 117} 118 119void __init arch_init_irq(void) 120{ 121 mips_cpu_irq_init(); 122} 123