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.
This commit is contained in:
Daniel Hellstrom
2014-12-03 11:35:52 +01:00
parent 4081032ce0
commit dff1803cfb
7 changed files with 157 additions and 96 deletions

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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
*/
.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
*/
.align 32 ! Align to 32-byte cache-line
PUBLIC(syscall)
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)
SYM(sparc_disable_interrupts):
mov SYS_irqdis, %g1
retl
ta 0
PUBLIC(sparc_enable_interrupts)
SYM(sparc_enable_interrupts):
mov SYS_irqen, %g1
retl
ta 0
PUBLIC(sparc_syscall_exit)
PUBLIC(sparc_syscall_exit)
SYM(sparc_syscall_exit):
mov SYS_exit, %g1
mov %o0, %g2 ! Additional exit code 1
mov %o1, %g3 ! Additional exit code 2
ta 0
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)
*/
.align 32 ! Align to 32-byte cache-line
PUBLIC(syscall_irqdis)
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
/*
* 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)
*/
.align 32 ! Align to 32-byte cache-line
PUBLIC(syscall_irqen)
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)

View File

@@ -1,3 +1 @@
#define SYS_exit 1
#define SYS_irqdis 2
#define SYS_irqen 3

View File

@@ -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

View File

@@ -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