From cf55ab899a2978b1ba4430da18853fe638adc328 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 22 Sep 2023 16:25:56 +0200 Subject: [PATCH] fix(freertos): Fixed xPortCanYield to correctly determine ISR context on esp32p4 This commit fixes an issue where xPortCanYield() function may not be able to detect an ISR context when HW interrupt nesting is active on a CLIC interrupt controller such as on esp32p4. --- .../portable/riscv/include/freertos/portmacro.h | 15 ++++++++++----- components/riscv/include/riscv/rv_utils.h | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) 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)