[PATCH 4/4 v2] SPARC: optimize IRQ enable & disable
Gedare Bloom
gedare at rtems.org
Mon Nov 24 15:30:51 UTC 2014
On Mon, Nov 24, 2014 at 5:15 AM, Daniel Hellstrom <daniel at gaisler.com> wrote:
> * Coding style cleanups.
> * Use OS reserved trap 0x89 for IRQ Disable
> * Use OS reserved trap 0x8A for IRQ Enable
>
> This will result in faster Disable/Enable code since the
> system trap handler does not need to decode which function
> the user wants. Besides the IRQ disable/enabled can now
> be inline which avoids the caller to take into account that
> o0-o7+g1-g4 registers are destroyed by trap handler.
>
> It was also possible to reduce the interrupt traphandler with
s/traphandler/trap handler
s/with/by
> five instructions due to this.
> ---
> c/src/lib/libbsp/sparc/leon3/startup/spurious.c | 9 +-
> c/src/lib/libbsp/sparc/shared/irq_asm.S | 42 ++++-----
> c/src/lib/libbsp/sparc/shared/start/start.S | 25 ++++-
> c/src/lib/libcpu/sparc/syscall/syscall.S | 118 +++++++++++++----------
> c/src/lib/libcpu/sparc/syscall/syscall.h | 2 -
> cpukit/score/cpu/sparc/rtems/score/sparc.h | 18 +++-
> 6 files changed, 124 insertions(+), 90 deletions(-)
>
> diff --git a/c/src/lib/libbsp/sparc/leon3/startup/spurious.c b/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
> index a29f113..6a93670 100644
> --- a/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
> +++ b/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
> @@ -146,14 +146,15 @@ void bsp_spurious_initialize()
>
> /*
> * Skip window overflow, underflow, and flush as well as software
> - * trap 0 which we will use as a shutdown. Also avoid trap 0x70 - 0x7f
> - * which cannot happen and where some of the space is used to pass
> - * paramaters to the program.
> + * trap 0,9,10 which we will use as a shutdown, IRQ disable, IRQ enable.
> + * Also avoid trap 0x70 - 0x7f which cannot happen and where some of the
> + * space is used to pass paramaters to the program.
> */
>
> if (( trap == 5 || trap == 6 ) ||
> (( trap >= 0x11 ) && ( trap <= 0x1f )) ||
> - (( trap >= 0x70 ) && ( trap <= 0x83 )))
> + (( trap >= 0x70 ) && ( trap <= 0x83 )) ||
> + (( trap >= 0x89 ) && ( trap <= 0x8a )))
> continue;
>
> set_vector(
> diff --git a/c/src/lib/libbsp/sparc/shared/irq_asm.S b/c/src/lib/libbsp/sparc/shared/irq_asm.S
> index 2ab0def..3e08795 100644
> --- a/c/src/lib/libbsp/sparc/shared/irq_asm.S
> +++ b/c/src/lib/libbsp/sparc/shared/irq_asm.S
> @@ -499,8 +499,7 @@ dont_fix_pil2:
> cmp %l7, 0
> bne profiling_not_outer_most_exit
> nop
> - call SYM(sparc_disable_interrupts), 0
> - nop
> + ta SPARC_SWTRAP_IRQDIS ! Call interrupt disable trap handler
> ld [%l4], %o2 ! o2 = 3rd arg = interrupt exit instant
> mov %l3, %o1 ! o1 = 2nd arg = interrupt entry instant
> call SYM(_Profiling_Outer_most_interrupt_entry_and_exit), 0
> @@ -585,38 +584,31 @@ profiling_not_outer_most_exit:
> nop
> isr_dispatch:
> call SYM(_Thread_Dispatch), 0
> - nop
> + nop
>
> - /*
> - * We invoked _Thread_Dispatch in a state similar to the interrupted
> - * task. In order to safely be able to tinker with the register
> - * windows and get the task back to its pre-interrupt state,
> - * we need to disable interrupts disabled so we can safely tinker
> - * with the register windowing. In particular, the CWP in the PSR
> - * is fragile during this period. (See PR578.)
> - */
> - mov 2,%g1 ! syscall (disable interrupts)
> - ta 0 ! syscall (disable interrupts)
> + /*
> + * We invoked _Thread_Dispatch in a state similar to the interrupted
> + * task. In order to safely be able to tinker with the register
> + * windows and get the task back to its pre-interrupt state,
> + * we need to disable interrupts disabled so we can safely tinker
> + * with the register windowing. In particular, the CWP in the PSR
> + * is fragile during this period. (See PR578.)
> + */
> + ta SPARC_SWTRAP_IRQDIS ! syscall (disable interrupts)
>
> /*
> * While we had ISR dispatching disabled in this thread,
> * did we miss anything. If so, then we need to do another
> * _Thread_Dispatch before leaving this ISR Dispatch context.
> */
> + ldub [%g6 + PER_CPU_DISPATCH_NEEDED], %l7
>
> - ldub [%g6 + PER_CPU_DISPATCH_NEEDED], %l7
> -
> - orcc %l7, %g0, %g0 ! Is thread switch necesary?
> - bz allow_nest_again ! No, then clear out and return
> - nop
> -
> - ! Yes, then invoke the dispatcher
> -dispatchAgain:
> - mov 3,%g1 ! syscall (enable interrupts)
> - ta 0 ! syscall (enable interrupts)
> - ba isr_dispatch
> - nop
> + orcc %l7, %g0, %g0 ! Is thread switch necesary?
> + bne,a isr_dispatch ! Yes, then invoke the dispatcher.
> + ! g1 = Old PSR PIL returned from IRQDis
> + ta SPARC_SWTRAP_IRQEN ! syscall (enable interrupts to same level)
>
> + ! No, then clear out and return
> allow_nest_again:
>
> ! Zero out ISR stack nesting prevention flag
> diff --git a/c/src/lib/libbsp/sparc/shared/start/start.S b/c/src/lib/libbsp/sparc/shared/start/start.S
> index 3e0e42e..9e9bcaf 100644
> --- a/c/src/lib/libbsp/sparc/shared/start/start.S
> +++ b/c/src/lib/libbsp/sparc/shared/start/start.S
> @@ -35,11 +35,20 @@
> /*
> * System call optimized trap table entry
> */
> -#define SYSCALL_TRAP(_vector, _handler) \
> +#define IRQDIS_TRAP(_vector, _handler) \
> mov %psr, %l0 ; \
> sethi %hi(_handler), %l4 ; \
> jmp %l4+%lo(_handler); \
> - subcc %g1, 3, %g0; ! prepare for syscall 3 check
> + or %l0, 0x0f00, %l3; ! Set PIL=0xf to disable IRQ
> +
> +/*
> + * System call optimized trap table entry
> + */
> +#define IRQEN_TRAP(_vector, _handler) \
> + mov %psr, %l0 ; \
> + sethi %hi(_handler), %l4 ; \
> + jmp %l4+%lo(_handler); \
> + andn %l0, 0xf00, %l3; ! Set PIL=0 to Enable IRQ
>
> /*
> * Window Overflow optimized trap table entry
> @@ -183,12 +192,20 @@ SYM(CLOCK_SPEED):
> * installed before.
> */
>
> - SYSCALL_TRAP( 0x80, SYM(syscall) ); ! 80 syscall SW trap
> + TRAP( 0x80, SYM(syscall) ); ! 80 halt syscall SW trap
> SOFT_TRAP; SOFT_TRAP; ! 81 - 82
> TRAP( 0x83, SYM(window_flush_trap_handler) ); ! 83 flush windows SW trap
>
> SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 84 - 87
> - SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 88 - 8B
> + SOFT_TRAP; ! 88
> +
> + /*
> + * SW Trap 9-15 Reserved for Operating System
> + */
> + IRQDIS_TRAP(0x89, SYM(syscall_irqdis)); ! 89 IRQ Disable syscall trap
> + IRQEN_TRAP(0x8A, SYM(syscall_irqen)); ! 8A IRQ Enable syscall trap
> +
> + SOFT_TRAP; ! 8B
> SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 8C - 8F
> SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90 - 93
> SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94 - 97
> diff --git a/c/src/lib/libcpu/sparc/syscall/syscall.S b/c/src/lib/libcpu/sparc/syscall/syscall.S
> index 9ce7fa5..64c4805 100644
> --- a/c/src/lib/libcpu/sparc/syscall/syscall.S
> +++ b/c/src/lib/libcpu/sparc/syscall/syscall.S
> @@ -19,69 +19,81 @@
> #include <rtems/asm.h>
> #include "syscall.h"
>
> - .seg "text"
> - /*
> - * system call
> - *
> - * On entry:
> - *
> - * l0 = psr (from trap table)
> - * l1 = pc
> - * l2 = npc
> - * g1 = system call id
> - *
> - * System Call 1 (exit):
> - * g2 = additional exit code 1
> - * g3 = additional exit code 2
> - */
> -
> -.align 32 ! Align to 32-byte cache-line
> - PUBLIC(syscall)
> + .seg "text"
> + /*
> + * system call - halt
> + *
> + * On entry:
> + *
> + * l0 = psr (from trap table)
> + * l1 = pc
> + * l2 = npc
> + * g1 = system call id (1)
> + *
> + * System Call 1 (exit):
> + * g2 = additional exit code 1
> + * g3 = additional exit code 2
> + */
> +
> + PUBLIC(syscall)
>
> SYM(syscall):
> + ta 0 ! syscall 1, halt with %g1,%g2,%g3 info
>
> - ! "subcc, %g1, 3, %g0" done in trap table
> - bne 2f ! syscall 3? enable interrupt
> - and %i0, SPARC_PSR_PIL_MASK, %l4
> - andn %l0, SPARC_PSR_PIL_MASK, %l5
> - wr %l4, %l5, %psr ! Update PSR according to syscall 3
> -1: ! leave, with 3 inst PSR-write delay
> - mov 0, %g1 ! clear %g1
> - or %l0, SPARC_PSR_ET_MASK, %i0 ! return old psr with ET=1. No
> - ! effect on syscall 3
> - jmpl %l2, %g0
> - rett %l2 + 4
> -
> -2: or %l0, 0x0f00, %l4 ! set PIL=15
> - subcc %g1, 2, %g0 ! syscall 2? disable interrupts
> - beq,a 1b ! Annul delay-slot for syscall 1
> - mov %l4, %psr ! Update PSR according to Syscall 2
> - ta 0 ! syscall 1 (not 2 or 3), halt
> -
> - PUBLIC(sparc_disable_interrupts)
> + PUBLIC(sparc_syscall_exit)
>
> -SYM(sparc_disable_interrupts):
> -
> - mov SYS_irqdis, %g1
> - retl
> - ta 0
> +SYM(sparc_syscall_exit):
>
> - PUBLIC(sparc_enable_interrupts)
> + mov SYS_exit, %g1
> + mov %o0, %g2 ! Additional exit code 1
> + mov %o1, %g3 ! Additional exit code 2
> + ta SPARC_SWTRAP_SYSCALL
> +
> + /*
> + * system call - Interrupt Disable
> + *
> + * On entry:
> + *
> + * l0 = psr (from trap table)
> + * l1 = pc
> + * l2 = npc
> + * l3 = psr | SPARC_PSR_PIL_MASK
> + *
> + * On exit:
> + * g1 = old psr (to user)
> + */
>
> -SYM(sparc_enable_interrupts):
> +.align 32 ! Align to 32-byte cache-line
> + PUBLIC(syscall_irqdis)
>
> - mov SYS_irqen, %g1
> - retl
> - ta 0
> +SYM(syscall_irqdis):
> + mov %l3, %psr ! Set PSR. Write delay 3 instr
> + or %l0, SPARC_PSR_ET_MASK, %g1 ! return old PSR with ET=1
> + nop ! PSR write delay
> + jmp %l2 ! Return to after TA 9.
> + rett %l2 + 4
>
> - PUBLIC(sparc_syscall_exit)
> + /*
> + * system call - Interrupt Enable
> + *
> + * On entry:
> + *
> + * l0 = psr (from trap table)
> + * l1 = pc
> + * l2 = npc
> + * l3 = psr & ~0x0f00
> + * g1 = new PIL to write (from user)
> + */
>
> -SYM(sparc_syscall_exit):
> +.align 32 ! Align to 32-byte cache-line
> + PUBLIC(syscall_irqen)
>
> - mov SYS_exit, %g1
> - mov %o0, %g2 ! Additional exit code 1
> - mov %o1, %g3 ! Additional exit code 2
> - ta 0
> +SYM(syscall_irqen):
> + and %g1, SPARC_PSR_PIL_MASK, %l4 ! %l4 = (%g1 & 0xf00)
> + wr %l3, %l4, %psr ! PSR = (PSR & ~0xf00) ^ %l4
> + nop; nop ! PSR write delay;
> + jmp %l2 ! Return to after TA 10.
> + rett %l2 + 4
>
> #if defined(RTEMS_PARAVIRT)
>
> diff --git a/c/src/lib/libcpu/sparc/syscall/syscall.h b/c/src/lib/libcpu/sparc/syscall/syscall.h
> index 9af3560..2f20886 100644
> --- a/c/src/lib/libcpu/sparc/syscall/syscall.h
> +++ b/c/src/lib/libcpu/sparc/syscall/syscall.h
> @@ -1,3 +1 @@
> #define SYS_exit 1
> -#define SYS_irqdis 2
> -#define SYS_irqen 3
> diff --git a/cpukit/score/cpu/sparc/rtems/score/sparc.h b/cpukit/score/cpu/sparc/rtems/score/sparc.h
> index e3251d8..7fe7ea4 100644
> --- a/cpukit/score/cpu/sparc/rtems/score/sparc.h
> +++ b/cpukit/score/cpu/sparc/rtems/score/sparc.h
> @@ -157,6 +157,11 @@ extern "C" {
>
> #define LEON3_ASR17_PROCESSOR_INDEX_SHIFT 28
>
> +/* SPARC Software Trap number definitions */
> +#define SPARC_SWTRAP_SYSCALL 0
> +#define SPARC_SWTRAP_IRQDIS 9
> +#define SPARC_SWTRAP_IRQEN 10
> +
> #ifndef ASM
>
> /**
> @@ -306,7 +311,12 @@ void _SPARC_Set_TBR( uint32_t new_tbr );
> *
> * @return This method returns the entire PSR contents.
> */
> -uint32_t sparc_disable_interrupts(void);
> +static inline uint32_t sparc_disable_interrupts(void)
> +{
> + register uint32_t psr __asm__("g1");
> + __asm__ volatile ( "ta %1\n\t" : "=r" (psr) : "i" (SPARC_SWTRAP_IRQDIS));
This is clever. A brief comment might be nice to help the reader
understand that writing to g1 is a side-effect of the trap handler.
> + return psr;
> +}
>
> /**
> * @brief SPARC enable processor interrupts.
> @@ -315,7 +325,11 @@ uint32_t sparc_disable_interrupts(void);
> *
> * @param[in] psr is the PSR returned by @ref sparc_disable_interrupts.
> */
> -void sparc_enable_interrupts(uint32_t psr);
> +static inline void sparc_enable_interrupts(uint32_t psr)
> +{
> + register uint32_t _psr __asm__("g1") = psr;
> + __asm__ volatile ( "ta %0\n" :: "i" (SPARC_SWTRAP_IRQEN), "r" (_psr));
Ditto, except this could clobber the g1 register directly instead of
through the _psr variable.
> +}
>
> /**
> * @brief SPARC exit through system call 1
> --
> 1.7.0.4
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list