| /* | |
| * Copyright 2012 Tilera Corporation. All Rights Reserved. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License | |
| * as published by the Free Software Foundation, version 2. | |
| * | |
| * This program is distributed in the hope that it will be useful, but | |
| * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
| * NON INFRINGEMENT. See the GNU General Public License for | |
| * more details. | |
| * | |
| * TILE-Gx specific __mcount support | |
| */ | |
| #include <linux/linkage.h> | |
| #include <asm/ftrace.h> | |
| #define REGSIZE 8 | |
| .text | |
| .global __mcount | |
| .macro MCOUNT_SAVE_REGS | |
| addli sp, sp, -REGSIZE | |
| { | |
| st sp, lr | |
| addli r29, sp, - (12 * REGSIZE) | |
| } | |
| { | |
| addli sp, sp, - (13 * REGSIZE) | |
| st r29, sp | |
| } | |
| addli r29, r29, REGSIZE | |
| { st r29, r0; addli r29, r29, REGSIZE } | |
| { st r29, r1; addli r29, r29, REGSIZE } | |
| { st r29, r2; addli r29, r29, REGSIZE } | |
| { st r29, r3; addli r29, r29, REGSIZE } | |
| { st r29, r4; addli r29, r29, REGSIZE } | |
| { st r29, r5; addli r29, r29, REGSIZE } | |
| { st r29, r6; addli r29, r29, REGSIZE } | |
| { st r29, r7; addli r29, r29, REGSIZE } | |
| { st r29, r8; addli r29, r29, REGSIZE } | |
| { st r29, r9; addli r29, r29, REGSIZE } | |
| { st r29, r10; addli r29, r29, REGSIZE } | |
| .endm | |
| .macro MCOUNT_RESTORE_REGS | |
| addli r29, sp, (2 * REGSIZE) | |
| { ld r0, r29; addli r29, r29, REGSIZE } | |
| { ld r1, r29; addli r29, r29, REGSIZE } | |
| { ld r2, r29; addli r29, r29, REGSIZE } | |
| { ld r3, r29; addli r29, r29, REGSIZE } | |
| { ld r4, r29; addli r29, r29, REGSIZE } | |
| { ld r5, r29; addli r29, r29, REGSIZE } | |
| { ld r6, r29; addli r29, r29, REGSIZE } | |
| { ld r7, r29; addli r29, r29, REGSIZE } | |
| { ld r8, r29; addli r29, r29, REGSIZE } | |
| { ld r9, r29; addli r29, r29, REGSIZE } | |
| { ld r10, r29; addli lr, sp, (13 * REGSIZE) } | |
| { ld lr, lr; addli sp, sp, (14 * REGSIZE) } | |
| .endm | |
| .macro RETURN_BACK | |
| { move r12, lr; move lr, r10 } | |
| jrp r12 | |
| .endm | |
| #ifdef CONFIG_DYNAMIC_FTRACE | |
| .align 64 | |
| STD_ENTRY(__mcount) | |
| __mcount: | |
| j ftrace_stub | |
| STD_ENDPROC(__mcount) | |
| .align 64 | |
| STD_ENTRY(ftrace_caller) | |
| moveli r11, hw2_last(function_trace_stop) | |
| { shl16insli r11, r11, hw1(function_trace_stop); move r12, lr } | |
| { shl16insli r11, r11, hw0(function_trace_stop); move lr, r10 } | |
| ld r11, r11 | |
| beqz r11, 1f | |
| jrp r12 | |
| 1: | |
| { move r10, lr; move lr, r12 } | |
| MCOUNT_SAVE_REGS | |
| /* arg1: self return address */ | |
| /* arg2: parent's return address */ | |
| { move r0, lr; move r1, r10 } | |
| .global ftrace_call | |
| ftrace_call: | |
| /* | |
| * a placeholder for the call to a real tracing function, i.e. | |
| * ftrace_trace_function() | |
| */ | |
| nop | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| .global ftrace_graph_call | |
| ftrace_graph_call: | |
| /* | |
| * a placeholder for the call to a real tracing function, i.e. | |
| * ftrace_graph_caller() | |
| */ | |
| nop | |
| #endif | |
| MCOUNT_RESTORE_REGS | |
| .global ftrace_stub | |
| ftrace_stub: | |
| RETURN_BACK | |
| STD_ENDPROC(ftrace_caller) | |
| #else /* ! CONFIG_DYNAMIC_FTRACE */ | |
| .align 64 | |
| STD_ENTRY(__mcount) | |
| moveli r11, hw2_last(function_trace_stop) | |
| { shl16insli r11, r11, hw1(function_trace_stop); move r12, lr } | |
| { shl16insli r11, r11, hw0(function_trace_stop); move lr, r10 } | |
| ld r11, r11 | |
| beqz r11, 1f | |
| jrp r12 | |
| 1: | |
| { move r10, lr; move lr, r12 } | |
| { | |
| moveli r11, hw2_last(ftrace_trace_function) | |
| moveli r13, hw2_last(ftrace_stub) | |
| } | |
| { | |
| shl16insli r11, r11, hw1(ftrace_trace_function) | |
| shl16insli r13, r13, hw1(ftrace_stub) | |
| } | |
| { | |
| shl16insli r11, r11, hw0(ftrace_trace_function) | |
| shl16insli r13, r13, hw0(ftrace_stub) | |
| } | |
| ld r11, r11 | |
| sub r14, r13, r11 | |
| bnez r14, static_trace | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| moveli r15, hw2_last(ftrace_graph_return) | |
| shl16insli r15, r15, hw1(ftrace_graph_return) | |
| shl16insli r15, r15, hw0(ftrace_graph_return) | |
| ld r15, r15 | |
| sub r15, r15, r13 | |
| bnez r15, ftrace_graph_caller | |
| { | |
| moveli r16, hw2_last(ftrace_graph_entry) | |
| moveli r17, hw2_last(ftrace_graph_entry_stub) | |
| } | |
| { | |
| shl16insli r16, r16, hw1(ftrace_graph_entry) | |
| shl16insli r17, r17, hw1(ftrace_graph_entry_stub) | |
| } | |
| { | |
| shl16insli r16, r16, hw0(ftrace_graph_entry) | |
| shl16insli r17, r17, hw0(ftrace_graph_entry_stub) | |
| } | |
| ld r16, r16 | |
| sub r17, r16, r17 | |
| bnez r17, ftrace_graph_caller | |
| #endif | |
| RETURN_BACK | |
| static_trace: | |
| MCOUNT_SAVE_REGS | |
| /* arg1: self return address */ | |
| /* arg2: parent's return address */ | |
| { move r0, lr; move r1, r10 } | |
| /* call ftrace_trace_function() */ | |
| jalr r11 | |
| MCOUNT_RESTORE_REGS | |
| .global ftrace_stub | |
| ftrace_stub: | |
| RETURN_BACK | |
| STD_ENDPROC(__mcount) | |
| #endif /* ! CONFIG_DYNAMIC_FTRACE */ | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| STD_ENTRY(ftrace_graph_caller) | |
| ftrace_graph_caller: | |
| #ifndef CONFIG_DYNAMIC_FTRACE | |
| MCOUNT_SAVE_REGS | |
| #endif | |
| /* arg1: Get the location of the parent's return address */ | |
| addi r0, sp, 12 * REGSIZE | |
| /* arg2: Get self return address */ | |
| move r1, lr | |
| jal prepare_ftrace_return | |
| MCOUNT_RESTORE_REGS | |
| RETURN_BACK | |
| STD_ENDPROC(ftrace_graph_caller) | |
| .global return_to_handler | |
| return_to_handler: | |
| MCOUNT_SAVE_REGS | |
| jal ftrace_return_to_handler | |
| /* restore the real parent address */ | |
| move r11, r0 | |
| MCOUNT_RESTORE_REGS | |
| jr r11 | |
| #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |