Skip to content

Commit

Permalink
Merge branch 'fix/freertos_optimize_critical_sections' into 'master'
Browse files Browse the repository at this point in the history
fix(riscv): Updated RISC-V functions to set interrupt threshold for CLIC targets

Closes IDFCI-2033, IDFCI-2034, IDF-8090, and IDF-8117

See merge request espressif/esp-idf!29055
  • Loading branch information
sudeep-mohanty committed Mar 1, 2024
2 parents c5f81bb + 459ff83 commit e4f167d
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 8 deletions.
12 changes: 6 additions & 6 deletions components/esp_hw_support/include/spinlock.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -87,7 +87,7 @@ static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *l
core_owner_id = xt_utils_get_raw_core_id();
#else //__riscv

irq_status = rv_utils_mask_int_level_lower_than(RVHAL_EXCM_LEVEL);
irq_status = rv_utils_set_intlevel_regval(RVHAL_EXCM_LEVEL_CLIC);
core_owner_id = rv_utils_get_core_id() == 0 ? SPINLOCK_OWNER_ID_0 : SPINLOCK_OWNER_ID_1;
#endif
other_core_owner_id = CORE_ID_REGVAL_XOR_SWAP ^ core_owner_id;
Expand All @@ -106,7 +106,7 @@ static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *l
#if __XTENSA__
XTOS_RESTORE_INTLEVEL(irq_status);
#else
rv_utils_restore_intlevel(irq_status);
rv_utils_restore_intlevel_regval(irq_status);
#endif
return true;
}
Expand Down Expand Up @@ -147,7 +147,7 @@ static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *l
#if __XTENSA__
XTOS_RESTORE_INTLEVEL(irq_status);
#else
rv_utils_restore_intlevel(irq_status);
rv_utils_restore_intlevel_regval(irq_status);
#endif
return lock_set;

Expand Down Expand Up @@ -181,7 +181,7 @@ static inline void __attribute__((always_inline)) spinlock_release(spinlock_t *l

core_owner_id = xt_utils_get_raw_core_id();
#else
irq_status = rv_utils_mask_int_level_lower_than(RVHAL_EXCM_LEVEL);
irq_status = rv_utils_set_intlevel_regval(RVHAL_EXCM_LEVEL_CLIC);
core_owner_id = rv_utils_get_core_id() == 0 ? SPINLOCK_OWNER_ID_0 : SPINLOCK_OWNER_ID_1;
#endif
assert(core_owner_id == lock->owner); // This is a lock that we didn't acquire, or the lock is corrupt
Expand All @@ -196,7 +196,7 @@ static inline void __attribute__((always_inline)) spinlock_release(spinlock_t *l
#if __XTENSA__
XTOS_RESTORE_INTLEVEL(irq_status);
#else
rv_utils_restore_intlevel(irq_status);
rv_utils_restore_intlevel_regval(irq_status);
#endif //#if __XTENSA__
#endif //#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE && !BOOTLOADER_BUILD
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,11 @@ void vPortTCBPreDeleteHook( void *pxTCB );
// --------------------- Interrupts ------------------------

#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK_FROM_ISR()
#if !SOC_INT_CLIC_SUPPORTED
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK_FROM_ISR(RVHAL_INTR_ENABLE_THRESH)
#else
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK_FROM_ISR(RVHAL_INTR_ENABLE_THRESH_CLIC)
#endif /* !SOC_INT_CLIC_SUPPORTED */

/**
* ISR versions to enable/disable interrupts
Expand Down
4 changes: 2 additions & 2 deletions components/freertos/FreeRTOS-Kernel/portable/riscv/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ UBaseType_t xPortSetInterruptMaskFromISR(void)
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
#else
/* When CLIC is supported, all interrupt priority levels less than or equal to the threshold level are masked. */
prev_int_level = rv_utils_mask_int_level_lower_than(RVHAL_EXCM_LEVEL);
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
Expand All @@ -474,7 +474,7 @@ 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(prev_int_level);
rv_utils_restore_intlevel_regval(prev_int_level);
#endif /* SOC_INIT_CLIC_SUPPORTED */
/**
* The delay between the moment we unmask the interrupt threshold register
Expand Down
4 changes: 4 additions & 0 deletions components/idf_test/include/esp32p4/idf_performance_target.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 1000
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 1000
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 1000

/* Spinlock performance on esp32p4 is slower. May need to adjust these values once IDF-7898 is fixed */
#define IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP 380
#define IDF_PERFORMANCE_MAX_FREERTOS_SPINLOCK_CYCLES_PER_OP_UNICORE 135
45 changes: 45 additions & 0 deletions components/riscv/include/riscv/rv_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ extern "C" {
#define RVHAL_INTR_ENABLE_THRESH 1
#endif /* SOC_INT_CLIC_SUPPORTED */

/* On CLIC, the interrupt threshold is stored in the upper (NLBITS) of the mintthresh register, with the other (8 - NLBITS)
* defaulted to 1. We form the interrupt level bits here to avoid doing this at run time */
#if SOC_INT_CLIC_SUPPORTED
/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */
#define CLIC_INT_THRESH(intlevel) (((((intlevel) << (8 - NLBITS))) | 0x1f) << CLIC_CPU_INT_THRESH_S)

/* Helper macro to set interrupt level RVHAL_EXCM_LEVEL. Used during critical sections */
#define RVHAL_EXCM_LEVEL_CLIC (CLIC_INT_THRESH(RVHAL_EXCM_LEVEL - 1))

/* Helper macro to enable interrupts. */
#define RVHAL_INTR_ENABLE_THRESH_CLIC (CLIC_INT_THRESH(RVHAL_INTR_ENABLE_THRESH))
#endif /* SOC_INT_CLIC_SUPPORTED */

/* --------------------------------------------------- CPU Control -----------------------------------------------------
*
* ------------------------------------------------------------------------------------------------------------------ */
Expand Down Expand Up @@ -192,6 +205,38 @@ FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_set_intlevel(
return old_thresh;
}

/* Direct register write version of rv_utils_restore_intlevel(). Used to speed up critical sections. */
FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_restore_intlevel_regval(uint32_t restoreval)
{
/* This function expects restoreval to be in the format needed to restore the interrupt level with
* 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);
}

/* Direct register write version of rv_utils_set_intlevel(). Used to speed up critical sections. */
FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_set_intlevel_regval(uint32_t intlevel)
{
uint32_t old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
uint32_t old_thresh = REG_READ(CLIC_INT_THRESH_REG);

/* This function expects the interrupt level to be available in the format needed for mintthresh reg.
* Providing an absolute interrupt level will result in incorrect behavior.
* See CLIC_INT_THRESH() macro for details of how the interrupt level must be provided. */
REG_WRITE(CLIC_INT_THRESH_REG, intlevel);
/**
* 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. It is then safe to re-enable MIE bit in mstatus.
*/
REG_READ(CLIC_INT_THRESH_REG);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);

/* We return the mintthresh register value and NOT the absolute interrupt threshold level.
* This is done to avoid extra bit manipulations during critical sections. */
return old_thresh;
}

FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_mask_int_level_lower_than(uint32_t intlevel)
{
/* CLIC's set interrupt level is inclusive, i.e. it does mask the set level */
Expand Down

0 comments on commit e4f167d

Please sign in to comment.