* mcount can be thought of as a function called in the middle of a subroutine
  * call.  As such, it needs to be transparent for both the caller and the
  * callee: the original lr needs to be restored when leaving mcount, and no
- * registers should be clobbered.  (In the __gnu_mcount_nc implementation, we
- * clobber the ip register.  This is OK because the ARM calling convention
- * allows it to be clobbered in subroutines and doesn't use it to hold
- * parameters.)
+ * registers should be clobbered.
  *
  * When using dynamic ftrace, we patch out the mcount call by a "add sp, #4"
  * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c).
 
 .macro __ftrace_regs_caller
 
-       sub     sp, sp, #8      @ space for PC and CPSR OLD_R0,
+       str     lr, [sp, #-8]!  @ store LR as PC and make space for CPSR/OLD_R0,
                                @ OLD_R0 will overwrite previous LR
 
-       add     ip, sp, #12     @ move in IP the value of SP as it was
-                               @ before the push {lr} of the mcount mechanism
+       ldr     lr, [sp, #8]    @ get previous LR
 
-       str     lr, [sp, #0]    @ store LR instead of PC
+       str     r0, [sp, #8]    @ write r0 as OLD_R0 over previous LR
 
-       ldr     lr, [sp, #8]    @ get previous LR
+       str     lr, [sp, #-4]!  @ store previous LR as LR
 
-       str     r0, [sp, #8]    @ write r0 as OLD_R0 over previous LR
+       add     lr, sp, #16     @ move in LR the value of SP as it was
+                               @ before the push {lr} of the mcount mechanism
 
-       stmdb   sp!, {ip, lr}
-       stmdb   sp!, {r0-r11, lr}
+       push    {r0-r11, ip, lr}
 
        @ stack content at this point:
        @ 0  4          48   52       56            60   64    68       72
-       @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 |
+       @ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 |
 
-       mov r3, sp                              @ struct pt_regs*
+       mov     r3, sp                          @ struct pt_regs*
 
        ldr r2, =function_trace_op
        ldr r2, [r2]                            @ pointer to the current
 #endif
 
        @ pop saved regs
-       ldmia   sp!, {r0-r12}                   @ restore r0 through r12
-       ldr     ip, [sp, #8]                    @ restore PC
-       ldr     lr, [sp, #4]                    @ restore LR
-       ldr     sp, [sp, #0]                    @ restore SP
-       mov     pc, ip                          @ return
+       pop     {r0-r11, ip, lr}                @ restore r0 through r12
+       ldr     lr, [sp], #4                    @ restore LR
+       ldr     pc, [sp], #12
 .endm
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        bl      prepare_ftrace_return
 
        @ pop registers saved in ftrace_regs_caller
-       ldmia   sp!, {r0-r12}                   @ restore r0 through r12
-       ldr     ip, [sp, #8]                    @ restore PC
-       ldr     lr, [sp, #4]                    @ restore LR
-       ldr     sp, [sp, #0]                    @ restore SP
-       mov     pc, ip                          @ return
+       pop     {r0-r11, ip, lr}                @ restore r0 through r12
+       ldr     lr, [sp], #4                    @ restore LR
+       ldr     pc, [sp], #12
 
 .endm
 #endif
 .endm
 
 .macro mcount_exit
-       ldmia   sp!, {r0-r3, ip, lr}
-       ret     ip
+       ldmia   sp!, {r0-r3}
+       ldr     lr, [sp, #4]
+       ldr     pc, [sp], #8
 .endm
 
 ENTRY(__gnu_mcount_nc)
 UNWIND(.fnstart)
 #ifdef CONFIG_DYNAMIC_FTRACE
-       mov     ip, lr
-       ldmia   sp!, {lr}
-       ret     ip
+       push    {lr}
+       ldr     lr, [sp, #4]
+       ldr     pc, [sp], #8
 #else
        __mcount
 #endif