Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96a3d998 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'x86-tracing-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 tracing updates from Ingo Molnar:
 "This tree adds IRQ vector tracepoints that are named after the handler
  and which output the vector #, based on a zero-overhead approach that
  relies on changing the IDT entries, by Seiji Aguchi.

  The new tracepoints look like this:

   # perf list | grep -i irq_vector
    irq_vectors:local_timer_entry                      [Tracepoint event]
    irq_vectors:local_timer_exit                       [Tracepoint event]
    irq_vectors:reschedule_entry                       [Tracepoint event]
    irq_vectors:reschedule_exit                        [Tracepoint event]
    irq_vectors:spurious_apic_entry                    [Tracepoint event]
    irq_vectors:spurious_apic_exit                     [Tracepoint event]
    irq_vectors:error_apic_entry                       [Tracepoint event]
    irq_vectors:error_apic_exit                        [Tracepoint event]
   [...]"

* 'x86-tracing-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/tracing: Add config option checking to the definitions of mce handlers
  trace,x86: Do not call local_irq_save() in load_current_idt()
  trace,x86: Move creation of irq tracepoints from apic.c to irq.c
  x86, trace: Add irq vector tracepoints
  x86: Rename variables for debugging
  x86, trace: Introduce entering/exiting_irq()
  tracing: Add DEFINE_EVENT_FN() macro
parents 3045f94a 5236eb96
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <asm/fixmap.h>
#include <asm/mpspec.h>
#include <asm/msr.h>
#include <asm/idle.h>

#define ARCH_APICTIMER_STOPS_ON_C3	1

@@ -687,5 +688,31 @@ extern int default_check_phys_apicid_present(int phys_apicid);
#endif

#endif /* CONFIG_X86_LOCAL_APIC */
extern void irq_enter(void);
extern void irq_exit(void);

static inline void entering_irq(void)
{
	irq_enter();
	exit_idle();
}

static inline void entering_ack_irq(void)
{
	ack_APIC_irq();
	entering_irq();
}

static inline void exiting_irq(void)
{
	irq_exit();
}

static inline void exiting_ack_irq(void)
{
	irq_exit();
	/* Ack only at the end to avoid potential reentry */
	ack_APIC_irq();
}

#endif /* _ASM_X86_APIC_H */
+112 −5
Original line number Diff line number Diff line
@@ -36,8 +36,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in

extern struct desc_ptr idt_descr;
extern gate_desc idt_table[];
extern struct desc_ptr nmi_idt_descr;
extern gate_desc nmi_idt_table[];
extern struct desc_ptr debug_idt_descr;
extern gate_desc debug_idt_table[];

struct gdt_page {
	struct desc_struct gdt[GDT_ENTRIES];
@@ -316,7 +316,20 @@ static inline void set_nmi_gate(int gate, void *addr)
	gate_desc s;

	pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS);
	write_idt_entry(nmi_idt_table, gate, &s);
	write_idt_entry(debug_idt_table, gate, &s);
}
#endif

#ifdef CONFIG_TRACING
extern struct desc_ptr trace_idt_descr;
extern gate_desc trace_idt_table[];
static inline void write_trace_idt_entry(int entry, const gate_desc *gate)
{
	write_idt_entry(trace_idt_table, entry, gate);
}
#else
static inline void write_trace_idt_entry(int entry, const gate_desc *gate)
{
}
#endif

@@ -331,6 +344,7 @@ static inline void _set_gate(int gate, unsigned type, void *addr,
	 * setup time
	 */
	write_idt_entry(idt_table, gate, &s);
	write_trace_idt_entry(gate, &s);
}

/*
@@ -360,12 +374,39 @@ static inline void alloc_system_vector(int vector)
	}
}

static inline void alloc_intr_gate(unsigned int n, void *addr)
#ifdef CONFIG_TRACING
static inline void trace_set_intr_gate(unsigned int gate, void *addr)
{
	gate_desc s;

	pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS);
	write_idt_entry(trace_idt_table, gate, &s);
}

static inline void __trace_alloc_intr_gate(unsigned int n, void *addr)
{
	trace_set_intr_gate(n, addr);
}
#else
static inline void trace_set_intr_gate(unsigned int gate, void *addr)
{
}

#define __trace_alloc_intr_gate(n, addr)
#endif

static inline void __alloc_intr_gate(unsigned int n, void *addr)
{
	alloc_system_vector(n);
	set_intr_gate(n, addr);
}

#define alloc_intr_gate(n, addr)				\
	do {							\
		alloc_system_vector(n);				\
		__alloc_intr_gate(n, addr);			\
		__trace_alloc_intr_gate(n, trace_##addr);	\
	} while (0)

/*
 * This routine sets up an interrupt gate at directory privilege level 3.
 */
@@ -405,4 +446,70 @@ static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist)
	_set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS);
}

#ifdef CONFIG_X86_64
DECLARE_PER_CPU(u32, debug_idt_ctr);
static inline bool is_debug_idt_enabled(void)
{
	if (this_cpu_read(debug_idt_ctr))
		return true;

	return false;
}

static inline void load_debug_idt(void)
{
	load_idt((const struct desc_ptr *)&debug_idt_descr);
}
#else
static inline bool is_debug_idt_enabled(void)
{
	return false;
}

static inline void load_debug_idt(void)
{
}
#endif

#ifdef CONFIG_TRACING
extern atomic_t trace_idt_ctr;
static inline bool is_trace_idt_enabled(void)
{
	if (atomic_read(&trace_idt_ctr))
		return true;

	return false;
}

static inline void load_trace_idt(void)
{
	load_idt((const struct desc_ptr *)&trace_idt_descr);
}
#else
static inline bool is_trace_idt_enabled(void)
{
	return false;
}

static inline void load_trace_idt(void)
{
}
#endif

/*
 * The load_current_idt() must be called with interrupts disabled
 * to avoid races. That way the IDT will always be set back to the expected
 * descriptor. It's also called when a CPU is being initialized, and
 * that doesn't need to disable interrupts, as nothing should be
 * bothering the CPU then.
 */
static inline void load_current_idt(void)
{
	if (is_debug_idt_enabled())
		load_debug_idt();
	else if (is_trace_idt_enabled())
		load_trace_idt();
	else
		load_idt((const struct desc_ptr *)&idt_descr);
}
#endif /* _ASM_X86_DESC_H */
+5 −3
Original line number Diff line number Diff line
@@ -13,14 +13,16 @@
BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR)
BUILD_INTERRUPT3(irq_move_cleanup_interrupt, IRQ_MOVE_CLEANUP_VECTOR,
		 smp_irq_move_cleanup_interrupt)
BUILD_INTERRUPT3(reboot_interrupt, REBOOT_VECTOR, smp_reboot_interrupt)
#endif

BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)

#ifdef CONFIG_HAVE_KVM
BUILD_INTERRUPT(kvm_posted_intr_ipi, POSTED_INTR_VECTOR)
BUILD_INTERRUPT3(kvm_posted_intr_ipi, POSTED_INTR_VECTOR,
		 smp_kvm_posted_intr_ipi)
#endif

/*
+17 −0
Original line number Diff line number Diff line
@@ -77,6 +77,23 @@ extern void threshold_interrupt(void);
extern void call_function_interrupt(void);
extern void call_function_single_interrupt(void);

#ifdef CONFIG_TRACING
/* Interrupt handlers registered during init_IRQ */
extern void trace_apic_timer_interrupt(void);
extern void trace_x86_platform_ipi(void);
extern void trace_error_interrupt(void);
extern void trace_irq_work_interrupt(void);
extern void trace_spurious_interrupt(void);
extern void trace_thermal_interrupt(void);
extern void trace_reschedule_interrupt(void);
extern void trace_threshold_interrupt(void);
extern void trace_call_function_interrupt(void);
extern void trace_call_function_single_interrupt(void);
#define trace_irq_move_cleanup_interrupt  irq_move_cleanup_interrupt
#define trace_reboot_interrupt  reboot_interrupt
#define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi
#endif /* CONFIG_TRACING */

/* IOAPIC */
#define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs))
extern unsigned long io_apic_irqs;
+3 −0
Original line number Diff line number Diff line
@@ -12,6 +12,9 @@ struct ms_hyperv_info {
extern struct ms_hyperv_info ms_hyperv;

void hyperv_callback_vector(void);
#ifdef CONFIG_TRACING
#define trace_hyperv_callback_vector hyperv_callback_vector
#endif
void hyperv_vector_handler(struct pt_regs *regs);
void hv_register_vmbus_handler(int irq, irq_handler_t handler);

Loading