Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 360155
b: refs/heads/master
c: 4788a59
h: refs/heads/master
i:
  360153: d2c1475
  360151: 2b6bcbf
v: v3
  • Loading branch information
Vineet Gupta committed Feb 15, 2013
1 parent bec6e80 commit 4e4c72d
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 769bc1fd7b8591a312d4c5c8834bc6510272938e
refs/heads/master: 4788a5942bc896803c87005be8c6dd14c373a2d3
19 changes: 19 additions & 0 deletions trunk/arch/arc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,25 @@ config ARC_PAGE_SIZE_4K

endchoice

config ARC_COMPACT_IRQ_LEVELS
bool "ARCompact IRQ Priorities: High(2)/Low(1)"
default n
# Timer HAS to be high priority, for any other high priority config
select ARC_IRQ3_LV2

if ARC_COMPACT_IRQ_LEVELS

config ARC_IRQ3_LV2
bool

config ARC_IRQ5_LV2
bool

config ARC_IRQ6_LV2
bool

endif

config ARC_FPU_SAVE_RESTORE
bool "Enable FPU state persistence across context switch"
default n
Expand Down
95 changes: 95 additions & 0 deletions trunk/arch/arc/include/asm/entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Vineetg: March 2009 (Supporting 2 levels of Interrupts)
* Stack switching code can no longer reliably rely on the fact that
* if we are NOT in user mode, stack is switched to kernel mode.
* e.g. L2 IRQ interrupted a L1 ISR which had not yet completed
* it's prologue including stack switching from user mode
*
* 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,
Expand Down Expand Up @@ -268,6 +274,33 @@
* assume SP is kernel mode SP. _NO_ need to do any stack switching
*/

#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
/* However....
* If Level 2 Interrupts enabled, we may end up with a corner case:
* 1. User Task executing
* 2. L1 IRQ taken, ISR starts (CPU auto-switched to KERNEL mode)
* 3. But before it could switch SP from USER to KERNEL stack
* a L2 IRQ "Interrupts" L1
* Thay way although L2 IRQ happened in Kernel mode, stack is still
* not switched.
* To handle this, we may need to switch stack even if in kernel mode
* provided SP has values in range of USER mode stack ( < 0x7000_0000 )
*/
brlo sp, VMALLOC_START, 88f

/* TODO: vineetg:
* We need to be a bit more cautious here. What if a kernel bug in
* L1 ISR, caused SP to go whaco (some small value which looks like
* USER stk) and then we take L2 ISR.
* Above brlo alone would treat it as a valid L1-L2 sceanrio
* instead of shouting alound
* The only feasible way is to make sure this L2 happened in
* L1 prelogue ONLY i.e. ilink2 is less than a pre-set marker in
* L1 ISR before it switches stack
*/

#endif

/* Save Pre Intr/Exception KERNEL MODE SP on kernel stack
* safe-keeping not really needed, but it keeps the epilogue code
* (SP restore) simpler/uniform.
Expand Down Expand Up @@ -503,6 +536,42 @@
sub sp, sp, 4
.endm

.macro SAVE_ALL_INT2

/* TODO-vineetg: SMP we can't use global nor can we use
* SCRATCH0 as we do for int1 because while int1 is using
* it, int2 can come
*/
/* retsore original r9 , saved in sys_saved_r9 */
ld r9, [@int2_saved_reg]

/* now we are ready to save the remaining context :) */
st orig_r8_IS_IRQ2, [sp, 8] /* Event Type */
st 0, [sp, 4] /* orig_r0 , N/A for IRQ */
SAVE_CALLER_SAVED
st.a r26, [sp, -4] /* gp */
st.a fp, [sp, -4]
st.a blink, [sp, -4]
st.a ilink2, [sp, -4]
lr r9, [status32_l2]
st.a r9, [sp, -4]
st.a lp_count, [sp, -4]
lr r9, [lp_end]
st.a r9, [sp, -4]
lr r9, [lp_start]
st.a r9, [sp, -4]
lr r9, [bta_l2]
st.a r9, [sp, -4]

#ifdef PT_REGS_CANARY
mov r9, 0xdeadbee2
st r9, [sp, -4]
#endif

/* move up by 1 word to "create" pt_regs->"stack_place_holder" */
sub sp, sp, 4
.endm

/*--------------------------------------------------------------
* Restore all registers used by interrupt handlers.
*
Expand Down Expand Up @@ -537,6 +606,32 @@
/* orig_r0 and orig_r8 skipped automatically */
.endm

.macro RESTORE_ALL_INT2
add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */

ld.ab r9, [sp, 4]
sr r9, [bta_l2]
ld.ab r9, [sp, 4]
sr r9, [lp_start]
ld.ab r9, [sp, 4]
sr r9, [lp_end]
ld.ab r9, [sp, 4]
mov lp_count, r9
ld.ab r9, [sp, 4]
sr r9, [status32_l2]
ld.ab r9, [sp, 4]
mov ilink2, r9
ld.ab blink, [sp, 4]
ld.ab fp, [sp, 4]
ld.ab r26, [sp, 4] /* gp */
RESTORE_CALLER_SAVED

ld sp, [sp] /* restore original sp */
/* orig_r0 and orig_r8 skipped automatically */

.endm


/* Get CPU-ID of this core */
.macro GET_CPU_ID reg
lr \reg, [identity]
Expand Down
6 changes: 5 additions & 1 deletion trunk/arch/arc/include/asm/irqflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ static inline long arch_local_save_flags(void)
*/
static inline int arch_irqs_disabled_flags(unsigned long flags)
{
return !(flags & (STATUS_E1_MASK));
return !(flags & (STATUS_E1_MASK
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
| STATUS_E2_MASK
#endif
));
}

static inline int arch_irqs_disabled(void)
Expand Down
117 changes: 117 additions & 0 deletions trunk/arch/arc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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
; ---------------------------------------------
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 4e4c72d

Please sign in to comment.