Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | /* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Code to handle x86 style IRQs plus some generic interrupt stuff. * * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle */ #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 <asm/uaccess.h> #ifdef CONFIG_KGDB int kgdb_early_setup; #endif static unsigned long irq_map[NR_IRQS / BITS_PER_LONG]; int allocate_irqno(void) { int irq; again: irq = find_first_zero_bit(irq_map, NR_IRQS); if (irq >= NR_IRQS) return -ENOSPC; if (test_and_set_bit(irq, irq_map)) goto again; return irq; } /* * Allocate the 16 legacy interrupts for i8259 devices. This happens early * in the kernel initialization so treating allocation failure as BUG() is * ok. */ void __init alloc_legacy_irqno(void) { int i; for (i = 0; i <= 16; i++) BUG_ON(test_and_set_bit(i, irq_map)); } void free_irqno(unsigned int irq) { smp_mb__before_clear_bit(); clear_bit(irq, irq_map); smp_mb__after_clear_bit(); } /* * '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) { smtc_im_ack_irq(irq); printk("unexpected IRQ # %d\n", irq); } atomic_t irq_err_count; /* * Generic, controller-independent functions: */ int show_interrupts(struct seq_file *p, void *v) { int i = *(loff_t *) v, j; struct irqaction * action; unsigned long flags; if (i == 0) { seq_printf(p, " "); for_each_online_cpu(j) seq_printf(p, "CPU%d ", j); seq_putc(p, '\n'); } if (i < NR_IRQS) { raw_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_each_online_cpu(j) seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); #endif seq_printf(p, " %14s", irq_desc[i].chip->name); 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: raw_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)); } return 0; } asmlinkage void spurious_interrupt(void) { atomic_inc(&irq_err_count); } void __init init_IRQ(void) { int i; #ifdef CONFIG_KGDB if (kgdb_early_setup) return; #endif for (i = 0; i < NR_IRQS; i++) set_irq_noprobe(i); arch_init_irq(); #ifdef CONFIG_KGDB if (!kgdb_early_setup) kgdb_early_setup = 1; #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(); __DO_IRQ_SMTC_HOOK(irq); generic_handle_irq(irq); irq_exit(); } #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF /* * To avoid inefficient and in some cases pathological re-checking of * IRQ affinity, we have this variant that skips the affinity check. */ void __irq_entry do_IRQ_no_affinity(unsigned int irq) { irq_enter(); __NO_AFFINITY_IRQ_SMTC_HOOK(irq); generic_handle_irq(irq); irq_exit(); } #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ |