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 /* No need to be aligned, but done to keep all IDTs defined the same way. */ 16 gate_desc trace_idt_table[NR_VECTORS] __page_aligned_bss; 17 18 static int trace_irq_vector_refcount; 19 static DEFINE_MUTEX(irq_vector_mutex); 20 21 static void set_trace_idt_ctr(int val) 22 { 23 atomic_set(&trace_idt_ctr, val); 24 /* Ensure the trace_idt_ctr is set before sending IPI */ 25 wmb(); 26 } 27 28 static void switch_idt(void *arg) 29 { 30 unsigned long flags; 31 32 local_irq_save(flags); 33 load_current_idt(); 34 local_irq_restore(flags); 35 } 36 37 int trace_irq_vector_regfunc(void) 38 { 39 mutex_lock(&irq_vector_mutex); 40 if (!trace_irq_vector_refcount) { 41 set_trace_idt_ctr(1); 42 smp_call_function(switch_idt, NULL, 0); 43 switch_idt(NULL); 44 } 45 trace_irq_vector_refcount++; 46 mutex_unlock(&irq_vector_mutex); 47 return 0; 48 } 49 50 void trace_irq_vector_unregfunc(void) 51 { 52 mutex_lock(&irq_vector_mutex); 53 trace_irq_vector_refcount--; 54 if (!trace_irq_vector_refcount) { 55 set_trace_idt_ctr(0); 56 smp_call_function(switch_idt, NULL, 0); 57 switch_idt(NULL); 58 } 59 mutex_unlock(&irq_vector_mutex); 60 } 61