1/* 2 * Carsten Langgaard, carstenl@mips.com 3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. 4 * 5 * ######################################################################## 6 * 7 * This program is free software; you can distribute it and/or modify it 8 * under the terms of the GNU General Public License (Version 2) as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 19 * 20 * ######################################################################## 21 * 22 * Routines for generic manipulation of the interrupts found on the 23 * Lasat boards. 24 * 25 */ 26#include <linux/config.h> 27#include <linux/init.h> 28#include <linux/sched.h> 29#include <linux/slab.h> 30#include <linux/interrupt.h> 31#include <linux/kernel_stat.h> 32 33#include <asm/bootinfo.h> 34#include <asm/irq.h> 35#include <asm/lasat/lasatint.h> 36#include <asm/gdb-stub.h> 37 38static volatile int *lasat_int_status = NULL; 39static volatile int *lasat_int_mask = NULL; 40static volatile int lasat_int_mask_shift; 41 42extern asmlinkage void mipsIRQ(void); 43extern void do_IRQ(int irq, struct pt_regs *regs); 44 45#define DEBUG_INT(x...) 46 47void disable_lasat_irq(unsigned int irq_nr) 48{ 49 unsigned long flags; 50 DEBUG_INT("disable_lasat_irq: %d", irq_nr); 51 52 save_and_cli(flags); 53 *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift; 54 restore_flags(flags); 55} 56 57void enable_lasat_irq(unsigned int irq_nr) 58{ 59 unsigned long flags; 60 DEBUG_INT("enable_lasat_irq: %d", irq_nr); 61 62 save_and_cli(flags); 63 *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift; 64 restore_flags(flags); 65} 66 67static unsigned int startup_lasat_irq(unsigned int irq) 68{ 69 enable_lasat_irq(irq); 70 return 0; /* never anything pending */ 71} 72 73#define shutdown_lasat_irq disable_lasat_irq 74 75#define mask_and_ack_lasat_irq disable_lasat_irq 76 77static void end_lasat_irq(unsigned int irq) 78{ 79 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 80 enable_lasat_irq(irq); 81} 82 83static struct hw_interrupt_type lasat_irq_type = { 84 "Lasat", 85 startup_lasat_irq, 86 shutdown_lasat_irq, 87 enable_lasat_irq, 88 disable_lasat_irq, 89 mask_and_ack_lasat_irq, 90 end_lasat_irq, 91 NULL 92}; 93 94static inline int ls1bit32(unsigned int x) 95{ 96 int b = 31, s; 97 98 s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; 99 s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; 100 s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; 101 s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; 102 s = 1; if (x << 1 == 0) s = 0; b -= s; 103 104 return b; 105} 106 107static unsigned long (* get_int_status)(void); 108 109static unsigned long get_int_status_100(void) 110{ 111 return (*lasat_int_status & *lasat_int_mask); 112} 113 114static unsigned long get_int_status_200(void) 115{ 116 unsigned long int_status; 117 118 int_status = *lasat_int_status; 119 int_status &= (int_status >> LASATINT_MASK_SHIFT_200) & 0xffff; 120 return int_status; 121} 122 123void lasat_hw0_irqdispatch(struct pt_regs *regs) 124{ 125 struct irqaction *action; 126 unsigned long int_status; 127 int irq, cpu = smp_processor_id(); 128 129 int_status = get_int_status(); 130 131 /* if int_status == 0, then the interrupt has already been cleared */ 132 if (int_status == 0) 133 return; 134 135 irq = ls1bit32(int_status); 136 action = irq_desc[irq].action; 137 138 DEBUG_INT("lasat_hw0_irqdispatch: irq=%d\n", irq); 139 140 /* if action == NULL, then we don't have a handler for the irq */ 141 if (action == NULL) { 142 printk("No handler for hw0 irq: %i\n", irq); 143 atomic_inc(&irq_err_count); 144 return; 145 } 146 147 irq_enter(cpu, irq); 148 kstat.irqs[0][irq]++; 149 action->handler(irq, action->dev_id, regs); 150 irq_exit(cpu, irq); 151 152 return; 153} 154 155void __init init_IRQ(void) 156{ 157 int i; 158 159 init_generic_irq(); 160 161 switch (mips_machtype) { 162 case MACH_LASAT_100: 163 lasat_int_status = LASAT_INT_STATUS_REG_100; 164 lasat_int_mask = LASAT_INT_MASK_REG_100; 165 lasat_int_mask_shift = LASATINT_MASK_SHIFT_100; 166 get_int_status = get_int_status_100; 167 *lasat_int_mask = 0; 168 break; 169 case MACH_LASAT_200: 170 lasat_int_status = LASAT_INT_STATUS_REG_200; 171 lasat_int_mask = LASAT_INT_MASK_REG_200; 172 lasat_int_mask_shift = LASATINT_MASK_SHIFT_200; 173 get_int_status = get_int_status_200; 174 *lasat_int_mask &= 0xffff; 175 break; 176 default: 177 panic("init_IRQ: mips_machtype incorrect"); 178 } 179 180 /* Now safe to set the exception vector. */ 181 set_except_vector(0, mipsIRQ); 182 183 for (i = 0; i <= LASATINT_END; i++) { 184 irq_desc[i].status = IRQ_DISABLED; 185 irq_desc[i].action = 0; 186 irq_desc[i].depth = 1; 187 irq_desc[i].handler = &lasat_irq_type; 188 } 189} 190