|  | /* | 
|  | * 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); | 
|  | } |