summaryrefslogtreecommitdiff
path: root/arch/arc/kernel/entry-compact.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc/kernel/entry-compact.S')
-rw-r--r--arch/arc/kernel/entry-compact.S43
1 files changed, 23 insertions, 20 deletions
diff --git a/arch/arc/kernel/entry-compact.S b/arch/arc/kernel/entry-compact.S
index 15d457b4403a..59f52035b4ea 100644
--- a/arch/arc/kernel/entry-compact.S
+++ b/arch/arc/kernel/entry-compact.S
@@ -86,7 +86,7 @@
*/
; ********* Critical System Events **********************
-VECTOR res_service ; 0x0, Restart Vector (0x0)
+VECTOR res_service ; 0x0, Reset Vector (0x0)
VECTOR mem_service ; 0x8, Mem exception (0x1)
VECTOR instr_service ; 0x10, Instrn Error (0x2)
@@ -155,13 +155,9 @@ int2_saved_reg:
; ---------------------------------------------
.section .text, "ax",@progbits
-res_service: ; processor restart
- flag 0x1 ; not implemented
- nop
- nop
-reserved: ; processor restart
- rtie ; jump to processor initializations
+reserved:
+ flag 1 ; Unexpected event, halt
;##################### Interrupt Handling ##############################
@@ -175,12 +171,25 @@ ENTRY(handle_interrupt_level2)
;------------------------------------------------------
; if L2 IRQ interrupted a L1 ISR, disable preemption
+ ;
+ ; This is to avoid a potential L1-L2-L1 scenario
+ ; -L1 IRQ taken
+ ; -L2 interrupts L1 (before L1 ISR could run)
+ ; -preemption off IRQ, user task in syscall picked to run
+ ; -RTIE to userspace
+ ; Returns from L2 context fine
+ ; But both L1 and L2 re-enabled, so another L1 can be taken
+ ; while prev L1 is still unserviced
+ ;
;------------------------------------------------------
+ ; L2 interrupting L1 implies both L2 and L1 active
+ ; However both A2 and A1 are NOT set in STATUS32, thus
+ ; need to check STATUS32_L2 to determine if L1 was active
+
ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs)
bbit0 r9, STATUS_A1_BIT, 1f ; L1 not active when L2 IRQ, so normal
- ; A1 is set in status32_l2
; bump thread_info->preempt_count (Disable preemption)
GET_CURR_THR_INFO_FROM_SP r10
ld r9, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -320,11 +329,10 @@ END(call_do_page_fault)
; Note that we use realtime STATUS32 (not pt_regs->status32) to
; decide that.
- ; if Returning from Exception
- btst r10, STATUS_AE_BIT
- bnz .Lexcep_ret
+ and.f 0, r10, (STATUS_A1_MASK|STATUS_A2_MASK)
+ bz .Lexcep_or_pure_K_ret
- ; Not Exception so maybe Interrupts (Level 1 or 2)
+ ; Returning from Interrupts (Level 1 or 2)
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
@@ -365,8 +373,7 @@ END(call_do_page_fault)
st r9, [r10, THREAD_INFO_PREEMPT_COUNT]
149:
- ;return from level 2
- INTERRUPT_EPILOGUE 2
+ INTERRUPT_EPILOGUE 2 ; return from level 2 interrupt
debug_marker_l2:
rtie
@@ -374,15 +381,11 @@ not_level2_interrupt:
#endif
- bbit0 r10, STATUS_A1_BIT, .Lpure_k_mode_ret
-
- ;return from level 1
- INTERRUPT_EPILOGUE 1
+ INTERRUPT_EPILOGUE 1 ; return from level 1 interrupt
debug_marker_l1:
rtie
-.Lexcep_ret:
-.Lpure_k_mode_ret:
+.Lexcep_or_pure_K_ret:
;this case is for syscalls or Exceptions or pure kernel mode