Merge branch 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux...
[safe/jmp/linux-2.6] / arch / powerpc / kernel / entry_64.S
index 388f861..43e0734 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc64/kernel/entry.S
- *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
@@ -20,7 +18,6 @@
  *  2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <asm/unistd.h>
 #include <asm/processor.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/cputable.h>
-
-#ifdef CONFIG_PPC_ISERIES
-#define DO_SOFT_DISABLE
-#endif
+#include <asm/firmware.h>
+#include <asm/bug.h>
+#include <asm/ptrace.h>
+#include <asm/irqflags.h>
+#include <asm/ftrace.h>
 
 /*
  * System calls.
@@ -44,7 +42,7 @@
 
 /* This value is used to mark exception frames on the stack. */
 exception_marker:
-       .tc     ID_72656773_68657265[TC],0x7265677368657265
+       .tc     ID_EXC_MARKER[TC],STACK_FRAME_REGS_MARKER
 
        .section        ".text"
        .align 7
@@ -63,6 +61,14 @@ system_call_common:
        std     r12,_MSR(r1)
        std     r0,GPR0(r1)
        std     r10,GPR1(r1)
+       ACCOUNT_CPU_USER_ENTRY(r10, r11)
+       /*
+        * This "crclr so" clears CR0.SO, which is the error indication on
+        * return from this system call.  There must be no cmp instruction
+        * between it and the "mfcr r9" below, otherwise if XER.SO is set,
+        * CR0.SO will get set, causing all system calls to appear to fail.
+        */
+       crclr   so
        std     r2,GPR2(r1)
        std     r3,GPR3(r1)
        std     r4,GPR4(r1)
@@ -76,7 +82,6 @@ system_call_common:
        std     r11,GPR11(r1)
        std     r11,GPR12(r1)
        std     r9,GPR13(r1)
-       crclr   so
        mfcr    r9
        mflr    r10
        li      r11,0xc01
@@ -92,15 +97,29 @@ system_call_common:
        addi    r9,r1,STACK_FRAME_OVERHEAD
        ld      r11,exception_marker@toc(r2)
        std     r11,-16(r9)             /* "regshere" marker */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       bl      .trace_hardirqs_on
+       REST_GPR(0,r1)
+       REST_4GPRS(3,r1)
+       REST_2GPRS(7,r1)
+       addi    r9,r1,STACK_FRAME_OVERHEAD
+       ld      r12,_MSR(r1)
+#endif /* CONFIG_TRACE_IRQFLAGS */
+       li      r10,1
+       stb     r10,PACASOFTIRQEN(r13)
+       stb     r10,PACAHARDIRQEN(r13)
+       std     r10,SOFTE(r1)
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
        /* Hack for handling interrupts when soft-enabling on iSeries */
        cmpdi   cr1,r0,0x5555           /* syscall 0x5555 */
        andi.   r10,r12,MSR_PR          /* from kernel */
        crand   4*cr0+eq,4*cr1+eq,4*cr0+eq
-       beq     hardware_interrupt_entry
-       lbz     r10,PACAPROCENABLED(r13)
-       std     r10,SOFTE(r1)
-#endif
+       bne     2f
+       b       hardware_interrupt_entry
+2:
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+#endif /* CONFIG_PPC_ISERIES */
        mfmsr   r11
        ori     r11,r11,MSR_EE
        mtmsrd  r11,1
@@ -160,7 +179,7 @@ syscall_exit:
        mtmsrd  r10,1
        ld      r9,TI_FLAGS(r12)
        li      r11,-_LAST_ERRNO
-       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR|_TIF_RESTORE_SIGMASK)
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK)
        bne-    syscall_exit_work
        cmpld   r3,r11
        ld      r5,_CCR(r1)
@@ -170,12 +189,18 @@ syscall_error_cont:
        stdcx.  r0,0,r1                 /* to clear the reservation */
        andi.   r6,r8,MSR_PR
        ld      r4,_LINK(r1)
-       beq-    1f                      /* only restore r13 if */
-       ld      r13,GPR13(r1)           /* returning to usermode */
-1:     ld      r2,GPR2(r1)
+       /*
+        * Clear RI before restoring r13.  If we are returning to
+        * userspace and we take an exception after restoring r13,
+        * we end up corrupting the userspace r13 value.
+        */
        li      r12,MSR_RI
        andc    r11,r10,r12
        mtmsrd  r11,1                   /* clear MSR.RI */
+       beq-    1f
+       ACCOUNT_CPU_USER_EXIT(r11, r12)
+       ld      r13,GPR13(r1)   /* only restore r13 if returning to usermode */
+1:     ld      r2,GPR2(r1)
        ld      r1,GPR1(r1)
        mtlr    r4
        mtcr    r5
@@ -195,7 +220,12 @@ syscall_dotrace:
        bl      .save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .do_syscall_trace_enter
-       ld      r0,GPR0(r1)     /* Restore original registers */
+       /*
+        * Restore argument registers possibly just changed.
+        * We use the return value of do_syscall_trace_enter
+        * for the call number to look up in the table (r0).
+        */
+       mr      r0,r3
        ld      r3,GPR3(r1)
        ld      r4,GPR4(r1)
        ld      r5,GPR5(r1)
@@ -216,8 +246,10 @@ syscall_exit_work:
         If TIF_NOERROR is set, just save r3 as it is. */
 
        andi.   r0,r9,_TIF_RESTOREALL
-       bne-    2f
-       cmpld   r3,r11          /* r10 is -LAST_ERRNO */
+       beq+    0f
+       REST_NVGPRS(r1)
+       b       2f
+0:     cmpld   r3,r11          /* r10 is -LAST_ERRNO */
        blt+    1f
        andi.   r0,r9,_TIF_NOERROR
        bne-    1f
@@ -229,9 +261,7 @@ syscall_exit_work:
 2:     andi.   r0,r9,(_TIF_PERSYSCALL_MASK)
        beq     4f
 
-       /* Clear per-syscall TIF flags if any are set, but _leave_
-       _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
-       yet.  */
+       /* Clear per-syscall TIF flags if any are set.  */
 
        li      r11,_TIF_PERSYSCALL_MASK
        addi    r12,r12,TI_FLAGS
@@ -240,10 +270,9 @@ syscall_exit_work:
        stdcx.  r10,0,r12
        bne-    3b
        subi    r12,r12,TI_FLAGS
-       
-4:     bl      .save_nvgprs
-       /* Anything else left to do? */
-       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+
+4:     /* Anything else left to do? */
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
        beq     .ret_from_except_lite
 
        /* Re-enable interrupts */
@@ -251,26 +280,10 @@ syscall_exit_work:
        ori     r10,r10,MSR_EE
        mtmsrd  r10,1
 
-       andi.   r0,r9,_TIF_SAVE_NVGPRS
-       bne     save_user_nvgprs
-
-       /* If tracing, re-enable interrupts and do it */
-save_user_nvgprs_cont: 
-       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
-       beq     5f
-       
+       bl      .save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .do_syscall_trace_leave
-       REST_NVGPRS(r1)
-       clrrdi  r12,r1,THREAD_SHIFT
-
-       /* Disable interrupts again and handle other work if any */
-5:     mfmsr   r10
-       rldicl  r10,r10,48,1
-       rotldi  r10,r10,16
-       mtmsrd  r10,1
-
-       b       .ret_from_except_lite
+       b       .ret_from_except
 
 /* Save non-volatile GPRs, if not already saved. */
 _GLOBAL(save_nvgprs)
@@ -282,51 +295,6 @@ _GLOBAL(save_nvgprs)
        std     r0,_TRAP(r1)
        blr
 
-
-save_user_nvgprs:
-       ld      r10,TI_SIGFRAME(r12)
-       andi.   r0,r9,_TIF_32BIT
-       beq-    save_user_nvgprs_64
-
-       /* 32-bit save to userspace */
-
-.macro savewords start, end
-  1:   stw \start,4*(\start)(r10)
-       .section __ex_table,"a"
-       .align  3
-       .llong  1b,save_user_nvgprs_fault
-       .previous
-       .if \end - \start
-       savewords "(\start+1)",\end
-       .endif
-.endm  
-       savewords 14,31
-       b       save_user_nvgprs_cont
-
-save_user_nvgprs_64:
-       /* 64-bit save to userspace */
-
-.macro savelongs start, end
-  1:   std \start,8*(\start)(r10)
-       .section __ex_table,"a"
-       .align  3
-       .llong  1b,save_user_nvgprs_fault
-       .previous
-       .if \end - \start
-       savelongs "(\start+1)",\end
-       .endif
-.endm  
-       savelongs 14,31
-       b       save_user_nvgprs_cont
-
-save_user_nvgprs_fault:
-       li      r3,11           /* SIGSEGV */
-       ld      r4,TI_TASK(r12)
-       bl      .force_sigsegv
-
-       clrrdi  r12,r1,THREAD_SHIFT
-       ld      r9,TI_FLAGS(r12)
-       b       save_user_nvgprs_cont
        
 /*
  * The sigsuspend and rt_sigsuspend system calls can call do_signal
@@ -352,6 +320,16 @@ _GLOBAL(ppc_clone)
        bl      .sys_clone
        b       syscall_exit
 
+_GLOBAL(ppc32_swapcontext)
+       bl      .save_nvgprs
+       bl      .compat_sys_swapcontext
+       b       syscall_exit
+
+_GLOBAL(ppc64_swapcontext)
+       bl      .save_nvgprs
+       bl      .sys_swapcontext
+       b       syscall_exit
+
 _GLOBAL(ret_from_fork)
        bl      .schedule_tail
        REST_NVGPRS(r1)
@@ -374,7 +352,7 @@ _GLOBAL(ret_from_fork)
  * the fork code also.
  *
  * The code which creates the new task context is in 'copy_thread'
- * in arch/ppc64/kernel/process.c
+ * in arch/powerpc/kernel/process.c 
  */
        .align  7
 _GLOBAL(_switch)
@@ -387,6 +365,11 @@ _GLOBAL(_switch)
        mflr    r20             /* Return to switch caller */
        mfmsr   r22
        li      r0, MSR_FP
+#ifdef CONFIG_VSX
+BEGIN_FTR_SECTION
+       oris    r0,r0,MSR_VSX@h /* Disable VSX */
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif /* CONFIG_VSX */
 #ifdef CONFIG_ALTIVEC
 BEGIN_FTR_SECTION
        oris    r0,r0,MSR_VEC@h /* Disable altivec */
@@ -417,8 +400,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 
        ld      r8,KSP(r4)      /* new stack pointer */
 BEGIN_FTR_SECTION
+  BEGIN_FTR_SECTION_NESTED(95)
        clrrdi  r6,r8,28        /* get its ESID */
        clrrdi  r9,r1,28        /* get current sp ESID */
+  FTR_SECTION_ELSE_NESTED(95)
+       clrrdi  r6,r8,40        /* get its 1T ESID */
+       clrrdi  r9,r1,40        /* get current sp 1T ESID */
+  ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_1T_SEGMENT, 95)
+FTR_SECTION_ELSE
+       b       2f
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_SLB)
        clrldi. r0,r6,2         /* is new ESID c00000000? */
        cmpd    cr1,r6,r9       /* or is new ESID the same as current ESID? */
        cror    eq,4*cr1+eq,eq
@@ -428,13 +419,34 @@ BEGIN_FTR_SECTION
        ld      r7,KSP_VSID(r4) /* Get new stack's VSID */
        oris    r0,r6,(SLB_ESID_V)@h
        ori     r0,r0,(SLB_NUM_BOLTED-1)@l
+BEGIN_FTR_SECTION
+       li      r9,MMU_SEGSIZE_1T       /* insert B field */
+       oris    r6,r6,(MMU_SEGSIZE_1T << SLBIE_SSIZE_SHIFT)@h
+       rldimi  r7,r9,SLB_VSID_SSIZE_SHIFT,0
+END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
+
+       /* Update the last bolted SLB.  No write barriers are needed
+        * here, provided we only update the current CPU's SLB shadow
+        * buffer.
+        */
+       ld      r9,PACA_SLBSHADOWPTR(r13)
+       li      r12,0
+       std     r12,SLBSHADOW_STACKESID(r9) /* Clear ESID */
+       std     r7,SLBSHADOW_STACKVSID(r9)  /* Save VSID */
+       std     r0,SLBSHADOW_STACKESID(r9)  /* Save ESID */
+
+       /* No need to check for CPU_FTR_NO_SLBIE_B here, since when
+        * we have 1TB segments, the only CPUs known to have the errata
+        * only support less than 1TB of system memory and we'll never
+        * actually hit this code path.
+        */
+
        slbie   r6
        slbie   r6              /* Workaround POWER5 < DD2.1 issue */
        slbmte  r7,r0
        isync
 
 2:
-END_FTR_SECTION_IFSET(CPU_FTR_SLB)
        clrrdi  r7,r8,THREAD_SHIFT      /* base of new stack */
        /* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE
           because we don't need to leave the 288-byte ABI gap at the
@@ -506,58 +518,61 @@ _GLOBAL(ret_from_except_lite)
 #endif
 
 restore:
-#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
        ld      r5,SOFTE(r1)
-       cmpdi   0,r5,0
-       beq     4f
-       /* Check for pending interrupts (iSeries) */
-       ld      r3,PACALPPACAPTR(r13)
-       ld      r3,LPPACAANYINT(r3)
-       cmpdi   r3,0
-       beq+    4f                      /* skip do_IRQ if no interrupts */
+FW_FTR_SECTION_ELSE
+       b       iseries_check_pending_irqs
+ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
+2:
+       TRACE_AND_RESTORE_IRQ(r5);
+
+#ifdef CONFIG_PERF_COUNTERS
+       /* check paca->perf_counter_pending if we're enabling ints */
+       lbz     r3,PACAPERFPEND(r13)
+       and.    r3,r3,r5
+       beq     27f
+       bl      .perf_counter_do_pending
+27:
+#endif /* CONFIG_PERF_COUNTERS */
+
+       /* extract EE bit and use it to restore paca->hard_enabled */
+       ld      r3,_MSR(r1)
+       rldicl  r4,r3,49,63             /* r0 = (r3 >> 15) & 1 */
+       stb     r4,PACAHARDIRQEN(r13)
 
-       li      r3,0
-       stb     r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */
-       ori     r10,r10,MSR_EE
-       mtmsrd  r10                     /* hard-enable again */
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_IRQ
-       b       .ret_from_except_lite           /* loop back and handle more */
+       ld      r4,_CTR(r1)
+       ld      r0,_LINK(r1)
+       mtctr   r4
+       mtlr    r0
+       ld      r4,_XER(r1)
+       mtspr   SPRN_XER,r4
 
-4:     stb     r5,PACAPROCENABLED(r13)
-#endif
+       REST_8GPRS(5, r1)
 
-       ld      r3,_MSR(r1)
        andi.   r0,r3,MSR_RI
        beq-    unrecov_restore
 
-       andi.   r0,r3,MSR_PR
+       stdcx.  r0,0,r1         /* to clear the reservation */
+
+       /*
+        * Clear RI before restoring r13.  If we are returning to
+        * userspace and we take an exception after restoring r13,
+        * we end up corrupting the userspace r13 value.
+        */
+       mfmsr   r4
+       andc    r4,r4,r0        /* r0 contains MSR_RI here */
+       mtmsrd  r4,1
 
        /*
         * r13 is our per cpu area, only restore it if we are returning to
         * userspace
         */
+       andi.   r0,r3,MSR_PR
        beq     1f
+       ACCOUNT_CPU_USER_EXIT(r2, r4)
        REST_GPR(13, r1)
 1:
-       ld      r3,_CTR(r1)
-       ld      r0,_LINK(r1)
-       mtctr   r3
-       mtlr    r0
-       ld      r3,_XER(r1)
-       mtspr   SPRN_XER,r3
-
-       REST_8GPRS(5, r1)
-
-       stdcx.  r0,0,r1         /* to clear the reservation */
-
-       mfmsr   r0
-       li      r2, MSR_RI
-       andc    r0,r0,r2
-       mtmsrd  r0,1
-
-       ld      r0,_MSR(r1)
-       mtspr   SPRN_SRR1,r0
+       mtspr   SPRN_SRR1,r3
 
        ld      r2,_CCR(r1)
        mtcrf   0xFF,r2
@@ -573,7 +588,30 @@ restore:
        rfid
        b       .       /* prevent speculative execution */
 
-/* Note: this must change if we start using the TIF_NOTIFY_RESUME bit */
+iseries_check_pending_irqs:
+#ifdef CONFIG_PPC_ISERIES
+       ld      r5,SOFTE(r1)
+       cmpdi   0,r5,0
+       beq     2b
+       /* Check for pending interrupts (iSeries) */
+       ld      r3,PACALPPACAPTR(r13)
+       ld      r3,LPPACAANYINT(r3)
+       cmpdi   r3,0
+       beq+    2b                      /* skip do_IRQ if no interrupts */
+
+       li      r3,0
+       stb     r3,PACASOFTIRQEN(r13)   /* ensure we are soft-disabled */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       bl      .trace_hardirqs_off
+       mfmsr   r10
+#endif
+       ori     r10,r10,MSR_EE
+       mtmsrd  r10                     /* hard-enable again */
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .do_IRQ
+       b       .ret_from_except_lite           /* loop back and handle more */
+#endif
+
 do_work:
 #ifdef CONFIG_PREEMPT
        andi.   r0,r3,MSR_PR    /* Returning to user mode? */
@@ -581,20 +619,25 @@ do_work:
        /* Check that preempt_count() == 0 and interrupts are enabled */
        lwz     r8,TI_PREEMPT(r9)
        cmpwi   cr1,r8,0
-#ifdef CONFIG_PPC_ISERIES
        ld      r0,SOFTE(r1)
        cmpdi   r0,0
-#else
-       andi.   r0,r3,MSR_EE
-#endif
        crandc  eq,cr1*4+eq,eq
        bne     restore
        /* here we are preempting the current task */
 1:
-#ifdef CONFIG_PPC_ISERIES
+#ifdef CONFIG_TRACE_IRQFLAGS
+       bl      .trace_hardirqs_on
+       /* Note: we just clobbered r10 which used to contain the previous
+        * MSR before the hard-disabling done by the caller of do_work.
+        * We don't have that value anymore, but it doesn't matter as
+        * we will hard-enable unconditionally, we can just reload the
+        * current MSR into r10
+        */
+       mfmsr   r10
+#endif /* CONFIG_TRACE_IRQFLAGS */
        li      r0,1
-       stb     r0,PACAPROCENABLED(r13)
-#endif
+       stb     r0,PACASOFTIRQEN(r13)
+       stb     r0,PACAHARDIRQEN(r13)
        ori     r10,r10,MSR_EE
        mtmsrd  r10,1           /* reenable interrupts */
        bl      .preempt_schedule
@@ -620,8 +663,7 @@ user_work:
        b       .ret_from_except_lite
 
 1:     bl      .save_nvgprs
-       li      r3,0
-       addi    r4,r1,STACK_FRAME_OVERHEAD
+       addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .do_signal
        b       .ret_from_except
 
@@ -663,25 +705,28 @@ _GLOBAL(enter_rtas)
        std     r7,_DAR(r1)
        mfdsisr r8
        std     r8,_DSISR(r1)
-       mfsrr0  r9
-       std     r9,_SRR0(r1)
-       mfsrr1  r10
-       std     r10,_SRR1(r1)
 
+       /* Temporary workaround to clear CR until RTAS can be modified to
+        * ignore all bits.
+        */
+       li      r0,0
+       mtcr    r0
+
+#ifdef CONFIG_BUG      
        /* There is no way it is acceptable to get here with interrupts enabled,
         * check it with the asm equivalent of WARN_ON
         */
-       mfmsr   r6
-       andi.   r0,r6,MSR_EE
+       lbz     r0,PACASOFTIRQEN(r13)
 1:     tdnei   r0,0
-.section __bug_table,"a"
-       .llong  1b,__LINE__ + 0x1000000, 1f, 2f
-.previous
-.section .rodata,"a"
-1:     .asciz  __FILE__
-2:     .asciz "enter_rtas"
-.previous
+       EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
+#endif
        
+       /* Hard-disable interrupts */
+       mfmsr   r6
+       rldicl  r7,r6,48,1
+       rotldi  r7,r7,16
+       mtmsrd  r7,1
+
        /* Unfortunately, the stack pointer and the MSR are also clobbered,
         * so they are saved in the PACA which allows us to restore
         * our original state after RTAS returns.
@@ -720,6 +765,10 @@ _STATIC(rtas_return_loc)
        mfspr   r4,SPRN_SPRG3           /* Get PACA */
        clrldi  r4,r4,2                 /* convert to realmode address */
 
+       bcl     20,31,$+4
+0:     mflr    r3
+       ld      r3,(1f-0b)(r3)          /* get &.rtas_restore_regs */
+
        mfmsr   r6
        li      r0,MSR_RI
        andc    r6,r6,r0
@@ -727,7 +776,6 @@ _STATIC(rtas_return_loc)
        mtmsrd  r6
         
         ld     r1,PACAR1(r4)           /* Restore our SP */
-       LOAD_REG_IMMEDIATE(r3,.rtas_restore_regs)
         ld     r4,PACASAVEDMSR(r4)     /* Restore our MSR */
 
        mtspr   SPRN_SRR0,r3
@@ -735,6 +783,9 @@ _STATIC(rtas_return_loc)
        rfid
        b       .       /* prevent speculative execution */
 
+       .align  3
+1:     .llong  .rtas_restore_regs
+
 _STATIC(rtas_restore_regs)
        /* relocation is on at this point */
        REST_GPR(2, r1)                 /* Restore the TOC */
@@ -754,10 +805,6 @@ _STATIC(rtas_restore_regs)
        mtdar   r7
        ld      r8,_DSISR(r1)
        mtdsisr r8
-       ld      r9,_SRR0(r1)
-       mtsrr0  r9
-       ld      r10,_SRR1(r1)
-       mtsrr1  r10
 
         addi   r1,r1,RTAS_FRAME_SIZE   /* Unstack our frame */
        ld      r0,16(r1)               /* get return address */
@@ -767,8 +814,6 @@ _STATIC(rtas_restore_regs)
 
 #endif /* CONFIG_PPC_RTAS */
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-
 _GLOBAL(enter_prom)
        mflr    r0
        std     r0,16(r1)
@@ -853,5 +898,138 @@ _GLOBAL(enter_prom)
        ld      r0,16(r1)
        mtlr    r0
         blr
-       
-#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+#ifdef CONFIG_FUNCTION_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
+_GLOBAL(mcount)
+_GLOBAL(_mcount)
+       blr
+
+_GLOBAL(ftrace_caller)
+       /* Taken from output of objdump from lib64/glibc */
+       mflr    r3
+       ld      r11, 0(r1)
+       stdu    r1, -112(r1)
+       std     r3, 128(r1)
+       ld      r4, 16(r11)
+       subi    r3, r3, MCOUNT_INSN_SIZE
+.globl ftrace_call
+ftrace_call:
+       bl      ftrace_stub
+       nop
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+.globl ftrace_graph_call
+ftrace_graph_call:
+       b       ftrace_graph_stub
+_GLOBAL(ftrace_graph_stub)
+#endif
+       ld      r0, 128(r1)
+       mtlr    r0
+       addi    r1, r1, 112
+_GLOBAL(ftrace_stub)
+       blr
+#else
+_GLOBAL(mcount)
+       blr
+
+_GLOBAL(_mcount)
+       /* Taken from output of objdump from lib64/glibc */
+       mflr    r3
+       ld      r11, 0(r1)
+       stdu    r1, -112(r1)
+       std     r3, 128(r1)
+       ld      r4, 16(r11)
+
+       subi    r3, r3, MCOUNT_INSN_SIZE
+       LOAD_REG_ADDR(r5,ftrace_trace_function)
+       ld      r5,0(r5)
+       ld      r5,0(r5)
+       mtctr   r5
+       bctrl
+       nop
+
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       b       ftrace_graph_caller
+#endif
+       ld      r0, 128(r1)
+       mtlr    r0
+       addi    r1, r1, 112
+_GLOBAL(ftrace_stub)
+       blr
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+_GLOBAL(ftrace_graph_caller)
+       /* load r4 with local address */
+       ld      r4, 128(r1)
+       subi    r4, r4, MCOUNT_INSN_SIZE
+
+       /* get the parent address */
+       ld      r11, 112(r1)
+       addi    r3, r11, 16
+
+       bl      .prepare_ftrace_return
+       nop
+
+       ld      r0, 128(r1)
+       mtlr    r0
+       addi    r1, r1, 112
+       blr
+
+_GLOBAL(return_to_handler)
+       /* need to save return values */
+       std     r4,  -24(r1)
+       std     r3,  -16(r1)
+       std     r31, -8(r1)
+       mr      r31, r1
+       stdu    r1, -112(r1)
+
+       bl      .ftrace_return_to_handler
+       nop
+
+       /* return value has real return address */
+       mtlr    r3
+
+       ld      r1, 0(r1)
+       ld      r4,  -24(r1)
+       ld      r3,  -16(r1)
+       ld      r31, -8(r1)
+
+       /* Jump back to real return address */
+       blr
+
+_GLOBAL(mod_return_to_handler)
+       /* need to save return values */
+       std     r4,  -32(r1)
+       std     r3,  -24(r1)
+       /* save TOC */
+       std     r2,  -16(r1)
+       std     r31, -8(r1)
+       mr      r31, r1
+       stdu    r1, -112(r1)
+
+       /*
+        * We are in a module using the module's TOC.
+        * Switch to our TOC to run inside the core kernel.
+        */
+       LOAD_REG_IMMEDIATE(r4,ftrace_return_to_handler)
+       ld      r2, 8(r4)
+
+       bl      .ftrace_return_to_handler
+       nop
+
+       /* return value has real return address */
+       mtlr    r3
+
+       ld      r1, 0(r1)
+       ld      r4,  -32(r1)
+       ld      r3,  -24(r1)
+       ld      r2,  -16(r1)
+       ld      r31, -8(r1)
+
+       /* Jump back to real return address */
+       blr
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#endif /* CONFIG_FUNCTION_TRACER */