diff options
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r-- | arch/blackfin/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/blackfin/kernel/bfin_ksyms.c | 5 | ||||
-rw-r--r-- | arch/blackfin/kernel/ftrace-entry.S | 72 |
3 files changed, 78 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index a66dda4f4b1f..d2ae285e5b6e 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile | |||
@@ -15,6 +15,7 @@ else | |||
15 | obj-y += time.o | 15 | obj-y += time.o |
16 | endif | 16 | endif |
17 | 17 | ||
18 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o | ||
18 | obj-$(CONFIG_IPIPE) += ipipe.o | 19 | obj-$(CONFIG_IPIPE) += ipipe.o |
19 | obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o | 20 | obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o |
20 | obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o | 21 | obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o |
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index 53e893ff708a..aa05e638fb7c 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c | |||
@@ -103,3 +103,8 @@ EXPORT_SYMBOL(__raw_smp_mark_barrier_asm); | |||
103 | EXPORT_SYMBOL(__raw_smp_check_barrier_asm); | 103 | EXPORT_SYMBOL(__raw_smp_check_barrier_asm); |
104 | #endif | 104 | #endif |
105 | #endif | 105 | #endif |
106 | |||
107 | #ifdef CONFIG_FUNCTION_TRACER | ||
108 | extern void _mcount(void); | ||
109 | EXPORT_SYMBOL(_mcount); | ||
110 | #endif | ||
diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S new file mode 100644 index 000000000000..ce71487b515f --- /dev/null +++ b/arch/blackfin/kernel/ftrace-entry.S | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * mcount and friends -- ftrace stuff | ||
3 | * | ||
4 | * Copyright (C) 2009 Analog Devices Inc. | ||
5 | * Licensed under the GPL-2 or later. | ||
6 | */ | ||
7 | |||
8 | #include <linux/linkage.h> | ||
9 | #include <asm/ftrace.h> | ||
10 | |||
11 | .text | ||
12 | |||
13 | /* GCC will have called us before setting up the function prologue, so we | ||
14 | * can clobber the normal scratch registers, but we need to make sure to | ||
15 | * save/restore the registers used for argument passing (R0-R2) in case | ||
16 | * the profiled function is using them. With data registers, R3 is the | ||
17 | * only one we can blow away. With pointer registers, we have P0-P2. | ||
18 | * | ||
19 | * Upon entry, the RETS will point to the top of the current profiled | ||
20 | * function. And since GCC setup the frame for us, the previous function | ||
21 | * will be waiting there. mmmm pie. | ||
22 | */ | ||
23 | ENTRY(__mcount) | ||
24 | /* save third function arg early so we can do testing below */ | ||
25 | [--sp] = r2; | ||
26 | |||
27 | /* load the function pointer to the tracer */ | ||
28 | p0.l = _ftrace_trace_function; | ||
29 | p0.h = _ftrace_trace_function; | ||
30 | r3 = [p0]; | ||
31 | |||
32 | /* optional micro optimization: don't call the stub tracer */ | ||
33 | r2.l = _ftrace_stub; | ||
34 | r2.h = _ftrace_stub; | ||
35 | cc = r2 == r3; | ||
36 | if ! cc jump .Ldo_trace; | ||
37 | |||
38 | r2 = [sp++]; | ||
39 | rts; | ||
40 | |||
41 | .Ldo_trace: | ||
42 | |||
43 | /* save first/second function arg and the return register */ | ||
44 | [--sp] = r0; | ||
45 | [--sp] = r1; | ||
46 | [--sp] = rets; | ||
47 | |||
48 | /* setup the tracer function */ | ||
49 | p0 = r3; | ||
50 | |||
51 | /* tracer(ulong frompc, ulong selfpc): | ||
52 | * frompc: the pc that did the call to ... | ||
53 | * selfpc: ... this location | ||
54 | * the selfpc itself will need adjusting for the mcount call | ||
55 | */ | ||
56 | r1 = rets; | ||
57 | r0 = [fp + 4]; | ||
58 | r1 += -MCOUNT_INSN_SIZE; | ||
59 | |||
60 | /* call the tracer */ | ||
61 | call (p0); | ||
62 | |||
63 | /* restore state and get out of dodge */ | ||
64 | rets = [sp++]; | ||
65 | r1 = [sp++]; | ||
66 | r0 = [sp++]; | ||
67 | r2 = [sp++]; | ||
68 | |||
69 | .globl _ftrace_stub | ||
70 | _ftrace_stub: | ||
71 | rts; | ||
72 | ENDPROC(__mcount) | ||