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

Daniel Hellstrom daniel at gaisler.com
Mon Nov 24 10:15:44 UTC 2014


* 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
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));
+  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));
+}
 
 /**
  * @brief SPARC exit through system call 1
-- 
1.7.0.4



More information about the devel mailing list