1/* 2 * linux/arch/m68knommu/platform/68328/ints.c 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file COPYING in the main directory of this archive 6 * for more details. 7 * 8 * Copyright 1996 Roman Zippel 9 * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com> 10 */ 11 12#include <linux/module.h> 13#include <linux/types.h> 14#include <linux/kernel.h> 15#include <linux/sched.h> 16#include <linux/kernel_stat.h> 17#include <linux/errno.h> 18#include <linux/interrupt.h> 19 20#include <asm/system.h> 21#include <asm/irq.h> 22#include <asm/irqnode.h> 23#include <asm/traps.h> 24#include <asm/io.h> 25#include <asm/machdep.h> 26#include <asm/setup.h> 27 28#if defined(CONFIG_M68328) 29#include <asm/MC68328.h> 30#elif defined(CONFIG_M68EZ328) 31#include <asm/MC68EZ328.h> 32#elif defined(CONFIG_M68VZ328) 33#include <asm/MC68VZ328.h> 34#endif 35 36/* assembler routines */ 37asmlinkage void system_call(void); 38asmlinkage void buserr(void); 39asmlinkage void trap(void); 40asmlinkage void trap3(void); 41asmlinkage void trap4(void); 42asmlinkage void trap5(void); 43asmlinkage void trap6(void); 44asmlinkage void trap7(void); 45asmlinkage void trap8(void); 46asmlinkage void trap9(void); 47asmlinkage void trap10(void); 48asmlinkage void trap11(void); 49asmlinkage void trap12(void); 50asmlinkage void trap13(void); 51asmlinkage void trap14(void); 52asmlinkage void trap15(void); 53asmlinkage void trap33(void); 54asmlinkage void trap34(void); 55asmlinkage void trap35(void); 56asmlinkage void trap36(void); 57asmlinkage void trap37(void); 58asmlinkage void trap38(void); 59asmlinkage void trap39(void); 60asmlinkage void trap40(void); 61asmlinkage void trap41(void); 62asmlinkage void trap42(void); 63asmlinkage void trap43(void); 64asmlinkage void trap44(void); 65asmlinkage void trap45(void); 66asmlinkage void trap46(void); 67asmlinkage void trap47(void); 68asmlinkage irqreturn_t bad_interrupt(int, void *); 69asmlinkage irqreturn_t inthandler(void); 70asmlinkage irqreturn_t inthandler1(void); 71asmlinkage irqreturn_t inthandler2(void); 72asmlinkage irqreturn_t inthandler3(void); 73asmlinkage irqreturn_t inthandler4(void); 74asmlinkage irqreturn_t inthandler5(void); 75asmlinkage irqreturn_t inthandler6(void); 76asmlinkage irqreturn_t inthandler7(void); 77 78extern e_vector *_ramvec; 79 80/* The number of spurious interrupts */ 81volatile unsigned int num_spurious; 82unsigned int local_irq_count[NR_CPUS]; 83 84/* irq node variables for the 32 (potential) on chip sources */ 85static irq_node_t int_irq_list[NR_IRQS]; 86 87/* 88 * This function should be called during kernel startup to initialize 89 * the IRQ handling routines. 90 */ 91void init_IRQ(void) 92{ 93 int i; 94 95 /* set up the vectors */ 96 for (i = 72; i < 256; ++i) 97 _ramvec[i] = (e_vector) bad_interrupt; 98 99 _ramvec[32] = system_call; 100 101 _ramvec[65] = (e_vector) inthandler1; 102 _ramvec[66] = (e_vector) inthandler2; 103 _ramvec[67] = (e_vector) inthandler3; 104 _ramvec[68] = (e_vector) inthandler4; 105 _ramvec[69] = (e_vector) inthandler5; 106 _ramvec[70] = (e_vector) inthandler6; 107 _ramvec[71] = (e_vector) inthandler7; 108 109 IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */ 110 111 /* initialize handlers */ 112 for (i = 0; i < NR_IRQS; i++) { 113 int_irq_list[i].handler = bad_interrupt; 114 int_irq_list[i].flags = IRQ_FLG_STD; 115 int_irq_list[i].dev_id = NULL; 116 int_irq_list[i].devname = NULL; 117 } 118 119 /* turn off all interrupts */ 120 IMR = ~0; 121} 122 123int request_irq( 124 unsigned int irq, 125 irq_handler_t handler, 126 unsigned long flags, 127 const char *devname, 128 void *dev_id) 129{ 130 if (irq >= NR_IRQS) { 131 printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); 132 return -ENXIO; 133 } 134 135 if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) { 136 if (int_irq_list[irq].flags & IRQ_FLG_LOCK) { 137 printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n", 138 __FUNCTION__, irq, int_irq_list[irq].devname); 139 return -EBUSY; 140 } 141 if (flags & IRQ_FLG_REPLACE) { 142 printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n", 143 __FUNCTION__, devname, irq, int_irq_list[irq].devname); 144 return -EBUSY; 145 } 146 } 147 148 int_irq_list[irq].handler = handler; 149 int_irq_list[irq].flags = flags; 150 int_irq_list[irq].dev_id = dev_id; 151 int_irq_list[irq].devname = devname; 152 153 IMR &= ~(1<<irq); 154 155 return 0; 156} 157 158EXPORT_SYMBOL(request_irq); 159 160void free_irq(unsigned int irq, void *dev_id) 161{ 162 if (irq >= NR_IRQS) { 163 printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq); 164 return; 165 } 166 167 if (int_irq_list[irq].dev_id != dev_id) 168 printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n", 169 __FUNCTION__, irq, int_irq_list[irq].devname); 170 171 int_irq_list[irq].handler = bad_interrupt; 172 int_irq_list[irq].flags = IRQ_FLG_STD; 173 int_irq_list[irq].dev_id = NULL; 174 int_irq_list[irq].devname = NULL; 175 176 IMR |= 1<<irq; 177} 178 179EXPORT_SYMBOL(free_irq); 180 181int show_interrupts(struct seq_file *p, void *v) 182{ 183 int i = *(loff_t *) v; 184 185 if (i < NR_IRQS) { 186 if (int_irq_list[i].devname) { 187 seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]); 188 if (int_irq_list[i].flags & IRQ_FLG_LOCK) 189 seq_printf(p, "L "); 190 else 191 seq_printf(p, " "); 192 seq_printf(p, "%s\n", int_irq_list[i].devname); 193 } 194 } 195 if (i == NR_IRQS) 196 seq_printf(p, " : %10u spurious\n", num_spurious); 197 198 return 0; 199} 200 201/* The 68k family did not have a good way to determine the source 202 * of interrupts until later in the family. The EC000 core does 203 * not provide the vector number on the stack, we vector everything 204 * into one vector and look in the blasted mask register... 205 * This code is designed to be fast, almost constant time, not clean! 206 */ 207void process_int(int vec, struct pt_regs *fp) 208{ 209 int irq; 210 int mask; 211 212 unsigned long pend = ISR; 213 214 while (pend) { 215 if (pend & 0x0000ffff) { 216 if (pend & 0x000000ff) { 217 if (pend & 0x0000000f) { 218 mask = 0x00000001; 219 irq = 0; 220 } else { 221 mask = 0x00000010; 222 irq = 4; 223 } 224 } else { 225 if (pend & 0x00000f00) { 226 mask = 0x00000100; 227 irq = 8; 228 } else { 229 mask = 0x00001000; 230 irq = 12; 231 } 232 } 233 } else { 234 if (pend & 0x00ff0000) { 235 if (pend & 0x000f0000) { 236 mask = 0x00010000; 237 irq = 16; 238 } else { 239 mask = 0x00100000; 240 irq = 20; 241 } 242 } else { 243 if (pend & 0x0f000000) { 244 mask = 0x01000000; 245 irq = 24; 246 } else { 247 mask = 0x10000000; 248 irq = 28; 249 } 250 } 251 } 252 253 while (! (mask & pend)) { 254 mask <<=1; 255 irq++; 256 } 257 258 kstat_cpu(0).irqs[irq]++; 259 260 if (int_irq_list[irq].handler) { 261 int_irq_list[irq].handler(irq, int_irq_list[irq].dev_id, fp); 262 } else { 263 printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the IMR...\n", irq); 264 IMR |= mask; 265 } 266 pend &= ~mask; 267 } 268} 269