esp_system: Fix esp_cpu_compare_and_set()

This commit fixes esp_cpu_compare_and_set() in the following ways

- Removed call to esp_ptr_external_ram() as it incurred > 80 CPU cycles (due to multiple nested
  function calls, and those functions not being in IRAM). We now check manually if the pointer
  is in external RAM for increased speed.
- Fixed infinite wait when attempting to get the external_ram_cas_lock. The function should
  return immediatley if any part of the compare and set call fails.
- The preprocessor conditions of esp_cpu_compare_and_set() to depend on CONFIG_SPIRAM instead
  of SOC_SPIRAM_SUPPORTED. Even if the target supports SPIRAM, we only need the external RAM
  compare and set feature if SPIRAM is enabled.

Also fixed incorrect inclusion of esp_intr_alloc.h in esp_cpu.h
This commit is contained in:
Darian Leung
2022-07-21 19:14:10 +08:00
parent 36f49f361c
commit 64117a0c59
2 changed files with 19 additions and 14 deletions

View File

@@ -620,7 +620,7 @@ esp_err_t esp_cpu_clear_watchpoint(int wp_num)
* *
* ------------------------------------------------------------------------------------------------------------------ */ * ------------------------------------------------------------------------------------------------------------------ */
#if __XTENSA__ && XCHAL_HAVE_S32C1I && SOC_SPIRAM_SUPPORTED #if __XTENSA__ && XCHAL_HAVE_S32C1I && CONFIG_SPIRAM
static DRAM_ATTR uint32_t external_ram_cas_lock = 0; static DRAM_ATTR uint32_t external_ram_cas_lock = 0;
#endif #endif
@@ -628,35 +628,39 @@ bool esp_cpu_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, ui
{ {
#if __XTENSA__ #if __XTENSA__
bool ret; bool ret;
#if XCHAL_HAVE_S32C1I && SOC_SPIRAM_SUPPORTED #if XCHAL_HAVE_S32C1I && CONFIG_SPIRAM
if (esp_ptr_external_ram((const void *)addr)) { // Check if the target address is in external RAM
if ((uint32_t)addr >= SOC_EXTRAM_DATA_LOW && (uint32_t)addr < SOC_EXTRAM_DATA_HIGH) {
/* The target address is in external RAM, thus the native CAS instruction cannot be used. Instead, we achieve
atomicity by disabling interrupts and then acquiring an external RAM CAS lock. */
uint32_t intr_level; uint32_t intr_level;
// Atomicity is achieved by disabling interrupts then acquiring a an external RAM CAS lock
__asm__ __volatile__ ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) "\n" __asm__ __volatile__ ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) "\n"
: "=r"(intr_level)); : "=r"(intr_level));
while (!xt_utils_compare_and_set(&external_ram_cas_lock, 0, 1)) { if (!xt_utils_compare_and_set(&external_ram_cas_lock, 0, 1)) {
; // External RAM CAS lock already taken. Exit
ret = false;
goto exit;
} }
// Now we compare and set the target address // Now we compare and set the target address
uint32_t old_value; ret = (*addr == compare_value);
old_value = *addr; if (ret) {
if (old_value == compare_value) {
*addr = new_value; *addr = new_value;
} }
// Release the external RAM CAS lock and reenable interrupts // Release the external RAM CAS lock
external_ram_cas_lock = 0; external_ram_cas_lock = 0;
exit:
// Reenable interrupts
__asm__ __volatile__ ("memw \n" __asm__ __volatile__ ("memw \n"
"wsr %0, ps\n" "wsr %0, ps\n"
:: "r"(intr_level)); :: "r"(intr_level));
ret = (old_value == compare_value);
} else } else
#endif //XCHAL_HAVE_S32C1I && SOC_SPIRAM_SUPPORTED #endif // XCHAL_HAVE_S32C1I && CONFIG_SPIRAM
{ {
// The target address is in internal RAM. Use the CPU's native CAS instruction
ret = xt_utils_compare_and_set(addr, compare_value, new_value); ret = xt_utils_compare_and_set(addr, compare_value, new_value);
} }
return ret; return ret;
#else #else // __XTENSA__
// Single core targets don't have atomic CAS instruction. So access method is the same for internal and external RAM // Single core targets don't have atomic CAS instruction. So access method is the same for internal and external RAM
return rv_utils_compare_and_set(addr, compare_value, new_value); return rv_utils_compare_and_set(addr, compare_value, new_value);
#endif #endif

View File

@@ -17,6 +17,7 @@
#elif __riscv #elif __riscv
#include "riscv/rv_utils.h" #include "riscv/rv_utils.h"
#endif #endif
#include "esp_intr_alloc.h"
#include "esp_err.h" #include "esp_err.h"
#ifdef __cplusplus #ifdef __cplusplus