From 19acb3bc1778df407847071197b2d4da7a7a298f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 12 Jan 2021 10:31:27 +0100 Subject: nios2: Optimize ISR dispatch variant Use _Thread_Do_dispatch() in _Nios2_ISR_Dispatch_with_shadow_non_preemptive(). --- cpukit/score/cpu/nios2/nios2-eic-il-low-level.S | 102 ++++++++++++++---------- 1 file changed, 60 insertions(+), 42 deletions(-) (limited to 'cpukit/score/cpu') diff --git a/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S b/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S index c215d4bd94..1632fbb8c2 100644 --- a/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S +++ b/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S @@ -55,16 +55,16 @@ _Nios2_ISR_Dispatch_with_shadow_non_preemptive: ldw r4, 8(et) /* Increment and store thread dispatch disable level */ - addi r9, r16, 1 - stw r9, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp) + addi r17, r16, 1 + stw r17, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp) /* Call high level handler with argument */ callr r8 - /* Load thread dispatch necessary */ + /* Load the thread dispatch necessary indicator */ ldb r12, %gprel(_Per_CPU_Information + PER_CPU_DISPATCH_NEEDED)(gp) - /* Load thread dispatch after ISR disable indicator */ + /* Load the thread dispatch after ISR disable indicator */ ldw r13, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp) /* Read status */ @@ -74,31 +74,36 @@ _Nios2_ISR_Dispatch_with_shadow_non_preemptive: subi ea, ea, 4 /* - * Restore the thread dispatch disable level. We must do this before - * we return to the normal register set, because otherwise we have - * problems if someone deletes or restarts the interrupted thread while - * we are in the thread dispatch helper. + * If the current thread dispatch disable level (r17) is one, then + * negate the thread dispatch necessary indicator, otherwise the value + * is irrelevant. Or it with the previous thread dispatch disable + * level value (r16). The r15 which will be used as a status to + * determine if a thread dispatch is necessary and allowed. */ - stw r16, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp) - - /* Is thread dispatch allowed? */ - bne r16, zero, no_thread_dispatch + xor r12, r17, r12 + or r15, r12, r16 - /* Is thread dispatch necessary? */ - beq r12, zero, no_thread_dispatch + /* + * Get the previous register set from r14. If it is zero, then this is + * the outermost interrupt. Or it to the thread dispatch status (r15). + */ + andhi r12, r14, 0x3f + or r15, r12, r15 - /* Is outermost interrupt? */ - andhi r14, r14, 0x3f - bne r14, zero, no_thread_dispatch + /* + * Or the thread dispatch after ISR disable indicator (r13) to the + * thread dispatch status (r15). + */ + or r15, r13, r15 - /* Is thread dispatch after ISR allowed? */ - bne r13, zero, no_thread_dispatch + /* Is a thread dispatch necessary and allowed? */ + bne r15, zero, no_thread_dispatch /* Obtain stack frame in normal register set */ rdprs r15, sp, -FRAME_SIZE /* Disable thread dispatch after ISR */ - stw r12, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp) + stw r17, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp) /* Save context */ stw sstatus, FRAME_OFFSET_STATUS(r15) @@ -111,12 +116,15 @@ _Nios2_ISR_Dispatch_with_shadow_non_preemptive: /* Update stack pointer in normal register set */ wrprs sp, r15 + /* Jump to thread dispatch helper */ + eret + no_thread_dispatch: - /* - * Return to thread dispatch helper, interrupted thread or interrupted - * lower level interrupt service routine. - */ + /* Restore the thread dispatch disable level */ + stw r16, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp) + + /* Return to interrupted context */ eret thread_dispatch_helper: @@ -141,9 +149,26 @@ thread_dispatch_helper: stw r14, FRAME_OFFSET_R14(sp) stw r15, FRAME_OFFSET_R15(sp) + /* + * Disable interrupts (1). + * + * We have the following invariants: + * 1. status.RSIE == 0: thread context initialization + * 2. status.CRS == 0: thread context initialization + * 3. status.PRS: arbitrary + * 4. status.IL < interrupt disable IL: else we would not be here + * 5. status.IH == 0: thread context initialization + * 6. status.U == 0: thread context initialization + * 7. status.PIE == 1: thread context initialization + * Thus we can use a constant to disable interrupts. + */ + movi r5, %lo(_Nios2_ISR_Status_interrupts_disabled) + wrctl status, r5 + do_thread_dispatch: - call _Thread_Dispatch + addi r4, gp, %gprel(_Per_CPU_Information) + call _Thread_Do_dispatch /* Restore some volatile registers */ ldw ra, FRAME_OFFSET_RA(sp) @@ -160,19 +185,7 @@ do_thread_dispatch: ldw r11, FRAME_OFFSET_R11(sp) ldw r12, FRAME_OFFSET_R12(sp) - /* - * Disable interrupts. - * - * We have the following invariants: - * 1. status.RSIE == 0: thread context initialization - * 2. status.CRS == 0: thread context initialization - * 3. status.PRS: arbitrary - * 4. status.IL < interrupt disable IL: else we would not be here - * 5. status.IH == 0: thread context initialization - * 6. status.U == 0: thread context initialization - * 7. status.PIE == 1: thread context initialization - * Thus we can use a constant to disable interrupts. - */ + /* Disable interrupts, see (1) */ rdctl r14, status movi r15, %lo(_Nios2_ISR_Status_interrupts_disabled) wrctl status, r15 @@ -181,7 +194,7 @@ do_thread_dispatch: ldb r13, %gprel(_Per_CPU_Information + PER_CPU_DISPATCH_NEEDED)(gp) /* Is thread dispatch necessary? */ - bne r13, zero, enable_interrupts_before_thread_dispatch + bne r13, zero, prepare_thread_dispatch /* Enable thread dispatch after ISR */ stw zero, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp) @@ -204,9 +217,14 @@ do_thread_dispatch: /* Return to interrupted thread */ eret -enable_interrupts_before_thread_dispatch: +prepare_thread_dispatch: + + /* Disable thread dispatching */ + movi r4, 1 + stw r4, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp) + stw r4, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp) - /* Restore status */ - wrctl status, r14 + /* Set interrupt level argument for _Thread_Do_dispatch() */ + mov r5, r15 br do_thread_dispatch -- cgit v1.2.3