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