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 91da177e4SLinus Torvalds #include <linux/module.h> 101da177e4SLinus Torvalds #include <linux/types.h> 111da177e4SLinus Torvalds #include <linux/sched.h> 126168a702SAndrew Morton #include <linux/interrupt.h> 131da177e4SLinus Torvalds #include <linux/kernel_stat.h> 141da177e4SLinus Torvalds #include <linux/errno.h> 151da177e4SLinus Torvalds #include <linux/init.h> 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <asm/setup.h> 181da177e4SLinus Torvalds #include <asm/system.h> 191da177e4SLinus Torvalds #include <asm/irq.h> 201da177e4SLinus Torvalds #include <asm/traps.h> 211da177e4SLinus Torvalds #include <asm/page.h> 221da177e4SLinus Torvalds #include <asm/machdep.h> 2368387c44SRoman Zippel #include <asm/cacheflush.h> 242850bc27SAl Viro #include <asm/irq_regs.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #ifdef CONFIG_Q40 271da177e4SLinus Torvalds #include <asm/q40ints.h> 281da177e4SLinus Torvalds #endif 291da177e4SLinus Torvalds 3068387c44SRoman Zippel extern u32 auto_irqhandler_fixup[]; 3168387c44SRoman Zippel extern u32 user_irqhandler_fixup[]; 3268387c44SRoman Zippel extern u16 user_irqvec_fixup[]; 3368387c44SRoman Zippel 34*4936f63cSGeert Uytterhoeven #ifndef CONFIG_GENERIC_HARDIRQS 351da177e4SLinus Torvalds /* table for system interrupt handlers */ 366549d537SGeert Uytterhoeven static struct irq_data *irq_list[NR_IRQS]; 37c288bf25SGeert Uytterhoeven static struct irq_chip *irq_chip[NR_IRQS]; 3868387c44SRoman Zippel static int irq_depth[NR_IRQS]; 3968387c44SRoman Zippel 4040a72c8fSGeert Uytterhoeven static inline int irq_set_chip(unsigned int irq, struct irq_chip *chip) 4140a72c8fSGeert Uytterhoeven { 4240a72c8fSGeert Uytterhoeven irq_chip[irq] = chip; 4340a72c8fSGeert Uytterhoeven return 0; 4440a72c8fSGeert Uytterhoeven } 45*4936f63cSGeert Uytterhoeven #define irq_set_chip_and_handler(irq, chip, dummy) irq_set_chip(irq, chip) 46*4936f63cSGeert Uytterhoeven #endif /* !CONFIG_GENERIC_HARDIRQS */ 4740a72c8fSGeert Uytterhoeven 4868387c44SRoman Zippel static int m68k_first_user_vec; 49b5dc7840SRoman Zippel 50c288bf25SGeert Uytterhoeven static struct irq_chip auto_irq_chip = { 51b5dc7840SRoman Zippel .name = "auto", 52c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup, 53c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown, 54b5dc7840SRoman Zippel }; 551da177e4SLinus Torvalds 56c288bf25SGeert Uytterhoeven static struct irq_chip user_irq_chip = { 5768387c44SRoman Zippel .name = "user", 58c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup, 59c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown, 601da177e4SLinus Torvalds }; 611da177e4SLinus Torvalds 62*4936f63cSGeert Uytterhoeven #ifndef CONFIG_GENERIC_HARDIRQS 631da177e4SLinus Torvalds #define NUM_IRQ_NODES 100 646549d537SGeert Uytterhoeven static struct irq_data nodes[NUM_IRQ_NODES]; 65*4936f63cSGeert Uytterhoeven #endif /* !CONFIG_GENERIC_HARDIRQS */ 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* 681da177e4SLinus Torvalds * void init_IRQ(void) 691da177e4SLinus Torvalds * 701da177e4SLinus Torvalds * Parameters: None 711da177e4SLinus Torvalds * 721da177e4SLinus Torvalds * Returns: Nothing 731da177e4SLinus Torvalds * 741da177e4SLinus Torvalds * This function should be called during kernel startup to initialize 751da177e4SLinus Torvalds * the IRQ handling routines. 761da177e4SLinus Torvalds */ 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds void __init init_IRQ(void) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds int i; 811da177e4SLinus Torvalds 826d2f16a8SRoman Zippel /* assembly irq entry code relies on this... */ 836d2f16a8SRoman Zippel if (HARDIRQ_MASK != 0x00ff0000) { 846d2f16a8SRoman Zippel extern void hardirq_mask_is_broken(void); 856d2f16a8SRoman Zippel hardirq_mask_is_broken(); 866d2f16a8SRoman Zippel } 876d2f16a8SRoman Zippel 8868387c44SRoman Zippel for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) 89*4936f63cSGeert Uytterhoeven irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds mach_init_IRQ(); 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 9468387c44SRoman Zippel /** 9568387c44SRoman Zippel * m68k_setup_auto_interrupt 9668387c44SRoman Zippel * @handler: called from auto vector interrupts 9768387c44SRoman Zippel * 9868387c44SRoman Zippel * setup the handler to be called from auto vector interrupts instead of the 991425df87SGeert Uytterhoeven * standard do_IRQ(), it will be called with irq numbers in the range 10068387c44SRoman Zippel * from IRQ_AUTO_1 - IRQ_AUTO_7. 10168387c44SRoman Zippel */ 10268387c44SRoman Zippel void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) 10368387c44SRoman Zippel { 10468387c44SRoman Zippel if (handler) 10568387c44SRoman Zippel *auto_irqhandler_fixup = (u32)handler; 10668387c44SRoman Zippel flush_icache(); 10768387c44SRoman Zippel } 10868387c44SRoman Zippel 10968387c44SRoman Zippel /** 11068387c44SRoman Zippel * m68k_setup_user_interrupt 11168387c44SRoman Zippel * @vec: first user vector interrupt to handle 11268387c44SRoman Zippel * @cnt: number of active user vector interrupts 11368387c44SRoman Zippel * @handler: called from user vector interrupts 11468387c44SRoman Zippel * 11568387c44SRoman Zippel * setup user vector interrupts, this includes activating the specified range 11668387c44SRoman Zippel * of interrupts, only then these interrupts can be requested (note: this is 11768387c44SRoman Zippel * different from auto vector interrupts). An optional handler can be installed 1181425df87SGeert Uytterhoeven * to be called instead of the default do_IRQ(), it will be called 11968387c44SRoman Zippel * with irq numbers starting from IRQ_USER. 12068387c44SRoman Zippel */ 12168387c44SRoman Zippel void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, 12268387c44SRoman Zippel void (*handler)(unsigned int, struct pt_regs *)) 12368387c44SRoman Zippel { 12468387c44SRoman Zippel int i; 12568387c44SRoman Zippel 12627123cbcSGeert Uytterhoeven BUG_ON(IRQ_USER + cnt > NR_IRQS); 12768387c44SRoman Zippel m68k_first_user_vec = vec; 12868387c44SRoman Zippel for (i = 0; i < cnt; i++) 12940a72c8fSGeert Uytterhoeven irq_set_chip(IRQ_USER + i, &user_irq_chip); 13068387c44SRoman Zippel *user_irqvec_fixup = vec - IRQ_USER; 13168387c44SRoman Zippel if (handler) 13268387c44SRoman Zippel *user_irqhandler_fixup = (u32)handler; 13368387c44SRoman Zippel flush_icache(); 13468387c44SRoman Zippel } 13568387c44SRoman Zippel 136*4936f63cSGeert Uytterhoeven #ifdef CONFIG_GENERIC_HARDIRQS 137*4936f63cSGeert Uytterhoeven 138*4936f63cSGeert Uytterhoeven /** 139*4936f63cSGeert Uytterhoeven * m68k_setup_irq_controller 140*4936f63cSGeert Uytterhoeven * @chip: irq chip which controls specified irq 141*4936f63cSGeert Uytterhoeven * @handle: flow handler which handles specified irq 142*4936f63cSGeert Uytterhoeven * @irq: first irq to be managed by the controller 143*4936f63cSGeert Uytterhoeven * @cnt: number of irqs to be managed by the controller 144*4936f63cSGeert Uytterhoeven * 145*4936f63cSGeert Uytterhoeven * Change the controller for the specified range of irq, which will be used to 146*4936f63cSGeert Uytterhoeven * manage these irq. auto/user irq already have a default controller, which can 147*4936f63cSGeert Uytterhoeven * be changed as well, but the controller probably should use m68k_irq_startup/ 148*4936f63cSGeert Uytterhoeven * m68k_irq_shutdown. 149*4936f63cSGeert Uytterhoeven */ 150*4936f63cSGeert Uytterhoeven void m68k_setup_irq_controller(struct irq_chip *chip, 151*4936f63cSGeert Uytterhoeven irq_flow_handler_t handle, unsigned int irq, 152*4936f63cSGeert Uytterhoeven unsigned int cnt) 153*4936f63cSGeert Uytterhoeven { 154*4936f63cSGeert Uytterhoeven int i; 155*4936f63cSGeert Uytterhoeven 156*4936f63cSGeert Uytterhoeven for (i = 0; i < cnt; i++) { 157*4936f63cSGeert Uytterhoeven irq_set_chip(irq + i, chip); 158*4936f63cSGeert Uytterhoeven if (handle) 159*4936f63cSGeert Uytterhoeven irq_set_handler(irq + i, handle); 160*4936f63cSGeert Uytterhoeven } 161*4936f63cSGeert Uytterhoeven } 162*4936f63cSGeert Uytterhoeven 163*4936f63cSGeert Uytterhoeven #else /* !CONFIG_GENERIC_HARDIRQS */ 164*4936f63cSGeert Uytterhoeven 16568387c44SRoman Zippel /** 166c288bf25SGeert Uytterhoeven * m68k_setup_irq_chip 16768387c44SRoman Zippel * @contr: irq controller which controls specified irq 16868387c44SRoman Zippel * @irq: first irq to be managed by the controller 16968387c44SRoman Zippel * 17068387c44SRoman Zippel * Change the controller for the specified range of irq, which will be used to 17168387c44SRoman Zippel * manage these irq. auto/user irq already have a default controller, which can 17268387c44SRoman Zippel * be changed as well, but the controller probably should use m68k_irq_startup/ 17368387c44SRoman Zippel * m68k_irq_shutdown. 17468387c44SRoman Zippel */ 175c288bf25SGeert Uytterhoeven void m68k_setup_irq_chip(struct irq_chip *contr, unsigned int irq, 17668387c44SRoman Zippel unsigned int cnt) 17768387c44SRoman Zippel { 17868387c44SRoman Zippel int i; 17968387c44SRoman Zippel 18068387c44SRoman Zippel for (i = 0; i < cnt; i++) 18140a72c8fSGeert Uytterhoeven irq_set_chip(irq + i, contr); 18268387c44SRoman Zippel } 18368387c44SRoman Zippel 1846549d537SGeert Uytterhoeven struct irq_data *new_irq_node(void) 1851da177e4SLinus Torvalds { 1866549d537SGeert Uytterhoeven struct irq_data *node; 1871da177e4SLinus Torvalds short i; 1881da177e4SLinus Torvalds 189b5dc7840SRoman Zippel for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { 190b5dc7840SRoman Zippel if (!node->handler) { 191b5dc7840SRoman Zippel memset(node, 0, sizeof(*node)); 1921da177e4SLinus Torvalds return node; 193b5dc7840SRoman Zippel } 194b5dc7840SRoman Zippel } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds printk ("new_irq_node: out of nodes\n"); 1971da177e4SLinus Torvalds return NULL; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 20013d6da35SGeert Uytterhoeven static int m68k_setup_irq(unsigned int irq, struct irq_data *node) 201b5dc7840SRoman Zippel { 202c288bf25SGeert Uytterhoeven struct irq_chip *contr; 2036549d537SGeert Uytterhoeven struct irq_data **prev; 204b5dc7840SRoman Zippel unsigned long flags; 205b5dc7840SRoman Zippel 206c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 207b5dc7840SRoman Zippel printk("%s: Incorrect IRQ %d from %s\n", 208f85e7cdcSHarvey Harrison __func__, irq, node->devname); 209b5dc7840SRoman Zippel return -ENXIO; 210b5dc7840SRoman Zippel } 211b5dc7840SRoman Zippel 212c288bf25SGeert Uytterhoeven local_irq_save(flags); 213b5dc7840SRoman Zippel 214b5dc7840SRoman Zippel prev = irq_list + irq; 215b5dc7840SRoman Zippel if (*prev) { 216b5dc7840SRoman Zippel /* Can't share interrupts unless both agree to */ 217b0b9fdc1SThomas Gleixner if (!((*prev)->flags & node->flags & IRQF_SHARED)) { 218c288bf25SGeert Uytterhoeven local_irq_restore(flags); 219b5dc7840SRoman Zippel return -EBUSY; 220b5dc7840SRoman Zippel } 221b5dc7840SRoman Zippel while (*prev) 222b5dc7840SRoman Zippel prev = &(*prev)->next; 223b5dc7840SRoman Zippel } 224b5dc7840SRoman Zippel 225b5dc7840SRoman Zippel if (!irq_list[irq]) { 226c288bf25SGeert Uytterhoeven if (contr->irq_startup) 227e8abf5e7SGeert Uytterhoeven contr->irq_startup(node); 228b5dc7840SRoman Zippel else 229e8abf5e7SGeert Uytterhoeven contr->irq_enable(node); 230b5dc7840SRoman Zippel } 231b5dc7840SRoman Zippel node->next = NULL; 232b5dc7840SRoman Zippel *prev = node; 233b5dc7840SRoman Zippel 234c288bf25SGeert Uytterhoeven local_irq_restore(flags); 235b5dc7840SRoman Zippel 236b5dc7840SRoman Zippel return 0; 237b5dc7840SRoman Zippel } 238b5dc7840SRoman Zippel 23968387c44SRoman Zippel int request_irq(unsigned int irq, 24040220c1aSDavid Howells irq_handler_t handler, 2411da177e4SLinus Torvalds unsigned long flags, const char *devname, void *dev_id) 2421da177e4SLinus Torvalds { 2436549d537SGeert Uytterhoeven struct irq_data *node; 244b5dc7840SRoman Zippel int res; 2451da177e4SLinus Torvalds 246b5dc7840SRoman Zippel node = new_irq_node(); 247b5dc7840SRoman Zippel if (!node) 248b5dc7840SRoman Zippel return -ENOMEM; 2491da177e4SLinus Torvalds 2506549d537SGeert Uytterhoeven node->irq = irq; 251b5dc7840SRoman Zippel node->handler = handler; 252b5dc7840SRoman Zippel node->flags = flags; 253b5dc7840SRoman Zippel node->dev_id = dev_id; 254b5dc7840SRoman Zippel node->devname = devname; 255b5dc7840SRoman Zippel 25613d6da35SGeert Uytterhoeven res = m68k_setup_irq(irq, node); 257b5dc7840SRoman Zippel if (res) 258b5dc7840SRoman Zippel node->handler = NULL; 259b5dc7840SRoman Zippel 260b5dc7840SRoman Zippel return res; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 26368387c44SRoman Zippel EXPORT_SYMBOL(request_irq); 26468387c44SRoman Zippel 26568387c44SRoman Zippel void free_irq(unsigned int irq, void *dev_id) 2661da177e4SLinus Torvalds { 267c288bf25SGeert Uytterhoeven struct irq_chip *contr; 2686549d537SGeert Uytterhoeven struct irq_data **p, *node; 269b5dc7840SRoman Zippel unsigned long flags; 270b5dc7840SRoman Zippel 271c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 272f85e7cdcSHarvey Harrison printk("%s: Incorrect IRQ %d\n", __func__, irq); 2731da177e4SLinus Torvalds return; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 276c288bf25SGeert Uytterhoeven local_irq_save(flags); 2771da177e4SLinus Torvalds 278b5dc7840SRoman Zippel p = irq_list + irq; 279b5dc7840SRoman Zippel while ((node = *p)) { 280b5dc7840SRoman Zippel if (node->dev_id == dev_id) 281b5dc7840SRoman Zippel break; 282b5dc7840SRoman Zippel p = &node->next; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds 285b5dc7840SRoman Zippel if (node) { 286b5dc7840SRoman Zippel *p = node->next; 287b5dc7840SRoman Zippel node->handler = NULL; 288b5dc7840SRoman Zippel } else 289b5dc7840SRoman Zippel printk("%s: Removing probably wrong IRQ %d\n", 290f85e7cdcSHarvey Harrison __func__, irq); 291b5dc7840SRoman Zippel 29268387c44SRoman Zippel if (!irq_list[irq]) { 293c288bf25SGeert Uytterhoeven if (contr->irq_shutdown) 294e8abf5e7SGeert Uytterhoeven contr->irq_shutdown(node); 29568387c44SRoman Zippel else 296e8abf5e7SGeert Uytterhoeven contr->irq_disable(node); 29768387c44SRoman Zippel } 298b5dc7840SRoman Zippel 299c288bf25SGeert Uytterhoeven local_irq_restore(flags); 300b5dc7840SRoman Zippel } 301b5dc7840SRoman Zippel 30268387c44SRoman Zippel EXPORT_SYMBOL(free_irq); 30368387c44SRoman Zippel 30468387c44SRoman Zippel void enable_irq(unsigned int irq) 30568387c44SRoman Zippel { 306c288bf25SGeert Uytterhoeven struct irq_chip *contr; 30768387c44SRoman Zippel unsigned long flags; 30868387c44SRoman Zippel 309c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 31068387c44SRoman Zippel printk("%s: Incorrect IRQ %d\n", 311f85e7cdcSHarvey Harrison __func__, irq); 31268387c44SRoman Zippel return; 31368387c44SRoman Zippel } 31468387c44SRoman Zippel 315c288bf25SGeert Uytterhoeven local_irq_save(flags); 31668387c44SRoman Zippel if (irq_depth[irq]) { 31768387c44SRoman Zippel if (!--irq_depth[irq]) { 318c288bf25SGeert Uytterhoeven if (contr->irq_enable) 319e8abf5e7SGeert Uytterhoeven contr->irq_enable(irq_list[irq]); 32068387c44SRoman Zippel } 32168387c44SRoman Zippel } else 32268387c44SRoman Zippel WARN_ON(1); 323c288bf25SGeert Uytterhoeven local_irq_restore(flags); 32468387c44SRoman Zippel } 32568387c44SRoman Zippel 32668387c44SRoman Zippel EXPORT_SYMBOL(enable_irq); 32768387c44SRoman Zippel 32868387c44SRoman Zippel void disable_irq(unsigned int irq) 32968387c44SRoman Zippel { 330c288bf25SGeert Uytterhoeven struct irq_chip *contr; 33168387c44SRoman Zippel unsigned long flags; 33268387c44SRoman Zippel 333c288bf25SGeert Uytterhoeven if (irq >= NR_IRQS || !(contr = irq_chip[irq])) { 33468387c44SRoman Zippel printk("%s: Incorrect IRQ %d\n", 335f85e7cdcSHarvey Harrison __func__, irq); 33668387c44SRoman Zippel return; 33768387c44SRoman Zippel } 33868387c44SRoman Zippel 339c288bf25SGeert Uytterhoeven local_irq_save(flags); 34068387c44SRoman Zippel if (!irq_depth[irq]++) { 341c288bf25SGeert Uytterhoeven if (contr->irq_disable) 342e8abf5e7SGeert Uytterhoeven contr->irq_disable(irq_list[irq]); 34368387c44SRoman Zippel } 344c288bf25SGeert Uytterhoeven local_irq_restore(flags); 34568387c44SRoman Zippel } 34668387c44SRoman Zippel 34768387c44SRoman Zippel EXPORT_SYMBOL(disable_irq); 34868387c44SRoman Zippel 349e9ed7e72SAl Viro void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq"))); 350e9ed7e72SAl Viro 351e9ed7e72SAl Viro EXPORT_SYMBOL(disable_irq_nosync); 352e9ed7e72SAl Viro 353*4936f63cSGeert Uytterhoeven #endif /* !CONFIG_GENERIC_HARDIRQS */ 354*4936f63cSGeert Uytterhoeven 355e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup_irq(unsigned int irq) 356b5dc7840SRoman Zippel { 357b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7) 358b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = auto_inthandler; 35968387c44SRoman Zippel else 36068387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; 361b5dc7840SRoman Zippel return 0; 362b5dc7840SRoman Zippel } 363b5dc7840SRoman Zippel 364e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup(struct irq_data *data) 365b5dc7840SRoman Zippel { 366e8abf5e7SGeert Uytterhoeven return m68k_irq_startup_irq(data->irq); 367e8abf5e7SGeert Uytterhoeven } 368e8abf5e7SGeert Uytterhoeven 369e8abf5e7SGeert Uytterhoeven void m68k_irq_shutdown(struct irq_data *data) 370e8abf5e7SGeert Uytterhoeven { 371e8abf5e7SGeert Uytterhoeven unsigned int irq = data->irq; 372e8abf5e7SGeert Uytterhoeven 373b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7) 374b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = bad_inthandler; 37568387c44SRoman Zippel else 37668387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; 377b5dc7840SRoman Zippel } 378b5dc7840SRoman Zippel 379b5dc7840SRoman Zippel 380*4936f63cSGeert Uytterhoeven #ifndef CONFIG_GENERIC_HARDIRQS 381*4936f63cSGeert Uytterhoeven 3821da177e4SLinus Torvalds /* 3831da177e4SLinus Torvalds * Do we need these probe functions on the m68k? 3841da177e4SLinus Torvalds * 3851da177e4SLinus Torvalds * ... may be useful with ISA devices 3861da177e4SLinus Torvalds */ 3871da177e4SLinus Torvalds unsigned long probe_irq_on (void) 3881da177e4SLinus Torvalds { 3891da177e4SLinus Torvalds #ifdef CONFIG_Q40 3901da177e4SLinus Torvalds if (MACH_IS_Q40) 3911da177e4SLinus Torvalds return q40_probe_irq_on(); 3921da177e4SLinus Torvalds #endif 3931da177e4SLinus Torvalds return 0; 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds EXPORT_SYMBOL(probe_irq_on); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds int probe_irq_off (unsigned long irqs) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds #ifdef CONFIG_Q40 4011da177e4SLinus Torvalds if (MACH_IS_Q40) 4021da177e4SLinus Torvalds return q40_probe_irq_off(irqs); 4031da177e4SLinus Torvalds #endif 4041da177e4SLinus Torvalds return 0; 4051da177e4SLinus Torvalds } 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds EXPORT_SYMBOL(probe_irq_off); 408*4936f63cSGeert Uytterhoeven #endif /* CONFIG_GENERIC_HARDIRQS */ 4091da177e4SLinus Torvalds 41068387c44SRoman Zippel unsigned int irq_canonicalize(unsigned int irq) 4111da177e4SLinus Torvalds { 41268387c44SRoman Zippel #ifdef CONFIG_Q40 41368387c44SRoman Zippel if (MACH_IS_Q40 && irq == 11) 41468387c44SRoman Zippel irq = 10; 41568387c44SRoman Zippel #endif 41668387c44SRoman Zippel return irq; 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 41968387c44SRoman Zippel EXPORT_SYMBOL(irq_canonicalize); 4201da177e4SLinus Torvalds 421*4936f63cSGeert Uytterhoeven #ifndef CONFIG_GENERIC_HARDIRQS 4221425df87SGeert Uytterhoeven void generic_handle_irq(unsigned int irq) 4231da177e4SLinus Torvalds { 4246549d537SGeert Uytterhoeven struct irq_data *node; 42592445eaaSRoman Zippel kstat_cpu(0).irqs[irq]++; 426b5dc7840SRoman Zippel node = irq_list[irq]; 427b5dc7840SRoman Zippel do { 4282850bc27SAl Viro node->handler(irq, node->dev_id); 429b5dc7840SRoman Zippel node = node->next; 430b5dc7840SRoman Zippel } while (node); 4311da177e4SLinus Torvalds } 43292445eaaSRoman Zippel 4331425df87SGeert Uytterhoeven asmlinkage void do_IRQ(int irq, struct pt_regs *regs) 4342850bc27SAl Viro { 4352850bc27SAl Viro struct pt_regs *old_regs; 4362850bc27SAl Viro old_regs = set_irq_regs(regs); 4371425df87SGeert Uytterhoeven generic_handle_irq(irq); 4382850bc27SAl Viro set_irq_regs(old_regs); 4392850bc27SAl Viro } 4402850bc27SAl Viro 44192445eaaSRoman Zippel asmlinkage void handle_badint(struct pt_regs *regs) 44292445eaaSRoman Zippel { 44392445eaaSRoman Zippel kstat_cpu(0).irqs[0]++; 44492445eaaSRoman Zippel printk("unexpected interrupt from %u\n", regs->vector); 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds int show_interrupts(struct seq_file *p, void *v) 4481da177e4SLinus Torvalds { 449c288bf25SGeert Uytterhoeven struct irq_chip *contr; 4506549d537SGeert Uytterhoeven struct irq_data *node; 4511da177e4SLinus Torvalds int i = *(loff_t *) v; 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds /* autovector interrupts */ 45468387c44SRoman Zippel if (irq_list[i]) { 455c288bf25SGeert Uytterhoeven contr = irq_chip[i]; 456b5dc7840SRoman Zippel node = irq_list[i]; 45768387c44SRoman Zippel seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); 458b5dc7840SRoman Zippel while ((node = node->next)) 459b5dc7840SRoman Zippel seq_printf(p, ", %s", node->devname); 460b5dc7840SRoman Zippel seq_puts(p, "\n"); 46168387c44SRoman Zippel } 4621da177e4SLinus Torvalds return 0; 4631da177e4SLinus Torvalds } 4641da177e4SLinus Torvalds 465da9870e4SGeert Uytterhoeven #ifdef CONFIG_PROC_FS 4661da177e4SLinus Torvalds void init_irq_proc(void) 4671da177e4SLinus Torvalds { 4681da177e4SLinus Torvalds /* Insert /proc/irq driver here */ 4691da177e4SLinus Torvalds } 470da9870e4SGeert Uytterhoeven #endif 471*4936f63cSGeert Uytterhoeven 472*4936f63cSGeert Uytterhoeven #else /* CONFIG_GENERIC_HARDIRQS */ 473*4936f63cSGeert Uytterhoeven 474*4936f63cSGeert Uytterhoeven asmlinkage void handle_badint(struct pt_regs *regs) 475*4936f63cSGeert Uytterhoeven { 476*4936f63cSGeert Uytterhoeven atomic_inc(&irq_err_count); 477*4936f63cSGeert Uytterhoeven pr_warn("unexpected interrupt from %u\n", regs->vector); 478*4936f63cSGeert Uytterhoeven } 479*4936f63cSGeert Uytterhoeven 480*4936f63cSGeert Uytterhoeven #endif /* CONFIG_GENERIC_HARDIRQS */ 481