forked from Imagelibrary/rtems
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:
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <bsp.h>
|
#include <bsp.h>
|
||||||
|
#include <rtems/score/cpu.h>
|
||||||
#include <rtems/bspIo.h>
|
#include <rtems/bspIo.h>
|
||||||
|
|
||||||
void _CPU_Exception_frame_print( const CPU_Exception_frame *frame )
|
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
|
* Skip window overflow, underflow, and flush as well as software
|
||||||
* trap 0 which we will use as a shutdown. Also avoid trap 0x70 - 0x7f
|
* trap 0,9,10 which we will use as a shutdown, IRQ disable, IRQ enable.
|
||||||
* which cannot happen and where some of the space is used to pass
|
* Also avoid trap 0x70 - 0x7f which cannot happen and where some of the
|
||||||
* paramaters to the program.
|
* space is used to pass paramaters to the program.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (( trap == 5 || trap == 6 ) ||
|
if (( trap == 5 ) || ( trap == 6 ) ||
|
||||||
(( trap >= 0x11 ) && ( trap <= 0x1f )) ||
|
(( trap >= 0x11 ) && ( trap <= 0x1f )) ||
|
||||||
(( trap >= 0x70 ) && ( trap <= 0x83 )))
|
(( trap >= 0x70 ) && ( trap <= 0x83 )) ||
|
||||||
|
( trap == SPARC_SWTRAP_IRQDIS ) || ( trap == SPARC_SWTRAP_IRQEN ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
set_vector(
|
set_vector(
|
||||||
|
|||||||
@@ -499,8 +499,7 @@ dont_fix_pil2:
|
|||||||
cmp %l7, 0
|
cmp %l7, 0
|
||||||
bne profiling_not_outer_most_exit
|
bne profiling_not_outer_most_exit
|
||||||
nop
|
nop
|
||||||
call SYM(sparc_disable_interrupts), 0
|
ta SPARC_SWTRAP_IRQDIS ! Call interrupt disable trap handler
|
||||||
nop
|
|
||||||
ld [%l4], %o2 ! o2 = 3rd arg = interrupt exit instant
|
ld [%l4], %o2 ! o2 = 3rd arg = interrupt exit instant
|
||||||
mov %l3, %o1 ! o1 = 2nd arg = interrupt entry instant
|
mov %l3, %o1 ! o1 = 2nd arg = interrupt entry instant
|
||||||
call SYM(_Profiling_Outer_most_interrupt_entry_and_exit), 0
|
call SYM(_Profiling_Outer_most_interrupt_entry_and_exit), 0
|
||||||
@@ -585,38 +584,31 @@ profiling_not_outer_most_exit:
|
|||||||
nop
|
nop
|
||||||
isr_dispatch:
|
isr_dispatch:
|
||||||
call SYM(_Thread_Dispatch), 0
|
call SYM(_Thread_Dispatch), 0
|
||||||
nop
|
nop
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We invoked _Thread_Dispatch in a state similar to the interrupted
|
* We invoked _Thread_Dispatch in a state similar to the interrupted
|
||||||
* task. In order to safely be able to tinker with the register
|
* task. In order to safely be able to tinker with the register
|
||||||
* windows and get the task back to its pre-interrupt state,
|
* windows and get the task back to its pre-interrupt state,
|
||||||
* we need to disable interrupts disabled so we can safely tinker
|
* we need to disable interrupts disabled so we can safely tinker
|
||||||
* with the register windowing. In particular, the CWP in the PSR
|
* with the register windowing. In particular, the CWP in the PSR
|
||||||
* is fragile during this period. (See PR578.)
|
* is fragile during this period. (See PR578.)
|
||||||
*/
|
*/
|
||||||
mov 2,%g1 ! syscall (disable interrupts)
|
ta SPARC_SWTRAP_IRQDIS ! syscall (disable interrupts)
|
||||||
ta 0 ! syscall (disable interrupts)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* While we had ISR dispatching disabled in this thread,
|
* While we had ISR dispatching disabled in this thread,
|
||||||
* did we miss anything. If so, then we need to do another
|
* did we miss anything. If so, then we need to do another
|
||||||
* _Thread_Dispatch before leaving this ISR Dispatch context.
|
* _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?
|
||||||
|
bne,a isr_dispatch ! Yes, then invoke the dispatcher.
|
||||||
orcc %l7, %g0, %g0 ! Is thread switch necesary?
|
! g1 = Old PSR PIL returned from IRQDis
|
||||||
bz allow_nest_again ! No, then clear out and return
|
ta SPARC_SWTRAP_IRQEN ! syscall (enable interrupts to same level)
|
||||||
nop
|
|
||||||
|
|
||||||
! Yes, then invoke the dispatcher
|
|
||||||
dispatchAgain:
|
|
||||||
mov 3,%g1 ! syscall (enable interrupts)
|
|
||||||
ta 0 ! syscall (enable interrupts)
|
|
||||||
ba isr_dispatch
|
|
||||||
nop
|
|
||||||
|
|
||||||
|
! No, then clear out and return
|
||||||
allow_nest_again:
|
allow_nest_again:
|
||||||
|
|
||||||
! Zero out ISR stack nesting prevention flag
|
! Zero out ISR stack nesting prevention flag
|
||||||
|
|||||||
@@ -35,11 +35,20 @@
|
|||||||
/*
|
/*
|
||||||
* System call optimized trap table entry
|
* System call optimized trap table entry
|
||||||
*/
|
*/
|
||||||
#define SYSCALL_TRAP(_vector, _handler) \
|
#define IRQDIS_TRAP(_handler) \
|
||||||
mov %psr, %l0 ; \
|
mov %psr, %l0 ; \
|
||||||
sethi %hi(_handler), %l4 ; \
|
sethi %hi(_handler), %l4 ; \
|
||||||
jmp %l4+%lo(_handler); \
|
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
|
* Window Overflow optimized trap table entry
|
||||||
@@ -183,12 +192,23 @@ SYM(CLOCK_SPEED):
|
|||||||
* installed before.
|
* 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
|
SOFT_TRAP; SOFT_TRAP; ! 81 - 82
|
||||||
TRAP( 0x83, SYM(window_flush_trap_handler) ); ! 83 flush windows SW trap
|
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; ! 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; ! 8C - 8F
|
||||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90 - 93
|
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90 - 93
|
||||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94 - 97
|
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94 - 97
|
||||||
|
|||||||
@@ -19,69 +19,81 @@
|
|||||||
#include <rtems/asm.h>
|
#include <rtems/asm.h>
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
|
||||||
.seg "text"
|
.seg "text"
|
||||||
/*
|
/*
|
||||||
* system call
|
* system call - halt
|
||||||
*
|
*
|
||||||
* On entry:
|
* On entry:
|
||||||
*
|
*
|
||||||
* l0 = psr (from trap table)
|
* l0 = psr (from trap table)
|
||||||
* l1 = pc
|
* l1 = pc
|
||||||
* l2 = npc
|
* l2 = npc
|
||||||
* g1 = system call id
|
* g1 = system call id (1)
|
||||||
*
|
*
|
||||||
* System Call 1 (exit):
|
* System Call 1 (exit):
|
||||||
* g2 = additional exit code 1
|
* g2 = additional exit code 1
|
||||||
* g3 = additional exit code 2
|
* g3 = additional exit code 2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.align 32 ! Align to 32-byte cache-line
|
PUBLIC(syscall)
|
||||||
PUBLIC(syscall)
|
|
||||||
|
|
||||||
SYM(syscall):
|
SYM(syscall):
|
||||||
|
ta 0 ! syscall 1, halt with %g1,%g2,%g3 info
|
||||||
|
|
||||||
! "subcc, %g1, 3, %g0" done in trap table
|
PUBLIC(sparc_syscall_exit)
|
||||||
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)
|
|
||||||
|
|
||||||
SYM(sparc_syscall_exit):
|
SYM(sparc_syscall_exit):
|
||||||
|
|
||||||
mov SYS_exit, %g1
|
mov SYS_exit, %g1
|
||||||
mov %o0, %g2 ! Additional exit code 1
|
mov %o0, %g2 ! Additional exit code 1
|
||||||
mov %o1, %g3 ! Additional exit code 2
|
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)
|
#if defined(RTEMS_PARAVIRT)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
#define SYS_exit 1
|
#define SYS_exit 1
|
||||||
#define SYS_irqdis 2
|
|
||||||
#define SYS_irqen 3
|
|
||||||
|
|||||||
@@ -149,6 +149,11 @@ extern "C" {
|
|||||||
|
|
||||||
#define LEON3_ASR17_PROCESSOR_INDEX_SHIFT 28
|
#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
|
#ifndef ASM
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -298,7 +303,12 @@ void _SPARC_Set_TBR( uint32_t new_tbr );
|
|||||||
*
|
*
|
||||||
* @return This method returns the entire PSR contents.
|
* @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.
|
* @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.
|
* @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
|
* @brief SPARC exit through system call 1
|
||||||
|
|||||||
@@ -851,7 +851,12 @@ supported by the SPARC architecture with level fifteen (15)
|
|||||||
being the highest priority. Level zero (0) indicates that
|
being the highest priority. Level zero (0) indicates that
|
||||||
interrupts are fully enabled. Interrupt requests for interrupts
|
interrupts are fully enabled. Interrupt requests for interrupts
|
||||||
with priorities less than or equal to the current interrupt mask
|
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
|
Although RTEMS supports 256 interrupt levels, the
|
||||||
SPARC only supports sixteen. RTEMS interrupt levels 0 through
|
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
|
other RTEMS interrupt levels are undefined and their behavior is
|
||||||
unpredictable.
|
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
|
@subsection Disabling of Interrupts by RTEMS
|
||||||
|
|
||||||
During the execution of directive calls, critical
|
During the execution of directive calls, critical
|
||||||
sections of code may be executed. When these sections are
|
sections of code may be executed. When these sections are
|
||||||
encountered, RTEMS disables interrupts to level seven (15)
|
encountered, RTEMS disables interrupts to level fifteen (15)
|
||||||
before the execution of this section and restores them to the
|
before the execution of the section and restores them to the
|
||||||
previous level upon completion of the section. RTEMS has been
|
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
|
RTEMS_MAXIMUM_DISABLE_PERIOD microseconds on a RTEMS_MAXIMUM_DISABLE_PERIOD_MHZ
|
||||||
Mhz ERC32 with zero wait states.
|
Mhz ERC32 with zero wait states.
|
||||||
These numbers will vary based the number of wait states and
|
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
|
sections. However, ISRs that make no system calls may safely
|
||||||
execute as non-maskable interrupts.
|
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
|
@subsection Interrupt Stack
|
||||||
|
|
||||||
The SPARC architecture does not provide for a
|
The SPARC architecture does not provide for a
|
||||||
|
|||||||
Reference in New Issue
Block a user