diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 646fa7686e..53502faacd 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -476,38 +476,20 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) UBaseType_t xPortSetInterruptMaskFromISR(void) { - UBaseType_t prev_int_level = 0; - + UBaseType_t prev_int_level = 0, int_level = 0; #if !SOC_INT_CLIC_SUPPORTED - unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE); - prev_int_level = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG); - REG_WRITE(INTERRUPT_CURRENT_CORE_INT_THRESH_REG, RVHAL_EXCM_LEVEL); - RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); + int_level = RVHAL_EXCM_LEVEL; #else - /* When CLIC is supported, all interrupt priority levels less than or equal to the threshold level are masked. */ - prev_int_level = rv_utils_set_intlevel_regval(RVHAL_EXCM_LEVEL_CLIC); -#endif /* !SOC_INIT_CLIC_SUPPORTED */ - /** - * In theory, this function should not return immediately as there is a - * delay between the moment we mask the interrupt threshold register and - * the moment a potential lower-priority interrupt is triggered (as said - * above), it should have a delay of 2 machine cycles/instructions. - * - * However, in practice, this function has an epilogue of one instruction, - * thus the instruction masking the interrupt threshold register is - * followed by two instructions: `ret` and `csrrs` (RV_SET_CSR). - * That's why we don't need any additional nop instructions here. - */ + int_level = RVHAL_EXCM_LEVEL_CLIC; +#endif + + prev_int_level = rv_utils_set_intlevel_regval(int_level); return prev_int_level; } void vPortClearInterruptMaskFromISR(UBaseType_t prev_int_level) { -#if !SOC_INT_CLIC_SUPPORTED - REG_WRITE(INTERRUPT_CURRENT_CORE_INT_THRESH_REG, prev_int_level); -#else rv_utils_restore_intlevel_regval(prev_int_level); -#endif /* SOC_INIT_CLIC_SUPPORTED */ /** * The delay between the moment we unmask the interrupt threshold register * and the moment the potential requested interrupt is triggered is not diff --git a/components/riscv/include/esp_private/interrupt_intc.h b/components/riscv/include/esp_private/interrupt_intc.h index dc8f47b590..262a60285c 100644 --- a/components/riscv/include/esp_private/interrupt_intc.h +++ b/components/riscv/include/esp_private/interrupt_intc.h @@ -11,6 +11,7 @@ #include "esp_attr.h" #include "soc/interrupt_reg.h" #include "soc/soc_caps.h" +#include "riscv/csr.h" #if !SOC_INT_CLIC_SUPPORTED && !SOC_INT_PLIC_SUPPORTED @@ -63,6 +64,33 @@ FORCE_INLINE_ATTR void rv_utils_intr_edge_ack(uint32_t intr_num) REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr_num); } +/** + * @brief Restore the CPU interrupt level to the value returned by `rv_utils_set_intlevel_regval`. + * + * @param restoreval Former raw interrupt level, it is NOT necessarily a value between 0 and 7, this is hardware and configuration dependent. + */ +FORCE_INLINE_ATTR void rv_utils_restore_intlevel_regval(uint32_t restoreval) +{ + REG_WRITE(INTERRUPT_CURRENT_CORE_INT_THRESH_REG, restoreval); +} + +/** + * @brief Set the interrupt threshold to `intlevel` while getting the current level. + * + * @param intlevel New raw interrupt level, it is NOT necessarily a value between 0 and 7, this is hardware and configuration dependent. + * + * @return Current raw interrupt level, can be restored by calling `rv_utils_restore_intlevel_regval`. + */ +FORCE_INLINE_ATTR uint32_t rv_utils_set_intlevel_regval(uint32_t intlevel) +{ + uint32_t old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE); + uint32_t old_thresh = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG); + rv_utils_restore_intlevel_regval(intlevel); + RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); + + return old_thresh; +} + #ifdef __cplusplus } diff --git a/components/riscv/include/esp_private/interrupt_plic.h b/components/riscv/include/esp_private/interrupt_plic.h index a6f1e302a8..4d1fbba34e 100644 --- a/components/riscv/include/esp_private/interrupt_plic.h +++ b/components/riscv/include/esp_private/interrupt_plic.h @@ -11,6 +11,7 @@ #include "esp_attr.h" #include "soc/interrupt_reg.h" #include "soc/soc_caps.h" +#include "riscv/csr.h" #if SOC_INT_PLIC_SUPPORTED @@ -64,6 +65,33 @@ FORCE_INLINE_ATTR void rv_utils_intr_edge_ack(uint32_t intr_num) REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr_num); } +/** + * @brief Restore the CPU interrupt level to the value returned by `rv_utils_set_intlevel_regval`. + * + * @param restoreval Former raw interrupt level, it is NOT necessarily a value between 0 and 7, this is hardware and configuration dependent. + */ +FORCE_INLINE_ATTR void rv_utils_restore_intlevel_regval(uint32_t restoreval) +{ + REG_WRITE(INTERRUPT_CURRENT_CORE_INT_THRESH_REG, restoreval); +} + +/** + * @brief Set the interrupt threshold to `intlevel` while getting the current level. + * + * @param intlevel New raw interrupt level, it is NOT necessarily a value between 0 and 7, this is hardware and configuration dependent. + * + * @return Current raw interrupt level, can be restored by calling `rv_utils_restore_intlevel_regval`. + */ +FORCE_INLINE_ATTR uint32_t rv_utils_set_intlevel_regval(uint32_t intlevel) +{ + uint32_t old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE); + uint32_t old_thresh = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG); + rv_utils_restore_intlevel_regval(intlevel); + RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); + + return old_thresh; +} + #ifdef __cplusplus }