aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:31:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:31:49 -0400
commit96a3d998fb92c28b9862297fcf93a24d8a0eac1d (patch)
tree7fe1a799a3a84d276e7dcf8b0afa5b4ceb56659f
parent3045f94a20cc54e3e5b20a843701eeab86f57163 (diff)
parent5236eb968ec21c693d463d0494e39b00c1bc174d (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.h27
-rw-r--r--arch/x86/include/asm/desc.h117
-rw-r--r--arch/x86/include/asm/entry_arch.h8
-rw-r--r--arch/x86/include/asm/hw_irq.h17
-rw-r--r--arch/x86/include/asm/mshyperv.h3
-rw-r--r--arch/x86/include/asm/trace/irq_vectors.h104
-rw-r--r--arch/x86/include/asm/uv/uv_bau.h3
-rw-r--r--arch/x86/kernel/Makefile3
-rw-r--r--arch/x86/kernel/apic/apic.c69
-rw-r--r--arch/x86/kernel/cpu/common.c20
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c24
-rw-r--r--arch/x86/kernel/cpu/mcheck/threshold.c24
-rw-r--r--arch/x86/kernel/entry_32.S12
-rw-r--r--arch/x86/kernel/entry_64.S36
-rw-r--r--arch/x86/kernel/head_64.S8
-rw-r--r--arch/x86/kernel/irq.c33
-rw-r--r--arch/x86/kernel/irq_work.c24
-rw-r--r--arch/x86/kernel/smp.c65
-rw-r--r--arch/x86/kernel/tracepoint.c61
-rw-r--r--arch/x86/kernel/traps.c2
-rw-r--r--include/linux/tracepoint.h2
-rw-r--r--include/trace/define_trace.h5
-rw-r--r--include/trace/ftrace.h4
-rw-r--r--include/xen/events.h3
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 */
691extern void irq_enter(void);
692extern void irq_exit(void);
693
694static inline void entering_irq(void)
695{
696 irq_enter();
697 exit_idle();
698}
699
700static inline void entering_ack_irq(void)
701{
702 ack_APIC_irq();
703 entering_irq();
704}
705
706static inline void exiting_irq(void)
707{
708 irq_exit();
709}
710
711static 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
37extern struct desc_ptr idt_descr; 37extern struct desc_ptr idt_descr;
38extern gate_desc idt_table[]; 38extern gate_desc idt_table[];
39extern struct desc_ptr nmi_idt_descr; 39extern struct desc_ptr debug_idt_descr;
40extern gate_desc nmi_idt_table[]; 40extern gate_desc debug_idt_table[];
41 41
42struct gdt_page { 42struct 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
324extern struct desc_ptr trace_idt_descr;
325extern gate_desc trace_idt_table[];
326static 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
331static 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
363static inline void alloc_intr_gate(unsigned int n, void *addr) 377#ifdef CONFIG_TRACING
378static 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
386static inline void __trace_alloc_intr_gate(unsigned int n, void *addr)
387{
388 trace_set_intr_gate(n, addr);
389}
390#else
391static 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
398static 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
450DECLARE_PER_CPU(u32, debug_idt_ctr);
451static 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
459static inline void load_debug_idt(void)
460{
461 load_idt((const struct desc_ptr *)&debug_idt_descr);
462}
463#else
464static inline bool is_debug_idt_enabled(void)
465{
466 return false;
467}
468
469static inline void load_debug_idt(void)
470{
471}
472#endif
473
474#ifdef CONFIG_TRACING
475extern atomic_t trace_idt_ctr;
476static inline bool is_trace_idt_enabled(void)
477{
478 if (atomic_read(&trace_idt_ctr))
479 return true;
480
481 return false;
482}
483
484static inline void load_trace_idt(void)
485{
486 load_idt((const struct desc_ptr *)&trace_idt_descr);
487}
488#else
489static inline bool is_trace_idt_enabled(void)
490{
491 return false;
492}
493
494static 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 */
506static 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 @@
13BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) 13BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
14BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) 14BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
15BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR) 15BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
16BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR) 16BUILD_INTERRUPT3(irq_move_cleanup_interrupt, IRQ_MOVE_CLEANUP_VECTOR,
17BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR) 17 smp_irq_move_cleanup_interrupt)
18BUILD_INTERRUPT3(reboot_interrupt, REBOOT_VECTOR, smp_reboot_interrupt)
18#endif 19#endif
19 20
20BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR) 21BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
21 22
22#ifdef CONFIG_HAVE_KVM 23#ifdef CONFIG_HAVE_KVM
23BUILD_INTERRUPT(kvm_posted_intr_ipi, POSTED_INTR_VECTOR) 24BUILD_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);
77extern void call_function_interrupt(void); 77extern void call_function_interrupt(void);
78extern void call_function_single_interrupt(void); 78extern void call_function_single_interrupt(void);
79 79
80#ifdef CONFIG_TRACING
81/* Interrupt handlers registered during init_IRQ */
82extern void trace_apic_timer_interrupt(void);
83extern void trace_x86_platform_ipi(void);
84extern void trace_error_interrupt(void);
85extern void trace_irq_work_interrupt(void);
86extern void trace_spurious_interrupt(void);
87extern void trace_thermal_interrupt(void);
88extern void trace_reschedule_interrupt(void);
89extern void trace_threshold_interrupt(void);
90extern void trace_call_function_interrupt(void);
91extern 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))
82extern unsigned long io_apic_irqs; 99extern 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 {
12extern struct ms_hyperv_info ms_hyperv; 12extern struct ms_hyperv_info ms_hyperv;
13 13
14void hyperv_callback_vector(void); 14void hyperv_callback_vector(void);
15#ifdef CONFIG_TRACING
16#define trace_hyperv_callback_vector hyperv_callback_vector
17#endif
15void hyperv_vector_handler(struct pt_regs *regs); 18void hyperv_vector_handler(struct pt_regs *regs);
16void hv_register_vmbus_handler(int irq, irq_handler_t handler); 19void 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
9extern void trace_irq_vector_regfunc(void);
10extern void trace_irq_vector_unregfunc(void);
11
12DECLARE_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) \
29DEFINE_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); \
34DEFINE_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 */
45DEFINE_IRQ_VECTOR_EVENT(local_timer);
46
47/*
48 * reschedule - called when entering/exiting a reschedule vector handler
49 */
50DEFINE_IRQ_VECTOR_EVENT(reschedule);
51
52/*
53 * spurious_apic - called when entering/exiting a spurious apic vector handler
54 */
55DEFINE_IRQ_VECTOR_EVENT(spurious_apic);
56
57/*
58 * error_apic - called when entering/exiting an error apic vector handler
59 */
60DEFINE_IRQ_VECTOR_EVENT(error_apic);
61
62/*
63 * x86_platform_ipi - called when entering/exiting a x86 platform ipi interrupt
64 * vector handler
65 */
66DEFINE_IRQ_VECTOR_EVENT(x86_platform_ipi);
67
68/*
69 * irq_work - called when entering/exiting a irq work interrupt
70 * vector handler
71 */
72DEFINE_IRQ_VECTOR_EVENT(irq_work);
73
74/*
75 * call_function - called when entering/exiting a call function interrupt
76 * vector handler
77 */
78DEFINE_IRQ_VECTOR_EVENT(call_function);
79
80/*
81 * call_function_single - called when entering/exiting a call function
82 * single interrupt vector handler
83 */
84DEFINE_IRQ_VECTOR_EVENT(call_function_single);
85
86/*
87 * threshold_apic - called when entering/exiting a threshold apic interrupt
88 * vector handler
89 */
90DEFINE_IRQ_VECTOR_EVENT(threshold_apic);
91
92/*
93 * thermal_apic - called when entering/exiting a thermal apic interrupt
94 * vector handler
95 */
96DEFINE_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
733extern void uv_bau_message_intr1(void); 733extern void uv_bau_message_intr1(void);
734#ifdef CONFIG_TRACING
735#define trace_uv_bau_message_intr1 uv_bau_message_intr1
736#endif
734extern void uv_bau_timeout_intr1(void); 737extern void uv_bau_timeout_intr1(void);
735 738
736struct atomic_short { 739struct 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
16CFLAGS_REMOVE_early_printk.o = -pg 16CFLAGS_REMOVE_early_printk.o = -pg
17endif 17endif
18 18
19CFLAGS_irq.o := -I$(src)/../include/asm/trace
20
19obj-y := process_$(BITS).o signal.o entry_$(BITS).o 21obj-y := process_$(BITS).o signal.o entry_$(BITS).o
20obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o 22obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
21obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o 23obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o
@@ -103,6 +105,7 @@ obj-$(CONFIG_OF) += devicetree.o
103obj-$(CONFIG_UPROBES) += uprobes.o 105obj-$(CONFIG_UPROBES) += uprobes.o
104 106
105obj-$(CONFIG_PERF_EVENTS) += perf_regs.o 107obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
108obj-$(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
935void __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 */
1910void smp_spurious_interrupt(struct pt_regs *regs) 1929static 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
1949void smp_spurious_interrupt(struct pt_regs *regs)
1950{
1951 entering_irq();
1952 __smp_spurious_interrupt();
1953 exiting_irq();
1954}
1955
1956void 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 */
1936void smp_error_interrupt(struct pt_regs *regs) 1968static 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
2005void smp_error_interrupt(struct pt_regs *regs)
2006{
2007 entering_irq();
2008 __smp_error_interrupt(regs);
2009 exiting_irq();
2010}
2011
2012void 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
1074struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; 1074struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
1075struct desc_ptr nmi_idt_descr = { NR_VECTORS * 16 - 1, 1075struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
1076 (unsigned long) nmi_idt_table }; 1076 (unsigned long) debug_idt_table };
1077 1077
1078DEFINE_PER_CPU_FIRST(union irq_stack_union, 1078DEFINE_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
1152static DEFINE_PER_CPU(u32, debug_stack_use_ctr); 1152DEFINE_PER_CPU(u32, debug_idt_ctr);
1153 1153
1154void debug_stack_set_zero(void) 1154void 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
1160void debug_stack_reset(void) 1160void 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
379static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt; 380static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt;
380 381
381asmlinkage void smp_thermal_interrupt(struct pt_regs *regs) 382static 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(); 388asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
389{
390 entering_irq();
391 __smp_thermal_interrupt();
392 exiting_ack_irq();
393}
394
395asmlinkage 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
12static void default_threshold_interrupt(void) 13static void default_threshold_interrupt(void)
13{ 14{
@@ -17,13 +18,24 @@ static void default_threshold_interrupt(void)
17 18
18void (*mce_threshold_vector)(void) = default_threshold_interrupt; 19void (*mce_threshold_vector)(void) = default_threshold_interrupt;
19 20
20asmlinkage void smp_threshold_interrupt(void) 21static 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(); 27asmlinkage void smp_threshold_interrupt(void)
28{
29 entering_irq();
30 __smp_threshold_interrupt();
31 exiting_ack_irq();
32}
33
34asmlinkage 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; \
802ENDPROC(name) 802ENDPROC(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
1142ENTRY(\sym) 1142ENTRY(\sym)
1143 INTR_FRAME 1143 INTR_FRAME
1144 ASM_CLAC 1144 ASM_CLAC
@@ -1150,15 +1150,32 @@ ENTRY(\sym)
1150END(\sym) 1150END(\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
1158apicinterrupt3 \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
1166apicinterrupt3 \num \sym \do_sym
1167trace_apicinterrupt \num \sym
1168.endm
1169
1153#ifdef CONFIG_SMP 1170#ifdef CONFIG_SMP
1154apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \ 1171apicinterrupt3 IRQ_MOVE_CLEANUP_VECTOR \
1155 irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt 1172 irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
1156apicinterrupt REBOOT_VECTOR \ 1173apicinterrupt3 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
1161apicinterrupt UV_BAU_MESSAGE \ 1178apicinterrupt3 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
1164apicinterrupt LOCAL_TIMER_VECTOR \ 1181apicinterrupt 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
1170apicinterrupt POSTED_INTR_VECTOR \ 1187apicinterrupt3 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
1174apicinterrupt THRESHOLD_APIC_VECTOR \ 1192apicinterrupt THRESHOLD_APIC_VECTOR \
1175 threshold_interrupt smp_threshold_interrupt 1193 threshold_interrupt smp_threshold_interrupt
1194#endif
1195
1196#ifdef CONFIG_X86_THERMAL_VECTOR
1176apicinterrupt THERMAL_APIC_VECTOR \ 1197apicinterrupt 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
1180apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ 1202apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
@@ -1451,13 +1473,13 @@ ENTRY(xen_failsafe_callback)
1451 CFI_ENDPROC 1473 CFI_ENDPROC
1452END(xen_failsafe_callback) 1474END(xen_failsafe_callback)
1453 1475
1454apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ 1476apicinterrupt3 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)
1460apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ 1482apicinterrupt3 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
521ENTRY(nmi_idt_table) 521ENTRY(debug_idt_table)
522 .skip IDT_ENTRIES * 16 522 .skip IDT_ENTRIES * 16
523 523
524#ifdef CONFIG_TRACING
525 .align L1_CACHE_BYTES
526ENTRY(trace_idt_table)
527 .skip IDT_ENTRIES * 16
528#endif
529
524 __PAGE_ALIGNED_BSS 530 __PAGE_ALIGNED_BSS
525NEXT_PAGE(empty_zero_page) 531NEXT_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
21atomic_t irq_err_count; 24atomic_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 */
207void smp_x86_platform_ipi(struct pt_regs *regs) 210void __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(); 218void 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
250void 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
249EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); 262EXPORT_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
12void smp_irq_work_interrupt(struct pt_regs *regs) 13static 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
19static 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
25void smp_irq_work_interrupt(struct pt_regs *regs)
26{
27 irq_work_entering_irq();
28 __smp_irq_work_interrupt();
29 exiting_irq();
30}
31
32void 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
21void arch_irq_work_raise(void) 41void 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 */
252void smp_reschedule_interrupt(struct pt_regs *regs) 253static 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
259void 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
262void smp_call_function_interrupt(struct pt_regs *regs) 268void 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
279static 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
285static 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
271void smp_call_function_single_interrupt(struct pt_regs *regs) 291void smp_call_function_interrupt(struct pt_regs *regs)
292{
293 call_function_entering_irq();
294 __smp_call_function_interrupt();
295 exiting_irq();
296}
297
298void 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
307static 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
313void 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
320void 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
280static int __init nonmi_ipi_setup(char *str) 329static 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
11atomic_t trace_idt_ctr = ATOMIC_INIT(0);
12struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1,
13 (unsigned long) trace_idt_table };
14
15#ifndef CONFIG_X86_64
16gate_desc trace_idt_table[NR_VECTORS] __page_aligned_data
17 = { { { { 0, 0 } } }, };
18#endif
19
20static int trace_irq_vector_refcount;
21static DEFINE_MUTEX(irq_vector_mutex);
22
23static 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
30static 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
39void 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
51void 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 */
78void xen_hvm_callback_vector(void); 78void xen_hvm_callback_vector(void);
79#ifdef CONFIG_TRACING
80#define trace_xen_hvm_callback_vector xen_hvm_callback_vector
81#endif
79extern int xen_have_vector_callback; 82extern int xen_have_vector_callback;
80int xen_set_callback_via(uint64_t via); 83int xen_set_callback_via(uint64_t via);
81void xen_evtchn_do_upcall(struct pt_regs *regs); 84void xen_evtchn_do_upcall(struct pt_regs *regs);