[PATCH 4/4 v2] SPARC: optimize IRQ enable & disable

Daniel Hellstrom daniel at gaisler.com
Mon Nov 24 15:41:02 UTC 2014


On 11/24/2014 04:29 PM, Gedare Bloom wrote:
> 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.
I will add a comment here.

>> +  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.

It does not clobber g1.

Thanks!

DanielH



More information about the devel mailing list