sh: shared register saving code for sh3/sh4/sh4a
authorMagnus Damm <damm@igel.co.jp>
Mon, 23 Feb 2009 07:14:02 +0000 (07:14 +0000)
committerPaul Mundt <lethal@linux-sh.org>
Fri, 27 Feb 2009 07:26:10 +0000 (16:26 +0900)
This patch reworks the sh3/sh4/sh4a register saving code in
the following ways:
 - break out prepare_stack_save_dsp() from handle_exception()
 - break out save_regs() from handle_exception()
 - the register saving order is unchanged
 - align new functions to fit in cache lines
 - separate exception code from interrupt code
 - keep main code flow in a single cache line per exception vector
 - use bsr/rts for regular functions (save pr first)
 - keep data in one shared cache line (exception_data)
 - document the functions
 - tie in the hp6xx code

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/boards/mach-hp6xx/pm_wakeup.S
arch/sh/kernel/cpu/sh3/entry.S

index 44b648cf6f235988e42c10a566f92a64c309a2db..4f18d44e05413f265e3de3d5629d6a8e97f50093 100644 (file)
 #include <linux/linkage.h>
 #include <cpu/mmu_context.h>
 
-#define k0     r0
-#define k1     r1
-#define k2     r2
-#define k3     r3
-#define k4     r4
-
 /*
  * Kernel mode register usage:
  *     k0      scratch
  *     k1      scratch
- *     k2      scratch (Exception code)
- *     k3      scratch (Return address)
- *     k4      scratch
- *     k5      reserved
- *     k6      Global Interrupt Mask (0--15 << 4)
- *     k7      CURRENT_THREAD_INFO (pointer to current thread info)
+ * For more details, please have a look at entry.S
  */
 
+#define k0     r0
+#define k1     r1
+
 ENTRY(wakeup_start)
 ! clear STBY bit
-       mov     #-126, k2
+       mov     #-126, k1
        and     #127, k0
-       mov.b   k0, @k2
+       mov.b   k0, @k1
 ! enable refresh
        mov.l   5f, k1
        mov.w   6f, k0
        mov.w   k0, @k1
 ! jump to handler
-       mov.l   2f, k2
-       mov.l   3f, k3
-       mov.l   @k2, k2
-
        mov.l   4f, k1
        jmp     @k1
-       nop
+        nop
 
        .align  2
-1:     .long   EXPEVT
-2:     .long   INTEVT
-3:     .long   ret_from_irq
-4:     .long   handle_exception
+4:     .long   handle_interrupt
 5:     .long   0xffffff68
 6:     .word   0x0524
 
index b4106d0c68ec0e0c8fc3db9365b5c289b15a961d..f3db143e70b2cb92be77f32e8fd51888b001c8f3 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/unistd.h>
 #include <cpu/mmu_context.h>
 #include <asm/page.h>
+#include <asm/cache.h>
 
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -294,7 +295,7 @@ skip_restore:
        mov     #0xf0, k1
        extu.b  k1, k1
        not     k1, k1
-       and     k1, k2                  ! Mask orignal SR value
+       and     k1, k2                  ! Mask original SR value
        !
        mov     k3, k0                  ! Calculate IMASK-bits
        shlr2   k0
@@ -335,82 +336,54 @@ skip_restore:
        .balign         4096,0,4096
 ENTRY(vbr_base)
        .long   0
+!
+! 0x100: General exception vector
 !
        .balign         256,0,256
 general_exception:
-       mov.l   1f, k2
-       mov.l   2f, k3
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
-       mov.l   @k2, k2
+#ifndef CONFIG_CPU_SUBTYPE_SHX3
+       bra     handle_exception
+        sts    pr, k3          ! save original pr value in k3
+#else
+       mov.l   1f, k4
+       mov.l   @k4, k4
 
        ! Is EXPEVT larger than 0x800?
        mov     #0x8, k0
        shll8   k0
-       cmp/hs  k0, k2
+       cmp/hs  k0, k4
        bf      0f
 
        ! then add 0x580 (k2 is 0xd80 or 0xda0)
        mov     #0x58, k0
        shll2   k0
        shll2   k0
-       add     k0, k2
+       add     k0, k4
 0:
-       bra     handle_exception
+       ! Setup stack and save DSP context (k0 contains original r15 on return)
+       bsr     prepare_stack_save_dsp
         nop
-#else
-       bra     handle_exception
-        mov.l  @k2, k2
-#endif
-       .align  2
-1:     .long   EXPEVT
-2:     .long   ret_from_exception
-!
-!
 
-       .balign         1024,0,1024
-tlb_miss:
-       mov.l   1f, k2
-       mov.l   4f, k3
-       bra     handle_exception
-        mov.l  @k2, k2
-!
-       .balign         512,0,512
-interrupt:
-       mov.l   3f, k3
-#if defined(CONFIG_KGDB)
-       mov.l   2f, k2
-       ! Debounce (filter nested NMI)
-       mov.l   @k2, k0
-       mov.l   5f, k1
-       cmp/eq  k1, k0
-       bf      0f
-       mov.l   6f, k1
-       tas.b   @k1
-       bt      0f
-       rte
+       ! Save registers / Switch to bank 0
+       bsr     save_regs       ! needs original pr value in k3
+        mov.l  k4, k2          ! keep vector in k2
+
+       bra     handle_exception_special
         nop
-       .align  2
-2:     .long   INTEVT
-5:     .long   NMI_VEC
-6:     .long   in_nmi
-0:
-#endif /* defined(CONFIG_KGDB) */
-       bra     handle_exception
-        mov    #-1, k2         ! interrupt exception marker
 
        .align  2
 1:     .long   EXPEVT
-3:     .long   ret_from_irq
-4:     .long   ret_from_exception
+#endif
 
-!
-!
-       .align  2
-ENTRY(handle_exception)
-       ! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
-       ! save all registers onto stack.
-       !
+! prepare_stack_save_dsp()
+! - roll back gRB
+! - switch to kernel stack
+! - save DSP
+! k0 returns original sp (after roll back)
+! k1 trashed
+! k2 trashed
 
+prepare_stack_save_dsp:
 #ifdef CONFIG_GUSA
        ! Check for roll back gRB (User and Kernel)
        mov     r15, k0
@@ -430,7 +403,7 @@ ENTRY(handle_exception)
 2:     mov     k1, r15         ! SP = r1
 1:
 #endif
-
+       ! Switch to kernel stack if needed
        stc     ssr, k0         ! Is it from kernel space?
        shll    k0              ! Check MD bit (bit30) by shifting it into...
        shll    k0              !       ...the T bit
@@ -443,18 +416,17 @@ ENTRY(handle_exception)
        add     current, k1
        mov     k1, r15         ! change to kernel stack
        !
-1:     mov.l   2f, k1
-       !
+1:
 #ifdef CONFIG_SH_DSP
-       mov.l   r2, @-r15               ! Save r2, we need another reg
-       stc     sr, k4
-       mov.l   1f, r2
-       tst     r2, k4                  ! Check if in DSP mode
-       mov.l   @r15+, r2               ! Restore r2 now
+       ! Save DSP context if needed
+       stc     sr, k1
+       mov     #0x10, k2
+       shll8   k2                      ! DSP=1 (0x00001000)
+       tst     k2, k1                  ! Check if in DSP mode (passed in k2)
        bt/s    skip_save
-        mov    #0, k4                  ! Set marker for no stack frame
+        mov    #0, k1                  ! Set marker for no stack frame
 
-       mov     r2, k4                  ! Backup r2 (in k4) for later
+       mov     k2, k1                  ! Save has-frame marker
 
        ! Save DSP registers on stack
        stc.l   mod, @-r15
@@ -473,35 +445,73 @@ ENTRY(handle_exception)
        ! as we're not at all interested in supporting ancient toolchains at
        ! this point. -- PFM.
 
-       mov     r15, r2
+       mov     r15, k2
        .word   0xf653                  ! movs.l        a1, @-r2
        .word   0xf6f3                  ! movs.l        a0g, @-r2
        .word   0xf6d3                  ! movs.l        a1g, @-r2
        .word   0xf6c3                  ! movs.l        m0, @-r2
        .word   0xf6e3                  ! movs.l        m1, @-r2
-       mov     r2, r15
+       mov     k2, r15
 
-       mov     k4, r2                  ! Restore r2
-       mov.l   1f, k4                  ! Force DSP stack frame
 skip_save:
-       mov.l   k4, @-r15               ! Push DSP mode marker onto stack
+       mov.l   k1, @-r15               ! Push DSP mode marker onto stack
 #endif
-       ! Save the user registers on the stack.
-       mov.l   k2, @-r15       ! EXPEVT
+       rts
+        nop
+!
+! 0x400: Instruction and Data TLB miss exception vector
+!
+       .balign         1024,0,1024
+tlb_miss:
+       sts     pr, k3          ! save original pr value in k3
 
-       mov     #-1, k4
-       mov.l   k4, @-r15       ! set TRA (default: -1)
-       !
+handle_exception:
+       ! Setup stack and save DSP context (k0 contains original r15 on return)
+       bsr     prepare_stack_save_dsp
+        nop
+
+       ! Save registers / Switch to bank 0
+       mov.l   5f, k2          ! vector register address
+       bsr     save_regs       ! needs original pr value in k3
+        mov.l  @k2, k2         ! read out vector and keep in k2
+
+handle_exception_special:
+       ! Setup return address and jump to exception handler
+       mov.l   7f, r9          ! fetch return address
+       stc     r2_bank, r0     ! k2 (vector)
+       mov.l   6f, r10
+       shlr2   r0
+       shlr    r0
+       mov.l   @(r0, r10), r10
+       jmp     @r10
+        lds    r9, pr          ! put return address in pr
+
+       .align  L1_CACHE_SHIFT
+
+! save_regs()
+! - save vector, default tra, macl, mach, gbr, ssr, pr* and spc on the stack
+! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
+! - switch bank
+! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
+! k0 contains original stack pointer*
+! k1 trashed
+! k2 passes vector (EXPEVT)
+! k3 passes original pr*
+! k4 trashed
+! BL=1 on entry, on exit BL=0.
+
+save_regs:
+       mov     #-1, r1
+       mov.l   k2, @-r15       ! vector in k2
+       mov.l   k1, @-r15       ! set TRA (default: -1)
        sts.l   macl, @-r15
        sts.l   mach, @-r15
        stc.l   gbr, @-r15
        stc.l   ssr, @-r15
-       sts.l   pr, @-r15
+       mov.l   k3, @-r15       ! original pr in k3
        stc.l   spc, @-r15
-       !
-       lds     k3, pr          ! Set the return address to pr
-       !
-       mov.l   k0, @-r15       ! save orignal stack
+
+       mov.l   k0, @-r15       ! original stack pointer in k0
        mov.l   r14, @-r15
        mov.l   r13, @-r15
        mov.l   r12, @-r15
@@ -509,13 +519,15 @@ skip_save:
        mov.l   r10, @-r15
        mov.l   r9, @-r15
        mov.l   r8, @-r15
-       !
-       stc     sr, r8          ! Back to normal register bank, and
-       or      k1, r8          ! Block all interrupts
-       mov.l   3f, k1
-       and     k1, r8          ! ...
-       ldc     r8, sr          ! ...changed here.
-       !
+
+       mov.l   0f, k3          ! SR bits to set in k3
+       mov.l   1f, k4          ! SR bits to clear in k4
+
+       stc     sr, r8
+       or      k3, r8
+       and     k4, r8
+       ldc     r8, sr
+
        mov.l   r7, @-r15
        mov.l   r6, @-r15
        mov.l   r5, @-r15
@@ -523,52 +535,61 @@ skip_save:
        mov.l   r3, @-r15
        mov.l   r2, @-r15
        mov.l   r1, @-r15
-       mov.l   r0, @-r15
-
-       /*
-        * This gets a bit tricky.. in the INTEVT case we don't want to use
-        * the VBR offset as a destination in the jump call table, since all
-        * of the destinations are the same. In this case, (interrupt) sets
-        * a marker in r2 (now r2_bank since SR.RB changed), which we check
-        * to determine the exception type. For all other exceptions, we
-        * forcibly read EXPEVT from memory and fix up the jump address, in
-        * the interrupt exception case we jump to do_IRQ() and defer the
-        * INTEVT read until there. As a bonus, we can also clean up the SR.RB
-        * checks that do_IRQ() was doing..
-        */
-       stc     r2_bank, r8
-       cmp/pz  r8
-       bf      interrupt_exception
-       shlr2   r8
-       shlr    r8
-       mov.l   4f, r9
-       add     r8, r9
-       mov.l   @r9, r9
-       jmp     @r9
-        nop
        rts
-        nop
+        mov.l  r0, @-r15
 
+!
+! 0x600: Interrupt / NMI vector
+!
+       .balign         512,0,512
+ENTRY(handle_interrupt)
+#if defined(CONFIG_KGDB)
+       mov.l   2f, k2
+       ! Debounce (filter nested NMI)
+       mov.l   @k2, k0
+       mov.l   9f, k1
+       cmp/eq  k1, k0
+       bf      11f
+       mov.l   10f, k1
+       tas.b   @k1
+       bt      11f
+       rte
+        nop
        .align  2
-1:     .long   0x00001000      ! DSP=1
-2:     .long   0x000080f0      ! FD=1, IMASK=15
-3:     .long   0xcfffffff      ! RB=0, BL=0
-4:     .long   exception_handling_table
+9:     .long   NMI_VEC
+10:    .long   in_nmi
+11:
+#endif /* defined(CONFIG_KGDB) */
+       sts     pr, k3          ! save original pr value in k3
 
-interrupt_exception:
-       mov.l   1f, r9
-       mov.l   2f, r4
-       mov.l   @r4, r4
-       jmp     @r9
-        mov    r15, r5
-       rts
+       ! Setup stack and save DSP context (k0 contains original r15 on return)
+       bsr     prepare_stack_save_dsp
         nop
 
-       .align 2
-1:     .long   do_IRQ
-2:     .long   INTEVT
+       ! Save registers / Switch to bank 0
+       bsr     save_regs       ! needs original pr value in k3
+        mov    #-1, k2         ! default vector kept in k2
+
+       ! Setup return address and jump to do_IRQ
+       mov.l   4f, r9          ! fetch return address
+       lds     r9, pr          ! put return address in pr
+       mov.l   2f, r4
+       mov.l   3f, r9
+       mov.l   @r4, r4         ! pass INTEVT vector as arg0
+       jmp     @r9
+        mov    r15, r5         ! pass saved registers as arg1
 
-       .align  2
 ENTRY(exception_none)
        rts
         nop
+
+       .align  L1_CACHE_SHIFT
+exception_data:
+0:     .long   0x000080f0      ! FD=1, IMASK=15
+1:     .long   0xcfffffff      ! RB=0, BL=0
+2:     .long   INTEVT
+3:     .long   do_IRQ
+4:     .long   ret_from_irq
+5:     .long   EXPEVT
+6:     .long   exception_handling_table
+7:     .long   ret_from_exception