1/*
2 *
3 * Copyright (C) SGI 1999, 2000
4 *
5 * Written by Dimitris Michailidis (dimitris@engr.sgi.com)
6 */
7
8#ifndef _ASM_KERNPROF_H
9#define _ASM_KERNPROF_H
10
11#ifdef __KERNEL__
12
13#include <asm/system.h>
14#include <asm/ptrace.h>
15#include <asm/msr.h>
16#include <asm/processor.h>
17
18#define DFL_PC_RES 4		/* default PC resolution for this platform */
19
20/*
21 * When executing in the BIOS or PROM (happens with APM) we get kernel-mode
22 * addresses below &_stext.
23 */
24#define in_firmware(regs) ((regs)->eip < (unsigned long) &_stext)
25
26struct st_limits {              /* valid kernel stack is between bot & top */
27	unsigned long *top;
28	unsigned long *bot;
29};
30
31struct frame_info {
32	struct st_limits limits;
33	unsigned long *frame_ptr; /* saved ebp */
34	unsigned long pc;         /* saved eip */
35};
36
37typedef struct frame_info frame_info_t;
38
39#define frame_get_pc(p) ((p)->pc)
40
41static __inline__ void get_stack_limits(struct pt_regs *regs,
42					struct st_limits *p)
43{
44	p->top = &regs->esp;
45	p->bot = (unsigned long *)((unsigned long) current + THREAD_SIZE);
46}
47
48/*
49 * A function sets up its stack frame with the instructions
50 *
51 * 	pushl %ebp
52 *	movl %esp, %ebp
53 *
54 * The timer interrupt may arrive at any time including right at the moment
55 * that the new frame is being set up, so we need to distinguish a few cases.
56 */
57static __inline__ void get_top_frame(struct pt_regs *regs, frame_info_t *p)
58{
59	unsigned long pc = regs->eip;
60
61	get_stack_limits(regs, &p->limits);
62	if (*p->limits.top == regs->ebp) {         /* between pushl and movl */
63		p->frame_ptr = p->limits.top;
64		p->pc = pc;
65	} else {
66		p->frame_ptr = (unsigned long *) regs->ebp;
67		if (*(unsigned char *)pc == 0x55)  /* right at pushl %ebp */
68			p->pc = *p->limits.top;
69		else
70			p->pc = pc;
71	}
72}
73
74/* Fabricate a stack frame that is sufficient to begin walking up the stack */
75static __inline__ int build_fake_frame(frame_info_t *p)
76{
77	__asm__ __volatile__("movl %%esp,%0" : "=m" (p->limits.top));
78	p->limits.bot = (unsigned long *)((unsigned long)current + THREAD_SIZE);
79	__asm__ __volatile__("movl %%ebp,%0" : "=m" (p->frame_ptr));
80	p->pc = (unsigned long)current_text_addr();
81	return 1;
82}
83
84/* This macro determines whether there are more frames to go on the stack */
85#define last_frame(p) \
86	((p)->frame_ptr < (p)->limits.top || (p)->frame_ptr >= (p)->limits.bot)
87
88static __inline__ int get_next_frame(frame_info_t *p)
89{
90	if (last_frame(p))
91		return 0;
92	p->pc = p->frame_ptr[1];
93	p->frame_ptr = (unsigned long *) *p->frame_ptr;
94	return 1;
95}
96
97/* These are called by mcount() so we want them to be fast. */
98void cg_record_arc(unsigned long, unsigned long) __attribute__((regparm(2)));
99void record_fn_call(unsigned long, unsigned long) __attribute__((regparm(2)));
100
101#define supports_call_graph (prof_have_mcount && prof_have_frameptr)
102
103#if defined(CONFIG_MCOUNT)
104#define MCOUNT_STEXT_LOCK "call mcount_stext_lock"
105#define MCOUNT_ASM        "call mcount_asm"
106#else
107#define MCOUNT_STEXT_LOCK
108#define MCOUNT_ASM
109#endif
110
111/* We can do 16-bit compare&swap */
112#define __HAVE_ARCH_CMPXCHG16 1
113
114/*
115 * Performance counters are supported only on P6-family systems with local APIC
116 * since we rely on the overflow interrupts.
117 */
118#ifdef CONFIG_X86_LOCAL_APIC
119#define have_perfctr() (cpu_has_msr && boot_cpu_data.x86 == 6)
120
121#define valid_perfctr_event(e) ((unsigned long)(e) <= 0xFFFFF)
122#define valid_perfctr_freq(n)  ((long)(n) >= 0)
123
124#define get_prof_freq()		(HZ * prof_multiplier[0])
125
126#define EVENTSEL0_ENABLE_MASK  0x00500000
127
128#define perfctr_reload(n)	wrmsr(MSR_P6_PERFCTR0, -(int)(n), 0)
129#define __perfctr_stop()	wrmsr(MSR_P6_EVNTSEL0, 0, 0)
130
131static __inline__ void __perfctr_commence(unsigned int freq, int evt)
132{
133	perfctr_reload(freq);
134	wrmsr(MSR_P6_EVNTSEL1, 0, 0);
135	wrmsr(MSR_P6_EVNTSEL0, EVENTSEL0_ENABLE_MASK | (evt), 0);
136}
137#else
138#define have_perfctr()		0
139#define valid_perfctr_event(e)	0
140#define valid_perfctr_freq(n)	0
141#define perfctr_reload(x)
142#define __perfctr_stop()
143#define __perfctr_commence(x,y)
144#define get_prof_freq()		HZ
145#define setup_profiling_timer(x) (-EINVAL)
146#endif
147
148#endif /* __KERNEL__ */
149
150#endif /* !_ASM_KERNPROF_H */
151