Xtensa: More interrupt-related logic

This commit is contained in:
Gregory Nutt
2016-10-20 14:28:14 -06:00
parent 9e1600b7d3
commit ed8377af72
2 changed files with 111 additions and 105 deletions
+2 -2
View File
@@ -205,9 +205,9 @@ _xtensa_context_save:
l32i a12, sp, (4 * REG_A12) /* Recover original a9,12,13 */
l32i a13, sp, (4 * REG_A13)
l32i a9, sp, (4 * REG_A9)
addi sp, sp, (4 * REG_FRMSZ) /* Restore the interruptee's SP */
addi sp, sp, (4 * XCPTCONTEXT_SIZE) /* Restore the interruptee's SP */
call0 xthal_window_spill_nw /* Preserves only a4,5,8,9,12,13 */
addi sp, sp, -(4 * REG_FRMSZ)
addi sp, sp, -(4 * XCPTCONTEXT_SIZE)
l32i a12, sp, (4 * REG_TMP0) /* Recover stuff from stack frame */
l32i a13, sp, (4 * REG_TMP1)
l32i a9, sp, (4 * REG_TMP2)
+109 -103
View File
@@ -78,10 +78,10 @@
.macro extract_msb aout ain
1:
addi \aout, \ain, -1 /* aout = ain - 1 */
and \ain, \ain, \aout /* ain = ain & aout */
bnez \ain, 1b /* repeat until ain == 0 */
addi \aout, \aout, 1 /* return aout + 1 */
addi \aout, \ain, -1 /* aout = ain - 1 */
and \ain, \ain, \aout /* ain = ain & aout */
bnez \ain, 1b /* Repeat until ain == 0 */
addi \aout, \aout, 1 /* Return aout + 1 */
.endm
/* Macro dispatch_c_isr - dispatch interrupts to user ISRs.
@@ -148,7 +148,6 @@
2:
#endif
/* Now look up in the dispatch table and call user ISR if any. */
/* If multiple bits are set then MSB has highest priority. */
extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */
@@ -179,23 +178,28 @@
wsr a4, INTCLEAR /* Clear sw or edge-triggered interrupt */
beq a3, a4, 7f /* If timer interrupt then skip table */
find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */
/* Call xtensa_int_decode with, passing that address of the register save
* area as a parameter (A2).
*/
movi a4, _xt_interrupt_table
addx8 a3, a3, a4 /* a3 = address of interrupt table entry */
l32i a4, a3, XIE_HANDLER /* a4 = handler address */
mov a2, sp /* Argument: Top of stack = register save area */
call0 xtensa_int_decode /* Call xtensa_int_decode */
#ifdef CONFIG_XTENSA_CALL0_ABI
mov a12, a6 /* Save in callee-saved reg */
l32i a2, a3, XIE_ARG /* a2 = handler arg */
callx0 a4 /* call handler */
mov a2, a12
#else
mov a2, a6 /* Save in windowed reg */
l32i a6, a3, XIE_ARG /* a6 = handler arg */
callx4 a4 /* Call handler */
#endif
/* On return from xtensa_int_decode, A2 will contain the address of the new
* register save area. Usually this would be the same as the current SP.
* But in the event of a context switch, A2 will instead refer to the TCB
* register save area.
*/
beq a2, sp, 3f /* If timer interrupt then skip table */
/* Switch stacks */
#warning REVIST: Should use register save are on stack.
l32i a4, sp, (4 * REG_A1) /* Retrieve stack ptr and replace */
addi sp, a4, -(4 * XCPTCONTEXT_SIZE)
3:
#ifdef CONFIG_XTENSA_USE_SWPRI
j 8f
#else
@@ -212,7 +216,7 @@
*/
#ifdef CONFIG_XTENSA_CALL0_ABI
mov a12, a6
mov a12, a6
call0 XT_RTOS_TIMER_INT
mov a2, a12
#else
@@ -236,8 +240,8 @@
movi a3, _xt_intdata
l32i a4, a3, 0 /* a4 = _xt_intenable */
s32i a2, a3, 4 /* update _xt_vpri_mask */
and a4, a4, a2 /* a4 = masked intenable */
wsr a4, INTENABLE /* update INTENABLE */
and a4, a4, a2 /* a4 = masked intenable */
wsr a4, INTENABLE /* update INTENABLE */
#endif
9:
@@ -277,17 +281,17 @@
#if XTENSA_EXCM_LEVEL >= 2
.section .iram1,"ax"
.type _xtensa_level2_handler,@function
.align 4
.type _xtensa_level2_handler,@function
.align 4
_xtensa_level2_handler:
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * REG_FRMSZ) /* Allocate interrupt stack frame */
mov a0, sp /* sp == a1 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_2 /* Save interruptee's PS */
rsr a0, EPS_2 /* Save interruptee's PS */
s32i a0, sp, (4 * REG_PS)
rsr a0, EPC_2 /* Save interruptee's PC */
rsr a0, EPC_2 /* Save interruptee's PC */
s32i a0, sp, (4 * REG_PC)
rsr a0, EXCSAVE_2 /* Save interruptee's a0 */
rsr a0, EXCSAVE_2 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0)
/* Save rest of interrupt context and enter RTOS. */
@@ -301,69 +305,71 @@ _xtensa_level2_handler:
#else
movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE
#endif
wsr a0, PS
wsr a0, PS
rsync
/* Decode and dispatch the interrupt. In the event of an interrupt
* level context xtensa_int_decode() will return a pointer to the new
* register state in A2.
* level context dispatch_c_isr() will switch stacks to the new task's
* context save area.
*/
dispatch_c_isr 2 XTENSA_INTLEVEL2_MASK
dispatch_c_isr 2 XTENSA_INTLEVEL2_MASK
/* Restore registers in preparation to return from interrupt */
call0 _xtensa_int_exit /* does not return directly here */
call0 _xtensa_int_exit
/* Restore only level-specific regs (the rest were already restored) */
l32i a0, sp, (4 * REG_PS) /* retrieve interruptee's PS */
wsr a0, EPS_2
wsr a0, EPS_2
l32i a0, sp, (4 * REG_PC) /* retrieve interruptee's PC */
wsr a0, EPC_2
wsr a0, EPC_2
l32i a0, sp, (4 * REG_A0) /* retrieve interruptee's A0 */
l32i sp, sp, (4 * REG_A1) /* remove interrupt stack frame */
rsync /* Ensure EPS and EPC written */
rsync /* Ensure EPS and EPC written */
/* Return from interrupt. RFI restores the PS from EPS_2 and jumps to
* the address in EPC_2.
*/
rfi 2
rfi 2
#endif /* XTENSA_EXCM_LEVEL >= 2 */
/*******************************************************************************
HIGH PRIORITY (LEVEL > XTENSA_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS
High priority interrupts are by definition those with priorities greater
than XTENSA_EXCM_LEVEL. This includes non-maskable (NMI). High priority
interrupts cannot interact with the RTOS, that is they must save all regs
they use and not call any RTOS function.
A further restriction imposed by the Xtensa windowed architecture is that
high priority interrupts must not modify the stack area even logically
"above" the top of the interrupted stack (they need to provide their
own stack or static save area).
Cadence Design Systems recommends high priority interrupt handlers be coded in assembly
and used for purposes requiring very short service times.
Here are templates for high priority (level 2+) interrupt vectors.
They assume only one interrupt per level to avoid the burden of identifying
which interrupts at this level are pending and enabled. This allows for
minimum latency and avoids having to save/restore a2 in addition to a0.
If more than one interrupt per high priority level is configured, this burden
is on the handler which in any case must provide a way to save and restore
registers it uses without touching the interrupted stack.
Each vector goes at a predetermined location according to the Xtensa
hardware configuration, which is ensured by its placement in a special
section known to the Xtensa linker support package (LSP). It performs
the minimum necessary before jumping to the handler in the .text section.
*******************************************************************************/
/****************************************************************************
*
* HIGH PRIORITY (LEVEL > XTENSA_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS
*
* High priority interrupts are by definition those with priorities greater
* than XTENSA_EXCM_LEVEL. This includes non-maskable (NMI). High priority
* interrupts cannot interact with the RTOS, that is they must save all regs
* they use and not call any RTOS function.
*
* A further restriction imposed by the Xtensa windowed architecture is that
* high priority interrupts must not modify the stack area even logically
* "above" the top of the interrupted stack (they need to provide their
* own stack or static save area).
*
* Cadence Design Systems recommends high priority interrupt handlers be
* coded in assembly and used for purposes requiring very short service
* times.
*
* Here are templates for high priority (level 2+) interrupt vectors.
* They assume only one interrupt per level to avoid the burden of
* identifying which interrupts at this level are pending and enabled. This
* allows for minimum latency and avoids having to save/restore a2 in
* addition to a0. If more than one interrupt per high priority level is
* configured, this burden is on the handler which in any case must provide
* a way to save and restore registers it uses without touching the
* interrupted stack.
*
* Each vector goes at a predetermined location according to the Xtensa
* hardware configuration, which is ensured by its placement in a special
* section known to the Xtensa linker support package (LSP). It performs
* the minimum necessary before jumping to the handler in the .text section.
*
****************************************************************************/
/*
Currently only shells for high priority interrupt handlers are provided
@@ -372,7 +378,7 @@ documentation: "Microprocessor Programmer's Guide".
*/
#if XTENSA_INT_NLEVELS >=2 && XTENSA_EXCM_LEVEL < 2 && XTENSA_DEBUGLEVEL !=2
.section .iram1,"ax"
.section .iram1,"ax"
.type _xtensa_level2_handler, @function
.align 4
_xtensa_level2_handler:
@@ -384,24 +390,24 @@ _xtensa_level2_handler:
l32i a0, a0, 2<<2
beqz a0, 1f
.Ln_xtensa_level2_handler_call_hook:
callx0 a0 /* must NOT disturb stack! */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
*/
* ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xtensa_level2_handler_exit:
rsr a0, EXCSAVE_2 /* restore a0 */
rfi 2
rsr a0, EXCSAVE_2 /* Restore a0 */
rfi 2
#endif /* XTENSA_INT_NLEVELS >=2 && XTENSA_EXCM_LEVEL < 2 && XTENSA_DEBUGLEVEL !=2 */
#if XTENSA_INT_NLEVELS >=3 && XTENSA_EXCM_LEVEL < 3 && XTENSA_DEBUGLEVEL !=3
.section .iram1,"ax"
.type _xtensa_level3_handler,@function
.section .iram1,"ax"
.type _xtensa_level3_handler, @function
.align 4
_xtensa_level3_handler:
@@ -412,23 +418,23 @@ _xtensa_level3_handler:
l32i a0, a0, 3<<2
beqz a0, 1f
.Ln_xtensa_level3_handler_call_hook:
callx0 a0 /* must NOT disturb stack! */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
*/
* ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xtensa_level3_handler_exit:
rsr a0, EXCSAVE_3 /* restore a0 */
rfi 3
rsr a0, EXCSAVE_3 /* Restore a0 */
rfi 3
#endif /* XTENSA_INT_NLEVELS >=3 && XTENSA_EXCM_LEVEL < 3 && XTENSA_DEBUGLEVEL !=3 */
#if XTENSA_INT_NLEVELS >=4 && XTENSA_EXCM_LEVEL < 4 && XTENSA_DEBUGLEVEL !=4
.section .iram1,"ax"
.section .iram1,"ax"
.type _xtensa_level4_handler,@function
.align 4
_xtensa_level4_handler:
@@ -437,26 +443,26 @@ _xtensa_level4_handler:
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 4<<2
l32i a0, a0, 4 << 2
beqz a0, 1f
.Ln_xtensa_level4_handler_call_hook:
callx0 a0 /* must NOT disturb stack! */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
*/
* ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xtensa_level4_handler_exit:
rsr a0, EXCSAVE_4 /* restore a0 */
rfi 4
rsr a0, EXCSAVE_4 /* Restore a0 */
rfi 4
#endif /* XTENSA_INT_NLEVELS >=4 && XTENSA_EXCM_LEVEL < 4 && XTENSA_DEBUGLEVEL !=4 */
#if XTENSA_INT_NLEVELS >=5 && XTENSA_EXCM_LEVEL < 5 && XTENSA_DEBUGLEVEL !=5
.section .iram1,"ax"
.section .iram1,"ax"
.type _xtensa_level5_handler,@function
.align 4
_xtensa_level5_handler:
@@ -465,26 +471,26 @@ _xtensa_level5_handler:
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 5<<2
l32i a0, a0, 5 << 2
beqz a0, 1f
.Ln_xtensa_level5_handler_call_hook:
callx0 a0 /* must NOT disturb stack! */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE.
*/
* ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xtensa_level5_handler_exit:
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
rsr a0, EXCSAVE_5 /* restore a0 */
rfi 5
#endif /* XTENSA_INT_NLEVELS >=5 && XTENSA_EXCM_LEVEL < 5 && XTENSA_DEBUGLEVEL !=5 */
#if XTENSA_INT_NLEVELS >=6 && XTENSA_EXCM_LEVEL < 6 && XTENSA_DEBUGLEVEL !=6
.section .iram1,"ax"
.section .iram1,"ax"
.type _xtensa_level6_handler, @function
.align 4
_xtensa_level6_handler:
@@ -493,20 +499,20 @@ _xtensa_level6_handler:
/* Call interrupt hook if present to (pre)handle interrupts. */
movi a0, _xt_intexc_hooks
l32i a0, a0, 6<<2
l32i a0, a0, 6 << 2
beqz a0, 1f
.Ln_xtensa_level6_handler_call_hook:
callx0 a0 /* must NOT disturb stack! */
callx0 a0 /* Must NOT disturb stack! */
1:
#endif
/* USER_EDIT:
ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
*/
* ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
*/
.align 4
.L_xtensa_level6_handler_exit:
rsr a0, EXCSAVE_6 /* restore a0 */
rfi 6
rsr a0, EXCSAVE_6 /* Restore a0 */
rfi 6
#endif /* XTENSA_INT_NLEVELS >=6 && XTENSA_EXCM_LEVEL < 6 && XTENSA_DEBUGLEVEL !=6 */