diff options
Diffstat (limited to 'arch/x86/kernel/tracepoint.c')
| -rw-r--r-- | arch/x86/kernel/tracepoint.c | 59 | 
1 files changed, 59 insertions, 0 deletions
diff --git a/arch/x86/kernel/tracepoint.c b/arch/x86/kernel/tracepoint.c new file mode 100644 index 00000000000..1c113db9ed5 --- /dev/null +++ b/arch/x86/kernel/tracepoint.c @@ -0,0 +1,59 @@ +/* + * Code for supporting irq vector tracepoints. + * + * Copyright (C) 2013 Seiji Aguchi <seiji.aguchi@hds.com> + * + */ +#include <asm/hw_irq.h> +#include <asm/desc.h> +#include <linux/atomic.h> + +atomic_t trace_idt_ctr = ATOMIC_INIT(0); +struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1, +				(unsigned long) trace_idt_table }; + +/* No need to be aligned, but done to keep all IDTs defined the same way. */ +gate_desc trace_idt_table[NR_VECTORS] __page_aligned_bss; + +static int trace_irq_vector_refcount; +static DEFINE_MUTEX(irq_vector_mutex); + +static void set_trace_idt_ctr(int val) +{ +	atomic_set(&trace_idt_ctr, val); +	/* Ensure the trace_idt_ctr is set before sending IPI */ +	wmb(); +} + +static void switch_idt(void *arg) +{ +	unsigned long flags; + +	local_irq_save(flags); +	load_current_idt(); +	local_irq_restore(flags); +} + +void trace_irq_vector_regfunc(void) +{ +	mutex_lock(&irq_vector_mutex); +	if (!trace_irq_vector_refcount) { +		set_trace_idt_ctr(1); +		smp_call_function(switch_idt, NULL, 0); +		switch_idt(NULL); +	} +	trace_irq_vector_refcount++; +	mutex_unlock(&irq_vector_mutex); +} + +void trace_irq_vector_unregfunc(void) +{ +	mutex_lock(&irq_vector_mutex); +	trace_irq_vector_refcount--; +	if (!trace_irq_vector_refcount) { +		set_trace_idt_ctr(0); +		smp_call_function(switch_idt, NULL, 0); +		switch_idt(NULL); +	} +	mutex_unlock(&irq_vector_mutex); +}  | 
