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