11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 51da177e4SLinus Torvalds * License. See the file COPYING in the main directory of this archive 61da177e4SLinus Torvalds * for more details. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * 07/03/96: Timer initialization, and thus mach_sched_init(), 91da177e4SLinus Torvalds * removed from request_irq() and moved to init_time(). 101da177e4SLinus Torvalds * We should therefore consider renaming our add_isr() and 111da177e4SLinus Torvalds * remove_isr() to request_irq() and free_irq() 121da177e4SLinus Torvalds * respectively, so they are compliant with the other 131da177e4SLinus Torvalds * architectures. /Jes 141da177e4SLinus Torvalds * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls. 151da177e4SLinus Torvalds * Removed irq list support, if any machine needs an irq server 161da177e4SLinus Torvalds * it must implement this itself (as it's already done), instead 171da177e4SLinus Torvalds * only default handler are used with mach_default_handler. 181da177e4SLinus Torvalds * request_irq got some flags different from other architectures: 191da177e4SLinus Torvalds * - IRQ_FLG_REPLACE : Replace an existing handler (the default one 201da177e4SLinus Torvalds * can be replaced without this flag) 211da177e4SLinus Torvalds * - IRQ_FLG_LOCK : handler can't be replaced 221da177e4SLinus Torvalds * There are other machine depending flags, see there 231da177e4SLinus Torvalds * If you want to replace a default handler you should know what 241da177e4SLinus Torvalds * you're doing, since it might handle different other irq sources 251da177e4SLinus Torvalds * which must be served /Roman Zippel 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <linux/module.h> 291da177e4SLinus Torvalds #include <linux/types.h> 301da177e4SLinus Torvalds #include <linux/sched.h> 316168a702SAndrew Morton #include <linux/interrupt.h> 321da177e4SLinus Torvalds #include <linux/kernel_stat.h> 331da177e4SLinus Torvalds #include <linux/errno.h> 341da177e4SLinus Torvalds #include <linux/init.h> 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #include <asm/setup.h> 371da177e4SLinus Torvalds #include <asm/system.h> 381da177e4SLinus Torvalds #include <asm/irq.h> 391da177e4SLinus Torvalds #include <asm/traps.h> 401da177e4SLinus Torvalds #include <asm/page.h> 411da177e4SLinus Torvalds #include <asm/machdep.h> 4268387c44SRoman Zippel #include <asm/cacheflush.h> 432850bc27SAl Viro #include <asm/irq_regs.h> 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #ifdef CONFIG_Q40 461da177e4SLinus Torvalds #include <asm/q40ints.h> 471da177e4SLinus Torvalds #endif 481da177e4SLinus Torvalds 4968387c44SRoman Zippel extern u32 auto_irqhandler_fixup[]; 5068387c44SRoman Zippel extern u32 user_irqhandler_fixup[]; 5168387c44SRoman Zippel extern u16 user_irqvec_fixup[]; 5268387c44SRoman Zippel 531da177e4SLinus Torvalds /* table for system interrupt handlers */ 546549d537SGeert Uytterhoeven static struct irq_data *irq_list[NR_IRQS]; 55c288bf25SGeert Uytterhoeven static struct irq_chip *irq_chip[NR_IRQS]; 5668387c44SRoman Zippel static int irq_depth[NR_IRQS]; 5768387c44SRoman Zippel 5840a72c8fSGeert Uytterhoeven static inline int irq_set_chip(unsigned int irq, struct irq_chip *chip) 5940a72c8fSGeert Uytterhoeven { 6040a72c8fSGeert Uytterhoeven irq_chip[irq] = chip; 6140a72c8fSGeert Uytterhoeven return 0; 6240a72c8fSGeert Uytterhoeven } 6340a72c8fSGeert Uytterhoeven 6468387c44SRoman Zippel static int m68k_first_user_vec; 65b5dc7840SRoman Zippel 66c288bf25SGeert Uytterhoeven static struct irq_chip auto_irq_chip = { 67b5dc7840SRoman Zippel .name = "auto", 68c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup, 69c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown, 70b5dc7840SRoman Zippel }; 711da177e4SLinus Torvalds 72c288bf25SGeert Uytterhoeven static struct irq_chip user_irq_chip = { 7368387c44SRoman Zippel .name = "user", 74c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup, 75c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown, 761da177e4SLinus Torvalds }; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds #define NUM_IRQ_NODES 100 796549d537SGeert Uytterhoeven static struct irq_data nodes[NUM_IRQ_NODES]; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds /* 821da177e4SLinus Torvalds * void init_IRQ(void) 831da177e4SLinus Torvalds * 841da177e4SLinus Torvalds * Parameters: None 851da177e4SLinus Torvalds * 861da177e4SLinus Torvalds * Returns: Nothing 871da177e4SLinus Torvalds * 881da177e4SLinus Torvalds * This function should be called during kernel startup to initialize 891da177e4SLinus Torvalds * the IRQ handling routines. 901da177e4SLinus Torvalds */ 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds void __init init_IRQ(void) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds int i; 951da177e4SLinus Torvalds 966d2f16a8SRoman Zippel /* assembly irq entry code relies on this... */ 976d2f16a8SRoman Zippel if (HARDIRQ_MASK != 0x00ff0000) { 986d2f16a8SRoman Zippel extern void hardirq_mask_is_broken(void); 996d2f16a8SRoman Zippel hardirq_mask_is_broken(); 1006d2f16a8SRoman Zippel } 1016d2f16a8SRoman Zippel 10268387c44SRoman Zippel for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) 10340a72c8fSGeert Uytterhoeven irq_set_chip(i, &auto_irq_chip); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds mach_init_IRQ(); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 10868387c44SRoman Zippel /** 10968387c44SRoman Zippel * m68k_setup_auto_interrupt 11068387c44SRoman Zippel * @handler: called from auto vector interrupts 11168387c44SRoman Zippel * 11268387c44SRoman Zippel * setup the handler to be called from auto vector interrupts instead of the 113*1425df87SGeert Uytterhoeven * standard do_IRQ(), it will be called with irq numbers in the range 11468387c44SRoman Zippel * from IRQ_AUTO_1 - IRQ_AUTO_7. 11568387c44SRoman Zippel */ 11668387c44SRoman Zippel void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) 11768387c44SRoman Zippel { 11868387c44SRoman Zippel if (handler) 11968387c44SRoman Zippel *auto_irqhandler_fixup = (u32)handler; 12068387c44SRoman Zippel flush_icache(); 12168387c44SRoman Zippel } 12268387c44SRoman Zippel 12368387c44SRoman Zippel /** 12468387c44SRoman Zippel * m68k_setup_user_interrupt 12568387c44SRoman Zippel * @vec: first user vector interrupt to handle 12668387c44SRoman Zippel * @cnt: number of active user vector interrupts 12768387c44SRoman Zippel * @handler: called from user vector interrupts 12868387c44SRoman Zippel * 12968387c44SRoman Zippel * setup user vector interrupts, this includes activating the specified range 13068387c44SRoman Zippel * of interrupts, only then these interrupts can be requested (note: this is 13168387c44SRoman Zippel * different from auto vector interrupts). An optional handler can be installed 132*1425df87SGeert Uytterhoeven * to be called instead of the default do_IRQ(), it will be called 13368387c44SRoman Zippel * with irq numbers starting from IRQ_USER. 13468387c44SRoman Zippel */ 13568387c44SRoman Zippel void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, 13668387c44SRoman Zippel void (*handler)(unsigned int, struct pt_regs *)) 13768387c44SRoman Zippel { 13868387c44SRoman Zippel int i; 13968387c44SRoman Zippel 14027123cbcSGeert Uytterhoeven BUG_ON(IRQ_USER + cnt > NR_IRQS); 14168387c44SRoman Zippel m68k_first_user_vec = vec; 14268387c44SRoman Zippel for (i = 0; i < cnt; i++) 14340a72c8fSGeert Uytterhoeven irq_set_chip(IRQ_USER + i, &user_irq_chip); 14468387c44SRoman Zippel *user_irqvec_fixup = vec - IRQ_USER; 14568387c44SRoman Zippel if (handler) 14668387c44SRoman Zippel *user_irqhandler_fixup = (u32)handler; 14768387c44SRoman Zippel flush_icache(); 14868387c44SRoman Zippel } 14968387c44SRoman Zippel 15068387c44SRoman Zippel /** 151c288bf25SGeert Uytterhoeven * m68k_setup_irq_chip 15268387c44SRoman Zippel * @contr: irq controller which controls specified irq 15368387c44SRoman Zippel * @irq: first irq to be managed by the controller 15468387c44SRoman Zippel * 15568387c44SRoman Zippel * Change the controller for the specified range of irq, which will be used to 15668387c44SRoman Zippel * manage these irq. auto/user irq already have a default controller, which can 15768387c44SRoman Zippel * be changed as well, but the controller probably should use m68k_irq_startup/ 15868387c44SRoman Zippel * m68k_irq_shutdown. 15968387c44SRoman Zippel */ 160c288bf25SGeert Uytterhoeven void m68k_setup_irq_chip(struct irq_chip *contr, unsigned int irq, 16168387c44SRoman Zippel unsigned int cnt) 16268387c44SRoman Zippel { 16368387c44SRoman Zippel int i; 16468387c44SRoman Zippel 16568387c44SRoman Zippel for (i = 0; i < cnt; i++) 16640a72c8fSGeert Uytterhoeven irq_set_chip(irq + i, contr); 16768387c44SRoman Zippel } 16868387c44SRoman Zippel 1696549d537SGeert Uytterhoeven struct irq_data *new_irq_node(void) 1701da177e4SLinus Torvalds { 1716549d537SGeert Uytterhoeven struct irq_data *node; 1721da177e4SLinus Torvalds short i; 1731da177e4SLinus Torvalds 174b5dc7840SRoman Zippel for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { 175b5dc7840SRoman Zippel if (!node->handler) { 176b5dc7840SRoman Zippel memset(node, 0, sizeof(*node)); 1771da177e4SLinus Torvalds return node; 178b5dc7840SRoman Zippel } 179b5dc7840SRoman Zippel } 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds printk ("new_irq_node: out of nodes\n"); 1821da177e4SLinus Torvalds return NULL; 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 18513d6da35SGeert Uytterhoeven static int m68k_setup_irq(unsigned int irq, struct irq_data *node) 186b5dc7840SRoman Zippel { 187c288bf25SGeert Uytterhoeven struct irq_chip *contr; 1886549d537SGeert Uytterhoeven struct irq_data **prev; 189b5dc7840SRoman Zippel unsigned long flags; 190b5dc7840SRoman Zippel 191c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 192b5dc7840SRoman Zippel printk("%s: Incorrect IRQ %d from %s\n", 193f85e7cdcSHarvey Harrison __func__, irq, node->devname); 194b5dc7840SRoman Zippel return -ENXIO; 195b5dc7840SRoman Zippel } 196b5dc7840SRoman Zippel 197c288bf25SGeert Uytterhoeven local_irq_save(flags); 198b5dc7840SRoman Zippel 199b5dc7840SRoman Zippel prev = irq_list + irq; 200b5dc7840SRoman Zippel if (*prev) { 201b5dc7840SRoman Zippel /* Can't share interrupts unless both agree to */ 202b0b9fdc1SThomas Gleixner if (!((*prev)->flags & node->flags & IRQF_SHARED)) { 203c288bf25SGeert Uytterhoeven local_irq_restore(flags); 204b5dc7840SRoman Zippel return -EBUSY; 205b5dc7840SRoman Zippel } 206b5dc7840SRoman Zippel while (*prev) 207b5dc7840SRoman Zippel prev = &(*prev)->next; 208b5dc7840SRoman Zippel } 209b5dc7840SRoman Zippel 210b5dc7840SRoman Zippel if (!irq_list[irq]) { 211c288bf25SGeert Uytterhoeven if (contr->irq_startup) 212e8abf5e7SGeert Uytterhoeven contr->irq_startup(node); 213b5dc7840SRoman Zippel else 214e8abf5e7SGeert Uytterhoeven contr->irq_enable(node); 215b5dc7840SRoman Zippel } 216b5dc7840SRoman Zippel node->next = NULL; 217b5dc7840SRoman Zippel *prev = node; 218b5dc7840SRoman Zippel 219c288bf25SGeert Uytterhoeven local_irq_restore(flags); 220b5dc7840SRoman Zippel 221b5dc7840SRoman Zippel return 0; 222b5dc7840SRoman Zippel } 223b5dc7840SRoman Zippel 22468387c44SRoman Zippel int request_irq(unsigned int irq, 22540220c1aSDavid Howells irq_handler_t handler, 2261da177e4SLinus Torvalds unsigned long flags, const char *devname, void *dev_id) 2271da177e4SLinus Torvalds { 2286549d537SGeert Uytterhoeven struct irq_data *node; 229b5dc7840SRoman Zippel int res; 2301da177e4SLinus Torvalds 231b5dc7840SRoman Zippel node = new_irq_node(); 232b5dc7840SRoman Zippel if (!node) 233b5dc7840SRoman Zippel return -ENOMEM; 2341da177e4SLinus Torvalds 2356549d537SGeert Uytterhoeven node->irq = irq; 236b5dc7840SRoman Zippel node->handler = handler; 237b5dc7840SRoman Zippel node->flags = flags; 238b5dc7840SRoman Zippel node->dev_id = dev_id; 239b5dc7840SRoman Zippel node->devname = devname; 240b5dc7840SRoman Zippel 24113d6da35SGeert Uytterhoeven res = m68k_setup_irq(irq, node); 242b5dc7840SRoman Zippel if (res) 243b5dc7840SRoman Zippel node->handler = NULL; 244b5dc7840SRoman Zippel 245b5dc7840SRoman Zippel return res; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds 24868387c44SRoman Zippel EXPORT_SYMBOL(request_irq); 24968387c44SRoman Zippel 25068387c44SRoman Zippel void free_irq(unsigned int irq, void *dev_id) 2511da177e4SLinus Torvalds { 252c288bf25SGeert Uytterhoeven struct irq_chip *contr; 2536549d537SGeert Uytterhoeven struct irq_data **p, *node; 254b5dc7840SRoman Zippel unsigned long flags; 255b5dc7840SRoman Zippel 256c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 257f85e7cdcSHarvey Harrison printk("%s: Incorrect IRQ %d\n", __func__, irq); 2581da177e4SLinus Torvalds return; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 261c288bf25SGeert Uytterhoeven local_irq_save(flags); 2621da177e4SLinus Torvalds 263b5dc7840SRoman Zippel p = irq_list + irq; 264b5dc7840SRoman Zippel while ((node = *p)) { 265b5dc7840SRoman Zippel if (node->dev_id == dev_id) 266b5dc7840SRoman Zippel break; 267b5dc7840SRoman Zippel p = &node->next; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 270b5dc7840SRoman Zippel if (node) { 271b5dc7840SRoman Zippel *p = node->next; 272b5dc7840SRoman Zippel node->handler = NULL; 273b5dc7840SRoman Zippel } else 274b5dc7840SRoman Zippel printk("%s: Removing probably wrong IRQ %d\n", 275f85e7cdcSHarvey Harrison __func__, irq); 276b5dc7840SRoman Zippel 27768387c44SRoman Zippel if (!irq_list[irq]) { 278c288bf25SGeert Uytterhoeven if (contr->irq_shutdown) 279e8abf5e7SGeert Uytterhoeven contr->irq_shutdown(node); 28068387c44SRoman Zippel else 281e8abf5e7SGeert Uytterhoeven contr->irq_disable(node); 28268387c44SRoman Zippel } 283b5dc7840SRoman Zippel 284c288bf25SGeert Uytterhoeven local_irq_restore(flags); 285b5dc7840SRoman Zippel } 286b5dc7840SRoman Zippel 28768387c44SRoman Zippel EXPORT_SYMBOL(free_irq); 28868387c44SRoman Zippel 28968387c44SRoman Zippel void enable_irq(unsigned int irq) 29068387c44SRoman Zippel { 291c288bf25SGeert Uytterhoeven struct irq_chip *contr; 29268387c44SRoman Zippel unsigned long flags; 29368387c44SRoman Zippel 294c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 29568387c44SRoman Zippel printk("%s: Incorrect IRQ %d\n", 296f85e7cdcSHarvey Harrison __func__, irq); 29768387c44SRoman Zippel return; 29868387c44SRoman Zippel } 29968387c44SRoman Zippel 300c288bf25SGeert Uytterhoeven local_irq_save(flags); 30168387c44SRoman Zippel if (irq_depth[irq]) { 30268387c44SRoman Zippel if (!--irq_depth[irq]) { 303c288bf25SGeert Uytterhoeven if (contr->irq_enable) 304e8abf5e7SGeert Uytterhoeven contr->irq_enable(irq_list[irq]); 30568387c44SRoman Zippel } 30668387c44SRoman Zippel } else 30768387c44SRoman Zippel WARN_ON(1); 308c288bf25SGeert Uytterhoeven local_irq_restore(flags); 30968387c44SRoman Zippel } 31068387c44SRoman Zippel 31168387c44SRoman Zippel EXPORT_SYMBOL(enable_irq); 31268387c44SRoman Zippel 31368387c44SRoman Zippel void disable_irq(unsigned int irq) 31468387c44SRoman Zippel { 315c288bf25SGeert Uytterhoeven struct irq_chip *contr; 31668387c44SRoman Zippel unsigned long flags; 31768387c44SRoman Zippel 318c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 31968387c44SRoman Zippel printk("%s: Incorrect IRQ %d\n", 320f85e7cdcSHarvey Harrison __func__, irq); 32168387c44SRoman Zippel return; 32268387c44SRoman Zippel } 32368387c44SRoman Zippel 324c288bf25SGeert Uytterhoeven local_irq_save(flags); 32568387c44SRoman Zippel if (!irq_depth[irq]++) { 326c288bf25SGeert Uytterhoeven if (contr->irq_disable) 327e8abf5e7SGeert Uytterhoeven contr->irq_disable(irq_list[irq]); 32868387c44SRoman Zippel } 329c288bf25SGeert Uytterhoeven local_irq_restore(flags); 33068387c44SRoman Zippel } 33168387c44SRoman Zippel 33268387c44SRoman Zippel EXPORT_SYMBOL(disable_irq); 33368387c44SRoman Zippel 334e9ed7e72SAl Viro void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq"))); 335e9ed7e72SAl Viro 336e9ed7e72SAl Viro EXPORT_SYMBOL(disable_irq_nosync); 337e9ed7e72SAl Viro 338e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup_irq(unsigned int irq) 339b5dc7840SRoman Zippel { 340b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7) 341b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = auto_inthandler; 34268387c44SRoman Zippel else 34368387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; 344b5dc7840SRoman Zippel return 0; 345b5dc7840SRoman Zippel } 346b5dc7840SRoman Zippel 347e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup(struct irq_data *data) 348b5dc7840SRoman Zippel { 349e8abf5e7SGeert Uytterhoeven return m68k_irq_startup_irq(data->irq); 350e8abf5e7SGeert Uytterhoeven } 351e8abf5e7SGeert Uytterhoeven 352e8abf5e7SGeert Uytterhoeven void m68k_irq_shutdown(struct irq_data *data) 353e8abf5e7SGeert Uytterhoeven { 354e8abf5e7SGeert Uytterhoeven unsigned int irq = data->irq; 355e8abf5e7SGeert Uytterhoeven 356b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7) 357b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = bad_inthandler; 35868387c44SRoman Zippel else 35968387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; 360b5dc7840SRoman Zippel } 361b5dc7840SRoman Zippel 362b5dc7840SRoman Zippel 3631da177e4SLinus Torvalds /* 3641da177e4SLinus Torvalds * Do we need these probe functions on the m68k? 3651da177e4SLinus Torvalds * 3661da177e4SLinus Torvalds * ... may be useful with ISA devices 3671da177e4SLinus Torvalds */ 3681da177e4SLinus Torvalds unsigned long probe_irq_on (void) 3691da177e4SLinus Torvalds { 3701da177e4SLinus Torvalds #ifdef CONFIG_Q40 3711da177e4SLinus Torvalds if (MACH_IS_Q40) 3721da177e4SLinus Torvalds return q40_probe_irq_on(); 3731da177e4SLinus Torvalds #endif 3741da177e4SLinus Torvalds return 0; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds EXPORT_SYMBOL(probe_irq_on); 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds int probe_irq_off (unsigned long irqs) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds #ifdef CONFIG_Q40 3821da177e4SLinus Torvalds if (MACH_IS_Q40) 3831da177e4SLinus Torvalds return q40_probe_irq_off(irqs); 3841da177e4SLinus Torvalds #endif 3851da177e4SLinus Torvalds return 0; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds EXPORT_SYMBOL(probe_irq_off); 3891da177e4SLinus Torvalds 39068387c44SRoman Zippel unsigned int irq_canonicalize(unsigned int irq) 3911da177e4SLinus Torvalds { 39268387c44SRoman Zippel #ifdef CONFIG_Q40 39368387c44SRoman Zippel if (MACH_IS_Q40 && irq == 11) 39468387c44SRoman Zippel irq = 10; 39568387c44SRoman Zippel #endif 39668387c44SRoman Zippel return irq; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 39968387c44SRoman Zippel EXPORT_SYMBOL(irq_canonicalize); 4001da177e4SLinus Torvalds 401*1425df87SGeert Uytterhoeven void generic_handle_irq(unsigned int irq) 4021da177e4SLinus Torvalds { 4036549d537SGeert Uytterhoeven struct irq_data *node; 40492445eaaSRoman Zippel kstat_cpu(0).irqs[irq]++; 405b5dc7840SRoman Zippel node = irq_list[irq]; 406b5dc7840SRoman Zippel do { 4072850bc27SAl Viro node->handler(irq, node->dev_id); 408b5dc7840SRoman Zippel node = node->next; 409b5dc7840SRoman Zippel } while (node); 4101da177e4SLinus Torvalds } 41192445eaaSRoman Zippel 412*1425df87SGeert Uytterhoeven asmlinkage void do_IRQ(int irq, struct pt_regs *regs) 4132850bc27SAl Viro { 4142850bc27SAl Viro struct pt_regs *old_regs; 4152850bc27SAl Viro old_regs = set_irq_regs(regs); 416*1425df87SGeert Uytterhoeven generic_handle_irq(irq); 4172850bc27SAl Viro set_irq_regs(old_regs); 4182850bc27SAl Viro } 4192850bc27SAl Viro 42092445eaaSRoman Zippel asmlinkage void handle_badint(struct pt_regs *regs) 42192445eaaSRoman Zippel { 42292445eaaSRoman Zippel kstat_cpu(0).irqs[0]++; 42392445eaaSRoman Zippel printk("unexpected interrupt from %u\n", regs->vector); 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds int show_interrupts(struct seq_file *p, void *v) 4271da177e4SLinus Torvalds { 428c288bf25SGeert Uytterhoeven struct irq_chip *contr; 4296549d537SGeert Uytterhoeven struct irq_data *node; 4301da177e4SLinus Torvalds int i = *(loff_t *) v; 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds /* autovector interrupts */ 43368387c44SRoman Zippel if (irq_list[i]) { 434c288bf25SGeert Uytterhoeven contr = irq_chip[i]; 435b5dc7840SRoman Zippel node = irq_list[i]; 43668387c44SRoman Zippel seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); 437b5dc7840SRoman Zippel while ((node = node->next)) 438b5dc7840SRoman Zippel seq_printf(p, ", %s", node->devname); 439b5dc7840SRoman Zippel seq_puts(p, "\n"); 44068387c44SRoman Zippel } 4411da177e4SLinus Torvalds return 0; 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds 444da9870e4SGeert Uytterhoeven #ifdef CONFIG_PROC_FS 4451da177e4SLinus Torvalds void init_irq_proc(void) 4461da177e4SLinus Torvalds { 4471da177e4SLinus Torvalds /* Insert /proc/irq driver here */ 4481da177e4SLinus Torvalds } 449da9870e4SGeert Uytterhoeven #endif 450