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