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