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/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 .flags = IRQF_NO_THREAD, 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 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 struct irq_desc *desc = irq_to_desc(irq); 74 struct irq_data *idata = irq_desc_get_irq_data(desc); 75 struct irq_chip *chip = irq_desc_get_chip(desc); 76 int ret; 77 78 if (chip->irq_mask_ack) 79 chip->irq_mask_ack(idata); 80 else { 81 chip->irq_mask(idata); 82 chip->irq_ack(idata); 83 } 84 ret = cascade->get_irq(irq); 85 irq = ret; 86 if (ret < 0) 87 atomic_inc(&irq_err_count); 88 else 89 irq_dispatch(irq); 90 if (!irqd_irq_disabled(idata) && chip->irq_unmask) 91 chip->irq_unmask(idata); 92 } else 93 do_IRQ(irq); 94} 95 96asmlinkage void plat_irq_dispatch(void) 97{ 98 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; 99 100 if (pending & CAUSEF_IP7) 101 do_IRQ(TIMER_IRQ); 102 else if (pending & 0x7800) { 103 if (pending & CAUSEF_IP3) 104 irq_dispatch(INT1_IRQ); 105 else if (pending & CAUSEF_IP4) 106 irq_dispatch(INT2_IRQ); 107 else if (pending & CAUSEF_IP5) 108 irq_dispatch(INT3_IRQ); 109 else if (pending & CAUSEF_IP6) 110 irq_dispatch(INT4_IRQ); 111 } else if (pending & CAUSEF_IP2) 112 irq_dispatch(INT0_IRQ); 113 else if (pending & CAUSEF_IP0) 114 do_IRQ(MIPS_SOFTINT0_IRQ); 115 else if (pending & CAUSEF_IP1) 116 do_IRQ(MIPS_SOFTINT1_IRQ); 117 else 118 spurious_interrupt(); 119} 120 121void __init arch_init_irq(void) 122{ 123 mips_cpu_irq_init(); 124} 125