From be839733ed4f80ee56fec63944dfb49f25c8a531 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 22 Mar 2024 12:11:28 +0800 Subject: [PATCH] fix(interrupt): fixed exit critical section on P4/C5 When adjusting the interrupt level treshold on P4/C6 during a critical section exit it would take a few cycles before this is taken into account by the CPU. This meant that under some circumstances, e.g. 02, we could do yield()->vPortExitCritical()->vPortEnterCritical() without getting rescheduled. This causes issues for freertos as it assumes the task will not continue into the vPortEnterCritical before the scheduler has schedulded it again. This meant that e.g. xTaskNotifyWait would yield, but then immeditaly continue as if it was already notified. --- components/riscv/include/riscv/rv_utils.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 9928e57134..722489b765 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -232,6 +232,16 @@ FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_restore_intlevel_ * a single write to the mintthresh register without further manipulations needed. * This is done to quicken up exit for critical sections */ REG_WRITE(CLIC_INT_THRESH_REG, restoreval); + + /** + * After writing the threshold register, the new threshold is not directly taken into account by the CPU. + * By executing ~8 nop instructions, or by performing a memory load right now, the previous memory write + * operations is forced, making the new threshold active. + * + * Without this we risk executing the next several instrucitons before getting interrupted + * This is especially bad if we immediatly enter a new critical section + */ + REG_READ(CLIC_INT_THRESH_REG); } /* Direct register write version of rv_utils_set_intlevel(). Used to speed up critical sections. */