1 /* 2 * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code 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 * 07/03/96: Timer initialization, and thus mach_sched_init(), 9 * removed from request_irq() and moved to init_time(). 10 * We should therefore consider renaming our add_isr() and 11 * remove_isr() to request_irq() and free_irq() 12 * respectively, so they are compliant with the other 13 * architectures. /Jes 14 * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls. 15 * Removed irq list support, if any machine needs an irq server 16 * it must implement this itself (as it's already done), instead 17 * only default handler are used with mach_default_handler. 18 * request_irq got some flags different from other architectures: 19 * - IRQ_FLG_REPLACE : Replace an existing handler (the default one 20 * can be replaced without this flag) 21 * - IRQ_FLG_LOCK : handler can't be replaced 22 * There are other machine depending flags, see there 23 * If you want to replace a default handler you should know what 24 * you're doing, since it might handle different other irq sources 25 * which must be served /Roman Zippel 26 */ 27 28 #include <linux/module.h> 29 #include <linux/types.h> 30 #include <linux/sched.h> 31 #include <linux/interrupt.h> 32 #include <linux/kernel_stat.h> 33 #include <linux/errno.h> 34 #include <linux/init.h> 35 36 #include <asm/setup.h> 37 #include <asm/system.h> 38 #include <asm/irq.h> 39 #include <asm/traps.h> 40 #include <asm/page.h> 41 #include <asm/machdep.h> 42 #include <asm/cacheflush.h> 43 #include <asm/irq_regs.h> 44 45 #ifdef CONFIG_Q40 46 #include <asm/q40ints.h> 47 #endif 48 49 extern u32 auto_irqhandler_fixup[]; 50 extern u32 user_irqhandler_fixup[]; 51 extern u16 user_irqvec_fixup[]; 52 53 /* table for system interrupt handlers */ 54 static struct irq_node *irq_list[NR_IRQS]; 55 static struct irq_controller *irq_controller[NR_IRQS]; 56 static int irq_depth[NR_IRQS]; 57 58 static int m68k_first_user_vec; 59 60 static struct irq_controller auto_irq_controller = { 61 .name = "auto", 62 .lock = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock), 63 .startup = m68k_irq_startup, 64 .shutdown = m68k_irq_shutdown, 65 }; 66 67 static struct irq_controller user_irq_controller = { 68 .name = "user", 69 .lock = __SPIN_LOCK_UNLOCKED(user_irq_controller.lock), 70 .startup = m68k_irq_startup, 71 .shutdown = m68k_irq_shutdown, 72 }; 73 74 #define NUM_IRQ_NODES 100 75 static irq_node_t nodes[NUM_IRQ_NODES]; 76 77 /* 78 * void init_IRQ(void) 79 * 80 * Parameters: None 81 * 82 * Returns: Nothing 83 * 84 * This function should be called during kernel startup to initialize 85 * the IRQ handling routines. 86 */ 87 88 void __init init_IRQ(void) 89 { 90 int i; 91 92 /* assembly irq entry code relies on this... */ 93 if (HARDIRQ_MASK != 0x00ff0000) { 94 extern void hardirq_mask_is_broken(void); 95 hardirq_mask_is_broken(); 96 } 97 98 for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) 99 irq_controller[i] = &auto_irq_controller; 100 101 mach_init_IRQ(); 102 } 103 104 /** 105 * m68k_setup_auto_interrupt 106 * @handler: called from auto vector interrupts 107 * 108 * setup the handler to be called from auto vector interrupts instead of the 109 * standard __m68k_handle_int(), it will be called with irq numbers in the range 110 * from IRQ_AUTO_1 - IRQ_AUTO_7. 111 */ 112 void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) 113 { 114 if (handler) 115 *auto_irqhandler_fixup = (u32)handler; 116 flush_icache(); 117 } 118 119 /** 120 * m68k_setup_user_interrupt 121 * @vec: first user vector interrupt to handle 122 * @cnt: number of active user vector interrupts 123 * @handler: called from user vector interrupts 124 * 125 * setup user vector interrupts, this includes activating the specified range 126 * of interrupts, only then these interrupts can be requested (note: this is 127 * different from auto vector interrupts). An optional handler can be installed 128 * to be called instead of the default __m68k_handle_int(), it will be called 129 * with irq numbers starting from IRQ_USER. 130 */ 131 void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, 132 void (*handler)(unsigned int, struct pt_regs *)) 133 { 134 int i; 135 136 BUG_ON(IRQ_USER + cnt > NR_IRQS); 137 m68k_first_user_vec = vec; 138 for (i = 0; i < cnt; i++) 139 irq_controller[IRQ_USER + i] = &user_irq_controller; 140 *user_irqvec_fixup = vec - IRQ_USER; 141 if (handler) 142 *user_irqhandler_fixup = (u32)handler; 143 flush_icache(); 144 } 145 146 /** 147 * m68k_setup_irq_controller 148 * @contr: irq controller which controls specified irq 149 * @irq: first irq to be managed by the controller 150 * 151 * Change the controller for the specified range of irq, which will be used to 152 * manage these irq. auto/user irq already have a default controller, which can 153 * be changed as well, but the controller probably should use m68k_irq_startup/ 154 * m68k_irq_shutdown. 155 */ 156 void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq, 157 unsigned int cnt) 158 { 159 int i; 160 161 for (i = 0; i < cnt; i++) 162 irq_controller[irq + i] = contr; 163 } 164 165 irq_node_t *new_irq_node(void) 166 { 167 irq_node_t *node; 168 short i; 169 170 for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { 171 if (!node->handler) { 172 memset(node, 0, sizeof(*node)); 173 return node; 174 } 175 } 176 177 printk ("new_irq_node: out of nodes\n"); 178 return NULL; 179 } 180 181 int setup_irq(unsigned int irq, struct irq_node *node) 182 { 183 struct irq_controller *contr; 184 struct irq_node **prev; 185 unsigned long flags; 186 187 if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 188 printk("%s: Incorrect IRQ %d from %s\n", 189 __func__, irq, node->devname); 190 return -ENXIO; 191 } 192 193 spin_lock_irqsave(&contr->lock, flags); 194 195 prev = irq_list + irq; 196 if (*prev) { 197 /* Can't share interrupts unless both agree to */ 198 if (!((*prev)->flags & node->flags & IRQF_SHARED)) { 199 spin_unlock_irqrestore(&contr->lock, flags); 200 return -EBUSY; 201 } 202 while (*prev) 203 prev = &(*prev)->next; 204 } 205 206 if (!irq_list[irq]) { 207 if (contr->startup) 208 contr->startup(irq); 209 else 210 contr->enable(irq); 211 } 212 node->next = NULL; 213 *prev = node; 214 215 spin_unlock_irqrestore(&contr->lock, flags); 216 217 return 0; 218 } 219 220 int request_irq(unsigned int irq, 221 irq_handler_t handler, 222 unsigned long flags, const char *devname, void *dev_id) 223 { 224 struct irq_node *node; 225 int res; 226 227 node = new_irq_node(); 228 if (!node) 229 return -ENOMEM; 230 231 node->handler = handler; 232 node->flags = flags; 233 node->dev_id = dev_id; 234 node->devname = devname; 235 236 res = setup_irq(irq, node); 237 if (res) 238 node->handler = NULL; 239 240 return res; 241 } 242 243 EXPORT_SYMBOL(request_irq); 244 245 void free_irq(unsigned int irq, void *dev_id) 246 { 247 struct irq_controller *contr; 248 struct irq_node **p, *node; 249 unsigned long flags; 250 251 if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 252 printk("%s: Incorrect IRQ %d\n", __func__, irq); 253 return; 254 } 255 256 spin_lock_irqsave(&contr->lock, flags); 257 258 p = irq_list + irq; 259 while ((node = *p)) { 260 if (node->dev_id == dev_id) 261 break; 262 p = &node->next; 263 } 264 265 if (node) { 266 *p = node->next; 267 node->handler = NULL; 268 } else 269 printk("%s: Removing probably wrong IRQ %d\n", 270 __func__, irq); 271 272 if (!irq_list[irq]) { 273 if (contr->shutdown) 274 contr->shutdown(irq); 275 else 276 contr->disable(irq); 277 } 278 279 spin_unlock_irqrestore(&contr->lock, flags); 280 } 281 282 EXPORT_SYMBOL(free_irq); 283 284 void enable_irq(unsigned int irq) 285 { 286 struct irq_controller *contr; 287 unsigned long flags; 288 289 if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 290 printk("%s: Incorrect IRQ %d\n", 291 __func__, irq); 292 return; 293 } 294 295 spin_lock_irqsave(&contr->lock, flags); 296 if (irq_depth[irq]) { 297 if (!--irq_depth[irq]) { 298 if (contr->enable) 299 contr->enable(irq); 300 } 301 } else 302 WARN_ON(1); 303 spin_unlock_irqrestore(&contr->lock, flags); 304 } 305 306 EXPORT_SYMBOL(enable_irq); 307 308 void disable_irq(unsigned int irq) 309 { 310 struct irq_controller *contr; 311 unsigned long flags; 312 313 if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 314 printk("%s: Incorrect IRQ %d\n", 315 __func__, irq); 316 return; 317 } 318 319 spin_lock_irqsave(&contr->lock, flags); 320 if (!irq_depth[irq]++) { 321 if (contr->disable) 322 contr->disable(irq); 323 } 324 spin_unlock_irqrestore(&contr->lock, flags); 325 } 326 327 EXPORT_SYMBOL(disable_irq); 328 329 void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq"))); 330 331 EXPORT_SYMBOL(disable_irq_nosync); 332 333 int m68k_irq_startup(unsigned int irq) 334 { 335 if (irq <= IRQ_AUTO_7) 336 vectors[VEC_SPUR + irq] = auto_inthandler; 337 else 338 vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; 339 return 0; 340 } 341 342 void m68k_irq_shutdown(unsigned int irq) 343 { 344 if (irq <= IRQ_AUTO_7) 345 vectors[VEC_SPUR + irq] = bad_inthandler; 346 else 347 vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; 348 } 349 350 351 /* 352 * Do we need these probe functions on the m68k? 353 * 354 * ... may be useful with ISA devices 355 */ 356 unsigned long probe_irq_on (void) 357 { 358 #ifdef CONFIG_Q40 359 if (MACH_IS_Q40) 360 return q40_probe_irq_on(); 361 #endif 362 return 0; 363 } 364 365 EXPORT_SYMBOL(probe_irq_on); 366 367 int probe_irq_off (unsigned long irqs) 368 { 369 #ifdef CONFIG_Q40 370 if (MACH_IS_Q40) 371 return q40_probe_irq_off(irqs); 372 #endif 373 return 0; 374 } 375 376 EXPORT_SYMBOL(probe_irq_off); 377 378 unsigned int irq_canonicalize(unsigned int irq) 379 { 380 #ifdef CONFIG_Q40 381 if (MACH_IS_Q40 && irq == 11) 382 irq = 10; 383 #endif 384 return irq; 385 } 386 387 EXPORT_SYMBOL(irq_canonicalize); 388 389 asmlinkage void m68k_handle_int(unsigned int irq) 390 { 391 struct irq_node *node; 392 kstat_cpu(0).irqs[irq]++; 393 node = irq_list[irq]; 394 do { 395 node->handler(irq, node->dev_id); 396 node = node->next; 397 } while (node); 398 } 399 400 asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs) 401 { 402 struct pt_regs *old_regs; 403 old_regs = set_irq_regs(regs); 404 m68k_handle_int(irq); 405 set_irq_regs(old_regs); 406 } 407 408 asmlinkage void handle_badint(struct pt_regs *regs) 409 { 410 kstat_cpu(0).irqs[0]++; 411 printk("unexpected interrupt from %u\n", regs->vector); 412 } 413 414 int show_interrupts(struct seq_file *p, void *v) 415 { 416 struct irq_controller *contr; 417 struct irq_node *node; 418 int i = *(loff_t *) v; 419 420 /* autovector interrupts */ 421 if (irq_list[i]) { 422 contr = irq_controller[i]; 423 node = irq_list[i]; 424 seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); 425 while ((node = node->next)) 426 seq_printf(p, ", %s", node->devname); 427 seq_puts(p, "\n"); 428 } 429 return 0; 430 } 431 432 #ifdef CONFIG_PROC_FS 433 void init_irq_proc(void) 434 { 435 /* Insert /proc/irq driver here */ 436 } 437 #endif 438