aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Korty <joe.korty@ccur.com>2007-10-17 12:04:40 -0400
committerThomas Gleixner <tglx@inhelltoy.tec.linutronix.de>2007-10-17 14:16:53 -0400
commit38e760a1335ffaca5a08624a9aed6fe2055c2c98 (patch)
treec313888b750a56db7c9c09c8af5be830bb75b81e
parent9aa8d7195acb18fc436847f6c66a97f8359ad54d (diff)
x86: expand /proc/interrupts to include missing vectors, v2
Add missing IRQs and IRQ descriptions to /proc/interrupts. /proc/interrupts is most useful when it displays every IRQ vector in use by the system, not just those somebody thought would be interesting. This patch inserts the following vector displays to the i386 and x86_64 platforms, as appropriate: rescheduling interrupts TLB flush interrupts function call interrupts thermal event interrupts threshold interrupts spurious interrupts A threshold interrupt occurs when ECC memory correction is occuring at too high a frequency. Thresholds are used by the ECC hardware as occasional ECC failures are part of normal operation, but long sequences of ECC failures usually indicate a memory chip that is about to fail. Thermal event interrupts occur when a temperature threshold has been exceeded for some CPU chip. IIRC, a thermal interrupt is also generated when the temperature drops back to a normal level. A spurious interrupt is an interrupt that was raised then lowered by the device before it could be fully processed by the APIC. Hence the apic sees the interrupt but does not know what device it came from. For this case the APIC hardware will assume a vector of 0xff. Rescheduling, call, and TLB flush interrupts are sent from one CPU to another per the needs of the OS. Typically, their statistics would be used to discover if an interrupt flood of the given type has been occuring. AK: merged v2 and v4 which had some more tweaks AK: replace Local interrupts with Local timer interrupts AK: Fixed description of interrupt types. [ tglx: arch/x86 adaptation ] [ mingo: small cleanup ] Signed-off-by: Joe Korty <joe.korty@ccur.com> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Tim Hockin <thockin@hockin.org> Cc: Andi Kleen <ak@suse.de> Cc: Ingo Molnar <mingo@elte.hu> Cc: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--Documentation/filesystems/proc.txt30
-rw-r--r--arch/x86/kernel/apic_32.c1
-rw-r--r--arch/x86/kernel/apic_64.c1
-rw-r--r--arch/x86/kernel/cpu/mcheck/p4.c1
-rw-r--r--arch/x86/kernel/irq_32.c31
-rw-r--r--arch/x86/kernel/irq_64.c30
-rw-r--r--arch/x86/kernel/mce_amd_64.c1
-rw-r--r--arch/x86/kernel/mce_intel_64.c1
-rw-r--r--arch/x86/kernel/smp_32.c3
-rw-r--r--arch/x86/kernel/smp_64.c3
-rw-r--r--arch/x86/mach-voyager/voyager_smp.c1
-rw-r--r--arch/x86/xen/smp.c1
-rw-r--r--include/asm-x86/hardirq_32.h5
-rw-r--r--include/asm-x86/pda.h6
14 files changed, 110 insertions, 5 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 4a37e25e694c..e5c1df52a876 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -347,7 +347,35 @@ connects the CPUs in a SMP system. This means that an error has been detected,
347the IO-APIC automatically retry the transmission, so it should not be a big 347the IO-APIC automatically retry the transmission, so it should not be a big
348problem, but you should read the SMP-FAQ. 348problem, but you should read the SMP-FAQ.
349 349
350In this context it could be interesting to note the new irq directory in 2.4. 350In 2.6.2* /proc/interrupts was expanded again. This time the goal was for
351/proc/interrupts to display every IRQ vector in use by the system, not
352just those considered 'most important'. The new vectors are:
353
354 THR -- interrupt raised when a machine check threshold counter
355 (typically counting ECC corrected errors of memory or cache) exceeds
356 a configurable threshold. Only available on some systems.
357
358 TRM -- a thermal event interrupt occurs when a temperature threshold
359 has been exceeded for the CPU. This interrupt may also be generated
360 when the temperature drops back to normal.
361
362 SPU -- a spurious interrupt is some interrupt that was raised then lowered
363 by some IO device before it could be fully processed by the APIC. Hence
364 the APIC sees the interrupt but does not know what device it came from.
365 For this case the APIC will generate the interrupt with a IRQ vector
366 of 0xff. This might also be generated by chipset bugs.
367
368 RES, CAL, TLB -- rescheduling, call and TLB flush interrupts are
369 sent from one CPU to another per the needs of the OS. Typically,
370 their statistics are used by kernel developers and interested users to
371 determine the occurance of interrupt of the given type.
372
373The above IRQ vectors are displayed only when relevent. For example,
374the threshold vector does not exist on x86_64 platforms. Others are
375suppressed when the system is a uniprocessor. As of this writing, only
376i386 and x86_64 platforms support the new IRQ vector displays.
377
378Of some interest is the introduction of the /proc/irq directory to 2.4.
351It could be used to set IRQ to CPU affinity, this means that you can "hook" an 379It could be used to set IRQ to CPU affinity, this means that you can "hook" an
352IRQ to only one CPU, or to exclude a CPU of handling IRQs. The contents of the 380IRQ to only one CPU, or to exclude a CPU of handling IRQs. The contents of the
353irq subdir is one subdir for each IRQ, and one file; prof_cpu_mask 381irq subdir is one subdir for each IRQ, and one file; prof_cpu_mask
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index 3d67ae18d762..793341fffc81 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -1277,6 +1277,7 @@ void smp_spurious_interrupt(struct pt_regs *regs)
1277 /* see sw-dev-man vol 3, chapter 7.4.13.5 */ 1277 /* see sw-dev-man vol 3, chapter 7.4.13.5 */
1278 printk(KERN_INFO "spurious APIC interrupt on CPU#%d, " 1278 printk(KERN_INFO "spurious APIC interrupt on CPU#%d, "
1279 "should never happen.\n", smp_processor_id()); 1279 "should never happen.\n", smp_processor_id());
1280 __get_cpu_var(irq_stat).irq_spurious_count++;
1280 irq_exit(); 1281 irq_exit();
1281} 1282}
1282 1283
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 2250c654eacc..f47bc493dba9 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -1140,6 +1140,7 @@ asmlinkage void smp_spurious_interrupt(void)
1140 if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) 1140 if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
1141 ack_APIC_irq(); 1141 ack_APIC_irq();
1142 1142
1143 add_pda(irq_spurious_count, 1);
1143 irq_exit(); 1144 irq_exit();
1144} 1145}
1145 1146
diff --git a/arch/x86/kernel/cpu/mcheck/p4.c b/arch/x86/kernel/cpu/mcheck/p4.c
index 1509edfb2313..be4dabfee1f5 100644
--- a/arch/x86/kernel/cpu/mcheck/p4.c
+++ b/arch/x86/kernel/cpu/mcheck/p4.c
@@ -61,6 +61,7 @@ fastcall void smp_thermal_interrupt(struct pt_regs *regs)
61{ 61{
62 irq_enter(); 62 irq_enter();
63 vendor_thermal_interrupt(regs); 63 vendor_thermal_interrupt(regs);
64 __get_cpu_var(irq_stat).irq_thermal_count++;
64 irq_exit(); 65 irq_exit();
65} 66}
66 67
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index e173b763f148..10f359021aae 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -280,14 +280,41 @@ skip:
280 seq_printf(p, "NMI: "); 280 seq_printf(p, "NMI: ");
281 for_each_online_cpu(j) 281 for_each_online_cpu(j)
282 seq_printf(p, "%10u ", nmi_count(j)); 282 seq_printf(p, "%10u ", nmi_count(j));
283 seq_putc(p, '\n'); 283 seq_printf(p, " Non-maskable interrupts\n");
284#ifdef CONFIG_X86_LOCAL_APIC 284#ifdef CONFIG_X86_LOCAL_APIC
285 seq_printf(p, "LOC: "); 285 seq_printf(p, "LOC: ");
286 for_each_online_cpu(j) 286 for_each_online_cpu(j)
287 seq_printf(p, "%10u ", 287 seq_printf(p, "%10u ",
288 per_cpu(irq_stat,j).apic_timer_irqs); 288 per_cpu(irq_stat,j).apic_timer_irqs);
289 seq_putc(p, '\n'); 289 seq_printf(p, " Local timer interrupts\n");
290#endif 290#endif
291#ifdef CONFIG_SMP
292 seq_printf(p, "RES: ");
293 for_each_online_cpu(j)
294 seq_printf(p, "%10u ",
295 per_cpu(irq_stat,j).irq_resched_count);
296 seq_printf(p, " Rescheduling interrupts\n");
297 seq_printf(p, "CAL: ");
298 for_each_online_cpu(j)
299 seq_printf(p, "%10u ",
300 per_cpu(irq_stat,j).irq_call_count);
301 seq_printf(p, " function call interrupts\n");
302 seq_printf(p, "TLB: ");
303 for_each_online_cpu(j)
304 seq_printf(p, "%10u ",
305 per_cpu(irq_stat,j).irq_tlb_count);
306 seq_printf(p, " TLB shootdowns\n");
307#endif
308 seq_printf(p, "TRM: ");
309 for_each_online_cpu(j)
310 seq_printf(p, "%10u ",
311 per_cpu(irq_stat,j).irq_thermal_count);
312 seq_printf(p, " Thermal event interrupts\n");
313 seq_printf(p, "SPU: ");
314 for_each_online_cpu(j)
315 seq_printf(p, "%10u ",
316 per_cpu(irq_stat,j).irq_spurious_count);
317 seq_printf(p, " Spurious interrupts\n");
291 seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); 318 seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
292#if defined(CONFIG_X86_IO_APIC) 319#if defined(CONFIG_X86_IO_APIC)
293 seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); 320 seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index 865669efc540..3881189df8ee 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -86,11 +86,37 @@ skip:
86 seq_printf(p, "NMI: "); 86 seq_printf(p, "NMI: ");
87 for_each_online_cpu(j) 87 for_each_online_cpu(j)
88 seq_printf(p, "%10u ", cpu_pda(j)->__nmi_count); 88 seq_printf(p, "%10u ", cpu_pda(j)->__nmi_count);
89 seq_putc(p, '\n'); 89 seq_printf(p, " Non-maskable interrupts\n");
90 seq_printf(p, "LOC: "); 90 seq_printf(p, "LOC: ");
91 for_each_online_cpu(j) 91 for_each_online_cpu(j)
92 seq_printf(p, "%10u ", cpu_pda(j)->apic_timer_irqs); 92 seq_printf(p, "%10u ", cpu_pda(j)->apic_timer_irqs);
93 seq_putc(p, '\n'); 93 seq_printf(p, " Local timer interrupts\n");
94#ifdef CONFIG_SMP
95 seq_printf(p, "RES: ");
96 for_each_online_cpu(j)
97 seq_printf(p, "%10u ", cpu_pda(j)->irq_resched_count);
98 seq_printf(p, " Rescheduling interrupts\n");
99 seq_printf(p, "CAL: ");
100 for_each_online_cpu(j)
101 seq_printf(p, "%10u ", cpu_pda(j)->irq_call_count);
102 seq_printf(p, " function call interrupts\n");
103 seq_printf(p, "TLB: ");
104 for_each_online_cpu(j)
105 seq_printf(p, "%10u ", cpu_pda(j)->irq_tlb_count);
106 seq_printf(p, " TLB shootdowns\n");
107#endif
108 seq_printf(p, "TRM: ");
109 for_each_online_cpu(j)
110 seq_printf(p, "%10u ", cpu_pda(j)->irq_thermal_count);
111 seq_printf(p, " Thermal event interrupts\n");
112 seq_printf(p, "THR: ");
113 for_each_online_cpu(j)
114 seq_printf(p, "%10u ", cpu_pda(j)->irq_threshold_count);
115 seq_printf(p, " Threshold APIC interrupts\n");
116 seq_printf(p, "SPU: ");
117 for_each_online_cpu(j)
118 seq_printf(p, "%10u ", cpu_pda(j)->irq_spurious_count);
119 seq_printf(p, " Spurious interrupts\n");
94 seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); 120 seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
95 } 121 }
96 return 0; 122 return 0;
diff --git a/arch/x86/kernel/mce_amd_64.c b/arch/x86/kernel/mce_amd_64.c
index 805b62b1e0df..0d2afd96aca4 100644
--- a/arch/x86/kernel/mce_amd_64.c
+++ b/arch/x86/kernel/mce_amd_64.c
@@ -237,6 +237,7 @@ asmlinkage void mce_threshold_interrupt(void)
237 } 237 }
238 } 238 }
239out: 239out:
240 add_pda(irq_threshold_count, 1);
240 irq_exit(); 241 irq_exit();
241} 242}
242 243
diff --git a/arch/x86/kernel/mce_intel_64.c b/arch/x86/kernel/mce_intel_64.c
index 6551505d8a2c..c17eaf5dd6dd 100644
--- a/arch/x86/kernel/mce_intel_64.c
+++ b/arch/x86/kernel/mce_intel_64.c
@@ -26,6 +26,7 @@ asmlinkage void smp_thermal_interrupt(void)
26 if (therm_throt_process(msr_val & 1)) 26 if (therm_throt_process(msr_val & 1))
27 mce_log_therm_throt_event(smp_processor_id(), msr_val); 27 mce_log_therm_throt_event(smp_processor_id(), msr_val);
28 28
29 add_pda(irq_thermal_count, 1);
29 irq_exit(); 30 irq_exit();
30} 31}
31 32
diff --git a/arch/x86/kernel/smp_32.c b/arch/x86/kernel/smp_32.c
index eebc6e82576c..791d9f8036ae 100644
--- a/arch/x86/kernel/smp_32.c
+++ b/arch/x86/kernel/smp_32.c
@@ -342,6 +342,7 @@ fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
342 smp_mb__after_clear_bit(); 342 smp_mb__after_clear_bit();
343out: 343out:
344 put_cpu_no_resched(); 344 put_cpu_no_resched();
345 __get_cpu_var(irq_stat).irq_tlb_count++;
345} 346}
346 347
347void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, 348void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
@@ -640,6 +641,7 @@ static void native_smp_send_stop(void)
640fastcall void smp_reschedule_interrupt(struct pt_regs *regs) 641fastcall void smp_reschedule_interrupt(struct pt_regs *regs)
641{ 642{
642 ack_APIC_irq(); 643 ack_APIC_irq();
644 __get_cpu_var(irq_stat).irq_resched_count++;
643} 645}
644 646
645fastcall void smp_call_function_interrupt(struct pt_regs *regs) 647fastcall void smp_call_function_interrupt(struct pt_regs *regs)
@@ -660,6 +662,7 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs)
660 */ 662 */
661 irq_enter(); 663 irq_enter();
662 (*func)(info); 664 (*func)(info);
665 __get_cpu_var(irq_stat).irq_call_count++;
663 irq_exit(); 666 irq_exit();
664 667
665 if (wait) { 668 if (wait) {
diff --git a/arch/x86/kernel/smp_64.c b/arch/x86/kernel/smp_64.c
index df4a82812adb..5c2964727d19 100644
--- a/arch/x86/kernel/smp_64.c
+++ b/arch/x86/kernel/smp_64.c
@@ -163,6 +163,7 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs)
163out: 163out:
164 ack_APIC_irq(); 164 ack_APIC_irq();
165 cpu_clear(cpu, f->flush_cpumask); 165 cpu_clear(cpu, f->flush_cpumask);
166 add_pda(irq_tlb_count, 1);
166} 167}
167 168
168static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, 169static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
@@ -493,6 +494,7 @@ void smp_send_stop(void)
493asmlinkage void smp_reschedule_interrupt(void) 494asmlinkage void smp_reschedule_interrupt(void)
494{ 495{
495 ack_APIC_irq(); 496 ack_APIC_irq();
497 add_pda(irq_resched_count, 1);
496} 498}
497 499
498asmlinkage void smp_call_function_interrupt(void) 500asmlinkage void smp_call_function_interrupt(void)
@@ -514,6 +516,7 @@ asmlinkage void smp_call_function_interrupt(void)
514 exit_idle(); 516 exit_idle();
515 irq_enter(); 517 irq_enter();
516 (*func)(info); 518 (*func)(info);
519 add_pda(irq_call_count, 1);
517 irq_exit(); 520 irq_exit();
518 if (wait) { 521 if (wait) {
519 mb(); 522 mb();
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c
index 1f86b529dbbb..e4928aa6bdfb 100644
--- a/arch/x86/mach-voyager/voyager_smp.c
+++ b/arch/x86/mach-voyager/voyager_smp.c
@@ -1037,6 +1037,7 @@ smp_call_function_interrupt(void)
1037 */ 1037 */
1038 irq_enter(); 1038 irq_enter();
1039 (*func)(info); 1039 (*func)(info);
1040 __get_cpu_var(irq_stat).irq_call_count++;
1040 irq_exit(); 1041 irq_exit();
1041 if (wait) { 1042 if (wait) {
1042 mb(); 1043 mb();
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 4fa33c27ccb6..6c058585459c 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -356,6 +356,7 @@ static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
356 */ 356 */
357 irq_enter(); 357 irq_enter();
358 (*func)(info); 358 (*func)(info);
359 __get_cpu_var(irq_stat).irq_call_count++;
359 irq_exit(); 360 irq_exit();
360 361
361 if (wait) { 362 if (wait) {
diff --git a/include/asm-x86/hardirq_32.h b/include/asm-x86/hardirq_32.h
index 918863530b92..4f85f0f4b563 100644
--- a/include/asm-x86/hardirq_32.h
+++ b/include/asm-x86/hardirq_32.h
@@ -10,6 +10,11 @@ typedef struct {
10 unsigned int __nmi_count; /* arch dependent */ 10 unsigned int __nmi_count; /* arch dependent */
11 unsigned int apic_timer_irqs; /* arch dependent */ 11 unsigned int apic_timer_irqs; /* arch dependent */
12 unsigned int irq0_irqs; 12 unsigned int irq0_irqs;
13 unsigned int irq_resched_count;
14 unsigned int irq_call_count;
15 unsigned int irq_tlb_count;
16 unsigned int irq_thermal_count;
17 unsigned int irq_spurious_count;
13} ____cacheline_aligned irq_cpustat_t; 18} ____cacheline_aligned irq_cpustat_t;
14 19
15DECLARE_PER_CPU(irq_cpustat_t, irq_stat); 20DECLARE_PER_CPU(irq_cpustat_t, irq_stat);
diff --git a/include/asm-x86/pda.h b/include/asm-x86/pda.h
index fb49f80eb94f..35962bbe5e72 100644
--- a/include/asm-x86/pda.h
+++ b/include/asm-x86/pda.h
@@ -30,6 +30,12 @@ struct x8664_pda {
30 struct mm_struct *active_mm; 30 struct mm_struct *active_mm;
31 unsigned apic_timer_irqs; 31 unsigned apic_timer_irqs;
32 unsigned irq0_irqs; 32 unsigned irq0_irqs;
33 unsigned irq_resched_count;
34 unsigned irq_call_count;
35 unsigned irq_tlb_count;
36 unsigned irq_thermal_count;
37 unsigned irq_threshold_count;
38 unsigned irq_spurious_count;
33} ____cacheline_aligned_in_smp; 39} ____cacheline_aligned_in_smp;
34 40
35extern struct x8664_pda *_cpu_pda[]; 41extern struct x8664_pda *_cpu_pda[];