61 lines
1.3 KiB
C
61 lines
1.3 KiB
C
/*
|
|
* 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);
|
|
}
|
|
|
|
int 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);
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
}
|