[rtems commit] SPARC: optimize IRQ enable & disable

Daniel Hellstrom danielh at rtems.org
Thu Dec 4 11:49:22 UTC 2014


Module:    rtems
Branch:    master
Commit:    dff1803cfbec3775fff1b9c34cc707c05494dc3b
Changeset: http://git.rtems.org/rtems/commit/?id=dff1803cfbec3775fff1b9c34cc707c05494dc3b

Author:    Daniel Hellstrom <daniel at gaisler.com>
Date:      Wed Dec  3 11:35:52 2014 +0100

SPARC: optimize IRQ enable & disable

* Coding style cleanups.
* Use OS reserved trap 0x89 for IRQ Disable
* Use OS reserved trap 0x8A for IRQ Enable
* Add to SPARC CPU supplement documentation

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 trap handler by
five instructions due to this.

---

 c/src/lib/libbsp/sparc/leon3/startup/spurious.c |  12 ++-
 c/src/lib/libbsp/sparc/shared/irq_asm.S         |  42 ++++-----
 c/src/lib/libbsp/sparc/shared/start/start.S     |  30 +++++-
 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 +++-
 doc/cpu_supplement/sparc.t                      |  31 ++++++-
 7 files changed, 157 insertions(+), 96 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..8801f6e 100644
--- a/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
+++ b/c/src/lib/libbsp/sparc/leon3/startup/spurious.c
@@ -18,6 +18,7 @@
  */
 
 #include <bsp.h>
+#include <rtems/score/cpu.h>
 #include <rtems/bspIo.h>
 
 void _CPU_Exception_frame_print( const CPU_Exception_frame *frame )
@@ -146,14 +147,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 ) ||
+    if (( trap == 5 ) || ( trap == 6 ) ||
         (( trap >= 0x11 ) && ( trap <= 0x1f )) ||
-        (( trap >= 0x70 ) && ( trap <= 0x83 )))
+        (( trap >= 0x70 ) && ( trap <= 0x83 )) ||
+        ( trap == SPARC_SWTRAP_IRQDIS ) || ( trap == SPARC_SWTRAP_IRQEN ))
       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..f38fe8c 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(_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(_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,23 @@ SYM(CLOCK_SPEED):
    *        installed before.
    */
 
-  SYSCALL_TRAP( 0x80, SYM(syscall) );		! 80 syscall SW trap
-  SOFT_TRAP; SOFT_TRAP;  	            	! 81 - 82
+  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
+   *  
+   *  SPARC_SWTRAP_IRQDIS
+   *  SPARC_SWTRAP_IRQEN
+   */
+  IRQDIS_TRAP(SYM(syscall_irqdis));             ! 89 IRQ Disable syscall trap
+  IRQEN_TRAP(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 abd0f8b..ac8c510 100644
--- a/cpukit/score/cpu/sparc/rtems/score/sparc.h
+++ b/cpukit/score/cpu/sparc/rtems/score/sparc.h
@@ -149,6 +149,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
 
 /**
@@ -298,7 +303,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"); /* return value of trap handler */
+  __asm__ volatile ( "ta %1\n\t" : "=r" (psr) : "i" (SPARC_SWTRAP_IRQDIS));
+  return psr;
+}
 
 /**
  * @brief SPARC enable processor interrupts.
@@ -307,7 +317,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; /* input to trap handler */
+  __asm__ volatile ( "ta %0\n" :: "i" (SPARC_SWTRAP_IRQEN), "r" (_psr));
+}
 
 /**
  * @brief SPARC exit through system call 1
diff --git a/doc/cpu_supplement/sparc.t b/doc/cpu_supplement/sparc.t
index 5ed0ec6..cd5602c 100644
--- a/doc/cpu_supplement/sparc.t
+++ b/doc/cpu_supplement/sparc.t
@@ -851,7 +851,12 @@ supported by the SPARC architecture with level fifteen (15)
 being the highest priority.  Level zero (0) indicates that
 interrupts are fully enabled.  Interrupt requests for interrupts
 with priorities less than or equal to the current interrupt mask
-level are ignored.
+level are ignored. Level fifteen (15) is a non-maskable interrupt
+(NMI), which makes it unsuitable for standard usage since it can
+affect the real-time behaviour by interrupting critical sections
+and spinlocks. Disabling traps stops also the NMI interrupt from
+happening. It can however be used for power-down or other
+critical events.
 
 Although RTEMS supports 256 interrupt levels, the
 SPARC only supports sixteen.  RTEMS interrupt levels 0 through
@@ -859,14 +864,21 @@ SPARC only supports sixteen.  RTEMS interrupt levels 0 through
 other RTEMS interrupt levels are undefined and their behavior is
 unpredictable.
 
+Many LEON SPARC v7/v8 systems features an extended interrupt controller
+which adds an extra step of interrupt decoding to allow handling of
+interrupt 16-31. When such an extended interrupt is generated the CPU
+traps into a specific interrupt trap level 1-14 and software reads out from
+the interrupt controller which extended interrupt source actually caused the
+interrupt.
+
 @subsection Disabling of Interrupts by RTEMS
 
 During the execution of directive calls, critical
 sections of code may be executed.  When these sections are
-encountered, RTEMS disables interrupts to level seven (15)
-before the execution of this section and restores them to the
+encountered, RTEMS disables interrupts to level fifteen (15)
+before the execution of the section and restores them to the
 previous level upon completion of the section.  RTEMS has been
-optimized to insure that interrupts are disabled for less than
+optimized to ensure that interrupts are disabled for less than
 RTEMS_MAXIMUM_DISABLE_PERIOD microseconds on a RTEMS_MAXIMUM_DISABLE_PERIOD_MHZ 
 Mhz ERC32 with zero wait states.
 These numbers will vary based the number of wait states and
@@ -887,6 +899,17 @@ occur due to the inability of RTEMS to protect its critical
 sections.  However, ISRs that make no system calls may safely
 execute as non-maskable interrupts.
 
+Interrupts are disabled or enabled by performing a system call
+to the Operating System reserved software traps 9
+(SPARC_SWTRAP_IRQDIS) or 10 (SPARC_SWTRAP_IRQDIS). The trap is
+generated by the software trap (Ticc) instruction or indirectly
+by calling sparc_disable_interrupts() or sparc_enable_interrupts()
+functions. Disabling interrupts return the previous interrupt level
+(on trap entry) in register G1 and sets PSR.PIL to 15 to disable
+all maskable interrupts. The interrupt level can be restored by
+trapping into the enable interrupt handler with G1 containing the
+new interrupt level.
+
 @subsection Interrupt Stack
 
 The SPARC architecture does not provide for a



More information about the vc mailing list