]>
Commit | Line | Data |
---|---|---|
6b39ba77 TG |
1 | /* |
2 | * Common interrupt code for 32 and 64 bit | |
3 | */ | |
4 | #include <linux/cpu.h> | |
5 | #include <linux/interrupt.h> | |
6 | #include <linux/kernel_stat.h> | |
7 | #include <linux/seq_file.h> | |
6a02e710 | 8 | #include <linux/smp.h> |
6b39ba77 TG |
9 | |
10 | #include <asm/apic.h> | |
11 | #include <asm/io_apic.h> | |
c3d80000 | 12 | #include <asm/irq.h> |
6b39ba77 TG |
13 | |
14 | atomic_t irq_err_count; | |
15 | ||
249f6d9e TG |
16 | /* |
17 | * 'what should we do if we get a hw irq event on an illegal vector'. | |
18 | * each architecture has to answer this themselves. | |
19 | */ | |
20 | void ack_bad_irq(unsigned int irq) | |
21 | { | |
22 | printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); | |
23 | ||
24 | #ifdef CONFIG_X86_LOCAL_APIC | |
25 | /* | |
26 | * Currently unexpected vectors happen only on SMP and APIC. | |
27 | * We _must_ ack these because every local APIC has only N | |
28 | * irq slots per priority level, and a 'hanging, unacked' IRQ | |
29 | * holds up an irq slot - in excessive cases (when multiple | |
30 | * unexpected vectors occur) that might lock up the APIC | |
31 | * completely. | |
32 | * But only ack when the APIC is enabled -AK | |
33 | */ | |
34 | if (cpu_has_apic) | |
35 | ack_APIC_irq(); | |
36 | #endif | |
37 | } | |
38 | ||
1b437c8c | 39 | #define irq_stats(x) (&per_cpu(irq_stat, x)) |
6b39ba77 TG |
40 | /* |
41 | * /proc/interrupts printing: | |
42 | */ | |
43 | static int show_other_interrupts(struct seq_file *p) | |
44 | { | |
45 | int j; | |
46 | ||
47 | seq_printf(p, "NMI: "); | |
48 | for_each_online_cpu(j) | |
49 | seq_printf(p, "%10u ", irq_stats(j)->__nmi_count); | |
50 | seq_printf(p, " Non-maskable interrupts\n"); | |
51 | #ifdef CONFIG_X86_LOCAL_APIC | |
52 | seq_printf(p, "LOC: "); | |
53 | for_each_online_cpu(j) | |
54 | seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs); | |
55 | seq_printf(p, " Local timer interrupts\n"); | |
56 | #endif | |
57 | #ifdef CONFIG_SMP | |
58 | seq_printf(p, "RES: "); | |
59 | for_each_online_cpu(j) | |
60 | seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count); | |
61 | seq_printf(p, " Rescheduling interrupts\n"); | |
62 | seq_printf(p, "CAL: "); | |
63 | for_each_online_cpu(j) | |
64 | seq_printf(p, "%10u ", irq_stats(j)->irq_call_count); | |
65 | seq_printf(p, " Function call interrupts\n"); | |
66 | seq_printf(p, "TLB: "); | |
67 | for_each_online_cpu(j) | |
68 | seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count); | |
69 | seq_printf(p, " TLB shootdowns\n"); | |
70 | #endif | |
71 | #ifdef CONFIG_X86_MCE | |
72 | seq_printf(p, "TRM: "); | |
73 | for_each_online_cpu(j) | |
74 | seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count); | |
75 | seq_printf(p, " Thermal event interrupts\n"); | |
76 | # ifdef CONFIG_X86_64 | |
77 | seq_printf(p, "THR: "); | |
78 | for_each_online_cpu(j) | |
79 | seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count); | |
80 | seq_printf(p, " Threshold APIC interrupts\n"); | |
81 | # endif | |
82 | #endif | |
83 | #ifdef CONFIG_X86_LOCAL_APIC | |
84 | seq_printf(p, "SPU: "); | |
85 | for_each_online_cpu(j) | |
86 | seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count); | |
87 | seq_printf(p, " Spurious interrupts\n"); | |
88 | #endif | |
89 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | |
90 | #if defined(CONFIG_X86_IO_APIC) | |
91 | seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); | |
92 | #endif | |
93 | return 0; | |
94 | } | |
95 | ||
96 | int show_interrupts(struct seq_file *p, void *v) | |
97 | { | |
98 | unsigned long flags, any_count = 0; | |
99 | int i = *(loff_t *) v, j; | |
100 | struct irqaction *action; | |
101 | struct irq_desc *desc; | |
102 | ||
103 | if (i > nr_irqs) | |
104 | return 0; | |
105 | ||
106 | if (i == nr_irqs) | |
107 | return show_other_interrupts(p); | |
108 | ||
109 | /* print header */ | |
110 | if (i == 0) { | |
111 | seq_printf(p, " "); | |
112 | for_each_online_cpu(j) | |
e9f95e63 | 113 | seq_printf(p, "CPU%-8d", j); |
6b39ba77 TG |
114 | seq_putc(p, '\n'); |
115 | } | |
116 | ||
117 | desc = irq_to_desc(i); | |
0b8f1efa YL |
118 | if (!desc) |
119 | return 0; | |
120 | ||
6b39ba77 TG |
121 | spin_lock_irqsave(&desc->lock, flags); |
122 | #ifndef CONFIG_SMP | |
123 | any_count = kstat_irqs(i); | |
124 | #else | |
125 | for_each_online_cpu(j) | |
126 | any_count |= kstat_irqs_cpu(i, j); | |
127 | #endif | |
128 | action = desc->action; | |
129 | if (!action && !any_count) | |
130 | goto out; | |
131 | ||
132 | seq_printf(p, "%3d: ", i); | |
133 | #ifndef CONFIG_SMP | |
134 | seq_printf(p, "%10u ", kstat_irqs(i)); | |
135 | #else | |
136 | for_each_online_cpu(j) | |
137 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | |
138 | #endif | |
139 | seq_printf(p, " %8s", desc->chip->name); | |
140 | seq_printf(p, "-%-8s", desc->name); | |
141 | ||
142 | if (action) { | |
143 | seq_printf(p, " %s", action->name); | |
144 | while ((action = action->next) != NULL) | |
145 | seq_printf(p, ", %s", action->name); | |
146 | } | |
147 | ||
148 | seq_putc(p, '\n'); | |
149 | out: | |
150 | spin_unlock_irqrestore(&desc->lock, flags); | |
151 | return 0; | |
152 | } | |
153 | ||
154 | /* | |
155 | * /proc/stat helpers | |
156 | */ | |
157 | u64 arch_irq_stat_cpu(unsigned int cpu) | |
158 | { | |
159 | u64 sum = irq_stats(cpu)->__nmi_count; | |
160 | ||
161 | #ifdef CONFIG_X86_LOCAL_APIC | |
162 | sum += irq_stats(cpu)->apic_timer_irqs; | |
163 | #endif | |
164 | #ifdef CONFIG_SMP | |
165 | sum += irq_stats(cpu)->irq_resched_count; | |
166 | sum += irq_stats(cpu)->irq_call_count; | |
167 | sum += irq_stats(cpu)->irq_tlb_count; | |
168 | #endif | |
169 | #ifdef CONFIG_X86_MCE | |
170 | sum += irq_stats(cpu)->irq_thermal_count; | |
171 | # ifdef CONFIG_X86_64 | |
172 | sum += irq_stats(cpu)->irq_threshold_count; | |
173 | #endif | |
174 | #endif | |
175 | #ifdef CONFIG_X86_LOCAL_APIC | |
176 | sum += irq_stats(cpu)->irq_spurious_count; | |
177 | #endif | |
178 | return sum; | |
179 | } | |
180 | ||
181 | u64 arch_irq_stat(void) | |
182 | { | |
183 | u64 sum = atomic_read(&irq_err_count); | |
184 | ||
185 | #ifdef CONFIG_X86_IO_APIC | |
186 | sum += atomic_read(&irq_mis_count); | |
187 | #endif | |
188 | return sum; | |
189 | } | |
c3d80000 IM |
190 | |
191 | EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); |