test_cache_msync.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "sdkconfig.h"
  7. #include <sys/param.h>
  8. #include <string.h>
  9. #include "inttypes.h"
  10. #include "esp_log.h"
  11. #include "esp_attr.h"
  12. #include "unity.h"
  13. #include "freertos/FreeRTOS.h"
  14. #include "freertos/task.h"
  15. #include "freertos/semphr.h"
  16. #include "esp_rom_sys.h"
  17. #include "esp_memory_utils.h"
  18. #include "esp_heap_caps.h"
  19. #include "esp_mmu_map.h"
  20. #include "esp_cache.h"
  21. #include "esp_timer.h"
  22. #include "esp_partition.h"
  23. #include "esp_flash.h"
  24. #include "test_mm_utils.h"
  25. #include "soc/ext_mem_defs.h"
  26. const static char *TAG = "CACHE_TEST";
  27. #define TEST_NUM 10
  28. #define TEST_BUF {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}
  29. #define TEST_OFFSET 0x100000
  30. #if CONFIG_IDF_TARGET_ESP32S2
  31. #define TEST_SYNC_START (SOC_DPORT_CACHE_ADDRESS_LOW + TEST_OFFSET)
  32. #elif CONFIG_IDF_TARGET_ESP32S3
  33. #define TEST_SYNC_START (SOC_DRAM0_CACHE_ADDRESS_LOW + TEST_OFFSET)
  34. #elif CONFIG_IDF_TARGET_ESP32P4
  35. #define TEST_SYNC_START (SOC_DRAM_PSRAM_ADDRESS_LOW + TEST_OFFSET)
  36. #endif
  37. #define TEST_SYNC_SIZE 0x8000
  38. #define RECORD_TIME_PREPARE() uint32_t __t1, __t2
  39. #define RECORD_TIME_START() do {__t1 = esp_cpu_get_cycle_count();} while(0)
  40. #define RECORD_TIME_END(p_time) do{__t2 = esp_cpu_get_cycle_count(); p_time = (__t2 - __t1);} while(0)
  41. #define GET_US_BY_CCOUNT(t) ((double)(t)/CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ)
  42. static void s_test_with_msync_cb(void *arg)
  43. {
  44. (void)arg;
  45. esp_cache_msync((void *)TEST_SYNC_START, TEST_SYNC_SIZE, ESP_CACHE_MSYNC_FLAG_INVALIDATE);
  46. }
  47. TEST_CASE("test cache msync short enough to be in an ISR", "[cache]")
  48. {
  49. uint32_t sync_time = 0;
  50. uint32_t sync_time_us = 200;
  51. RECORD_TIME_PREPARE();
  52. #if CONFIG_SPIRAM
  53. //prepare the cache
  54. TEST_ESP_OK(test_set_buffer_dirty(TEST_SYNC_START, TEST_SYNC_SIZE));
  55. #endif
  56. //do once to record time
  57. RECORD_TIME_START();
  58. TEST_ESP_OK(esp_cache_msync((void *)TEST_SYNC_START, TEST_SYNC_SIZE, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE | ESP_CACHE_MSYNC_FLAG_UNALIGNED));
  59. RECORD_TIME_END(sync_time);
  60. sync_time_us = GET_US_BY_CCOUNT(sync_time);
  61. printf("sync_time_us: %"PRId32"\n", sync_time_us);
  62. esp_timer_handle_t timer;
  63. const esp_timer_create_args_t oneshot_timer_args = {
  64. .callback = &s_test_with_msync_cb,
  65. .arg = NULL,
  66. .dispatch_method = ESP_TIMER_ISR,
  67. .name = "test_ro_suspend"
  68. };
  69. TEST_ESP_OK(esp_timer_create(&oneshot_timer_args, &timer));
  70. #if CONFIG_SPIRAM
  71. //prepare the cache
  72. TEST_ESP_OK(test_set_buffer_dirty(TEST_SYNC_START, TEST_SYNC_SIZE));
  73. #endif
  74. //start timer
  75. uint32_t period = sync_time_us * 2;
  76. TEST_ESP_OK(esp_timer_start_periodic(timer, period));
  77. //10ms
  78. esp_rom_delay_us(10 * 1000);
  79. TEST_ESP_OK(esp_timer_stop(timer));
  80. ESP_LOGI(TAG, "Finish");
  81. TEST_ESP_OK(esp_timer_delete(timer));
  82. }
  83. #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
  84. static const esp_partition_t *s_get_partition(void)
  85. {
  86. //Find the "storage1" partition defined in `partitions.csv`
  87. const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1");
  88. if (!result) {
  89. ESP_LOGE(TAG, "Can't find the partition, please define it correctly in `partitions.csv`");
  90. abort();
  91. }
  92. return result;
  93. }
  94. TEST_CASE("test cache msync work with Flash operation when XIP from PSRAM", "[cache]")
  95. {
  96. uint32_t sync_time = 0;
  97. RECORD_TIME_PREPARE();
  98. //prepare the cache
  99. TEST_ESP_OK(test_set_buffer_dirty(TEST_SYNC_START, TEST_SYNC_SIZE));
  100. //do once to record time
  101. RECORD_TIME_START();
  102. TEST_ESP_OK(esp_cache_msync((void *)TEST_SYNC_START, TEST_SYNC_SIZE, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE));
  103. RECORD_TIME_END(sync_time);
  104. uint32_t sync_time_us = GET_US_BY_CCOUNT(sync_time);
  105. printf("sync_time_us: %"PRId32"\n", sync_time_us);
  106. //Get the partition used for SPI1 erase operation
  107. const esp_partition_t *part = s_get_partition();
  108. ESP_LOGI(TAG, "found partition '%s' at offset 0x%"PRIx32" with size 0x%"PRIx32, part->label, part->address, part->size);
  109. //Erase whole region
  110. TEST_ESP_OK(esp_flash_erase_region(part->flash_chip, part->address, part->size));
  111. esp_timer_handle_t timer;
  112. const esp_timer_create_args_t oneshot_timer_args = {
  113. .callback = &s_test_with_msync_cb,
  114. .arg = NULL,
  115. .dispatch_method = ESP_TIMER_ISR,
  116. .name = "test_ro_suspend"
  117. };
  118. TEST_ESP_OK(esp_timer_create(&oneshot_timer_args, &timer));
  119. //prepare the cache
  120. TEST_ESP_OK(test_set_buffer_dirty(TEST_SYNC_START, TEST_SYNC_SIZE));
  121. //start timer
  122. uint32_t period = sync_time_us * 2;
  123. TEST_ESP_OK(esp_timer_start_periodic(timer, period));
  124. //erase
  125. ESP_ERROR_CHECK(esp_flash_erase_region(part->flash_chip, part->address, part->size));
  126. TEST_ESP_OK(esp_timer_stop(timer));
  127. ESP_LOGI(TAG, "Finish");
  128. TEST_ESP_OK(esp_timer_delete(timer));
  129. }
  130. #endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
  131. #if CONFIG_SPIRAM
  132. /*---------------------------------------------------------------
  133. Test esp_cache_msync with PSRAM stack
  134. ---------------------------------------------------------------*/
  135. static void test_msync_on_psram(void *arg)
  136. {
  137. SemaphoreHandle_t test_semphr = *(SemaphoreHandle_t *)arg;
  138. extern int _instruction_reserved_end;
  139. extern int _rodata_reserved_end;
  140. esp_rom_printf("_instruction_reserved_end: %p\n", &_instruction_reserved_end);
  141. esp_rom_printf("_rodata_reserved_end: %p\n", &_rodata_reserved_end);
  142. StackType_t *start_addr_stack = esp_cpu_get_sp();
  143. TEST_ASSERT(esp_ptr_external_ram(start_addr_stack));
  144. TEST_ESP_OK(test_set_buffer_dirty(TEST_SYNC_START, TEST_SYNC_SIZE));
  145. uint32_t sync_time = 0;
  146. RECORD_TIME_PREPARE();
  147. printf("doing msync...\n");
  148. RECORD_TIME_START();
  149. TEST_ESP_OK(esp_cache_msync((void *)TEST_SYNC_START, 0x8000, ESP_CACHE_MSYNC_FLAG_INVALIDATE));
  150. RECORD_TIME_END(sync_time);
  151. printf("msync done\n");
  152. uint32_t sync_time_us = GET_US_BY_CCOUNT(sync_time);
  153. printf("sync_time_us: %"PRId32"\n", sync_time_us);
  154. xSemaphoreGive(test_semphr);
  155. vTaskDelete(NULL);
  156. }
  157. TEST_CASE("test cache msync work with PSRAM stack", "[cache]")
  158. {
  159. SemaphoreHandle_t test_semphr = xSemaphoreCreateBinary();
  160. TEST_ASSERT(test_semphr);
  161. int size_stack = 1024 * 4;
  162. StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
  163. printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task);
  164. static StaticTask_t task_buf;
  165. xTaskCreateStaticPinnedToCore(test_msync_on_psram, "test_msync_on_psram", size_stack, &test_semphr, 5, stack_for_task, &task_buf, 0);
  166. xSemaphoreTake(test_semphr, portMAX_DELAY);
  167. vSemaphoreDelete(test_semphr);
  168. free(stack_for_task);
  169. }
  170. #endif //#if CONFIG_SPIRAM