arch: arc: add nested interrupt support
* add nested interrupt support for interrupts + use a varibale exc_nest_count to trace nest interrupt and exception + regular interrupts can be nested by regular interrupts and fast interrupts + fast interrupt's priority is the highest, cannot be nested * remove the firq stack and exception stack + remove the coressponding kconfig option + all interrupts (normal and fast) and exceptions will be handled in the same stack (_interrupt stack) + the pros are, smaller memory footprint (no firq stack), simpler stack management, simpler codes, etc.. The cons are, possible 10-15 instructions overhead for the case where fast irq nests regular irq * add the case of ARC in test/kernel/gen_isr_table Signed-off-by: Wayne Ren <wei.ren@synopsys.com> Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
072ef10baf
commit
f8d061faf7
13 changed files with 158 additions and 247 deletions
|
@ -103,15 +103,6 @@ config RGF_NUM_BANKS
|
||||||
register bank, the fast interrupt handler must save
|
register bank, the fast interrupt handler must save
|
||||||
and restore general purpose registers.
|
and restore general purpose registers.
|
||||||
|
|
||||||
config FIRQ_STACK_SIZE
|
|
||||||
int
|
|
||||||
prompt "Size of stack for FIRQs (in bytes)"
|
|
||||||
depends on CPU_ARCV2
|
|
||||||
default 1024
|
|
||||||
help
|
|
||||||
FIRQs and regular IRQs have different stacks so that a FIRQ can start
|
|
||||||
running without doing stack switching in software.
|
|
||||||
|
|
||||||
config ARC_STACK_CHECKING
|
config ARC_STACK_CHECKING
|
||||||
bool "Enable Stack Checking"
|
bool "Enable Stack Checking"
|
||||||
depends on CPU_ARCV2
|
depends on CPU_ARCV2
|
||||||
|
|
|
@ -21,27 +21,13 @@
|
||||||
|
|
||||||
GTEXT(_firq_enter)
|
GTEXT(_firq_enter)
|
||||||
GTEXT(_firq_exit)
|
GTEXT(_firq_exit)
|
||||||
GTEXT(_firq_stack_setup)
|
|
||||||
GTEXT(_firq_stack_suspend)
|
|
||||||
GTEXT(_firq_stack_resume)
|
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS != 1
|
GDATA(exc_nest_count)
|
||||||
GDATA(_firq_stack)
|
|
||||||
GDATA(_saved_firq_stack)
|
|
||||||
|
|
||||||
SECTION_VAR(NOINIT, _firq_stack)
|
|
||||||
.space CONFIG_FIRQ_STACK_SIZE
|
|
||||||
#else
|
|
||||||
GDATA(saved_r0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.macro _firq_return
|
|
||||||
#if CONFIG_RGF_NUM_BANKS == 1
|
#if CONFIG_RGF_NUM_BANKS == 1
|
||||||
b _firq_no_reschedule
|
GDATA(saved_r0)
|
||||||
#else
|
#else
|
||||||
rtie
|
GDATA(saved_sp)
|
||||||
#endif
|
#endif
|
||||||
.endm
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -66,7 +52,6 @@ GDATA(saved_r0)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _firq_enter)
|
SECTION_FUNC(TEXT, _firq_enter)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ATTENTION:
|
* ATTENTION:
|
||||||
* If CONFIG_RGF_NUM_BANKS>1, firq uses a 2nd register bank so GPRs do
|
* If CONFIG_RGF_NUM_BANKS>1, firq uses a 2nd register bank so GPRs do
|
||||||
|
@ -74,7 +59,6 @@ SECTION_FUNC(TEXT, _firq_enter)
|
||||||
* If CONFIG_RGF_NUM_BANKS==1, firq must use the stack to save registers.
|
* If CONFIG_RGF_NUM_BANKS==1, firq must use the stack to save registers.
|
||||||
* This has already been done by _isr_wrapper.
|
* This has already been done by _isr_wrapper.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||||
/* disable stack checking */
|
/* disable stack checking */
|
||||||
lr r2, [_ARC_V2_STATUS32]
|
lr r2, [_ARC_V2_STATUS32]
|
||||||
|
@ -95,8 +79,41 @@ SECTION_FUNC(TEXT, _firq_enter)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ld r1, [exc_nest_count]
|
||||||
|
add r0, r1, 1
|
||||||
|
st r0, [exc_nest_count]
|
||||||
|
cmp r1, 0
|
||||||
|
|
||||||
|
bgt.d firq_nest
|
||||||
|
mov r0, sp
|
||||||
|
|
||||||
|
mov r1, _kernel
|
||||||
|
ld sp, [r1, _kernel_offset_to_irq_stack]
|
||||||
|
#if CONFIG_RGF_NUM_BANKS != 1
|
||||||
|
b firq_nest_1
|
||||||
|
firq_nest:
|
||||||
|
mov r1, ilink
|
||||||
|
lr r0, [_ARC_V2_STATUS32]
|
||||||
|
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
|
||||||
|
kflag r0
|
||||||
|
|
||||||
|
st sp, [saved_sp]
|
||||||
|
|
||||||
|
lr ilink, [_ARC_V2_STATUS32]
|
||||||
|
or ilink, ilink, _ARC_V2_STATUS32_RB(1)
|
||||||
|
kflag ilink
|
||||||
|
mov r0, sp
|
||||||
|
ld sp, [saved_sp]
|
||||||
|
mov ilink, r1
|
||||||
|
firq_nest_1:
|
||||||
|
#else
|
||||||
|
firq_nest:
|
||||||
|
#endif
|
||||||
|
push_s r0
|
||||||
j @_isr_demux
|
j @_isr_demux
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @brief Work to be done exiting a FIRQ
|
* @brief Work to be done exiting a FIRQ
|
||||||
|
@ -106,6 +123,8 @@ SECTION_FUNC(TEXT, _firq_enter)
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _firq_exit)
|
SECTION_FUNC(TEXT, _firq_exit)
|
||||||
|
|
||||||
|
pop sp
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS != 1
|
#if CONFIG_RGF_NUM_BANKS != 1
|
||||||
#ifndef CONFIG_FIRQ_NO_LPCC
|
#ifndef CONFIG_FIRQ_NO_LPCC
|
||||||
/* restore lp_count, lp_start, lp_end from r23-r25 */
|
/* restore lp_count, lp_start, lp_end from r23-r25 */
|
||||||
|
@ -114,29 +133,20 @@ SECTION_FUNC(TEXT, _firq_exit)
|
||||||
sr r25, [_ARC_V2_LP_END]
|
sr r25, [_ARC_V2_LP_END]
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
/* check if we're a nested interrupt: if so, let the interrupted
|
||||||
|
* interrupt handle the reschedule */
|
||||||
|
mov r1, exc_nest_count
|
||||||
|
ld r0, [r1]
|
||||||
|
sub r0, r0, 1
|
||||||
|
cmp r0, 0
|
||||||
|
bne.d _firq_no_reschedule
|
||||||
|
st r0, [r1]
|
||||||
|
|
||||||
#ifdef CONFIG_PREEMPT_ENABLED
|
#ifdef CONFIG_PREEMPT_ENABLED
|
||||||
|
|
||||||
mov_s r1, _kernel
|
mov_s r1, _kernel
|
||||||
ld_s r2, [r1, _kernel_offset_to_current]
|
ld_s r2, [r1, _kernel_offset_to_current]
|
||||||
|
|
||||||
#if CONFIG_NUM_IRQ_PRIO_LEVELS > 1
|
|
||||||
/* check if we're a nested interrupt: if so, let the interrupted
|
|
||||||
* interrupt handle the reschedule */
|
|
||||||
|
|
||||||
lr r3, [_ARC_V2_AUX_IRQ_ACT]
|
|
||||||
|
|
||||||
/* the OS on ARCv2 always runs in kernel mode, so assume bit31 [U] in
|
|
||||||
* AUX_IRQ_ACT is always 0: if the contents of AUX_IRQ_ACT is not 1, it
|
|
||||||
* means that another bit is set so an interrupt was interrupted.
|
|
||||||
*/
|
|
||||||
|
|
||||||
breq r3, 1, _firq_check_for_swap
|
|
||||||
|
|
||||||
_firq_return
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.balign 4
|
|
||||||
_firq_check_for_swap:
|
|
||||||
/*
|
/*
|
||||||
* Non-preemptible thread ? Do not schedule (see explanation of
|
* Non-preemptible thread ? Do not schedule (see explanation of
|
||||||
* preempt field in kernel_struct.h).
|
* preempt field in kernel_struct.h).
|
||||||
|
@ -180,7 +190,6 @@ _firq_no_reschedule:
|
||||||
sr r0, [_ARC_V2_LP_START]
|
sr r0, [_ARC_V2_LP_START]
|
||||||
pop_s r0
|
pop_s r0
|
||||||
mov lp_count,r0
|
mov lp_count,r0
|
||||||
ld r0,[saved_r0]
|
|
||||||
#ifdef CONFIG_CODE_DENSITY
|
#ifdef CONFIG_CODE_DENSITY
|
||||||
pop_s r0
|
pop_s r0
|
||||||
sr r0, [_ARC_V2_EI_BASE]
|
sr r0, [_ARC_V2_EI_BASE]
|
||||||
|
@ -189,6 +198,7 @@ _firq_no_reschedule:
|
||||||
pop_s r0
|
pop_s r0
|
||||||
sr r0, [_ARC_V2_JLI_BASE]
|
sr r0, [_ARC_V2_JLI_BASE]
|
||||||
#endif
|
#endif
|
||||||
|
ld r0,[saved_r0]
|
||||||
add sp,sp,8 /* don't need ilink & status32_po from stack */
|
add sp,sp,8 /* don't need ilink & status32_po from stack */
|
||||||
#endif
|
#endif
|
||||||
rtie
|
rtie
|
||||||
|
@ -295,84 +305,3 @@ _firq_return_from_firq:
|
||||||
rtie
|
rtie
|
||||||
|
|
||||||
#endif /* CONFIG_PREEMPT_ENABLED */
|
#endif /* CONFIG_PREEMPT_ENABLED */
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Install the FIRQ stack in register bank 1 if CONFIG_RGF_NUM_BANK!=1
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _firq_stack_setup)
|
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS != 1
|
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
|
||||||
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
|
|
||||||
or r0, r0, _ARC_V2_STATUS32_RB(1)
|
|
||||||
kflag r0
|
|
||||||
|
|
||||||
mov sp, _firq_stack
|
|
||||||
add sp, sp, CONFIG_FIRQ_STACK_SIZE
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We have to reload r0 here, because it is bank1 r0 which contains
|
|
||||||
* garbage, not bank0 r0 containing the previous value of status32.
|
|
||||||
*/
|
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
|
||||||
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
|
|
||||||
kflag r0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
j_s [blink]
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Save the FIRQ context if CONFIG_RGF_NUM_BANK!=1
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _firq_stack_suspend)
|
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS != 1
|
|
||||||
/* Switch to bank 1 */
|
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
|
||||||
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
|
|
||||||
or r0, r0, _ARC_V2_STATUS32_RB(1)
|
|
||||||
kflag r0
|
|
||||||
|
|
||||||
st sp, [_saved_firq_stack]
|
|
||||||
|
|
||||||
/* Switch back to bank 0 */
|
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
|
||||||
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
|
|
||||||
kflag r0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
j_s [blink]
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Restore the FIRQ context if CONFIG_RGF_NUM_BANK!=1
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _firq_stack_resume)
|
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS != 1
|
|
||||||
/* Switch to bank 1 */
|
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
|
||||||
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
|
|
||||||
or r0, r0, _ARC_V2_STATUS32_RB(1)
|
|
||||||
kflag r0
|
|
||||||
|
|
||||||
ld sp, [_saved_firq_stack]
|
|
||||||
|
|
||||||
/* Switch back to bank 0 */
|
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
|
||||||
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
|
|
||||||
kflag r0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
j_s [blink]
|
|
||||||
|
|
|
@ -33,18 +33,7 @@ GTEXT(__ev_div_zero)
|
||||||
GTEXT(__ev_dc_error)
|
GTEXT(__ev_dc_error)
|
||||||
GTEXT(__ev_maligned)
|
GTEXT(__ev_maligned)
|
||||||
|
|
||||||
SECTION_VAR(BSS, saved_stack_pointer)
|
GDATA(exc_nest_count)
|
||||||
.balign 4
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS == 1
|
|
||||||
GDATA(_exception_stack)
|
|
||||||
SECTION_VAR(NOINIT, _exception_stack)
|
|
||||||
.space 512
|
|
||||||
/* note: QUARK_SE_C1000_SS can't afford 512B */
|
|
||||||
#else
|
|
||||||
GDATA(_firq_stack)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief Fault handler installed in the fault and reserved vectors
|
* @brief Fault handler installed in the fault and reserved vectors
|
||||||
|
@ -82,15 +71,6 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
|
||||||
pop_s r2
|
pop_s r2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
st sp, [saved_stack_pointer]
|
|
||||||
#if CONFIG_RGF_NUM_BANKS == 1
|
|
||||||
mov_s sp, _exception_stack
|
|
||||||
add sp, sp, 512
|
|
||||||
#else
|
|
||||||
mov_s sp, _firq_stack
|
|
||||||
add sp, sp, CONFIG_FIRQ_STACK_SIZE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* save caller saved registers */
|
/* save caller saved registers */
|
||||||
_create_irq_stack_frame
|
_create_irq_stack_frame
|
||||||
|
|
||||||
|
@ -99,13 +79,32 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
|
||||||
lr r0,[_ARC_V2_ERET]
|
lr r0,[_ARC_V2_ERET]
|
||||||
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
||||||
|
|
||||||
|
|
||||||
|
ld r1, [exc_nest_count]
|
||||||
|
add r0, r1, 1
|
||||||
|
st r0, [exc_nest_count]
|
||||||
|
cmp r1, 0
|
||||||
|
|
||||||
|
bgt.d exc_nest_handle
|
||||||
|
mov r0, sp
|
||||||
|
|
||||||
|
mov r1, _kernel
|
||||||
|
ld sp, [r1, _kernel_offset_to_irq_stack]
|
||||||
|
exc_nest_handle:
|
||||||
|
push_s r0
|
||||||
|
|
||||||
jl _Fault
|
jl _Fault
|
||||||
|
|
||||||
|
pop sp
|
||||||
|
|
||||||
|
mov r1, exc_nest_count
|
||||||
|
ld r0, [r1]
|
||||||
|
sub r0, r0, 1
|
||||||
|
st r0, [r1]
|
||||||
|
|
||||||
/* if _Fault returns, restore the registers */
|
/* if _Fault returns, restore the registers */
|
||||||
_pop_irq_stack_frame
|
_pop_irq_stack_frame
|
||||||
|
|
||||||
/* now restore the stack */
|
|
||||||
ld sp,[saved_stack_pointer]
|
|
||||||
rtie
|
rtie
|
||||||
|
|
||||||
#ifdef CONFIG_IRQ_OFFLOAD
|
#ifdef CONFIG_IRQ_OFFLOAD
|
||||||
|
@ -136,26 +135,41 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
|
||||||
lr r0,[_ARC_V2_ERET]
|
lr r0,[_ARC_V2_ERET]
|
||||||
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
||||||
|
|
||||||
|
ld r1, [exc_nest_count]
|
||||||
|
add r0, r1, 1
|
||||||
|
st r0, [exc_nest_count]
|
||||||
|
cmp r1, 0
|
||||||
|
|
||||||
|
bgt.d trap_nest_handle
|
||||||
|
mov r0, sp
|
||||||
|
|
||||||
|
mov r1, _kernel
|
||||||
|
ld sp, [r1, _kernel_offset_to_irq_stack]
|
||||||
|
trap_nest_handle:
|
||||||
|
push_s r0
|
||||||
|
|
||||||
jl _irq_do_offload
|
jl _irq_do_offload
|
||||||
|
|
||||||
mov_s r1, _kernel
|
pop sp
|
||||||
ld_s r2, [r1, _kernel_offset_to_current]
|
|
||||||
/* check if we're a nested interrupt: if so, let the
|
/* check if we're a nested interrupt: if so, let the
|
||||||
* interrupted interrupt handle the reschedule
|
* interrupted interrupt handle the reschedule
|
||||||
*/
|
*/
|
||||||
lr r3, [_ARC_V2_AUX_IRQ_ACT]
|
mov r1, exc_nest_count
|
||||||
/* the OS on ARCv2 always runs in kernel mode, so assume bit31 [U] in
|
ld r0, [r1]
|
||||||
* AUX_IRQ_ACT is always 0: if the contents of AUX_IRQ_ACT is 0, it
|
sub r0, r0, 1
|
||||||
* means trap was taken from outside an interrupt handler.
|
cmp r0, 0
|
||||||
* But if it was inside, let that handler do the swap.
|
beq.d _trap_check_for_swap
|
||||||
*/
|
st r0, [r1]
|
||||||
breq r3, 0, _trap_check_for_swap
|
|
||||||
_trap_return:
|
_trap_return:
|
||||||
_pop_irq_stack_frame
|
_pop_irq_stack_frame
|
||||||
rtie
|
rtie
|
||||||
|
|
||||||
.balign 4
|
.balign 4
|
||||||
_trap_check_for_swap:
|
_trap_check_for_swap:
|
||||||
|
mov_s r1, _kernel
|
||||||
|
ld_s r2, [r1, _kernel_offset_to_current]
|
||||||
/*
|
/*
|
||||||
* Non-preemptible thread ? Do not schedule (see explanation of
|
* Non-preemptible thread ? Do not schedule (see explanation of
|
||||||
* preempt field in kernel_struct.h).
|
* preempt field in kernel_struct.h).
|
||||||
|
|
|
@ -23,13 +23,24 @@
|
||||||
GTEXT(_isr_wrapper)
|
GTEXT(_isr_wrapper)
|
||||||
GTEXT(_isr_demux)
|
GTEXT(_isr_demux)
|
||||||
|
|
||||||
|
GDATA(exc_nest_count)
|
||||||
|
SECTION_VAR(BSS, exc_nest_count)
|
||||||
|
.balign 4
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS == 1
|
#if CONFIG_RGF_NUM_BANKS == 1
|
||||||
GDATA(saved_r0)
|
GDATA(saved_r0)
|
||||||
|
|
||||||
SECTION_VAR(BSS, saved_r0)
|
SECTION_VAR(BSS, saved_r0)
|
||||||
.balign 4
|
.balign 4
|
||||||
.word 0
|
.word 0
|
||||||
|
#else
|
||||||
|
GDATA(saved_sp)
|
||||||
|
|
||||||
|
SECTION_VAR(BSS, saved_sp)
|
||||||
|
.balign 4
|
||||||
|
.word 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_SYS_POWER_MANAGEMENT)
|
#if defined(CONFIG_SYS_POWER_MANAGEMENT)
|
||||||
|
@ -231,6 +242,14 @@ SECTION_FUNC(TEXT, _isr_wrapper)
|
||||||
push_s r0
|
push_s r0
|
||||||
mov r0,ilink
|
mov r0,ilink
|
||||||
push_s r0
|
push_s r0
|
||||||
|
#ifdef CONFIG_CODE_DENSITY
|
||||||
|
lr r0, [_ARC_V2_JLI_BASE]
|
||||||
|
push_s r0
|
||||||
|
lr r0, [_ARC_V2_LDI_BASE]
|
||||||
|
push_s r0
|
||||||
|
lr r0, [_ARC_V2_EI_BASE]
|
||||||
|
push_s r0
|
||||||
|
#endif
|
||||||
mov r0,lp_count
|
mov r0,lp_count
|
||||||
push_s r0
|
push_s r0
|
||||||
lr r0, [_ARC_V2_LP_START]
|
lr r0, [_ARC_V2_LP_START]
|
||||||
|
@ -326,6 +345,7 @@ _skip_sys_power_save_idle_exit:
|
||||||
SECTION_FUNC(TEXT, _isr_demux)
|
SECTION_FUNC(TEXT, _isr_demux)
|
||||||
push_s r3
|
push_s r3
|
||||||
|
|
||||||
|
|
||||||
/* cannot be done before this point because we must be able to run C */
|
/* cannot be done before this point because we must be able to run C */
|
||||||
/* r0 is available to be stomped here, and exit_tickless_idle uses it */
|
/* r0 is available to be stomped here, and exit_tickless_idle uses it */
|
||||||
exit_tickless_idle
|
exit_tickless_idle
|
||||||
|
@ -333,6 +353,12 @@ SECTION_FUNC(TEXT, _isr_demux)
|
||||||
log_sleep_k_event
|
log_sleep_k_event
|
||||||
|
|
||||||
lr r0, [_ARC_V2_ICAUSE]
|
lr r0, [_ARC_V2_ICAUSE]
|
||||||
|
/* handle software triggered interrupt */
|
||||||
|
lr r3, [_ARC_V2_AUX_IRQ_HINT]
|
||||||
|
brne r3, r0, irq_hint_handled
|
||||||
|
sr 0, [_ARC_V2_AUX_IRQ_HINT]
|
||||||
|
irq_hint_handled:
|
||||||
|
|
||||||
sub r0, r0, 16
|
sub r0, r0, 16
|
||||||
|
|
||||||
mov r1, _sw_isr_table
|
mov r1, _sw_isr_table
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
GTEXT(_rirq_enter)
|
GTEXT(_rirq_enter)
|
||||||
GTEXT(_rirq_exit)
|
GTEXT(_rirq_exit)
|
||||||
GTEXT(_rirq_common_interrupt_swap)
|
GTEXT(_rirq_common_interrupt_swap)
|
||||||
|
GDATA(exc_nest_count)
|
||||||
|
|
||||||
#if 0 /* TODO: when FIRQ is not present, all would be regular */
|
#if 0 /* TODO: when FIRQ is not present, all would be regular */
|
||||||
#define NUM_REGULAR_IRQ_PRIO_LEVELS CONFIG_NUM_IRQ_PRIO_LEVELS
|
#define NUM_REGULAR_IRQ_PRIO_LEVELS CONFIG_NUM_IRQ_PRIO_LEVELS
|
||||||
|
@ -34,14 +35,6 @@ GTEXT(_rirq_common_interrupt_swap)
|
||||||
* TODO: Revist this if FIRQ becomes configurable.
|
* TODO: Revist this if FIRQ becomes configurable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if NUM_REGULAR_IRQ_PRIO_LEVELS > 1
|
|
||||||
#error "nested regular interrupts are not supported."
|
|
||||||
/*
|
|
||||||
* Nesting of Regularing interrupts is not yet supported.
|
|
||||||
* Set CONFIG_NUM_IRQ_PRIO_LEVELS to 2 even if SOC supports more.
|
|
||||||
*/
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -58,20 +51,28 @@ GTEXT(_rirq_common_interrupt_swap)
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _rirq_enter)
|
SECTION_FUNC(TEXT, _rirq_enter)
|
||||||
|
|
||||||
mov r1, _kernel
|
|
||||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||||
/* disable stack checking */
|
/* disable stack checking */
|
||||||
lr r2, [_ARC_V2_STATUS32]
|
lr r2, [_ARC_V2_STATUS32]
|
||||||
bclr r2, r2, _ARC_V2_STATUS32_SC_BIT
|
bclr r2, r2, _ARC_V2_STATUS32_SC_BIT
|
||||||
kflag r2
|
kflag r2
|
||||||
#endif
|
#endif
|
||||||
ld_s r2, [r1, _kernel_offset_to_current]
|
clri
|
||||||
#if NUM_REGULAR_IRQ_PRIO_LEVELS == 1
|
ld r1, [exc_nest_count]
|
||||||
st sp, [r2, _thread_offset_to_sp]
|
add r0, r1, 1
|
||||||
|
st r0, [exc_nest_count]
|
||||||
|
cmp r1, 0
|
||||||
|
|
||||||
|
bgt.d rirq_nest
|
||||||
|
mov r0, sp
|
||||||
|
|
||||||
|
mov r1, _kernel
|
||||||
ld sp, [r1, _kernel_offset_to_irq_stack]
|
ld sp, [r1, _kernel_offset_to_irq_stack]
|
||||||
#else
|
rirq_nest:
|
||||||
#error regular irq nesting is not implemented
|
push_s r0
|
||||||
#endif
|
|
||||||
|
seti
|
||||||
j _isr_demux
|
j _isr_demux
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,6 +84,16 @@ SECTION_FUNC(TEXT, _rirq_enter)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _rirq_exit)
|
SECTION_FUNC(TEXT, _rirq_exit)
|
||||||
|
clri
|
||||||
|
|
||||||
|
pop sp
|
||||||
|
|
||||||
|
mov r1, exc_nest_count
|
||||||
|
ld r0, [r1]
|
||||||
|
sub r0, r0, 1
|
||||||
|
cmp r0, 0
|
||||||
|
bne.d _rirq_return_from_rirq
|
||||||
|
st r0, [r1]
|
||||||
|
|
||||||
#ifdef CONFIG_PREEMPT_ENABLED
|
#ifdef CONFIG_PREEMPT_ENABLED
|
||||||
|
|
||||||
|
@ -94,26 +105,6 @@ SECTION_FUNC(TEXT, _rirq_exit)
|
||||||
* point on until return from interrupt.
|
* point on until return from interrupt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
clri
|
|
||||||
|
|
||||||
#if NUM_REGULAR_IRQ_PRIO_LEVELS > 1
|
|
||||||
/* check if we're a nested interrupt: if so, let the interrupted interrupt
|
|
||||||
* handle the reschedule */
|
|
||||||
|
|
||||||
lr r3, [_ARC_V2_AUX_IRQ_ACT]
|
|
||||||
ffs r0, r3
|
|
||||||
|
|
||||||
asl r0, 1, r0
|
|
||||||
|
|
||||||
/* the OS on ARCv2 always runs in kernel mode, so assume bit31 [U] in
|
|
||||||
* AUX_IRQ_ACT is always 0: if the contents of AUX_IRQ_ACT is greater
|
|
||||||
* than FFS(AUX_IRQ_ACT), it means that another bit is set so an
|
|
||||||
* interrupt was interrupted.
|
|
||||||
*/
|
|
||||||
|
|
||||||
cmp r0, r3
|
|
||||||
brgt _rirq_return_from_rirq
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non-preemptible thread ? Do not schedule (see explanation of
|
* Non-preemptible thread ? Do not schedule (see explanation of
|
||||||
|
@ -134,8 +125,6 @@ SECTION_FUNC(TEXT, _rirq_exit)
|
||||||
* b) needs to load it to restore the interrupted context.
|
* b) needs to load it to restore the interrupted context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ld sp, [r2, _thread_offset_to_sp]
|
|
||||||
|
|
||||||
/* check if the current thread needs to be rescheduled */
|
/* check if the current thread needs to be rescheduled */
|
||||||
ld_s r0, [r1, _kernel_offset_to_ready_q_cache]
|
ld_s r0, [r1, _kernel_offset_to_ready_q_cache]
|
||||||
cmp_s r0, r2
|
cmp_s r0, r2
|
||||||
|
@ -218,10 +207,6 @@ _rirq_return_from_coop:
|
||||||
|
|
||||||
/* fall through to rtie instruction */
|
/* fall through to rtie instruction */
|
||||||
|
|
||||||
.balign 4
|
|
||||||
_rirq_return_from_firq:
|
|
||||||
_rirq_return_from_rirq:
|
|
||||||
|
|
||||||
/* rtie will pop the rest from the stack */
|
/* rtie will pop the rest from the stack */
|
||||||
|
|
||||||
/* fall through to rtie instruction */
|
/* fall through to rtie instruction */
|
||||||
|
@ -229,6 +214,8 @@ _rirq_return_from_rirq:
|
||||||
#endif /* CONFIG_PREEMPT_ENABLED */
|
#endif /* CONFIG_PREEMPT_ENABLED */
|
||||||
|
|
||||||
.balign 4
|
.balign 4
|
||||||
|
_rirq_return_from_firq:
|
||||||
|
_rirq_return_from_rirq:
|
||||||
_rirq_no_reschedule:
|
_rirq_no_reschedule:
|
||||||
|
|
||||||
rtie
|
rtie
|
||||||
|
|
|
@ -17,26 +17,13 @@
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
GDATA(_interrupt_stack)
|
GDATA(_interrupt_stack)
|
||||||
GDATA(_firq_stack)
|
|
||||||
GDATA(_main_stack)
|
GDATA(_main_stack)
|
||||||
|
|
||||||
/* use one of the available interrupt stacks during init */
|
/* use one of the available interrupt stacks during init */
|
||||||
|
|
||||||
/* FIRQ only ? */
|
|
||||||
#if CONFIG_NUM_IRQ_PRIO_LEVELS == 1
|
|
||||||
|
|
||||||
/* FIRQ, but uses _interrupt_stack ? */
|
#define INIT_STACK _interrupt_stack
|
||||||
#if CONFIG_RGF_NUM_BANKS == 1
|
#define INIT_STACK_SIZE CONFIG_ISR_STACK_SIZE
|
||||||
#define INIT_STACK _interrupt_stack
|
|
||||||
#define INIT_STACK_SIZE CONFIG_ISR_STACK_SIZE
|
|
||||||
#else
|
|
||||||
#define INIT_STACK _firq_stack
|
|
||||||
#define INIT_STACK_SIZE CONFIG_FIRQ_STACK_SIZE
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define INIT_STACK _interrupt_stack
|
|
||||||
#define INIT_STACK_SIZE CONFIG_ISR_STACK_SIZE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GTEXT(__reset)
|
GTEXT(__reset)
|
||||||
GTEXT(__start)
|
GTEXT(__start)
|
||||||
|
@ -106,13 +93,6 @@ done_cache_invalidate:
|
||||||
mov_s r2, CONFIG_ISR_STACK_SIZE
|
mov_s r2, CONFIG_ISR_STACK_SIZE
|
||||||
jl memset
|
jl memset
|
||||||
|
|
||||||
#if CONFIG_RGF_NUM_BANKS != 1
|
|
||||||
mov_s r0, _firq_stack
|
|
||||||
mov_s r1, 0xaa
|
|
||||||
mov_s r2, CONFIG_FIRQ_STACK_SIZE
|
|
||||||
jl memset
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* CONFIG_INIT_STACKS */
|
#endif /* CONFIG_INIT_STACKS */
|
||||||
|
|
||||||
mov sp, INIT_STACK
|
mov sp, INIT_STACK
|
||||||
|
|
|
@ -32,7 +32,6 @@ extern "C" {
|
||||||
|
|
||||||
#ifndef _ASMLANGUAGE
|
#ifndef _ASMLANGUAGE
|
||||||
|
|
||||||
extern void _firq_stack_setup(void);
|
|
||||||
extern K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE);
|
extern K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -56,7 +55,6 @@ static ALWAYS_INLINE void _irq_setup(void)
|
||||||
|
|
||||||
_kernel.irq_stack =
|
_kernel.irq_stack =
|
||||||
K_THREAD_STACK_BUFFER(_interrupt_stack) + CONFIG_ISR_STACK_SIZE;
|
K_THREAD_STACK_BUFFER(_interrupt_stack) + CONFIG_ISR_STACK_SIZE;
|
||||||
_firq_stack_setup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _ASMLANGUAGE */
|
#endif /* _ASMLANGUAGE */
|
||||||
|
|
|
@ -13,9 +13,7 @@ config SOC
|
||||||
config NUM_IRQ_PRIO_LEVELS
|
config NUM_IRQ_PRIO_LEVELS
|
||||||
# This processor supports 4 priority levels:
|
# This processor supports 4 priority levels:
|
||||||
# 0 for Fast Interrupts (FIRQs) and 1-3 for Regular Interrupts (IRQs).
|
# 0 for Fast Interrupts (FIRQs) and 1-3 for Regular Interrupts (IRQs).
|
||||||
# TODO: But regular irq nesting is not implemented --
|
default 4
|
||||||
# so this must be 2 for now.
|
|
||||||
default 2
|
|
||||||
|
|
||||||
config NUM_IRQS
|
config NUM_IRQS
|
||||||
# must be > the highest interrupt number used
|
# must be > the highest interrupt number used
|
||||||
|
|
|
@ -13,9 +13,7 @@ config SOC
|
||||||
config NUM_IRQ_PRIO_LEVELS
|
config NUM_IRQ_PRIO_LEVELS
|
||||||
# This processor supports 4 priority levels:
|
# This processor supports 4 priority levels:
|
||||||
# 0 for Fast Interrupts (FIRQs) and 1-3 for Regular Interrupts (IRQs).
|
# 0 for Fast Interrupts (FIRQs) and 1-3 for Regular Interrupts (IRQs).
|
||||||
# TODO: But regular irq nesting is not implemented --
|
default 4
|
||||||
# so this must be 2 for now.
|
|
||||||
default 2
|
|
||||||
|
|
||||||
config NUM_IRQS
|
config NUM_IRQS
|
||||||
# must be > the highest interrupt number used
|
# must be > the highest interrupt number used
|
||||||
|
|
|
@ -13,9 +13,7 @@ config SOC
|
||||||
config NUM_IRQ_PRIO_LEVELS
|
config NUM_IRQ_PRIO_LEVELS
|
||||||
# This processor supports 4 priority levels:
|
# This processor supports 4 priority levels:
|
||||||
# 0 for Fast Interrupts (FIRQs) and 1-3 for Regular Interrupts (IRQs).
|
# 0 for Fast Interrupts (FIRQs) and 1-3 for Regular Interrupts (IRQs).
|
||||||
# TODO: But regular irq nesting is not implemented --
|
default 4
|
||||||
# so this must be 2 for now.
|
|
||||||
default 2
|
|
||||||
|
|
||||||
config NUM_IRQS
|
config NUM_IRQS
|
||||||
# must be > the highest interrupt number used
|
# must be > the highest interrupt number used
|
||||||
|
|
|
@ -29,7 +29,6 @@ extern void *_VectorTable;
|
||||||
#include <v2/irq.h>
|
#include <v2/irq.h>
|
||||||
|
|
||||||
static u32_t _arc_v2_irq_unit_device_power_state = DEVICE_PM_ACTIVE_STATE;
|
static u32_t _arc_v2_irq_unit_device_power_state = DEVICE_PM_ACTIVE_STATE;
|
||||||
u32_t _saved_firq_stack;
|
|
||||||
struct arc_v2_irq_unit_ctx {
|
struct arc_v2_irq_unit_ctx {
|
||||||
u32_t irq_ctrl; /* Interrupt Context Saving Control Register. */
|
u32_t irq_ctrl; /* Interrupt Context Saving Control Register. */
|
||||||
u32_t irq_vect_base; /* Interrupt Vector Base. */
|
u32_t irq_vect_base; /* Interrupt Vector Base. */
|
||||||
|
@ -97,8 +96,6 @@ unsigned int _arc_v2_irq_unit_trigger_get(int irq)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||||
extern void _firq_stack_suspend(void);
|
|
||||||
extern void _firq_stack_resume(void);
|
|
||||||
|
|
||||||
static int _arc_v2_irq_unit_suspend(struct device *dev)
|
static int _arc_v2_irq_unit_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@ -123,8 +120,6 @@ static int _arc_v2_irq_unit_suspend(struct device *dev)
|
||||||
ctx.irq_ctrl = _arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_CTRL);
|
ctx.irq_ctrl = _arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_CTRL);
|
||||||
ctx.irq_vect_base = _arc_v2_aux_reg_read(_ARC_V2_IRQ_VECT_BASE);
|
ctx.irq_vect_base = _arc_v2_aux_reg_read(_ARC_V2_IRQ_VECT_BASE);
|
||||||
|
|
||||||
_firq_stack_suspend();
|
|
||||||
|
|
||||||
_arc_v2_irq_unit_device_power_state = DEVICE_PM_SUSPEND_STATE;
|
_arc_v2_irq_unit_device_power_state = DEVICE_PM_SUSPEND_STATE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -137,8 +132,6 @@ static int _arc_v2_irq_unit_resume(struct device *dev)
|
||||||
|
|
||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
_firq_stack_resume();
|
|
||||||
|
|
||||||
/* Interrupts from 0 to 15 are exceptions and they are ignored
|
/* Interrupts from 0 to 15 are exceptions and they are ignored
|
||||||
* by IRQ auxiliary registers. For that reason we skip those
|
* by IRQ auxiliary registers. For that reason we skip those
|
||||||
* values in this loop.
|
* values in this loop.
|
||||||
|
|
|
@ -124,9 +124,6 @@ extern void idle(void *unused1, void *unused2, void *unused3);
|
||||||
#if defined(CONFIG_INIT_STACKS) && defined(CONFIG_PRINTK)
|
#if defined(CONFIG_INIT_STACKS) && defined(CONFIG_PRINTK)
|
||||||
extern K_THREAD_STACK_DEFINE(sys_work_q_stack,
|
extern K_THREAD_STACK_DEFINE(sys_work_q_stack,
|
||||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE);
|
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE);
|
||||||
#if defined(CONFIG_ARC) && CONFIG_RGF_NUM_BANKS != 1
|
|
||||||
extern K_THREAD_STACK_DEFINE(_firq_stack, CONFIG_FIRQ_STACK_SIZE);
|
|
||||||
#endif /* CONFIG_ARC */
|
|
||||||
|
|
||||||
|
|
||||||
void k_call_stacks_analyze(void)
|
void k_call_stacks_analyze(void)
|
||||||
|
@ -134,9 +131,6 @@ void k_call_stacks_analyze(void)
|
||||||
printk("Kernel stacks:\n");
|
printk("Kernel stacks:\n");
|
||||||
STACK_ANALYZE("main ", _main_stack);
|
STACK_ANALYZE("main ", _main_stack);
|
||||||
STACK_ANALYZE("idle ", _idle_stack);
|
STACK_ANALYZE("idle ", _idle_stack);
|
||||||
#if defined(CONFIG_ARC) && CONFIG_RGF_NUM_BANKS != 1
|
|
||||||
STACK_ANALYZE("firq ", _firq_stack);
|
|
||||||
#endif /* CONFIG_ARC */
|
|
||||||
STACK_ANALYZE("interrupt", _interrupt_stack);
|
STACK_ANALYZE("interrupt", _interrupt_stack);
|
||||||
STACK_ANALYZE("workqueue", sys_work_q_stack);
|
STACK_ANALYZE("workqueue", sys_work_q_stack);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,11 @@ void trigger_irq(int irq)
|
||||||
: "=r" (mip)
|
: "=r" (mip)
|
||||||
: "r" (1 << irq));
|
: "r" (1 << irq));
|
||||||
}
|
}
|
||||||
|
#elif defined(CONFIG_CPU_ARCV2)
|
||||||
|
void trigger_irq(int irq)
|
||||||
|
{
|
||||||
|
_arc_v2_aux_reg_write(_ARC_V2_AUX_IRQ_HINT, irq);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
/* So far, Nios II does not support this */
|
/* So far, Nios II does not support this */
|
||||||
#define NO_TRIGGER_FROM_SW
|
#define NO_TRIGGER_FROM_SW
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue