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#include <linux/irq.h> 23 24#include <asm/irq_cpu.h> 25#include <asm/system.h> 26#include <asm/vr41xx/irq.h> 27 28typedef struct irq_cascade { 29 int (*get_irq)(unsigned int); 30} irq_cascade_t; 31 32static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned; 33 34static struct irqaction cascade_irqaction = { 35 .handler = no_action, 36 .name = "cascade", 37}; 38 39int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int)) 40{ 41 int retval = 0; 42 43 if (irq >= NR_IRQS) 44 return -EINVAL; 45 46 if (irq_cascade[irq].get_irq != NULL) 47 free_irq(irq, NULL); 48 49 irq_cascade[irq].get_irq = get_irq; 50 51 if (get_irq != NULL) { 52 retval = setup_irq(irq, &cascade_irqaction); 53 if (retval < 0) 54 irq_cascade[irq].get_irq = NULL; 55 } 56 57 return retval; 58} 59 60EXPORT_SYMBOL_GPL(cascade_irq); 61 62static void irq_dispatch(unsigned int irq) 63{ 64 irq_cascade_t *cascade; 65 struct irq_desc *desc; 66 67 if (irq >= NR_IRQS) { 68 atomic_inc(&irq_err_count); 69 return; 70 } 71 72 cascade = irq_cascade + irq; 73 if (cascade->get_irq != NULL) { 74 unsigned int source_irq = irq; 75 int ret; 76 desc = irq_desc + source_irq; 77 if (desc->chip->mask_ack) 78 desc->chip->mask_ack(source_irq); 79 else { 80 desc->chip->mask(source_irq); 81 desc->chip->ack(source_irq); 82 } 83 ret = cascade->get_irq(irq); 84 irq = ret; 85 if (ret < 0) 86 atomic_inc(&irq_err_count); 87 else 88 irq_dispatch(irq); 89 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) 90 desc->chip->unmask(source_irq); 91 } else 92 do_IRQ(irq); 93} 94 95asmlinkage void plat_irq_dispatch(void) 96{ 97 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; 98 99 if (pending & CAUSEF_IP7) 100 do_IRQ(TIMER_IRQ); 101 else if (pending & 0x7800) { 102 if (pending & CAUSEF_IP3) 103 irq_dispatch(INT1_IRQ); 104 else if (pending & CAUSEF_IP4) 105 irq_dispatch(INT2_IRQ); 106 else if (pending & CAUSEF_IP5) 107 irq_dispatch(INT3_IRQ); 108 else if (pending & CAUSEF_IP6) 109 irq_dispatch(INT4_IRQ); 110 } else if (pending & CAUSEF_IP2) 111 irq_dispatch(INT0_IRQ); 112 else if (pending & CAUSEF_IP0) 113 do_IRQ(MIPS_SOFTINT0_IRQ); 114 else if (pending & CAUSEF_IP1) 115 do_IRQ(MIPS_SOFTINT1_IRQ); 116 else 117 spurious_interrupt(); 118} 119 120void __init arch_init_irq(void) 121{ 122 mips_cpu_irq_init(); 123} 124