mm: hugetlb: fix hugepage memory leak caused by wrong reserve count
[linux/fpc-iii.git] / arch / blackfin / kernel / ftrace-entry.S
blob28d059540424f5ac07ffae53e556d5d2c6f1393f
1 /*
2  * mcount and friends -- ftrace stuff
3  *
4  * Copyright (C) 2009-2010 Analog Devices Inc.
5  * Licensed under the GPL-2 or later.
6  */
8 #include <linux/linkage.h>
9 #include <asm/ftrace.h>
11 .text
13 #ifdef CONFIG_DYNAMIC_FTRACE
15 /* Simple stub so we can boot the kernel until runtime patching has
16  * disabled all calls to this.  Then it'll be unused.
17  */
18 ENTRY(__mcount)
19 # if ANOMALY_05000371
20         nop; nop; nop; nop;
21 # endif
22         rts;
23 ENDPROC(__mcount)
25 /* GCC will have called us before setting up the function prologue, so we
26  * can clobber the normal scratch registers, but we need to make sure to
27  * save/restore the registers used for argument passing (R0-R2) in case
28  * the profiled function is using them.  With data registers, R3 is the
29  * only one we can blow away.  With pointer registers, we have P0-P2.
30  *
31  * Upon entry, the RETS will point to the top of the current profiled
32  * function.  And since GCC pushed the previous RETS for us, the previous
33  * function will be waiting there.  mmmm pie.
34  */
35 ENTRY(_ftrace_caller)
36         /* save first/second/third function arg and the return register */
37         [--sp] = r2;
38         [--sp] = r0;
39         [--sp] = r1;
40         [--sp] = rets;
42         /* function_trace_call(unsigned long ip, unsigned long parent_ip):
43          *  ip: this point was called by ...
44          *  parent_ip: ... this function
45          * the ip itself will need adjusting for the mcount call
46          */
47         r0 = rets;
48         r1 = [sp + 16]; /* skip the 4 local regs on stack */
49         r0 += -MCOUNT_INSN_SIZE;
51 .globl _ftrace_call
52 _ftrace_call:
53         call _ftrace_stub
55 # ifdef CONFIG_FUNCTION_GRAPH_TRACER
56 .globl _ftrace_graph_call
57 _ftrace_graph_call:
58         nop;    /* jump _ftrace_graph_caller; */
59 # endif
61         /* restore state and get out of dodge */
62 .Lfinish_trace:
63         rets = [sp++];
64         r1 = [sp++];
65         r0 = [sp++];
66         r2 = [sp++];
68 .globl _ftrace_stub
69 _ftrace_stub:
70         rts;
71 ENDPROC(_ftrace_caller)
73 #else
75 /* See documentation for _ftrace_caller */
76 ENTRY(__mcount)
77         /* save third function arg early so we can do testing below */
78         [--sp] = r2;
80         /* load the function pointer to the tracer */
81         p0.l = _ftrace_trace_function;
82         p0.h = _ftrace_trace_function;
83         r3 = [p0];
85         /* optional micro optimization: don't call the stub tracer */
86         r2.l = _ftrace_stub;
87         r2.h = _ftrace_stub;
88         cc = r2 == r3;
89         if ! cc jump .Ldo_trace;
91 # ifdef CONFIG_FUNCTION_GRAPH_TRACER
92         /* if the ftrace_graph_return function pointer is not set to
93          * the ftrace_stub entry, call prepare_ftrace_return().
94          */
95         p0.l = _ftrace_graph_return;
96         p0.h = _ftrace_graph_return;
97         r3 = [p0];
98         cc = r2 == r3;
99         if ! cc jump _ftrace_graph_caller;
101         /* similarly, if the ftrace_graph_entry function pointer is not
102          * set to the ftrace_graph_entry_stub entry, ...
103          */
104         p0.l = _ftrace_graph_entry;
105         p0.h = _ftrace_graph_entry;
106         r2.l = _ftrace_graph_entry_stub;
107         r2.h = _ftrace_graph_entry_stub;
108         r3 = [p0];
109         cc = r2 == r3;
110         if ! cc jump _ftrace_graph_caller;
111 # endif
113         r2 = [sp++];
114         rts;
116 .Ldo_trace:
118         /* save first/second function arg and the return register */
119         [--sp] = r0;
120         [--sp] = r1;
121         [--sp] = rets;
123         /* setup the tracer function */
124         p0 = r3;
126         /* function_trace_call(unsigned long ip, unsigned long parent_ip):
127          *  ip: this point was called by ...
128          *  parent_ip: ... this function
129          * the ip itself will need adjusting for the mcount call
130          */
131         r0 = rets;
132         r1 = [sp + 16]; /* skip the 4 local regs on stack */
133         r0 += -MCOUNT_INSN_SIZE;
135         /* call the tracer */
136         call (p0);
138         /* restore state and get out of dodge */
139 .Lfinish_trace:
140         rets = [sp++];
141         r1 = [sp++];
142         r0 = [sp++];
143         r2 = [sp++];
145 .globl _ftrace_stub
146 _ftrace_stub:
147         rts;
148 ENDPROC(__mcount)
150 #endif
152 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
153 /* The prepare_ftrace_return() function is similar to the trace function
154  * except it takes a pointer to the location of the frompc.  This is so
155  * the prepare_ftrace_return() can hijack it temporarily for probing
156  * purposes.
157  */
158 ENTRY(_ftrace_graph_caller)
159 # ifndef CONFIG_DYNAMIC_FTRACE
160         /* save first/second function arg and the return register */
161         [--sp] = r0;
162         [--sp] = r1;
163         [--sp] = rets;
165         /* prepare_ftrace_return(parent, self_addr, frame_pointer) */
166         r0 = sp;        /* unsigned long *parent */
167         r1 = rets;      /* unsigned long self_addr */
168 # else
169         r0 = sp;        /* unsigned long *parent */
170         r1 = [sp];      /* unsigned long self_addr */
171 # endif
172 # ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
173         r2 = fp;        /* unsigned long frame_pointer */
174 # endif
175         r0 += 16;       /* skip the 4 local regs on stack */
176         r1 += -MCOUNT_INSN_SIZE;
177         call _prepare_ftrace_return;
179         jump .Lfinish_trace;
180 ENDPROC(_ftrace_graph_caller)
182 /* Undo the rewrite caused by ftrace_graph_caller().  The common function
183  * ftrace_return_to_handler() will return the original rets so we can
184  * restore it and be on our way.
185  */
186 ENTRY(_return_to_handler)
187         /* make sure original return values are saved */
188         [--sp] = p0;
189         [--sp] = r0;
190         [--sp] = r1;
192         /* get original return address */
193 # ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
194         r0 = fp;        /* Blackfin is sane, so omit this */
195 # endif
196         call _ftrace_return_to_handler;
197         rets = r0;
199         /* anomaly 05000371 - make sure we have at least three instructions
200          * between rets setting and the return
201          */
202         r1 = [sp++];
203         r0 = [sp++];
204         p0 = [sp++];
205         rts;
206 ENDPROC(_return_to_handler)
207 #endif