summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/trace/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/trace/ftrace.c')
-rw-r--r--arch/powerpc/kernel/trace/ftrace.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c
index 72864fb7a6cc..a47f30373423 100644
--- a/arch/powerpc/kernel/trace/ftrace.c
+++ b/arch/powerpc/kernel/trace/ftrace.c
@@ -727,6 +727,15 @@ int __init ftrace_dyn_arch_init(void)
{
int i;
unsigned int *tramp[] = { ftrace_tramp_text, ftrace_tramp_init };
+#ifdef CONFIG_PPC_KERNEL_PCREL
+ u32 stub_insns[] = {
+ /* pla r12,addr */
+ PPC_PREFIX_MLS | __PPC_PRFX_R(1),
+ PPC_INST_PADDI | ___PPC_RT(_R12),
+ PPC_RAW_MTCTR(_R12),
+ PPC_RAW_BCTR()
+ };
+#else
u32 stub_insns[] = {
PPC_RAW_LD(_R12, _R13, PACATOC),
PPC_RAW_ADDIS(_R12, _R12, 0),
@@ -734,6 +743,8 @@ int __init ftrace_dyn_arch_init(void)
PPC_RAW_MTCTR(_R12),
PPC_RAW_BCTR()
};
+#endif
+
unsigned long addr;
long reladdr;
@@ -742,19 +753,36 @@ int __init ftrace_dyn_arch_init(void)
else
addr = ppc_global_function_entry((void *)ftrace_caller);
- reladdr = addr - kernel_toc_addr();
+ if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) {
+ for (i = 0; i < 2; i++) {
+ reladdr = addr - (unsigned long)tramp[i];
- if (reladdr >= SZ_2G || reladdr < -(long)SZ_2G) {
- pr_err("Address of %ps out of range of kernel_toc.\n",
+ if (reladdr >= (long)SZ_8G || reladdr < -(long)SZ_8G) {
+ pr_err("Address of %ps out of range of pcrel address.\n",
+ (void *)addr);
+ return -1;
+ }
+
+ memcpy(tramp[i], stub_insns, sizeof(stub_insns));
+ tramp[i][0] |= IMM_H18(reladdr);
+ tramp[i][1] |= IMM_L(reladdr);
+ add_ftrace_tramp((unsigned long)tramp[i]);
+ }
+ } else {
+ reladdr = addr - kernel_toc_addr();
+
+ if (reladdr >= (long)SZ_2G || reladdr < -(long)SZ_2G) {
+ pr_err("Address of %ps out of range of kernel_toc.\n",
(void *)addr);
- return -1;
- }
+ return -1;
+ }
- for (i = 0; i < 2; i++) {
- memcpy(tramp[i], stub_insns, sizeof(stub_insns));
- tramp[i][1] |= PPC_HA(reladdr);
- tramp[i][2] |= PPC_LO(reladdr);
- add_ftrace_tramp((unsigned long)tramp[i]);
+ for (i = 0; i < 2; i++) {
+ memcpy(tramp[i], stub_insns, sizeof(stub_insns));
+ tramp[i][1] |= PPC_HA(reladdr);
+ tramp[i][2] |= PPC_LO(reladdr);
+ add_ftrace_tramp((unsigned long)tramp[i]);
+ }
}
return 0;