diff options
Diffstat (limited to 'arch/mips/kernel/irq.c')
| -rw-r--r-- | arch/mips/kernel/irq.c | 175 |
1 files changed, 91 insertions, 84 deletions
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 7d93992e462..d2bfbc2e899 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -8,133 +8,140 @@ * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> -#include <linux/module.h> #include <linux/proc_fs.h> -#include <linux/slab.h> #include <linux/mm.h> #include <linux/random.h> #include <linux/sched.h> #include <linux/seq_file.h> #include <linux/kallsyms.h> +#include <linux/kgdb.h> +#include <linux/ftrace.h> -#include <asm/atomic.h> -#include <asm/system.h> +#include <linux/atomic.h> #include <asm/uaccess.h> -/* - * 'what should we do if we get a hw irq event on an illegal vector'. - * each architecture has to answer this themselves. - */ -void ack_bad_irq(unsigned int irq) +#ifdef CONFIG_KGDB +int kgdb_early_setup; +#endif + +static unsigned long irq_map[NR_IRQS / BITS_PER_LONG]; + +int allocate_irqno(void) { - printk("unexpected IRQ # %d\n", irq); -} + int irq; -atomic_t irq_err_count; +again: + irq = find_first_zero_bit(irq_map, NR_IRQS); -#undef do_IRQ + if (irq >= NR_IRQS) + return -ENOSPC; + + if (test_and_set_bit(irq, irq_map)) + goto again; + + return irq; +} /* - * do_IRQ handles all normal device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). + * Allocate the 16 legacy interrupts for i8259 devices. This happens early + * in the kernel initialization so treating allocation failure as BUG() is + * ok. */ -asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs) +void __init alloc_legacy_irqno(void) { - irq_enter(); - - __do_IRQ(irq, regs); + int i; - irq_exit(); + for (i = 0; i <= 16; i++) + BUG_ON(test_and_set_bit(i, irq_map)); +} - return 1; +void free_irqno(unsigned int irq) +{ + smp_mb__before_atomic(); + clear_bit(irq, irq_map); + smp_mb__after_atomic(); } /* - * Generic, controller-independent functions: + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves. */ - -int show_interrupts(struct seq_file *p, void *v) +void ack_bad_irq(unsigned int irq) { - int i = *(loff_t *) v, j; - struct irqaction * action; - unsigned long flags; - - if (i == 0) { - seq_printf(p, " "); - for (j=0; j<NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); - seq_putc(p, '\n'); - } + printk("unexpected IRQ # %d\n", irq); +} - if (i < NR_IRQS) { - spin_lock_irqsave(&irq_desc[i].lock, flags); - action = irq_desc[i].action; - if (!action) - goto skip; - seq_printf(p, "%3d: ",i); -#ifndef CONFIG_SMP - seq_printf(p, "%10u ", kstat_irqs(i)); -#else - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); -#endif - seq_printf(p, " %14s", irq_desc[i].handler->typename); - seq_printf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - seq_printf(p, ", %s", action->name); - - seq_putc(p, '\n'); -skip: - spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } else if (i == NR_IRQS) { - seq_putc(p, '\n'); - seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); - } +atomic_t irq_err_count; + +int arch_show_interrupts(struct seq_file *p, int prec) +{ + seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); return 0; } -#ifdef CONFIG_KGDB -extern void breakpoint(void); -extern void set_debug_traps(void); - -static int kgdb_flag = 1; -static int __init nokgdb(char *str) +asmlinkage void spurious_interrupt(void) { - kgdb_flag = 0; - return 1; + atomic_inc(&irq_err_count); } -__setup("nokgdb", nokgdb); -#endif void __init init_IRQ(void) { int i; - for (i = 0; i < NR_IRQS; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &no_irq_type; - spin_lock_init(&irq_desc[i].lock); - } +#ifdef CONFIG_KGDB + if (kgdb_early_setup) + return; +#endif + + for (i = 0; i < NR_IRQS; i++) + irq_set_noprobe(i); arch_init_irq(); #ifdef CONFIG_KGDB - if (kgdb_flag) { - printk("Wait for gdb client connection ...\n"); - set_debug_traps(); - breakpoint(); + if (!kgdb_early_setup) + kgdb_early_setup = 1; +#endif +} + +#ifdef DEBUG_STACKOVERFLOW +static inline void check_stack_overflow(void) +{ + unsigned long sp; + + __asm__ __volatile__("move %0, $sp" : "=r" (sp)); + sp &= THREAD_MASK; + + /* + * Check for stack overflow: is there less than STACK_WARN free? + * STACK_WARN is defined as 1/8 of THREAD_SIZE by default. + */ + if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { + printk("do_IRQ: stack overflow: %ld\n", + sp - sizeof(struct thread_info)); + dump_stack(); } +} +#else +static inline void check_stack_overflow(void) {} #endif + + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +void __irq_entry do_IRQ(unsigned int irq) +{ + irq_enter(); + check_stack_overflow(); + generic_handle_irq(irq); + irq_exit(); } + |
