ARC: Support for high priority interrupts in the in-core intc
There is a bit of hack/kludge right now where we disable preemption if a L2 (High prio) IRQ is taken while L1 (Low prio) is active. Need to revisit this Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cette révision appartient à :
@@ -31,6 +31,8 @@
|
||||
* exception. Thus FAKE RTIE needed in low level Priv-Violation handler.
|
||||
* Instr Error could also cause similar scenario, so same there as well.
|
||||
*
|
||||
* Vineetg: March 2009 (Supporting 2 levels of Interrupts)
|
||||
*
|
||||
* Vineetg: Aug 28th 2008: Bug #94984
|
||||
* -Zero Overhead Loop Context shd be cleared when entering IRQ/EXcp/Trap
|
||||
* Normally CPU does this automatically, however when doing FAKE rtie,
|
||||
@@ -96,13 +98,25 @@ VECTOR mem_service ; 0x8, Mem exception (0x1)
|
||||
VECTOR instr_service ; 0x10, Instrn Error (0x2)
|
||||
|
||||
; ******************** Device ISRs **********************
|
||||
#ifdef CONFIG_ARC_IRQ3_LV2
|
||||
VECTOR handle_interrupt_level2
|
||||
#else
|
||||
VECTOR handle_interrupt_level1
|
||||
#endif
|
||||
|
||||
VECTOR handle_interrupt_level1
|
||||
|
||||
#ifdef CONFIG_ARC_IRQ5_LV2
|
||||
VECTOR handle_interrupt_level2
|
||||
#else
|
||||
VECTOR handle_interrupt_level1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARC_IRQ6_LV2
|
||||
VECTOR handle_interrupt_level2
|
||||
#else
|
||||
VECTOR handle_interrupt_level1
|
||||
#endif
|
||||
|
||||
.rept 25
|
||||
VECTOR handle_interrupt_level1 ; Other devices
|
||||
@@ -139,6 +153,17 @@ VECTOR reserved ; Reserved Exceptions
|
||||
int1_saved_reg:
|
||||
.zero 4
|
||||
|
||||
/* Each Interrupt level needs it's own scratch */
|
||||
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
|
||||
|
||||
.section .data ; NOT .global
|
||||
.type int2_saved_reg, @object
|
||||
.size int2_saved_reg, 4
|
||||
int2_saved_reg:
|
||||
.zero 4
|
||||
|
||||
#endif
|
||||
|
||||
; ---------------------------------------------
|
||||
.section .text, "ax",@progbits
|
||||
|
||||
@@ -152,6 +177,55 @@ reserved: ; processor restart
|
||||
|
||||
;##################### Interrupt Handling ##############################
|
||||
|
||||
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
|
||||
; ---------------------------------------------
|
||||
; Level 2 ISR: Can interrupt a Level 1 ISR
|
||||
; ---------------------------------------------
|
||||
ARC_ENTRY handle_interrupt_level2
|
||||
|
||||
; TODO-vineetg for SMP this wont work
|
||||
; free up r9 as scratchpad
|
||||
st r9, [@int2_saved_reg]
|
||||
|
||||
;Which mode (user/kernel) was the system in when intr occured
|
||||
lr r9, [status32_l2]
|
||||
|
||||
SWITCH_TO_KERNEL_STK
|
||||
SAVE_ALL_INT2
|
||||
|
||||
;------------------------------------------------------
|
||||
; if L2 IRQ interrupted a L1 ISR, disable preemption
|
||||
;------------------------------------------------------
|
||||
|
||||
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]
|
||||
add r9, r9, 1
|
||||
st r9, [r10, THREAD_INFO_PREEMPT_COUNT]
|
||||
|
||||
1:
|
||||
;------------------------------------------------------
|
||||
; setup params for Linux common ISR and invoke it
|
||||
;------------------------------------------------------
|
||||
lr r0, [icause2]
|
||||
and r0, r0, 0x1f
|
||||
|
||||
bl.d @arch_do_IRQ
|
||||
mov r1, sp
|
||||
|
||||
mov r8,0x2
|
||||
sr r8, [AUX_IRQ_LV12] ; clear bit in Sticky Status Reg
|
||||
|
||||
b ret_from_exception
|
||||
|
||||
ARC_EXIT handle_interrupt_level2
|
||||
|
||||
#endif
|
||||
|
||||
; ---------------------------------------------
|
||||
; Level 1 ISR
|
||||
; ---------------------------------------------
|
||||
@@ -619,6 +693,49 @@ restore_regs :
|
||||
|
||||
not_exception:
|
||||
|
||||
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
|
||||
|
||||
bbit0 r10, STATUS_A2_BIT, not_level2_interrupt
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; if L2 IRQ interrupted a L1 ISR, we'd disbaled preemption earlier
|
||||
; so that sched doesnt move to new task, causing L1 to be delayed
|
||||
; undeterministically. Now that we've achieved that, lets reset
|
||||
; things to what they were, before returning from L2 context
|
||||
;----------------------------------------------------------------
|
||||
|
||||
ld r9, [sp, PT_orig_r8] ; get orig_r8 to make sure it is
|
||||
brne r9, orig_r8_IS_IRQ2, 149f ; infact a L2 ISR ret path
|
||||
|
||||
ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs)
|
||||
bbit0 r9, STATUS_A1_BIT, 149f ; L1 not active when L2 IRQ, so normal
|
||||
|
||||
; A1 is set in status32_l2
|
||||
; decrement thread_info->preempt_count (re-enable preemption)
|
||||
GET_CURR_THR_INFO_FROM_SP r10
|
||||
ld r9, [r10, THREAD_INFO_PREEMPT_COUNT]
|
||||
|
||||
; paranoid check, given A1 was active when A2 happened, preempt count
|
||||
; must not be 0 beccause we would have incremented it.
|
||||
; If this does happen we simply HALT as it means a BUG !!!
|
||||
cmp r9, 0
|
||||
bnz 2f
|
||||
flag 1
|
||||
|
||||
2:
|
||||
sub r9, r9, 1
|
||||
st r9, [r10, THREAD_INFO_PREEMPT_COUNT]
|
||||
|
||||
149:
|
||||
;return from level 2
|
||||
RESTORE_ALL_INT2
|
||||
debug_marker_l2:
|
||||
rtie
|
||||
|
||||
not_level2_interrupt:
|
||||
|
||||
#endif
|
||||
|
||||
bbit0 r10, STATUS_A1_BIT, not_level1_interrupt
|
||||
|
||||
;return from level 1
|
||||
|
Référencer dans un nouveau ticket
Bloquer un utilisateur