Skip to content

Commit 0bc169e

Browse files
committed
fix(freertos): optimize HWLP context switch by disabling it when unused
1 parent c26879d commit 0bc169e

File tree

3 files changed

+36
-28
lines changed

3 files changed

+36
-28
lines changed

components/freertos/FreeRTOS-Kernel/portable/riscv/port.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* SPDX-License-Identifier: MIT
88
*
9-
* SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD
9+
* SPDX-FileContributor: 2023-2025 Espressif Systems (Shanghai) CO LTD
1010
*
1111
* Permission is hereby granted, free of charge, to any person obtaining a copy of
1212
* this software and associated documentation files (the "Software"), to deal in
@@ -297,15 +297,19 @@ static void vPortCleanUpCoprocArea(void *pvTCB)
297297
const UBaseType_t bottomstack = (UBaseType_t) task->pxDummy8;
298298
RvCoprocSaveArea* sa = pxRetrieveCoprocSaveAreaFromStackPointer(bottomstack);
299299

300-
/* If the Task used any coprocessor, check if it is the actual owner of any.
301-
* If yes, reset the owner. */
302-
if (sa->sa_enable != 0) {
300+
/* If the Task ever saved the original stack pointer, restore it before returning */
301+
if (sa->sa_allocator != 0) {
303302
/* Restore the original lowest address of the stack in the TCB */
304303
task->pxDummy6 = sa->sa_tcbstack;
305304

306305
/* Get the core the task is pinned on */
307306
#if ( configNUM_CORES > 1 )
308307
const BaseType_t coreID = task->xDummyCoreID;
308+
/* If the task is not pinned on any core, it didn't use any coprocessor than need to be freed (FPU or PIE).
309+
* If it used the HWLP coprocessor, it has nothing to clear since there is no "owner" for it. */
310+
if (coreID == tskNO_AFFINITY) {
311+
return;
312+
}
309313
#else /* configNUM_CORES > 1 */
310314
const BaseType_t coreID = 0;
311315
#endif /* configNUM_CORES > 1 */

components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -205,27 +205,28 @@ hwlp_restore_if_used:
205205
li a2, HWLP_COPROC_IDX
206206
call pxPortGetCoprocArea
207207
/* Get the enable flags from the coprocessor save area */
208-
lw a1, RV_COPROC_ENABLE(a0)
209-
/* To avoid having branches below, set the coprocessor enable flag now */
210-
andi a2, a1, 1 << HWLP_COPROC_IDX
211-
beqz a2, _hwlp_restore_end
208+
lw a2, RV_COPROC_ENABLE(a0)
209+
andi a1, a2, 1 << HWLP_COPROC_IDX
210+
beqz a1, _hwlp_restore_end
212211
/* Enable bit was set, restore the coprocessor context */
213-
lw a0, RV_COPROC_SA+HWLP_COPROC_IDX*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[HWLP_COPROC_IDX] */
214-
/* This will set the dirty flag for sure */
215-
hwlp_restore_regs a0
212+
lw a3, RV_COPROC_SA+HWLP_COPROC_IDX*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[HWLP_COPROC_IDX] */
213+
/* This will set the dirty flag for sure, a2 is preserved */
214+
hwlp_restore_regs a3
216215
#if SOC_CPU_HAS_HWLOOP_STATE_BUG && ESP32P4_REV_MIN_FULL <= 1
217216
/* The hardware doesn't update the HWLP state properly after executing the last instruction,
218217
* as such, we must manually put the state of the HWLP to dirty now if any counter is not 0 */
219-
csrr a0, CSR_LOOP0_COUNT
220-
bnez a0, _hwlp_restore_end
221-
csrr a0, CSR_LOOP1_COUNT
222-
bnez a0, _hwlp_restore_end
223-
/* The counters are 0, cleaning the state */
218+
csrr a3, CSR_LOOP0_COUNT
219+
bnez a3, _hwlp_restore_end
220+
csrr a3, CSR_LOOP1_COUNT
221+
bnez a3, _hwlp_restore_end
222+
/* The counters are 0, mark the HWLP coprocessor as disabled in the enable flag and clean the state */
223+
xori a2, a2, 1 << HWLP_COPROC_IDX
224+
sw a2, RV_COPROC_ENABLE(a0)
224225
#endif /* SOC_CPU_HAS_HWLOOP_STATE_BUG && ESP32P4_REV_MIN_FULL <= 1 */
225226
csrwi CSR_HWLP_STATE_REG, HWLP_CLEAN_STATE
226227
_hwlp_restore_end:
227-
lw ra, (sp)
228-
addi sp, sp, 16
228+
lw ra, (sp)
229+
addi sp, sp, 16
229230
ret
230231

231232
#endif /* SOC_CPU_HAS_HWLOOP */

components/riscv/vectors.S

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,23 +236,26 @@ _panic_handler:
236236
la ra, _return_from_exception
237237
/* EXT_ILL CSR should contain the reason for the Illegal Instruction */
238238
csrrw a0, EXT_ILL_CSR, zero
239-
#if SOC_CPU_HAS_HWLOOP
240-
/* Check if the HWLP bit is set. */
241-
andi a1, a0, EXT_ILL_RSN_HWLP
242-
beqz a1, hwlp_not_used
243-
/* HWLP used in an ISR, abort */
244-
mv a0, sp
245-
j vPortCoprocUsedInISR
246-
hwlp_not_used:
247-
#endif /* SOC_CPU_HAS_HWLOOP */
248239

249-
/* Hardware loop cannot be treated lazily, so we should never end here if a HWLP instruction is used */
250240
#if SOC_CPU_HAS_PIE
251241
/* Check if the PIE bit is set. */
252242
andi a1, a0, EXT_ILL_RSN_PIE
253243
bnez a1, rtos_save_pie_coproc
254244
#endif /* SOC_CPU_HAS_PIE */
255245

246+
/* We cannot check the HWLP bit in a0 since a hardware bug may set this bit even though no HWLP
247+
* instruction was executed in the program at all, so check mtval (`t0`) */
248+
#if SOC_CPU_HAS_HWLOOP
249+
/* HWLP instructions all have an opcode of 0b0101011 */
250+
andi a1, t0, 0b1111111
251+
addi a1, a1, -0b0101011
252+
bnez a1, hwlp_not_used
253+
/* HWLP used in an ISR, abort */
254+
mv a0, sp
255+
j vPortCoprocUsedInISR
256+
hwlp_not_used:
257+
#endif /* SOC_CPU_HAS_HWLOOP */
258+
256259
#if SOC_CPU_HAS_FPU
257260
/* Check if the FPU bit is set. When targets have the FPU reason bug (SOC_CPU_HAS_FPU_EXT_ILL_BUG),
258261
* it is possible that another bit is set even if the reason is an FPU instruction.

0 commit comments

Comments
 (0)