summaryrefslogtreecommitdiffstats
path: root/arch/xtensa/kernel/entry.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/xtensa/kernel/entry.S')
-rw-r--r--arch/xtensa/kernel/entry.S69
1 files changed, 56 insertions, 13 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 3777fec85e7c..63845f950792 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -7,7 +7,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2004-2007 by Tensilica Inc.
+ * Copyright (C) 2004 - 2008 by Tensilica Inc.
*
* Chris Zankel <chris@zankel.net>
*
@@ -130,6 +130,11 @@ _user_exception:
s32i a3, a1, PT_SAR
s32i a2, a1, PT_ICOUNTLEVEL
+#if XCHAL_HAVE_THREADPTR
+ rur a2, threadptr
+ s32i a2, a1, PT_THREADPTR
+#endif
+
/* Rotate ws so that the current windowbase is at bit0. */
/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */
@@ -349,15 +354,16 @@ common_exception:
* so we can allow exceptions and interrupts (*) again.
* Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
*
- * (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before
- * (interrupts disabled) and if this exception is not an interrupt.
+ * (*) We only allow interrupts of higher priority than current IRQ
*/
rsr a3, ps
addi a0, a0, -4
movi a2, 1
- extui a3, a3, 0, 1 # a3 = PS.INTLEVEL[0]
- moveqz a3, a2, a0 # a3 = 1 iff interrupt exception
+ extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
+ # a3 = PS.INTLEVEL
+ movnez a2, a3, a3 # a2 = 1: level-1, > 1: high priority
+ moveqz a3, a2, a0 # a3 = IRQ level iff interrupt
movi a2, 1 << PS_WOE_BIT
or a3, a3, a2
rsr a0, exccause
@@ -398,7 +404,7 @@ common_exception:
callx4 a4
/* Jump here for exception exit */
-
+ .global common_exception_return
common_exception_return:
/* Jump if we are returning from kernel exceptions. */
@@ -509,6 +515,11 @@ user_exception_exit:
* (if we have restored WSBITS-1 frames).
*/
+#if XCHAL_HAVE_THREADPTR
+ l32i a3, a1, PT_THREADPTR
+ wur a3, threadptr
+#endif
+
2: j common_exception_exit
/* This is the kernel exception exit.
@@ -641,19 +652,51 @@ common_exception_exit:
l32i a0, a1, PT_DEPC
l32i a3, a1, PT_AREG3
+ _bltui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+ wsr a0, depc
l32i a2, a1, PT_AREG2
- _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+ l32i a0, a1, PT_AREG0
+ l32i a1, a1, PT_AREG1
+ rfde
+1:
/* Restore a0...a3 and return */
+ rsr a0, ps
+ extui a2, a0, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
+ movi a0, 2f
+ slli a2, a2, 4
+ add a0, a2, a0
+ l32i a2, a1, PT_AREG2
+ jx a0
+
+ .macro irq_exit_level level
+ .align 16
+ .if XCHAL_EXCM_LEVEL >= \level
+ l32i a0, a1, PT_PC
+ wsr a0, epc\level
l32i a0, a1, PT_AREG0
l32i a1, a1, PT_AREG1
- rfe
+ rfi \level
+ .endif
+ .endm
-1: wsr a0, depc
+ .align 16
+2:
l32i a0, a1, PT_AREG0
l32i a1, a1, PT_AREG1
- rfde
+ rfe
+
+ .align 16
+ /* no rfi for level-1 irq, handled by rfe above*/
+ nop
+
+ irq_exit_level 2
+ irq_exit_level 3
+ irq_exit_level 4
+ irq_exit_level 5
+ irq_exit_level 6
ENDPROC(kernel_exception)
@@ -753,7 +796,7 @@ ENTRY(unrecoverable_exception)
wsr a1, windowbase
rsync
- movi a1, (1 << PS_WOE_BIT) | 1
+ movi a1, (1 << PS_WOE_BIT) | LOCKLEVEL
wsr a1, ps
rsync
@@ -1474,7 +1517,7 @@ ENTRY(_spill_registers)
l32i a1, a3, EXC_TABLE_KSTK
wsr a3, excsave1
- movi a4, (1 << PS_WOE_BIT) | 1
+ movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL
wsr a4, ps
rsync
@@ -1922,7 +1965,7 @@ ENTRY(_switch_to)
s32i a6, a3, EXC_TABLE_FIXUP
s32i a7, a3, EXC_TABLE_KSTK
- /* restore context of the task that 'next' addresses */
+ /* restore context of the task 'next' */
l32i a0, a13, THREAD_RA # restore return address
l32i a1, a13, THREAD_SP # restore stack pointer