Skip to content

Commit 89e0d89

Browse files
committed
OS/ThreadX: fix threadx smp scheduler flow and core control handling
- always process thread time slice in SysTick_Handler - clear tx_thread_smp_core_control before first thread restore in gcc/iar context.S - update PortThreadSwitch to synchronize tx_thread_smp_core_control state transitions - add missing memory barriers in scheduler return path - fix _tx_thread_smp_protect_count reset in _tx_thread_smp_force_unprotect - fix _tx_thread_interrupt_control and enable TSP on boot hart Signed-off-by: Huaqi Fang <578567190@qq.com>
1 parent e8c0c89 commit 89e0d89

4 files changed

Lines changed: 74 additions & 22 deletions

File tree

OS/ThreadX/ports_smp/nuclei/gcc/context.S

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@
99

1010
#define portCONTEXT_SIZE ( portRegNum * REGBYTES )
1111

12+
#if __riscv_xlen == 64
13+
#define CALL_FRAME_SIZE 32
14+
#else
15+
#define CALL_FRAME_SIZE 16
16+
#endif
17+
1218
.extern _tx_thread_current_ptr
1319
.extern _tx_thread_execute_ptr
20+
.extern _tx_clear_thread_smp_core_control
1421

1522

1623
.section .text
@@ -77,13 +84,23 @@ _tx_thread_schedule_ready:
7784
la a1, _tx_thread_current_ptr /* _tx_thread_current_ptr = _tx_thread_execute_ptr */
7885
#endif
7986
STORE a0, 0(a1)
87+
addi sp, sp, -CALL_FRAME_SIZE
88+
STORE ra, 0 * REGBYTES(sp)
89+
STORE a0, 1 * REGBYTES(sp)
90+
STORE a1, 2 * REGBYTES(sp)
91+
jal _tx_clear_thread_smp_core_control
92+
LOAD ra, 0 * REGBYTES(sp)
93+
LOAD a0, 1 * REGBYTES(sp)
94+
LOAD a1, 2 * REGBYTES(sp)
95+
addi sp, sp, CALL_FRAME_SIZE
96+
8097
/* Increment the run count for this thread. */
8198
/* _tx_thread_current_ptr[coreid] -> tx_thread_run_count++; */
8299
LOAD t0, 1 * REGBYTES(a0)
83100
addi t0, t0, 1
84101
STORE t0, 1 * REGBYTES(a0)
85102

86-
LOAD sp, 2 * REGBYTES(a0) /* Read sp from _tx_thread_execute_ptr[coreid] -> tx_thread_stack_ptr */
103+
LOAD sp, 2 * REGBYTES(a0) /* Read sp from _tx_thread_execute_ptr[coreid] -> tx_thread_stack_ptr */
87104
/* Pop PC from stack and set MEPC */
88105
LOAD t0, 0 * REGBYTES(sp)
89106
csrw CSR_MEPC, t0

OS/ThreadX/ports_smp/nuclei/iar/context.S

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@
99

1010
#define portCONTEXT_SIZE ( portRegNum * REGBYTES )
1111

12+
#if __riscv_xlen == 64
13+
#define CALL_FRAME_SIZE 32
14+
#else
15+
#define CALL_FRAME_SIZE 16
16+
#endif
17+
1218
EXTERN _tx_thread_current_ptr
1319
EXTERN _tx_thread_execute_ptr
20+
EXTERN _tx_clear_thread_smp_core_control
1421
EXTERN CSTACK$$Limit
1522
EXTERN PortThreadSwitch
1623
PUBLIC _tx_thread_schedule, eclic_msip_handler
@@ -79,6 +86,15 @@ _tx_thread_schedule_ready:
7986
la a1, _tx_thread_current_ptr /* _tx_thread_current_ptr = _tx_thread_execute_ptr */
8087
#endif
8188
STORE a0, 0(a1)
89+
addi sp, sp, -CALL_FRAME_SIZE
90+
STORE ra, 0 * REGBYTES(sp)
91+
STORE a0, 1 * REGBYTES(sp)
92+
STORE a1, 2 * REGBYTES(sp)
93+
jal _tx_clear_thread_smp_core_control
94+
LOAD ra, 0 * REGBYTES(sp)
95+
LOAD a0, 1 * REGBYTES(sp)
96+
LOAD a1, 2 * REGBYTES(sp)
97+
addi sp, sp, CALL_FRAME_SIZE
8298

8399
/* Increment the run count for this thread. */
84100
/* _tx_thread_current_ptr[coreid] -> tx_thread_run_count++; */

OS/ThreadX/ports_smp/nuclei/port.c

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "core_feature_base.h"
12
#define TX_SOURCE_CODE
23
#define TX_THREAD_SMP_SOURCE_CODE
34

@@ -49,29 +50,32 @@ void SysTick_Handler(void)
4950

5051
/* See if anything has expired. */
5152
if (_tx_timer_expired) {
52-
/* Did a timer expire? */
53-
if (_tx_timer_expired) {
54-
/* Process timer expiration. */
55-
_tx_timer_expiration_process();
56-
}
57-
/* Did time slice expire? */
58-
if (_tx_timer_expired_time_slice) {
59-
/* Time slice interrupted thread. */
60-
_tx_thread_time_slice();
61-
}
53+
/* Process timer expiration. */
54+
_tx_timer_expiration_process();
6255
}
63-
/* Increment the system active counter. */
64-
_tx_timer_interrupt_active ++;
56+
/* Call time-slice processing to process time-slice for all threads on each core. */
57+
_tx_thread_time_slice();
58+
/* Decrease the system active counter. */
59+
_tx_timer_interrupt_active --;
6560
/* Release the protection. */
6661
_tx_thread_smp_unprotect(saved_posture);
6762
}
6863

64+
void _tx_clear_thread_smp_core_control(TX_THREAD *thread_ptr)
65+
{
66+
if (thread_ptr != TX_NULL) {
67+
thread_ptr->tx_thread_smp_core_control = 0;
68+
__RWMB();
69+
}
70+
}
71+
6972
// Task Switch code called in eclic_msip_handler
7073
void PortThreadSwitch(void)
7174
{
7275
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
7376
_tx_execution_thread_exit();
7477
#endif
78+
TX_THREAD *rdy_thread;
7579
UINT coreid = _tx_thread_smp_core_get();
7680
/*
7781
* Magic idle task emulation for threadx
@@ -84,9 +88,15 @@ void PortThreadSwitch(void)
8488
_tx_thread_current_ptr[coreid] -> tx_thread_time_slice = _tx_timer_time_slice[coreid];
8589
_tx_timer_time_slice[coreid] = 0;
8690
}
87-
_tx_thread_current_ptr[coreid] = TX_NULL;
91+
if (_tx_thread_current_ptr[coreid]) {
92+
/* Current thread context is saved, ready for scheduling */
93+
_tx_thread_current_ptr[coreid] -> tx_thread_smp_core_control = 1;
94+
_tx_thread_current_ptr[coreid] = TX_NULL;
95+
__RWMB();
96+
}
8897

89-
if (!_tx_thread_execute_ptr[coreid]) {
98+
rdy_thread = _tx_thread_execute_ptr[coreid];
99+
if ((!rdy_thread) || (rdy_thread ->tx_thread_smp_core_control != 1)) {
90100
if (coreid == 0) {
91101
/* increase the timer interrupt to higher priority to enable interrupt nesting */
92102
ECLIC_SetLevelIRQ(SysTimer_IRQn, KERNEL_INTERRUPT_PRIORITY + 1);
@@ -100,11 +110,13 @@ void PortThreadSwitch(void)
100110
rv_csr_t msubm = __RV_CSR_READ(CSR_MSUBM);
101111
__enable_irq();
102112
__RWMB();
113+
rdy_thread = _tx_thread_execute_ptr[coreid];
103114
/* If no ready task just go to idle and wait for interrupt */
104-
while (!_tx_thread_execute_ptr[coreid]) {
115+
while ((!rdy_thread) || (rdy_thread ->tx_thread_smp_core_control != 1)) {
105116
// if wfi here, it may not wakeup even swi is pending, since new swi could happen during eclic_msip_handler
106117
__NOP();
107118
__RWMB();
119+
rdy_thread = _tx_thread_execute_ptr[coreid];
108120
}
109121
/* disable interrupt to avoid interrupt nesting since new task handle found */
110122
__disable_irq();
@@ -121,7 +133,9 @@ void PortThreadSwitch(void)
121133
}
122134
}
123135

124-
_tx_thread_current_ptr[coreid] = _tx_thread_execute_ptr[coreid];
136+
/* Clear the execution control flag. */
137+
rdy_thread -> tx_thread_smp_core_control = 0;
138+
_tx_thread_current_ptr[coreid] = rdy_thread;
125139
_tx_thread_current_ptr[coreid] -> tx_thread_run_count ++;
126140
/* Clear Software IRQ, A MUST */
127141
SysTimer_ClearSWIRQ();
@@ -159,7 +173,7 @@ VOID _tx_initialize_low_level(VOID)
159173
// _tx_initialize_unused_memory = s_threadx_heap;
160174
_tx_initialize_unused_memory = NULL;
161175
SetupSysTickInterrupt();
162-
_tx_thread_interrupt_control(0);
176+
_tx_thread_interrupt_control(TX_INT_DISABLE);
163177
}
164178

165179
UINT _tx_thread_interrupt_control(UINT new_posture)
@@ -168,9 +182,9 @@ UINT _tx_thread_interrupt_control(UINT new_posture)
168182

169183
if (new_posture == TX_INT_DISABLE) {
170184
// clear interrupt
171-
temp = __RV_CSR_READ_CLEAR(CSR_MSTATUS, MSTATUS_MIE);
185+
temp = __RV_CSR_READ_CLEAR(CSR_MSTATUS, MSTATUS_MIE) & MSTATUS_MIE;
172186
} else {
173-
temp = __RV_CSR_SWAP(CSR_MSTATUS, new_posture);
187+
temp = __RV_CSR_READ_SET(CSR_MSTATUS, MSTATUS_MIE) & MSTATUS_MIE;
174188
}
175189
__RWMB();
176190
return (UINT)temp;
@@ -185,7 +199,7 @@ void _tx_thread_smp_force_unprotect(UINT new_interrupt_posture)
185199
__RV_CSR_READ_CLEAR(CSR_MSTATUS, MSTATUS_MIE);
186200
core_id = _tx_thread_smp_core_get();
187201
if (_tx_thread_smp_protection.tx_thread_smp_protect_core == core_id) {
188-
_tx_thread_smp_protection.tx_thread_smp_protect_count == 0;
202+
_tx_thread_smp_protection.tx_thread_smp_protect_count = 0;
189203
if ((_tx_thread_smp_protection.tx_thread_smp_protect_count == 0) && (_tx_thread_preempt_disable == 0)) {
190204
_tx_thread_smp_protection.tx_thread_smp_protect_core = ((ULONG) 0xFFFFFFFFUL);
191205
__RWMB(); /* ensure prior stores visible */
@@ -202,6 +216,7 @@ extern volatile UINT _tx_thread_preempt_disable;
202216
void _tx_thread_system_return(void)
203217
{
204218
_tx_thread_preempt_disable = 0;
219+
__RWMB();
205220
_tx_thread_smp_force_unprotect(MSTATUS_MIE);
206221

207222
/* Set a software interrupt(SWI) request to request a context switch. */
@@ -329,7 +344,10 @@ ULONG _tx_thread_smp_time_get(void)
329344
/* core. */
330345
void _tx_thread_smp_low_level_initialize(UINT number_of_cores)
331346
{
332-
347+
// Enable interrupt and task sp swap
348+
#if defined(ECLIC_HW_CTX_AUTO) && defined(CFG_HAS_ECLICV2)
349+
__RV_CSR_SET(CSR_MECLIC_CTL, MECLIC_CTL_TSP_EN);
350+
#endif
333351
}
334352

335353
/* This function is the place where additional cores wait until */

doc/source/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ This is release version of ``0.9.0`` of Nuclei SDK.
135135
- Fix ThreadX ``tx_port.h`` interrupt disable/restore macros (``TX_DISABLE``/``TX_RESTORE``) by adding ``volatile`` keyword and ``memory`` clobber to inline assembly to prevent compiler reordering and ensure proper memory barrier semantics
136136
- Add memory barriers to ThreadX UP and SMP ports after interrupt control operations (such as ``__enable_irq()`` and ``CSR_MSTATUS`` access) to ensure proper synchronization and prevent potential compiler/CPU reordering issues
137137
- Fix ThreadX SMP port ``PortThreadSwitch`` function by adding memory barriers (``__RWMB()``) around ECLIC IRQ priority changes and stack pointer swaps to ensure proper ordering of memory operations on Nuclei 1000 series out-of-order processors, preventing potential race conditions in multi-core task switching
138+
- Fix ThreadX SMP scheduler flow by always processing time-slice updates in ``SysTick_Handler``, clearing/checking ``tx_thread_smp_core_control`` during first-thread restore and ``PortThreadSwitch``, adding missing memory barriers in the return path, and correcting the ``_tx_thread_smp_protect_count`` reset bug
138139

139140
* Build System
140141

0 commit comments

Comments
 (0)