[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