return (char *)&ftrace_nop;
 }
 
-static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static unsigned char *
+ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
 {
        static unsigned int op;
 
         */
        addr = GET_ADDR(addr);
 
-       /* Set to "bl addr" */
-       op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc);
+       /* if (link) set op to 'bl' else 'b' */
+       op = 0x48000000 | (link ? 1 : 0);
+       op |= (ftrace_calc_offset(ip, addr) & 0x03fffffc);
 
        /*
         * No locking needed, this must be called via kstop_machine
         */
        if (test_24bit_addr(ip, addr)) {
                /* within range */
-               old = ftrace_call_replace(ip, addr);
+               old = ftrace_call_replace(ip, addr, 1);
                new = ftrace_nop_replace();
                return ftrace_modify_code(ip, old, new);
        }
        if (test_24bit_addr(ip, addr)) {
                /* within range */
                old = ftrace_nop_replace();
-               new = ftrace_call_replace(ip, addr);
+               new = ftrace_call_replace(ip, addr, 1);
                return ftrace_modify_code(ip, old, new);
        }
 
        int ret;
 
        memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
-       new = ftrace_call_replace(ip, (unsigned long)func);
+       new = ftrace_call_replace(ip, (unsigned long)func, 1);
        ret = ftrace_modify_code(ip, old, new);
 
        return ret;
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
+extern void ftrace_graph_stub(void);
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+       unsigned long ip = (unsigned long)(&ftrace_graph_call);
+       unsigned long addr = (unsigned long)(&ftrace_graph_caller);
+       unsigned long stub = (unsigned long)(&ftrace_graph_stub);
+       unsigned char old[MCOUNT_INSN_SIZE], *new;
+
+       new = ftrace_call_replace(ip, stub, 0);
+       memcpy(old, new, MCOUNT_INSN_SIZE);
+       new = ftrace_call_replace(ip, addr, 0);
+
+       return ftrace_modify_code(ip, old, new);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+       unsigned long ip = (unsigned long)(&ftrace_graph_call);
+       unsigned long addr = (unsigned long)(&ftrace_graph_caller);
+       unsigned long stub = (unsigned long)(&ftrace_graph_stub);
+       unsigned char old[MCOUNT_INSN_SIZE], *new;
+
+       new = ftrace_call_replace(ip, addr, 0);
+       memcpy(old, new, MCOUNT_INSN_SIZE);
+       new = ftrace_call_replace(ip, stub, 0);
+
+       return ftrace_modify_code(ip, old, new);
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
 /*
  * Hook the return address and push it in the stack of return addrs
  * in current thread info.