]>
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> | |
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 | ||
6b39ba77 | 39 | #ifdef CONFIG_X86_32 |
e9f95e63 | 40 | # define irq_stats(x) (&per_cpu(irq_stat, x)) |
6b39ba77 TG |
41 | #else |
42 | # define irq_stats(x) cpu_pda(x) | |
43 | #endif | |
44 | /* | |
45 | * /proc/interrupts printing: | |
46 | */ | |
47 | static int show_other_interrupts(struct seq_file *p) | |
48 | { | |
49 | int j; | |
50 | ||
51 | seq_printf(p, "NMI: "); | |
52 | for_each_online_cpu(j) | |
53 | seq_printf(p, "%10u ", irq_stats(j)->__nmi_count); | |
54 | seq_printf(p, " Non-maskable interrupts\n"); | |
55 | #ifdef CONFIG_X86_LOCAL_APIC | |
56 | seq_printf(p, "LOC: "); | |
57 | for_each_online_cpu(j) | |
58 | seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs); | |
59 | seq_printf(p, " Local timer interrupts\n"); | |
60 | #endif | |
61 | #ifdef CONFIG_SMP | |
62 | seq_printf(p, "RES: "); | |
63 | for_each_online_cpu(j) | |
64 | seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count); | |
65 | seq_printf(p, " Rescheduling interrupts\n"); | |
66 | seq_printf(p, "CAL: "); | |
67 | for_each_online_cpu(j) | |
68 | seq_printf(p, "%10u ", irq_stats(j)->irq_call_count); | |
69 | seq_printf(p, " Function call interrupts\n"); | |
70 | seq_printf(p, "TLB: "); | |
71 | for_each_online_cpu(j) | |
72 | seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count); | |
73 | seq_printf(p, " TLB shootdowns\n"); | |
74 | #endif | |
75 | #ifdef CONFIG_X86_MCE | |
76 | seq_printf(p, "TRM: "); | |
77 | for_each_online_cpu(j) | |
78 | seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count); | |
79 | seq_printf(p, " Thermal event interrupts\n"); | |
80 | # ifdef CONFIG_X86_64 | |
81 | seq_printf(p, "THR: "); | |
82 | for_each_online_cpu(j) | |
83 | seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count); | |
84 | seq_printf(p, " Threshold APIC interrupts\n"); | |
85 | # endif | |
86 | #endif | |
87 | #ifdef CONFIG_X86_LOCAL_APIC | |
88 | seq_printf(p, "SPU: "); | |
89 | for_each_online_cpu(j) | |
90 | seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count); | |
91 | seq_printf(p, " Spurious interrupts\n"); | |
92 | #endif | |
93 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | |
94 | #if defined(CONFIG_X86_IO_APIC) | |
95 | seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); | |
96 | #endif | |
97 | return 0; | |
98 | } | |
99 | ||
100 | int show_interrupts(struct seq_file *p, void *v) | |
101 | { | |
102 | unsigned long flags, any_count = 0; | |
103 | int i = *(loff_t *) v, j; | |
104 | struct irqaction *action; | |
105 | struct irq_desc *desc; | |
106 | ||
107 | if (i > nr_irqs) | |
108 | return 0; | |
109 | ||
110 | if (i == nr_irqs) | |
111 | return show_other_interrupts(p); | |
112 | ||
113 | /* print header */ | |
114 | if (i == 0) { | |
115 | seq_printf(p, " "); | |
116 | for_each_online_cpu(j) | |
e9f95e63 | 117 | seq_printf(p, "CPU%-8d", j); |
6b39ba77 TG |
118 | seq_putc(p, '\n'); |
119 | } | |
120 | ||
121 | desc = irq_to_desc(i); | |
0b8f1efa YL |
122 | if (!desc) |
123 | return 0; | |
124 | ||
6b39ba77 TG |
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; | |
167 | #endif | |
168 | #ifdef CONFIG_SMP | |
169 | sum += irq_stats(cpu)->irq_resched_count; | |
170 | sum += irq_stats(cpu)->irq_call_count; | |
171 | sum += irq_stats(cpu)->irq_tlb_count; | |
172 | #endif | |
173 | #ifdef CONFIG_X86_MCE | |
174 | sum += irq_stats(cpu)->irq_thermal_count; | |
175 | # ifdef CONFIG_X86_64 | |
176 | sum += irq_stats(cpu)->irq_threshold_count; | |
177 | #endif | |
178 | #endif | |
179 | #ifdef CONFIG_X86_LOCAL_APIC | |
180 | sum += irq_stats(cpu)->irq_spurious_count; | |
181 | #endif | |
182 | return sum; | |
183 | } | |
184 | ||
185 | u64 arch_irq_stat(void) | |
186 | { | |
187 | u64 sum = atomic_read(&irq_err_count); | |
188 | ||
189 | #ifdef CONFIG_X86_IO_APIC | |
190 | sum += atomic_read(&irq_mis_count); | |
191 | #endif | |
192 | return sum; | |
193 | } | |
c3d80000 IM |
194 | |
195 | EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); |