diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 19:31:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 19:31:49 -0400 |
commit | 96a3d998fb92c28b9862297fcf93a24d8a0eac1d (patch) | |
tree | 7fe1a799a3a84d276e7dcf8b0afa5b4ceb56659f | |
parent | 3045f94a20cc54e3e5b20a843701eeab86f57163 (diff) | |
parent | 5236eb968ec21c693d463d0494e39b00c1bc174d (diff) |
Merge branch 'x86-tracing-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 tracing updates from Ingo Molnar:
"This tree adds IRQ vector tracepoints that are named after the handler
and which output the vector #, based on a zero-overhead approach that
relies on changing the IDT entries, by Seiji Aguchi.
The new tracepoints look like this:
# perf list | grep -i irq_vector
irq_vectors:local_timer_entry [Tracepoint event]
irq_vectors:local_timer_exit [Tracepoint event]
irq_vectors:reschedule_entry [Tracepoint event]
irq_vectors:reschedule_exit [Tracepoint event]
irq_vectors:spurious_apic_entry [Tracepoint event]
irq_vectors:spurious_apic_exit [Tracepoint event]
irq_vectors:error_apic_entry [Tracepoint event]
irq_vectors:error_apic_exit [Tracepoint event]
[...]"
* 'x86-tracing-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/tracing: Add config option checking to the definitions of mce handlers
trace,x86: Do not call local_irq_save() in load_current_idt()
trace,x86: Move creation of irq tracepoints from apic.c to irq.c
x86, trace: Add irq vector tracepoints
x86: Rename variables for debugging
x86, trace: Introduce entering/exiting_irq()
tracing: Add DEFINE_EVENT_FN() macro
-rw-r--r-- | arch/x86/include/asm/apic.h | 27 | ||||
-rw-r--r-- | arch/x86/include/asm/desc.h | 117 | ||||
-rw-r--r-- | arch/x86/include/asm/entry_arch.h | 8 | ||||
-rw-r--r-- | arch/x86/include/asm/hw_irq.h | 17 | ||||
-rw-r--r-- | arch/x86/include/asm/mshyperv.h | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/trace/irq_vectors.h | 104 | ||||
-rw-r--r-- | arch/x86/include/asm/uv/uv_bau.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 69 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 20 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/therm_throt.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/threshold.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/entry_32.S | 12 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 36 | ||||
-rw-r--r-- | arch/x86/kernel/head_64.S | 8 | ||||
-rw-r--r-- | arch/x86/kernel/irq.c | 33 | ||||
-rw-r--r-- | arch/x86/kernel/irq_work.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/smp.c | 65 | ||||
-rw-r--r-- | arch/x86/kernel/tracepoint.c | 61 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 2 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 2 | ||||
-rw-r--r-- | include/trace/define_trace.h | 5 | ||||
-rw-r--r-- | include/trace/ftrace.h | 4 | ||||
-rw-r--r-- | include/xen/events.h | 3 |
24 files changed, 602 insertions, 72 deletions
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 338803422239..f8119b582c3c 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <asm/fixmap.h> | 12 | #include <asm/fixmap.h> |
13 | #include <asm/mpspec.h> | 13 | #include <asm/mpspec.h> |
14 | #include <asm/msr.h> | 14 | #include <asm/msr.h> |
15 | #include <asm/idle.h> | ||
15 | 16 | ||
16 | #define ARCH_APICTIMER_STOPS_ON_C3 1 | 17 | #define ARCH_APICTIMER_STOPS_ON_C3 1 |
17 | 18 | ||
@@ -687,5 +688,31 @@ extern int default_check_phys_apicid_present(int phys_apicid); | |||
687 | #endif | 688 | #endif |
688 | 689 | ||
689 | #endif /* CONFIG_X86_LOCAL_APIC */ | 690 | #endif /* CONFIG_X86_LOCAL_APIC */ |
691 | extern void irq_enter(void); | ||
692 | extern void irq_exit(void); | ||
693 | |||
694 | static inline void entering_irq(void) | ||
695 | { | ||
696 | irq_enter(); | ||
697 | exit_idle(); | ||
698 | } | ||
699 | |||
700 | static inline void entering_ack_irq(void) | ||
701 | { | ||
702 | ack_APIC_irq(); | ||
703 | entering_irq(); | ||
704 | } | ||
705 | |||
706 | static inline void exiting_irq(void) | ||
707 | { | ||
708 | irq_exit(); | ||
709 | } | ||
710 | |||
711 | static inline void exiting_ack_irq(void) | ||
712 | { | ||
713 | irq_exit(); | ||
714 | /* Ack only at the end to avoid potential reentry */ | ||
715 | ack_APIC_irq(); | ||
716 | } | ||
690 | 717 | ||
691 | #endif /* _ASM_X86_APIC_H */ | 718 | #endif /* _ASM_X86_APIC_H */ |
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index 8bf1c06070d5..b90e5dfeee46 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h | |||
@@ -36,8 +36,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in | |||
36 | 36 | ||
37 | extern struct desc_ptr idt_descr; | 37 | extern struct desc_ptr idt_descr; |
38 | extern gate_desc idt_table[]; | 38 | extern gate_desc idt_table[]; |
39 | extern struct desc_ptr nmi_idt_descr; | 39 | extern struct desc_ptr debug_idt_descr; |
40 | extern gate_desc nmi_idt_table[]; | 40 | extern gate_desc debug_idt_table[]; |
41 | 41 | ||
42 | struct gdt_page { | 42 | struct gdt_page { |
43 | struct desc_struct gdt[GDT_ENTRIES]; | 43 | struct desc_struct gdt[GDT_ENTRIES]; |
@@ -316,7 +316,20 @@ static inline void set_nmi_gate(int gate, void *addr) | |||
316 | gate_desc s; | 316 | gate_desc s; |
317 | 317 | ||
318 | pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS); | 318 | pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS); |
319 | write_idt_entry(nmi_idt_table, gate, &s); | 319 | write_idt_entry(debug_idt_table, gate, &s); |
320 | } | ||
321 | #endif | ||
322 | |||
323 | #ifdef CONFIG_TRACING | ||
324 | extern struct desc_ptr trace_idt_descr; | ||
325 | extern gate_desc trace_idt_table[]; | ||
326 | static inline void write_trace_idt_entry(int entry, const gate_desc *gate) | ||
327 | { | ||
328 | write_idt_entry(trace_idt_table, entry, gate); | ||
329 | } | ||
330 | #else | ||
331 | static inline void write_trace_idt_entry(int entry, const gate_desc *gate) | ||
332 | { | ||
320 | } | 333 | } |
321 | #endif | 334 | #endif |
322 | 335 | ||
@@ -331,6 +344,7 @@ static inline void _set_gate(int gate, unsigned type, void *addr, | |||
331 | * setup time | 344 | * setup time |
332 | */ | 345 | */ |
333 | write_idt_entry(idt_table, gate, &s); | 346 | write_idt_entry(idt_table, gate, &s); |
347 | write_trace_idt_entry(gate, &s); | ||
334 | } | 348 | } |
335 | 349 | ||
336 | /* | 350 | /* |
@@ -360,12 +374,39 @@ static inline void alloc_system_vector(int vector) | |||
360 | } | 374 | } |
361 | } | 375 | } |
362 | 376 | ||
363 | static inline void alloc_intr_gate(unsigned int n, void *addr) | 377 | #ifdef CONFIG_TRACING |
378 | static inline void trace_set_intr_gate(unsigned int gate, void *addr) | ||
379 | { | ||
380 | gate_desc s; | ||
381 | |||
382 | pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS); | ||
383 | write_idt_entry(trace_idt_table, gate, &s); | ||
384 | } | ||
385 | |||
386 | static inline void __trace_alloc_intr_gate(unsigned int n, void *addr) | ||
387 | { | ||
388 | trace_set_intr_gate(n, addr); | ||
389 | } | ||
390 | #else | ||
391 | static inline void trace_set_intr_gate(unsigned int gate, void *addr) | ||
392 | { | ||
393 | } | ||
394 | |||
395 | #define __trace_alloc_intr_gate(n, addr) | ||
396 | #endif | ||
397 | |||
398 | static inline void __alloc_intr_gate(unsigned int n, void *addr) | ||
364 | { | 399 | { |
365 | alloc_system_vector(n); | ||
366 | set_intr_gate(n, addr); | 400 | set_intr_gate(n, addr); |
367 | } | 401 | } |
368 | 402 | ||
403 | #define alloc_intr_gate(n, addr) \ | ||
404 | do { \ | ||
405 | alloc_system_vector(n); \ | ||
406 | __alloc_intr_gate(n, addr); \ | ||
407 | __trace_alloc_intr_gate(n, trace_##addr); \ | ||
408 | } while (0) | ||
409 | |||
369 | /* | 410 | /* |
370 | * This routine sets up an interrupt gate at directory privilege level 3. | 411 | * This routine sets up an interrupt gate at directory privilege level 3. |
371 | */ | 412 | */ |
@@ -405,4 +446,70 @@ static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist) | |||
405 | _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); | 446 | _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); |
406 | } | 447 | } |
407 | 448 | ||
449 | #ifdef CONFIG_X86_64 | ||
450 | DECLARE_PER_CPU(u32, debug_idt_ctr); | ||
451 | static inline bool is_debug_idt_enabled(void) | ||
452 | { | ||
453 | if (this_cpu_read(debug_idt_ctr)) | ||
454 | return true; | ||
455 | |||
456 | return false; | ||
457 | } | ||
458 | |||
459 | static inline void load_debug_idt(void) | ||
460 | { | ||
461 | load_idt((const struct desc_ptr *)&debug_idt_descr); | ||
462 | } | ||
463 | #else | ||
464 | static inline bool is_debug_idt_enabled(void) | ||
465 | { | ||
466 | return false; | ||
467 | } | ||
468 | |||
469 | static inline void load_debug_idt(void) | ||
470 | { | ||
471 | } | ||
472 | #endif | ||
473 | |||
474 | #ifdef CONFIG_TRACING | ||
475 | extern atomic_t trace_idt_ctr; | ||
476 | static inline bool is_trace_idt_enabled(void) | ||
477 | { | ||
478 | if (atomic_read(&trace_idt_ctr)) | ||
479 | return true; | ||
480 | |||
481 | return false; | ||
482 | } | ||
483 | |||
484 | static inline void load_trace_idt(void) | ||
485 | { | ||
486 | load_idt((const struct desc_ptr *)&trace_idt_descr); | ||
487 | } | ||
488 | #else | ||
489 | static inline bool is_trace_idt_enabled(void) | ||
490 | { | ||
491 | return false; | ||
492 | } | ||
493 | |||
494 | static inline void load_trace_idt(void) | ||
495 | { | ||
496 | } | ||
497 | #endif | ||
498 | |||
499 | /* | ||
500 | * The load_current_idt() must be called with interrupts disabled | ||
501 | * to avoid races. That way the IDT will always be set back to the expected | ||
502 | * descriptor. It's also called when a CPU is being initialized, and | ||
503 | * that doesn't need to disable interrupts, as nothing should be | ||
504 | * bothering the CPU then. | ||
505 | */ | ||
506 | static inline void load_current_idt(void) | ||
507 | { | ||
508 | if (is_debug_idt_enabled()) | ||
509 | load_debug_idt(); | ||
510 | else if (is_trace_idt_enabled()) | ||
511 | load_trace_idt(); | ||
512 | else | ||
513 | load_idt((const struct desc_ptr *)&idt_descr); | ||
514 | } | ||
408 | #endif /* _ASM_X86_DESC_H */ | 515 | #endif /* _ASM_X86_DESC_H */ |
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h index 9bd4ecac72be..dc5fa661465f 100644 --- a/arch/x86/include/asm/entry_arch.h +++ b/arch/x86/include/asm/entry_arch.h | |||
@@ -13,14 +13,16 @@ | |||
13 | BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) | 13 | BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) |
14 | BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) | 14 | BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) |
15 | BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR) | 15 | BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR) |
16 | BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR) | 16 | BUILD_INTERRUPT3(irq_move_cleanup_interrupt, IRQ_MOVE_CLEANUP_VECTOR, |
17 | BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR) | 17 | smp_irq_move_cleanup_interrupt) |
18 | BUILD_INTERRUPT3(reboot_interrupt, REBOOT_VECTOR, smp_reboot_interrupt) | ||
18 | #endif | 19 | #endif |
19 | 20 | ||
20 | BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR) | 21 | BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR) |
21 | 22 | ||
22 | #ifdef CONFIG_HAVE_KVM | 23 | #ifdef CONFIG_HAVE_KVM |
23 | BUILD_INTERRUPT(kvm_posted_intr_ipi, POSTED_INTR_VECTOR) | 24 | BUILD_INTERRUPT3(kvm_posted_intr_ipi, POSTED_INTR_VECTOR, |
25 | smp_kvm_posted_intr_ipi) | ||
24 | #endif | 26 | #endif |
25 | 27 | ||
26 | /* | 28 | /* |
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 1da97efad08a..e4ac559c4a24 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h | |||
@@ -77,6 +77,23 @@ extern void threshold_interrupt(void); | |||
77 | extern void call_function_interrupt(void); | 77 | extern void call_function_interrupt(void); |
78 | extern void call_function_single_interrupt(void); | 78 | extern void call_function_single_interrupt(void); |
79 | 79 | ||
80 | #ifdef CONFIG_TRACING | ||
81 | /* Interrupt handlers registered during init_IRQ */ | ||
82 | extern void trace_apic_timer_interrupt(void); | ||
83 | extern void trace_x86_platform_ipi(void); | ||
84 | extern void trace_error_interrupt(void); | ||
85 | extern void trace_irq_work_interrupt(void); | ||
86 | extern void trace_spurious_interrupt(void); | ||
87 | extern void trace_thermal_interrupt(void); | ||
88 | extern void trace_reschedule_interrupt(void); | ||
89 | extern void trace_threshold_interrupt(void); | ||
90 | extern void trace_call_function_interrupt(void); | ||
91 | extern void trace_call_function_single_interrupt(void); | ||
92 | #define trace_irq_move_cleanup_interrupt irq_move_cleanup_interrupt | ||
93 | #define trace_reboot_interrupt reboot_interrupt | ||
94 | #define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi | ||
95 | #endif /* CONFIG_TRACING */ | ||
96 | |||
80 | /* IOAPIC */ | 97 | /* IOAPIC */ |
81 | #define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs)) | 98 | #define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs)) |
82 | extern unsigned long io_apic_irqs; | 99 | extern unsigned long io_apic_irqs; |
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index c2934be2446a..cd9c41938b8a 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h | |||
@@ -12,6 +12,9 @@ struct ms_hyperv_info { | |||
12 | extern struct ms_hyperv_info ms_hyperv; | 12 | extern struct ms_hyperv_info ms_hyperv; |
13 | 13 | ||
14 | void hyperv_callback_vector(void); | 14 | void hyperv_callback_vector(void); |
15 | #ifdef CONFIG_TRACING | ||
16 | #define trace_hyperv_callback_vector hyperv_callback_vector | ||
17 | #endif | ||
15 | void hyperv_vector_handler(struct pt_regs *regs); | 18 | void hyperv_vector_handler(struct pt_regs *regs); |
16 | void hv_register_vmbus_handler(int irq, irq_handler_t handler); | 19 | void hv_register_vmbus_handler(int irq, irq_handler_t handler); |
17 | 20 | ||
diff --git a/arch/x86/include/asm/trace/irq_vectors.h b/arch/x86/include/asm/trace/irq_vectors.h new file mode 100644 index 000000000000..2874df24e7a4 --- /dev/null +++ b/arch/x86/include/asm/trace/irq_vectors.h | |||
@@ -0,0 +1,104 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM irq_vectors | ||
3 | |||
4 | #if !defined(_TRACE_IRQ_VECTORS_H) || defined(TRACE_HEADER_MULTI_READ) | ||
5 | #define _TRACE_IRQ_VECTORS_H | ||
6 | |||
7 | #include <linux/tracepoint.h> | ||
8 | |||
9 | extern void trace_irq_vector_regfunc(void); | ||
10 | extern void trace_irq_vector_unregfunc(void); | ||
11 | |||
12 | DECLARE_EVENT_CLASS(x86_irq_vector, | ||
13 | |||
14 | TP_PROTO(int vector), | ||
15 | |||
16 | TP_ARGS(vector), | ||
17 | |||
18 | TP_STRUCT__entry( | ||
19 | __field( int, vector ) | ||
20 | ), | ||
21 | |||
22 | TP_fast_assign( | ||
23 | __entry->vector = vector; | ||
24 | ), | ||
25 | |||
26 | TP_printk("vector=%d", __entry->vector) ); | ||
27 | |||
28 | #define DEFINE_IRQ_VECTOR_EVENT(name) \ | ||
29 | DEFINE_EVENT_FN(x86_irq_vector, name##_entry, \ | ||
30 | TP_PROTO(int vector), \ | ||
31 | TP_ARGS(vector), \ | ||
32 | trace_irq_vector_regfunc, \ | ||
33 | trace_irq_vector_unregfunc); \ | ||
34 | DEFINE_EVENT_FN(x86_irq_vector, name##_exit, \ | ||
35 | TP_PROTO(int vector), \ | ||
36 | TP_ARGS(vector), \ | ||
37 | trace_irq_vector_regfunc, \ | ||
38 | trace_irq_vector_unregfunc); | ||
39 | |||
40 | |||
41 | /* | ||
42 | * local_timer - called when entering/exiting a local timer interrupt | ||
43 | * vector handler | ||
44 | */ | ||
45 | DEFINE_IRQ_VECTOR_EVENT(local_timer); | ||
46 | |||
47 | /* | ||
48 | * reschedule - called when entering/exiting a reschedule vector handler | ||
49 | */ | ||
50 | DEFINE_IRQ_VECTOR_EVENT(reschedule); | ||
51 | |||
52 | /* | ||
53 | * spurious_apic - called when entering/exiting a spurious apic vector handler | ||
54 | */ | ||
55 | DEFINE_IRQ_VECTOR_EVENT(spurious_apic); | ||
56 | |||
57 | /* | ||
58 | * error_apic - called when entering/exiting an error apic vector handler | ||
59 | */ | ||
60 | DEFINE_IRQ_VECTOR_EVENT(error_apic); | ||
61 | |||
62 | /* | ||
63 | * x86_platform_ipi - called when entering/exiting a x86 platform ipi interrupt | ||
64 | * vector handler | ||
65 | */ | ||
66 | DEFINE_IRQ_VECTOR_EVENT(x86_platform_ipi); | ||
67 | |||
68 | /* | ||
69 | * irq_work - called when entering/exiting a irq work interrupt | ||
70 | * vector handler | ||
71 | */ | ||
72 | DEFINE_IRQ_VECTOR_EVENT(irq_work); | ||
73 | |||
74 | /* | ||
75 | * call_function - called when entering/exiting a call function interrupt | ||
76 | * vector handler | ||
77 | */ | ||
78 | DEFINE_IRQ_VECTOR_EVENT(call_function); | ||
79 | |||
80 | /* | ||
81 | * call_function_single - called when entering/exiting a call function | ||
82 | * single interrupt vector handler | ||
83 | */ | ||
84 | DEFINE_IRQ_VECTOR_EVENT(call_function_single); | ||
85 | |||
86 | /* | ||
87 | * threshold_apic - called when entering/exiting a threshold apic interrupt | ||
88 | * vector handler | ||
89 | */ | ||
90 | DEFINE_IRQ_VECTOR_EVENT(threshold_apic); | ||
91 | |||
92 | /* | ||
93 | * thermal_apic - called when entering/exiting a thermal apic interrupt | ||
94 | * vector handler | ||
95 | */ | ||
96 | DEFINE_IRQ_VECTOR_EVENT(thermal_apic); | ||
97 | |||
98 | #undef TRACE_INCLUDE_PATH | ||
99 | #define TRACE_INCLUDE_PATH . | ||
100 | #define TRACE_INCLUDE_FILE irq_vectors | ||
101 | #endif /* _TRACE_IRQ_VECTORS_H */ | ||
102 | |||
103 | /* This part must be outside protection */ | ||
104 | #include <trace/define_trace.h> | ||
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index a06983cdc125..0b46ef261c77 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h | |||
@@ -731,6 +731,9 @@ static inline void bau_cpubits_clear(struct bau_local_cpumask *dstp, int nbits) | |||
731 | } | 731 | } |
732 | 732 | ||
733 | extern void uv_bau_message_intr1(void); | 733 | extern void uv_bau_message_intr1(void); |
734 | #ifdef CONFIG_TRACING | ||
735 | #define trace_uv_bau_message_intr1 uv_bau_message_intr1 | ||
736 | #endif | ||
734 | extern void uv_bau_timeout_intr1(void); | 737 | extern void uv_bau_timeout_intr1(void); |
735 | 738 | ||
736 | struct atomic_short { | 739 | struct atomic_short { |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 612ed3435c0d..88d99ea77723 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -16,6 +16,8 @@ CFLAGS_REMOVE_ftrace.o = -pg | |||
16 | CFLAGS_REMOVE_early_printk.o = -pg | 16 | CFLAGS_REMOVE_early_printk.o = -pg |
17 | endif | 17 | endif |
18 | 18 | ||
19 | CFLAGS_irq.o := -I$(src)/../include/asm/trace | ||
20 | |||
19 | obj-y := process_$(BITS).o signal.o entry_$(BITS).o | 21 | obj-y := process_$(BITS).o signal.o entry_$(BITS).o |
20 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o | 22 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o |
21 | obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o | 23 | obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o |
@@ -103,6 +105,7 @@ obj-$(CONFIG_OF) += devicetree.o | |||
103 | obj-$(CONFIG_UPROBES) += uprobes.o | 105 | obj-$(CONFIG_UPROBES) += uprobes.o |
104 | 106 | ||
105 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o | 107 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o |
108 | obj-$(CONFIG_TRACING) += tracepoint.o | ||
106 | 109 | ||
107 | ### | 110 | ### |
108 | # 64 bit specific files | 111 | # 64 bit specific files |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 1600b1ca4f04..99663b59123a 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/smp.h> | 35 | #include <linux/smp.h> |
36 | #include <linux/mm.h> | 36 | #include <linux/mm.h> |
37 | 37 | ||
38 | #include <asm/trace/irq_vectors.h> | ||
38 | #include <asm/irq_remapping.h> | 39 | #include <asm/irq_remapping.h> |
39 | #include <asm/perf_event.h> | 40 | #include <asm/perf_event.h> |
40 | #include <asm/x86_init.h> | 41 | #include <asm/x86_init.h> |
@@ -919,17 +920,35 @@ void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs) | |||
919 | /* | 920 | /* |
920 | * NOTE! We'd better ACK the irq immediately, | 921 | * NOTE! We'd better ACK the irq immediately, |
921 | * because timer handling can be slow. | 922 | * because timer handling can be slow. |
923 | * | ||
924 | * update_process_times() expects us to have done irq_enter(). | ||
925 | * Besides, if we don't timer interrupts ignore the global | ||
926 | * interrupt lock, which is the WrongThing (tm) to do. | ||
922 | */ | 927 | */ |
923 | ack_APIC_irq(); | 928 | entering_ack_irq(); |
929 | local_apic_timer_interrupt(); | ||
930 | exiting_irq(); | ||
931 | |||
932 | set_irq_regs(old_regs); | ||
933 | } | ||
934 | |||
935 | void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs) | ||
936 | { | ||
937 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
938 | |||
924 | /* | 939 | /* |
940 | * NOTE! We'd better ACK the irq immediately, | ||
941 | * because timer handling can be slow. | ||
942 | * | ||
925 | * update_process_times() expects us to have done irq_enter(). | 943 | * update_process_times() expects us to have done irq_enter(). |
926 | * Besides, if we don't timer interrupts ignore the global | 944 | * Besides, if we don't timer interrupts ignore the global |
927 | * interrupt lock, which is the WrongThing (tm) to do. | 945 | * interrupt lock, which is the WrongThing (tm) to do. |
928 | */ | 946 | */ |
929 | irq_enter(); | 947 | entering_ack_irq(); |
930 | exit_idle(); | 948 | trace_local_timer_entry(LOCAL_TIMER_VECTOR); |
931 | local_apic_timer_interrupt(); | 949 | local_apic_timer_interrupt(); |
932 | irq_exit(); | 950 | trace_local_timer_exit(LOCAL_TIMER_VECTOR); |
951 | exiting_irq(); | ||
933 | 952 | ||
934 | set_irq_regs(old_regs); | 953 | set_irq_regs(old_regs); |
935 | } | 954 | } |
@@ -1907,12 +1926,10 @@ int __init APIC_init_uniprocessor(void) | |||
1907 | /* | 1926 | /* |
1908 | * This interrupt should _never_ happen with our APIC/SMP architecture | 1927 | * This interrupt should _never_ happen with our APIC/SMP architecture |
1909 | */ | 1928 | */ |
1910 | void smp_spurious_interrupt(struct pt_regs *regs) | 1929 | static inline void __smp_spurious_interrupt(void) |
1911 | { | 1930 | { |
1912 | u32 v; | 1931 | u32 v; |
1913 | 1932 | ||
1914 | irq_enter(); | ||
1915 | exit_idle(); | ||
1916 | /* | 1933 | /* |
1917 | * Check if this really is a spurious interrupt and ACK it | 1934 | * Check if this really is a spurious interrupt and ACK it |
1918 | * if it is a vectored one. Just in case... | 1935 | * if it is a vectored one. Just in case... |
@@ -1927,13 +1944,28 @@ void smp_spurious_interrupt(struct pt_regs *regs) | |||
1927 | /* see sw-dev-man vol 3, chapter 7.4.13.5 */ | 1944 | /* see sw-dev-man vol 3, chapter 7.4.13.5 */ |
1928 | pr_info("spurious APIC interrupt on CPU#%d, " | 1945 | pr_info("spurious APIC interrupt on CPU#%d, " |
1929 | "should never happen.\n", smp_processor_id()); | 1946 | "should never happen.\n", smp_processor_id()); |
1930 | irq_exit(); | 1947 | } |
1948 | |||
1949 | void smp_spurious_interrupt(struct pt_regs *regs) | ||
1950 | { | ||
1951 | entering_irq(); | ||
1952 | __smp_spurious_interrupt(); | ||
1953 | exiting_irq(); | ||
1954 | } | ||
1955 | |||
1956 | void smp_trace_spurious_interrupt(struct pt_regs *regs) | ||
1957 | { | ||
1958 | entering_irq(); | ||
1959 | trace_spurious_apic_entry(SPURIOUS_APIC_VECTOR); | ||
1960 | __smp_spurious_interrupt(); | ||
1961 | trace_spurious_apic_exit(SPURIOUS_APIC_VECTOR); | ||
1962 | exiting_irq(); | ||
1931 | } | 1963 | } |
1932 | 1964 | ||
1933 | /* | 1965 | /* |
1934 | * This interrupt should never happen with our APIC/SMP architecture | 1966 | * This interrupt should never happen with our APIC/SMP architecture |
1935 | */ | 1967 | */ |
1936 | void smp_error_interrupt(struct pt_regs *regs) | 1968 | static inline void __smp_error_interrupt(struct pt_regs *regs) |
1937 | { | 1969 | { |
1938 | u32 v0, v1; | 1970 | u32 v0, v1; |
1939 | u32 i = 0; | 1971 | u32 i = 0; |
@@ -1948,8 +1980,6 @@ void smp_error_interrupt(struct pt_regs *regs) | |||
1948 | "Illegal register address", /* APIC Error Bit 7 */ | 1980 | "Illegal register address", /* APIC Error Bit 7 */ |
1949 | }; | 1981 | }; |
1950 | 1982 | ||
1951 | irq_enter(); | ||
1952 | exit_idle(); | ||
1953 | /* First tickle the hardware, only then report what went on. -- REW */ | 1983 | /* First tickle the hardware, only then report what went on. -- REW */ |
1954 | v0 = apic_read(APIC_ESR); | 1984 | v0 = apic_read(APIC_ESR); |
1955 | apic_write(APIC_ESR, 0); | 1985 | apic_write(APIC_ESR, 0); |
@@ -1970,7 +2000,22 @@ void smp_error_interrupt(struct pt_regs *regs) | |||
1970 | 2000 | ||
1971 | apic_printk(APIC_DEBUG, KERN_CONT "\n"); | 2001 | apic_printk(APIC_DEBUG, KERN_CONT "\n"); |
1972 | 2002 | ||
1973 | irq_exit(); | 2003 | } |
2004 | |||
2005 | void smp_error_interrupt(struct pt_regs *regs) | ||
2006 | { | ||
2007 | entering_irq(); | ||
2008 | __smp_error_interrupt(regs); | ||
2009 | exiting_irq(); | ||
2010 | } | ||
2011 | |||
2012 | void smp_trace_error_interrupt(struct pt_regs *regs) | ||
2013 | { | ||
2014 | entering_irq(); | ||
2015 | trace_error_apic_entry(ERROR_APIC_VECTOR); | ||
2016 | __smp_error_interrupt(regs); | ||
2017 | trace_error_apic_exit(ERROR_APIC_VECTOR); | ||
2018 | exiting_irq(); | ||
1974 | } | 2019 | } |
1975 | 2020 | ||
1976 | /** | 2021 | /** |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a4a07c0acb1f..548bd039784e 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -1072,8 +1072,8 @@ __setup("clearcpuid=", setup_disablecpuid); | |||
1072 | 1072 | ||
1073 | #ifdef CONFIG_X86_64 | 1073 | #ifdef CONFIG_X86_64 |
1074 | struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; | 1074 | struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; |
1075 | struct desc_ptr nmi_idt_descr = { NR_VECTORS * 16 - 1, | 1075 | struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1, |
1076 | (unsigned long) nmi_idt_table }; | 1076 | (unsigned long) debug_idt_table }; |
1077 | 1077 | ||
1078 | DEFINE_PER_CPU_FIRST(union irq_stack_union, | 1078 | DEFINE_PER_CPU_FIRST(union irq_stack_union, |
1079 | irq_stack_union) __aligned(PAGE_SIZE); | 1079 | irq_stack_union) __aligned(PAGE_SIZE); |
@@ -1149,20 +1149,20 @@ int is_debug_stack(unsigned long addr) | |||
1149 | addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ)); | 1149 | addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ)); |
1150 | } | 1150 | } |
1151 | 1151 | ||
1152 | static DEFINE_PER_CPU(u32, debug_stack_use_ctr); | 1152 | DEFINE_PER_CPU(u32, debug_idt_ctr); |
1153 | 1153 | ||
1154 | void debug_stack_set_zero(void) | 1154 | void debug_stack_set_zero(void) |
1155 | { | 1155 | { |
1156 | this_cpu_inc(debug_stack_use_ctr); | 1156 | this_cpu_inc(debug_idt_ctr); |
1157 | load_idt((const struct desc_ptr *)&nmi_idt_descr); | 1157 | load_current_idt(); |
1158 | } | 1158 | } |
1159 | 1159 | ||
1160 | void debug_stack_reset(void) | 1160 | void debug_stack_reset(void) |
1161 | { | 1161 | { |
1162 | if (WARN_ON(!this_cpu_read(debug_stack_use_ctr))) | 1162 | if (WARN_ON(!this_cpu_read(debug_idt_ctr))) |
1163 | return; | 1163 | return; |
1164 | if (this_cpu_dec_return(debug_stack_use_ctr) == 0) | 1164 | if (this_cpu_dec_return(debug_idt_ctr) == 0) |
1165 | load_idt((const struct desc_ptr *)&idt_descr); | 1165 | load_current_idt(); |
1166 | } | 1166 | } |
1167 | 1167 | ||
1168 | #else /* CONFIG_X86_64 */ | 1168 | #else /* CONFIG_X86_64 */ |
@@ -1258,7 +1258,7 @@ void __cpuinit cpu_init(void) | |||
1258 | switch_to_new_gdt(cpu); | 1258 | switch_to_new_gdt(cpu); |
1259 | loadsegment(fs, 0); | 1259 | loadsegment(fs, 0); |
1260 | 1260 | ||
1261 | load_idt((const struct desc_ptr *)&idt_descr); | 1261 | load_current_idt(); |
1262 | 1262 | ||
1263 | memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8); | 1263 | memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8); |
1264 | syscall_init(); | 1264 | syscall_init(); |
@@ -1335,7 +1335,7 @@ void __cpuinit cpu_init(void) | |||
1335 | if (cpu_has_vme || cpu_has_tsc || cpu_has_de) | 1335 | if (cpu_has_vme || cpu_has_tsc || cpu_has_de) |
1336 | clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); | 1336 | clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); |
1337 | 1337 | ||
1338 | load_idt(&idt_descr); | 1338 | load_current_idt(); |
1339 | switch_to_new_gdt(cpu); | 1339 | switch_to_new_gdt(cpu); |
1340 | 1340 | ||
1341 | /* | 1341 | /* |
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 47a1870279aa..2f3a7995e56a 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/idle.h> | 29 | #include <asm/idle.h> |
30 | #include <asm/mce.h> | 30 | #include <asm/mce.h> |
31 | #include <asm/msr.h> | 31 | #include <asm/msr.h> |
32 | #include <asm/trace/irq_vectors.h> | ||
32 | 33 | ||
33 | /* How long to wait between reporting thermal events */ | 34 | /* How long to wait between reporting thermal events */ |
34 | #define CHECK_INTERVAL (300 * HZ) | 35 | #define CHECK_INTERVAL (300 * HZ) |
@@ -378,15 +379,26 @@ static void unexpected_thermal_interrupt(void) | |||
378 | 379 | ||
379 | static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt; | 380 | static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt; |
380 | 381 | ||
381 | asmlinkage void smp_thermal_interrupt(struct pt_regs *regs) | 382 | static inline void __smp_thermal_interrupt(void) |
382 | { | 383 | { |
383 | irq_enter(); | ||
384 | exit_idle(); | ||
385 | inc_irq_stat(irq_thermal_count); | 384 | inc_irq_stat(irq_thermal_count); |
386 | smp_thermal_vector(); | 385 | smp_thermal_vector(); |
387 | irq_exit(); | 386 | } |
388 | /* Ack only at the end to avoid potential reentry */ | 387 | |
389 | ack_APIC_irq(); | 388 | asmlinkage void smp_thermal_interrupt(struct pt_regs *regs) |
389 | { | ||
390 | entering_irq(); | ||
391 | __smp_thermal_interrupt(); | ||
392 | exiting_ack_irq(); | ||
393 | } | ||
394 | |||
395 | asmlinkage void smp_trace_thermal_interrupt(struct pt_regs *regs) | ||
396 | { | ||
397 | entering_irq(); | ||
398 | trace_thermal_apic_entry(THERMAL_APIC_VECTOR); | ||
399 | __smp_thermal_interrupt(); | ||
400 | trace_thermal_apic_exit(THERMAL_APIC_VECTOR); | ||
401 | exiting_ack_irq(); | ||
390 | } | 402 | } |
391 | 403 | ||
392 | /* Thermal monitoring depends on APIC, ACPI and clock modulation */ | 404 | /* Thermal monitoring depends on APIC, ACPI and clock modulation */ |
diff --git a/arch/x86/kernel/cpu/mcheck/threshold.c b/arch/x86/kernel/cpu/mcheck/threshold.c index aa578cadb940..fe6b1c86645b 100644 --- a/arch/x86/kernel/cpu/mcheck/threshold.c +++ b/arch/x86/kernel/cpu/mcheck/threshold.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <asm/apic.h> | 8 | #include <asm/apic.h> |
9 | #include <asm/idle.h> | 9 | #include <asm/idle.h> |
10 | #include <asm/mce.h> | 10 | #include <asm/mce.h> |
11 | #include <asm/trace/irq_vectors.h> | ||
11 | 12 | ||
12 | static void default_threshold_interrupt(void) | 13 | static void default_threshold_interrupt(void) |
13 | { | 14 | { |
@@ -17,13 +18,24 @@ static void default_threshold_interrupt(void) | |||
17 | 18 | ||
18 | void (*mce_threshold_vector)(void) = default_threshold_interrupt; | 19 | void (*mce_threshold_vector)(void) = default_threshold_interrupt; |
19 | 20 | ||
20 | asmlinkage void smp_threshold_interrupt(void) | 21 | static inline void __smp_threshold_interrupt(void) |
21 | { | 22 | { |
22 | irq_enter(); | ||
23 | exit_idle(); | ||
24 | inc_irq_stat(irq_threshold_count); | 23 | inc_irq_stat(irq_threshold_count); |
25 | mce_threshold_vector(); | 24 | mce_threshold_vector(); |
26 | irq_exit(); | 25 | } |
27 | /* Ack only at the end to avoid potential reentry */ | 26 | |
28 | ack_APIC_irq(); | 27 | asmlinkage void smp_threshold_interrupt(void) |
28 | { | ||
29 | entering_irq(); | ||
30 | __smp_threshold_interrupt(); | ||
31 | exiting_ack_irq(); | ||
32 | } | ||
33 | |||
34 | asmlinkage void smp_trace_threshold_interrupt(void) | ||
35 | { | ||
36 | entering_irq(); | ||
37 | trace_threshold_apic_entry(THRESHOLD_APIC_VECTOR); | ||
38 | __smp_threshold_interrupt(); | ||
39 | trace_threshold_apic_exit(THRESHOLD_APIC_VECTOR); | ||
40 | exiting_ack_irq(); | ||
29 | } | 41 | } |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 8f3e2dec1df3..2cfbc3a3a2dd 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -801,7 +801,17 @@ ENTRY(name) \ | |||
801 | CFI_ENDPROC; \ | 801 | CFI_ENDPROC; \ |
802 | ENDPROC(name) | 802 | ENDPROC(name) |
803 | 803 | ||
804 | #define BUILD_INTERRUPT(name, nr) BUILD_INTERRUPT3(name, nr, smp_##name) | 804 | |
805 | #ifdef CONFIG_TRACING | ||
806 | #define TRACE_BUILD_INTERRUPT(name, nr) \ | ||
807 | BUILD_INTERRUPT3(trace_##name, nr, smp_trace_##name) | ||
808 | #else | ||
809 | #define TRACE_BUILD_INTERRUPT(name, nr) | ||
810 | #endif | ||
811 | |||
812 | #define BUILD_INTERRUPT(name, nr) \ | ||
813 | BUILD_INTERRUPT3(name, nr, smp_##name); \ | ||
814 | TRACE_BUILD_INTERRUPT(name, nr) | ||
805 | 815 | ||
806 | /* The include is where all of the SMP etc. interrupts come from */ | 816 | /* The include is where all of the SMP etc. interrupts come from */ |
807 | #include <asm/entry_arch.h> | 817 | #include <asm/entry_arch.h> |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 5fe1fb2d1490..1b69951a81e2 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -1138,7 +1138,7 @@ END(common_interrupt) | |||
1138 | /* | 1138 | /* |
1139 | * APIC interrupts. | 1139 | * APIC interrupts. |
1140 | */ | 1140 | */ |
1141 | .macro apicinterrupt num sym do_sym | 1141 | .macro apicinterrupt3 num sym do_sym |
1142 | ENTRY(\sym) | 1142 | ENTRY(\sym) |
1143 | INTR_FRAME | 1143 | INTR_FRAME |
1144 | ASM_CLAC | 1144 | ASM_CLAC |
@@ -1150,15 +1150,32 @@ ENTRY(\sym) | |||
1150 | END(\sym) | 1150 | END(\sym) |
1151 | .endm | 1151 | .endm |
1152 | 1152 | ||
1153 | #ifdef CONFIG_TRACING | ||
1154 | #define trace(sym) trace_##sym | ||
1155 | #define smp_trace(sym) smp_trace_##sym | ||
1156 | |||
1157 | .macro trace_apicinterrupt num sym | ||
1158 | apicinterrupt3 \num trace(\sym) smp_trace(\sym) | ||
1159 | .endm | ||
1160 | #else | ||
1161 | .macro trace_apicinterrupt num sym do_sym | ||
1162 | .endm | ||
1163 | #endif | ||
1164 | |||
1165 | .macro apicinterrupt num sym do_sym | ||
1166 | apicinterrupt3 \num \sym \do_sym | ||
1167 | trace_apicinterrupt \num \sym | ||
1168 | .endm | ||
1169 | |||
1153 | #ifdef CONFIG_SMP | 1170 | #ifdef CONFIG_SMP |
1154 | apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \ | 1171 | apicinterrupt3 IRQ_MOVE_CLEANUP_VECTOR \ |
1155 | irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt | 1172 | irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt |
1156 | apicinterrupt REBOOT_VECTOR \ | 1173 | apicinterrupt3 REBOOT_VECTOR \ |
1157 | reboot_interrupt smp_reboot_interrupt | 1174 | reboot_interrupt smp_reboot_interrupt |
1158 | #endif | 1175 | #endif |
1159 | 1176 | ||
1160 | #ifdef CONFIG_X86_UV | 1177 | #ifdef CONFIG_X86_UV |
1161 | apicinterrupt UV_BAU_MESSAGE \ | 1178 | apicinterrupt3 UV_BAU_MESSAGE \ |
1162 | uv_bau_message_intr1 uv_bau_message_interrupt | 1179 | uv_bau_message_intr1 uv_bau_message_interrupt |
1163 | #endif | 1180 | #endif |
1164 | apicinterrupt LOCAL_TIMER_VECTOR \ | 1181 | apicinterrupt LOCAL_TIMER_VECTOR \ |
@@ -1167,14 +1184,19 @@ apicinterrupt X86_PLATFORM_IPI_VECTOR \ | |||
1167 | x86_platform_ipi smp_x86_platform_ipi | 1184 | x86_platform_ipi smp_x86_platform_ipi |
1168 | 1185 | ||
1169 | #ifdef CONFIG_HAVE_KVM | 1186 | #ifdef CONFIG_HAVE_KVM |
1170 | apicinterrupt POSTED_INTR_VECTOR \ | 1187 | apicinterrupt3 POSTED_INTR_VECTOR \ |
1171 | kvm_posted_intr_ipi smp_kvm_posted_intr_ipi | 1188 | kvm_posted_intr_ipi smp_kvm_posted_intr_ipi |
1172 | #endif | 1189 | #endif |
1173 | 1190 | ||
1191 | #ifdef CONFIG_X86_MCE_THRESHOLD | ||
1174 | apicinterrupt THRESHOLD_APIC_VECTOR \ | 1192 | apicinterrupt THRESHOLD_APIC_VECTOR \ |
1175 | threshold_interrupt smp_threshold_interrupt | 1193 | threshold_interrupt smp_threshold_interrupt |
1194 | #endif | ||
1195 | |||
1196 | #ifdef CONFIG_X86_THERMAL_VECTOR | ||
1176 | apicinterrupt THERMAL_APIC_VECTOR \ | 1197 | apicinterrupt THERMAL_APIC_VECTOR \ |
1177 | thermal_interrupt smp_thermal_interrupt | 1198 | thermal_interrupt smp_thermal_interrupt |
1199 | #endif | ||
1178 | 1200 | ||
1179 | #ifdef CONFIG_SMP | 1201 | #ifdef CONFIG_SMP |
1180 | apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ | 1202 | apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ |
@@ -1451,13 +1473,13 @@ ENTRY(xen_failsafe_callback) | |||
1451 | CFI_ENDPROC | 1473 | CFI_ENDPROC |
1452 | END(xen_failsafe_callback) | 1474 | END(xen_failsafe_callback) |
1453 | 1475 | ||
1454 | apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ | 1476 | apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ |
1455 | xen_hvm_callback_vector xen_evtchn_do_upcall | 1477 | xen_hvm_callback_vector xen_evtchn_do_upcall |
1456 | 1478 | ||
1457 | #endif /* CONFIG_XEN */ | 1479 | #endif /* CONFIG_XEN */ |
1458 | 1480 | ||
1459 | #if IS_ENABLED(CONFIG_HYPERV) | 1481 | #if IS_ENABLED(CONFIG_HYPERV) |
1460 | apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ | 1482 | apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ |
1461 | hyperv_callback_vector hyperv_vector_handler | 1483 | hyperv_callback_vector hyperv_vector_handler |
1462 | #endif /* CONFIG_HYPERV */ | 1484 | #endif /* CONFIG_HYPERV */ |
1463 | 1485 | ||
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 321d65ebaffe..5e4d8a8a5c40 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
@@ -518,9 +518,15 @@ ENTRY(idt_table) | |||
518 | .skip IDT_ENTRIES * 16 | 518 | .skip IDT_ENTRIES * 16 |
519 | 519 | ||
520 | .align L1_CACHE_BYTES | 520 | .align L1_CACHE_BYTES |
521 | ENTRY(nmi_idt_table) | 521 | ENTRY(debug_idt_table) |
522 | .skip IDT_ENTRIES * 16 | 522 | .skip IDT_ENTRIES * 16 |
523 | 523 | ||
524 | #ifdef CONFIG_TRACING | ||
525 | .align L1_CACHE_BYTES | ||
526 | ENTRY(trace_idt_table) | ||
527 | .skip IDT_ENTRIES * 16 | ||
528 | #endif | ||
529 | |||
524 | __PAGE_ALIGNED_BSS | 530 | __PAGE_ALIGNED_BSS |
525 | NEXT_PAGE(empty_zero_page) | 531 | NEXT_PAGE(empty_zero_page) |
526 | .skip PAGE_SIZE | 532 | .skip PAGE_SIZE |
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index ac0631d8996f..3a8185c042a2 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <asm/mce.h> | 18 | #include <asm/mce.h> |
19 | #include <asm/hw_irq.h> | 19 | #include <asm/hw_irq.h> |
20 | 20 | ||
21 | #define CREATE_TRACE_POINTS | ||
22 | #include <asm/trace/irq_vectors.h> | ||
23 | |||
21 | atomic_t irq_err_count; | 24 | atomic_t irq_err_count; |
22 | 25 | ||
23 | /* Function pointer for generic interrupt vector handling */ | 26 | /* Function pointer for generic interrupt vector handling */ |
@@ -204,23 +207,21 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs) | |||
204 | /* | 207 | /* |
205 | * Handler for X86_PLATFORM_IPI_VECTOR. | 208 | * Handler for X86_PLATFORM_IPI_VECTOR. |
206 | */ | 209 | */ |
207 | void smp_x86_platform_ipi(struct pt_regs *regs) | 210 | void __smp_x86_platform_ipi(void) |
208 | { | 211 | { |
209 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
210 | |||
211 | ack_APIC_irq(); | ||
212 | |||
213 | irq_enter(); | ||
214 | |||
215 | exit_idle(); | ||
216 | |||
217 | inc_irq_stat(x86_platform_ipis); | 212 | inc_irq_stat(x86_platform_ipis); |
218 | 213 | ||
219 | if (x86_platform_ipi_callback) | 214 | if (x86_platform_ipi_callback) |
220 | x86_platform_ipi_callback(); | 215 | x86_platform_ipi_callback(); |
216 | } | ||
221 | 217 | ||
222 | irq_exit(); | 218 | void smp_x86_platform_ipi(struct pt_regs *regs) |
219 | { | ||
220 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
223 | 221 | ||
222 | entering_ack_irq(); | ||
223 | __smp_x86_platform_ipi(); | ||
224 | exiting_irq(); | ||
224 | set_irq_regs(old_regs); | 225 | set_irq_regs(old_regs); |
225 | } | 226 | } |
226 | 227 | ||
@@ -246,6 +247,18 @@ void smp_kvm_posted_intr_ipi(struct pt_regs *regs) | |||
246 | } | 247 | } |
247 | #endif | 248 | #endif |
248 | 249 | ||
250 | void smp_trace_x86_platform_ipi(struct pt_regs *regs) | ||
251 | { | ||
252 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
253 | |||
254 | entering_ack_irq(); | ||
255 | trace_x86_platform_ipi_entry(X86_PLATFORM_IPI_VECTOR); | ||
256 | __smp_x86_platform_ipi(); | ||
257 | trace_x86_platform_ipi_exit(X86_PLATFORM_IPI_VECTOR); | ||
258 | exiting_irq(); | ||
259 | set_irq_regs(old_regs); | ||
260 | } | ||
261 | |||
249 | EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); | 262 | EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); |
250 | 263 | ||
251 | #ifdef CONFIG_HOTPLUG_CPU | 264 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c index ca8f703a1e70..636a55e4a13c 100644 --- a/arch/x86/kernel/irq_work.c +++ b/arch/x86/kernel/irq_work.c | |||
@@ -8,14 +8,34 @@ | |||
8 | #include <linux/irq_work.h> | 8 | #include <linux/irq_work.h> |
9 | #include <linux/hardirq.h> | 9 | #include <linux/hardirq.h> |
10 | #include <asm/apic.h> | 10 | #include <asm/apic.h> |
11 | #include <asm/trace/irq_vectors.h> | ||
11 | 12 | ||
12 | void smp_irq_work_interrupt(struct pt_regs *regs) | 13 | static inline void irq_work_entering_irq(void) |
13 | { | 14 | { |
14 | irq_enter(); | 15 | irq_enter(); |
15 | ack_APIC_irq(); | 16 | ack_APIC_irq(); |
17 | } | ||
18 | |||
19 | static inline void __smp_irq_work_interrupt(void) | ||
20 | { | ||
16 | inc_irq_stat(apic_irq_work_irqs); | 21 | inc_irq_stat(apic_irq_work_irqs); |
17 | irq_work_run(); | 22 | irq_work_run(); |
18 | irq_exit(); | 23 | } |
24 | |||
25 | void smp_irq_work_interrupt(struct pt_regs *regs) | ||
26 | { | ||
27 | irq_work_entering_irq(); | ||
28 | __smp_irq_work_interrupt(); | ||
29 | exiting_irq(); | ||
30 | } | ||
31 | |||
32 | void smp_trace_irq_work_interrupt(struct pt_regs *regs) | ||
33 | { | ||
34 | irq_work_entering_irq(); | ||
35 | trace_irq_work_entry(IRQ_WORK_VECTOR); | ||
36 | __smp_irq_work_interrupt(); | ||
37 | trace_irq_work_exit(IRQ_WORK_VECTOR); | ||
38 | exiting_irq(); | ||
19 | } | 39 | } |
20 | 40 | ||
21 | void arch_irq_work_raise(void) | 41 | void arch_irq_work_raise(void) |
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 48d2b7ded422..f4fe0b8879e0 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/proto.h> | 30 | #include <asm/proto.h> |
31 | #include <asm/apic.h> | 31 | #include <asm/apic.h> |
32 | #include <asm/nmi.h> | 32 | #include <asm/nmi.h> |
33 | #include <asm/trace/irq_vectors.h> | ||
33 | /* | 34 | /* |
34 | * Some notes on x86 processor bugs affecting SMP operation: | 35 | * Some notes on x86 processor bugs affecting SMP operation: |
35 | * | 36 | * |
@@ -249,32 +250,80 @@ finish: | |||
249 | /* | 250 | /* |
250 | * Reschedule call back. | 251 | * Reschedule call back. |
251 | */ | 252 | */ |
252 | void smp_reschedule_interrupt(struct pt_regs *regs) | 253 | static inline void __smp_reschedule_interrupt(void) |
253 | { | 254 | { |
254 | ack_APIC_irq(); | ||
255 | inc_irq_stat(irq_resched_count); | 255 | inc_irq_stat(irq_resched_count); |
256 | scheduler_ipi(); | 256 | scheduler_ipi(); |
257 | } | ||
258 | |||
259 | void smp_reschedule_interrupt(struct pt_regs *regs) | ||
260 | { | ||
261 | ack_APIC_irq(); | ||
262 | __smp_reschedule_interrupt(); | ||
257 | /* | 263 | /* |
258 | * KVM uses this interrupt to force a cpu out of guest mode | 264 | * KVM uses this interrupt to force a cpu out of guest mode |
259 | */ | 265 | */ |
260 | } | 266 | } |
261 | 267 | ||
262 | void smp_call_function_interrupt(struct pt_regs *regs) | 268 | void smp_trace_reschedule_interrupt(struct pt_regs *regs) |
269 | { | ||
270 | ack_APIC_irq(); | ||
271 | trace_reschedule_entry(RESCHEDULE_VECTOR); | ||
272 | __smp_reschedule_interrupt(); | ||
273 | trace_reschedule_exit(RESCHEDULE_VECTOR); | ||
274 | /* | ||
275 | * KVM uses this interrupt to force a cpu out of guest mode | ||
276 | */ | ||
277 | } | ||
278 | |||
279 | static inline void call_function_entering_irq(void) | ||
263 | { | 280 | { |
264 | ack_APIC_irq(); | 281 | ack_APIC_irq(); |
265 | irq_enter(); | 282 | irq_enter(); |
283 | } | ||
284 | |||
285 | static inline void __smp_call_function_interrupt(void) | ||
286 | { | ||
266 | generic_smp_call_function_interrupt(); | 287 | generic_smp_call_function_interrupt(); |
267 | inc_irq_stat(irq_call_count); | 288 | inc_irq_stat(irq_call_count); |
268 | irq_exit(); | ||
269 | } | 289 | } |
270 | 290 | ||
271 | void smp_call_function_single_interrupt(struct pt_regs *regs) | 291 | void smp_call_function_interrupt(struct pt_regs *regs) |
292 | { | ||
293 | call_function_entering_irq(); | ||
294 | __smp_call_function_interrupt(); | ||
295 | exiting_irq(); | ||
296 | } | ||
297 | |||
298 | void smp_trace_call_function_interrupt(struct pt_regs *regs) | ||
299 | { | ||
300 | call_function_entering_irq(); | ||
301 | trace_call_function_entry(CALL_FUNCTION_VECTOR); | ||
302 | __smp_call_function_interrupt(); | ||
303 | trace_call_function_exit(CALL_FUNCTION_VECTOR); | ||
304 | exiting_irq(); | ||
305 | } | ||
306 | |||
307 | static inline void __smp_call_function_single_interrupt(void) | ||
272 | { | 308 | { |
273 | ack_APIC_irq(); | ||
274 | irq_enter(); | ||
275 | generic_smp_call_function_single_interrupt(); | 309 | generic_smp_call_function_single_interrupt(); |
276 | inc_irq_stat(irq_call_count); | 310 | inc_irq_stat(irq_call_count); |
277 | irq_exit(); | 311 | } |
312 | |||
313 | void smp_call_function_single_interrupt(struct pt_regs *regs) | ||
314 | { | ||
315 | call_function_entering_irq(); | ||
316 | __smp_call_function_single_interrupt(); | ||
317 | exiting_irq(); | ||
318 | } | ||
319 | |||
320 | void smp_trace_call_function_single_interrupt(struct pt_regs *regs) | ||
321 | { | ||
322 | call_function_entering_irq(); | ||
323 | trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR); | ||
324 | __smp_call_function_single_interrupt(); | ||
325 | trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR); | ||
326 | exiting_irq(); | ||
278 | } | 327 | } |
279 | 328 | ||
280 | static int __init nonmi_ipi_setup(char *str) | 329 | static int __init nonmi_ipi_setup(char *str) |
diff --git a/arch/x86/kernel/tracepoint.c b/arch/x86/kernel/tracepoint.c new file mode 100644 index 000000000000..4e584a8d6edd --- /dev/null +++ b/arch/x86/kernel/tracepoint.c | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Code for supporting irq vector tracepoints. | ||
3 | * | ||
4 | * Copyright (C) 2013 Seiji Aguchi <seiji.aguchi@hds.com> | ||
5 | * | ||
6 | */ | ||
7 | #include <asm/hw_irq.h> | ||
8 | #include <asm/desc.h> | ||
9 | #include <linux/atomic.h> | ||
10 | |||
11 | atomic_t trace_idt_ctr = ATOMIC_INIT(0); | ||
12 | struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1, | ||
13 | (unsigned long) trace_idt_table }; | ||
14 | |||
15 | #ifndef CONFIG_X86_64 | ||
16 | gate_desc trace_idt_table[NR_VECTORS] __page_aligned_data | ||
17 | = { { { { 0, 0 } } }, }; | ||
18 | #endif | ||
19 | |||
20 | static int trace_irq_vector_refcount; | ||
21 | static DEFINE_MUTEX(irq_vector_mutex); | ||
22 | |||
23 | static void set_trace_idt_ctr(int val) | ||
24 | { | ||
25 | atomic_set(&trace_idt_ctr, val); | ||
26 | /* Ensure the trace_idt_ctr is set before sending IPI */ | ||
27 | wmb(); | ||
28 | } | ||
29 | |||
30 | static void switch_idt(void *arg) | ||
31 | { | ||
32 | unsigned long flags; | ||
33 | |||
34 | local_irq_save(flags); | ||
35 | load_current_idt(); | ||
36 | local_irq_restore(flags); | ||
37 | } | ||
38 | |||
39 | void trace_irq_vector_regfunc(void) | ||
40 | { | ||
41 | mutex_lock(&irq_vector_mutex); | ||
42 | if (!trace_irq_vector_refcount) { | ||
43 | set_trace_idt_ctr(1); | ||
44 | smp_call_function(switch_idt, NULL, 0); | ||
45 | switch_idt(NULL); | ||
46 | } | ||
47 | trace_irq_vector_refcount++; | ||
48 | mutex_unlock(&irq_vector_mutex); | ||
49 | } | ||
50 | |||
51 | void trace_irq_vector_unregfunc(void) | ||
52 | { | ||
53 | mutex_lock(&irq_vector_mutex); | ||
54 | trace_irq_vector_refcount--; | ||
55 | if (!trace_irq_vector_refcount) { | ||
56 | set_trace_idt_ctr(0); | ||
57 | smp_call_function(switch_idt, NULL, 0); | ||
58 | switch_idt(NULL); | ||
59 | } | ||
60 | mutex_unlock(&irq_vector_mutex); | ||
61 | } | ||
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index ee3d8e510504..b0865e88d3cc 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -788,7 +788,7 @@ void __init trap_init(void) | |||
788 | x86_init.irqs.trap_init(); | 788 | x86_init.irqs.trap_init(); |
789 | 789 | ||
790 | #ifdef CONFIG_X86_64 | 790 | #ifdef CONFIG_X86_64 |
791 | memcpy(&nmi_idt_table, &idt_table, IDT_ENTRIES * 16); | 791 | memcpy(&debug_idt_table, &idt_table, IDT_ENTRIES * 16); |
792 | set_nmi_gate(X86_TRAP_DB, &debug); | 792 | set_nmi_gate(X86_TRAP_DB, &debug); |
793 | set_nmi_gate(X86_TRAP_BP, &int3); | 793 | set_nmi_gate(X86_TRAP_BP, &int3); |
794 | #endif | 794 | #endif |
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index f8e084d0fc77..ebeab360d851 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -378,6 +378,8 @@ static inline void tracepoint_synchronize_unregister(void) | |||
378 | #define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) | 378 | #define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) |
379 | #define DEFINE_EVENT(template, name, proto, args) \ | 379 | #define DEFINE_EVENT(template, name, proto, args) \ |
380 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) | 380 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) |
381 | #define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg)\ | ||
382 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) | ||
381 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ | 383 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ |
382 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) | 384 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) |
383 | #define DEFINE_EVENT_CONDITION(template, name, proto, \ | 385 | #define DEFINE_EVENT_CONDITION(template, name, proto, \ |
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h index 1905ca8dd399..02e1003568a4 100644 --- a/include/trace/define_trace.h +++ b/include/trace/define_trace.h | |||
@@ -44,6 +44,10 @@ | |||
44 | #define DEFINE_EVENT(template, name, proto, args) \ | 44 | #define DEFINE_EVENT(template, name, proto, args) \ |
45 | DEFINE_TRACE(name) | 45 | DEFINE_TRACE(name) |
46 | 46 | ||
47 | #undef DEFINE_EVENT_FN | ||
48 | #define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg) \ | ||
49 | DEFINE_TRACE_FN(name, reg, unreg) | ||
50 | |||
47 | #undef DEFINE_EVENT_PRINT | 51 | #undef DEFINE_EVENT_PRINT |
48 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ | 52 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ |
49 | DEFINE_TRACE(name) | 53 | DEFINE_TRACE(name) |
@@ -91,6 +95,7 @@ | |||
91 | #undef TRACE_EVENT_CONDITION | 95 | #undef TRACE_EVENT_CONDITION |
92 | #undef DECLARE_EVENT_CLASS | 96 | #undef DECLARE_EVENT_CLASS |
93 | #undef DEFINE_EVENT | 97 | #undef DEFINE_EVENT |
98 | #undef DEFINE_EVENT_FN | ||
94 | #undef DEFINE_EVENT_PRINT | 99 | #undef DEFINE_EVENT_PRINT |
95 | #undef DEFINE_EVENT_CONDITION | 100 | #undef DEFINE_EVENT_CONDITION |
96 | #undef TRACE_HEADER_MULTI_READ | 101 | #undef TRACE_HEADER_MULTI_READ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 19edd7facaa1..d615f78cc6b6 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -71,6 +71,10 @@ | |||
71 | static struct ftrace_event_call __used \ | 71 | static struct ftrace_event_call __used \ |
72 | __attribute__((__aligned__(4))) event_##name | 72 | __attribute__((__aligned__(4))) event_##name |
73 | 73 | ||
74 | #undef DEFINE_EVENT_FN | ||
75 | #define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg) \ | ||
76 | DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) | ||
77 | |||
74 | #undef DEFINE_EVENT_PRINT | 78 | #undef DEFINE_EVENT_PRINT |
75 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ | 79 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ |
76 | DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) | 80 | DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) |
diff --git a/include/xen/events.h b/include/xen/events.h index b2b27c6a0f7b..c9ea10ee2273 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
@@ -76,6 +76,9 @@ unsigned irq_from_evtchn(unsigned int evtchn); | |||
76 | 76 | ||
77 | /* Xen HVM evtchn vector callback */ | 77 | /* Xen HVM evtchn vector callback */ |
78 | void xen_hvm_callback_vector(void); | 78 | void xen_hvm_callback_vector(void); |
79 | #ifdef CONFIG_TRACING | ||
80 | #define trace_xen_hvm_callback_vector xen_hvm_callback_vector | ||
81 | #endif | ||
79 | extern int xen_have_vector_callback; | 82 | extern int xen_have_vector_callback; |
80 | int xen_set_callback_via(uint64_t via); | 83 | int xen_set_callback_via(uint64_t via); |
81 | void xen_evtchn_do_upcall(struct pt_regs *regs); | 84 | void xen_evtchn_do_upcall(struct pt_regs *regs); |