1/* 2 * Interrupt handing routines for NEC VR4100 series. 3 * 4 * Copyright (C) 2005-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> 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 .mask = CPU_MASK_NONE, 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 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 irq = cascade->get_irq(irq); 83 if (irq < 0) 84 atomic_inc(&irq_err_count); 85 else 86 irq_dispatch(irq); 87 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) 88 desc->chip->unmask(source_irq); 89 } else 90 do_IRQ(irq); 91} 92 93asmlinkage void plat_irq_dispatch(void) 94{ 95 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; 96 97 if (pending & CAUSEF_IP7) 98 do_IRQ(TIMER_IRQ); 99 else if (pending & 0x7800) { 100 if (pending & CAUSEF_IP3) 101 irq_dispatch(INT1_IRQ); 102 else if (pending & CAUSEF_IP4) 103 irq_dispatch(INT2_IRQ); 104 else if (pending & CAUSEF_IP5) 105 irq_dispatch(INT3_IRQ); 106 else if (pending & CAUSEF_IP6) 107 irq_dispatch(INT4_IRQ); 108 } else if (pending & CAUSEF_IP2) 109 irq_dispatch(INT0_IRQ); 110 else if (pending & CAUSEF_IP0) 111 do_IRQ(MIPS_SOFTINT0_IRQ); 112 else if (pending & CAUSEF_IP1) 113 do_IRQ(MIPS_SOFTINT1_IRQ); 114 else 115 spurious_interrupt(); 116} 117 118void __init arch_init_irq(void) 119{ 120 mips_cpu_irq_init(); 121} 122