diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h index b026bf49b9..dfe2f7161d 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h @@ -645,13 +645,18 @@ FORCE_INLINE_ATTR bool xPortCanYield(void) { uint32_t threshold = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG); #if SOC_INT_CLIC_SUPPORTED + /* When CLIC is supported: + * - The lowest interrupt threshold level is 0. Therefore, an interrupt threshold level above 0 would mean that we + * are in a critical section. + * - Since CLIC enables HW interrupt nesting, we do not have the updated interrupt level in the + * INTERRUPT_CURRENT_CORE_INT_THRESH_REG register when nested interrupts occur. To know the current interrupt + * level, we read the machine-mode interrupt level (mil) field from the mintstatus CSR. A non-zero value indicates + * that we are in an interrupt context. + */ + uint32_t intr_level = rv_utils_get_interrupt_level(); threshold = threshold >> (CLIC_CPU_INT_THRESH_S + (8 - NLBITS)); - /* When CLIC is supported, the lowest interrupt threshold level is 0. - * Therefore, an interrupt threshold level above 0 would mean that we - * are either in a critical section or in an ISR. - */ - return (threshold == 0); + return ((intr_level == 0) && (threshold == 0)); #endif /* SOC_INT_CLIC_SUPPORTED */ /* when enter critical code, FreeRTOS will mask threshold to RVHAL_EXCM_LEVEL * and exit critical code, will recover threshold value (1). so threshold <= 1 diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index cb3fed9cd2..cd16ac457d 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -113,6 +113,20 @@ FORCE_INLINE_ATTR void rv_utils_set_mtvec(uint32_t mtvec_val) RV_WRITE_CSR(mtvec, mtvec_val); } +#if SOC_INT_CLIC_SUPPORTED + FORCE_INLINE_ATTR __attribute__((pure)) uint32_t rv_utils_get_interrupt_level(void) +{ +#if CONFIG_IDF_TARGET_ESP32P4 + // As per CLIC specs, mintstatus CSR should be at 0xFB1, however esp32p4 implements it at 0x346 + #define MINTSTATUS 0x346 +#else + #error "rv_utils_get_mintstatus() is not implemented. Check for correct mintstatus register address." +#endif /* CONFIG_IDF_TARGET_ESP32P4 */ + uint32_t mintstatus = RV_READ_CSR(MINTSTATUS); + return ((mintstatus >> 24) & 0xFF); // Return the mintstatus[31:24] bits to get the mil field +} +#endif /* SOC_INT_CLIC_SUPPORTED */ + // ------------------ Interrupt Control -------------------- FORCE_INLINE_ATTR void rv_utils_intr_enable(uint32_t intr_mask)