From 44c917e6b2e8d1c5f7f615bf7d3e1669f3b2e4f0 Mon Sep 17 00:00:00 2001 From: Wayne Ren Date: Wed, 14 Aug 2019 00:45:13 +0800 Subject: [PATCH] arch: arc: fix the bug that interrupt stack is not switched For the old codes, if nest interrupts come out after _isr_wrapper and before _check_nest_int_by_irq_act, then multi-bits in irq_act will be set, this will result irq stack will not be switched in correctly As a fix, it's still need to use nest interrupt counter to do interrupt stack switch as before The difference is in the past exc_nest_count is used, but here _kernel.nested/_kernel.cpus[cpu_id].nested is used. Signed-off-by: Wayne Ren --- arch/arc/core/fast_irq.S | 4 +++- arch/arc/core/fault_s.S | 8 ++++--- arch/arc/core/regular_irq.S | 5 ++++- arch/arc/include/swap_macros.h | 39 ++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/arch/arc/core/fast_irq.S b/arch/arc/core/fast_irq.S index eee3c0014be..748b157e21b 100644 --- a/arch/arc/core/fast_irq.S +++ b/arch/arc/core/fast_irq.S @@ -76,7 +76,8 @@ SECTION_FUNC(TEXT, _firq_enter) lr r25, [_ARC_V2_LP_END] #endif - _check_nest_int_by_irq_act r0, r1 + /* check whether irq stack is used */ + _check_and_inc_int_nest_counter r0, r1 bne.d firq_nest mov r0, sp @@ -138,6 +139,7 @@ SECTION_FUNC(TEXT, _firq_exit) sr r24, [_ARC_V2_LP_START] sr r25, [_ARC_V2_LP_END] #endif + _dec_int_nest_counter r0, r1 _check_nest_int_by_irq_act r0, r1 diff --git a/arch/arc/core/fault_s.S b/arch/arc/core/fault_s.S index aedfdf9e07b..667108e53d2 100644 --- a/arch/arc/core/fault_s.S +++ b/arch/arc/core/fault_s.S @@ -246,9 +246,9 @@ _do_non_syscall_trap: st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ - lr r0, [_ARC_V2_AUX_IRQ_ACT] - and r0, r0, 0xffff - cmp r0, 0 + /* check whether irq stack is used */ + _check_and_inc_int_nest_counter r0, r1 + bne.d exc_nest_handle mov r0, sp @@ -260,6 +260,8 @@ exc_nest_handle: pop sp + _dec_int_nest_counter r0, r1 + lr r0, [_ARC_V2_AUX_IRQ_ACT] and r0, r0, 0xffff cmp r0, 0 diff --git a/arch/arc/core/regular_irq.S b/arch/arc/core/regular_irq.S index f56fd4595fe..d2f95501f1c 100644 --- a/arch/arc/core/regular_irq.S +++ b/arch/arc/core/regular_irq.S @@ -67,7 +67,8 @@ SECTION_FUNC(TEXT, _rirq_enter) #endif clri - _check_nest_int_by_irq_act r0, r1 + /* check whether irq stack is used */ + _check_and_inc_int_nest_counter r0, r1 bne.d rirq_nest mov r0, sp @@ -92,6 +93,8 @@ SECTION_FUNC(TEXT, _rirq_exit) pop sp + _dec_int_nest_counter r0, r1 + _check_nest_int_by_irq_act r0, r1 jne _rirq_no_reschedule diff --git a/arch/arc/include/swap_macros.h b/arch/arc/include/swap_macros.h index a13114787a2..09c9b6c7c4a 100644 --- a/arch/arc/include/swap_macros.h +++ b/arch/arc/include/swap_macros.h @@ -294,6 +294,45 @@ #endif /* CONFIG_ARC_SECURE_FIRMWARE */ .endm +/* check and increase the interrupt nest counter + * after increase, check whether nest counter == 1 + * the result will be EQ bit of status32 + */ +.macro _check_and_inc_int_nest_counter reg1 reg2 +#ifdef CONFIG_SMP + _get_cpu_id \reg1 + ld.as \reg1, [@_curr_cpu, \reg1] + ld \reg2, [\reg1, ___cpu_t_nested_OFFSET] +#else + mov \reg1, _kernel + ld \reg2, [\reg1, ___kernel_t_nested_OFFSET] +#endif + add \reg2, \reg2, 1 +#ifdef CONFIG_SMP + st \reg2, [\reg1, ___cpu_t_nested_OFFSET] +#else + st \reg2, [\reg1, ___kernel_t_nested_OFFSET] +#endif + cmp \reg2, 1 +.endm + +/* decrease interrupt nest counter */ +.macro _dec_int_nest_counter reg1 reg2 +#ifdef CONFIG_SMP + _get_cpu_id \reg1 + ld.as \reg1, [@_curr_cpu, \reg1] + ld \reg2, [\reg1, ___cpu_t_nested_OFFSET] +#else + mov \reg1, _kernel + ld \reg2, [\reg1, ___kernel_t_nested_OFFSET] +#endif + sub \reg2, \reg2, 1 +#ifdef CONFIG_SMP + st \reg2, [\reg1, ___cpu_t_nested_OFFSET] +#else + st \reg2, [\reg1, ___kernel_t_nested_OFFSET] +#endif +.endm /* If multi bits in IRQ_ACT are set, i.e. last bit != fist bit, it's * in nest interrupt. The result will be EQ bit of status32