Fix int level 4 panics to give a correct backtrace. Add cache invalid access interrupt to panic handler reasons and wire it up to panic(). Fix issue where cache was re-enabled for pro cpu and pro cpu continuing execution while cache was still disabled on app cpu.
This commit is contained in:
parent
c9a7d21068
commit
c09ba35d3b
3 changed files with 61 additions and 51 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
This code triggers a psram-related silicon bug in rev0 silicon. The bug is fixed in rev1 silicon.
|
This code tests the interaction between PSRAM and SPI flash routines.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <esp_types.h>
|
#include <esp_types.h>
|
||||||
|
@ -29,47 +29,47 @@ This code triggers a psram-related silicon bug in rev0 silicon. The bug is fixed
|
||||||
volatile static int res[2];
|
volatile static int res[2];
|
||||||
|
|
||||||
void tstMem(void *arg) {
|
void tstMem(void *arg) {
|
||||||
volatile unsigned char *mem=(volatile unsigned char*)arg;
|
volatile unsigned char *mem=(volatile unsigned char*)arg;
|
||||||
int p=0;
|
int p=0;
|
||||||
while(1) {
|
while(1) {
|
||||||
for (int i=0; i<TSTSZ; i++) {
|
for (int i=0; i<TSTSZ; i++) {
|
||||||
mem[i]=(i^p);
|
mem[i]=(i^p);
|
||||||
}
|
}
|
||||||
// vTaskDelay(1);
|
// vTaskDelay(1);
|
||||||
for (int i=0; i<TSTSZ; i++) {
|
for (int i=0; i<TSTSZ; i++) {
|
||||||
if (mem[i]!=((i^p)&0xff)) {
|
if (mem[i]!=((i^p)&0xff)) {
|
||||||
printf("Core %d mem err! Got %x espected %x at addr %p\n", xPortGetCoreID(), mem[i], (i^p)&0xff, &mem[i]);
|
printf("Core %d mem err! Got %x espected %x at addr %p\n", xPortGetCoreID(), mem[i], (i^p)&0xff, &mem[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
res[xPortGetCoreID()]++;
|
res[xPortGetCoreID()]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("PSram cache flush on mmap", "[psram][ignore]")
|
TEST_CASE("PSram cache flush on mmap", "[psram][ignore]")
|
||||||
{
|
{
|
||||||
void *mem[2];
|
void *mem[2];
|
||||||
res[0]=0; res[1]=0;
|
res[0]=0; res[1]=0;
|
||||||
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
||||||
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
||||||
TaskHandle_t th[2];
|
TaskHandle_t th[2];
|
||||||
printf("Creating tasks\n");
|
printf("Creating tasks\n");
|
||||||
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
|
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
|
||||||
xTaskCreatePinnedToCore(tstMem , "tsktwo" , 2048, mem[1], 3, &th[1], 1);
|
xTaskCreatePinnedToCore(tstMem , "tsktwo" , 2048, mem[1], 3, &th[1], 1);
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
for (int i=0; i<4*1024*1024; i+=512) {
|
for (int i=0; i<4*1024*1024; i+=512) {
|
||||||
spi_flash_read(i, buf, 512);
|
spi_flash_read(i, buf, 512);
|
||||||
vTaskDelay(1);
|
vTaskDelay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Checked memory %d and %d times.\n", res[0], res[1]);
|
printf("Checked memory %d and %d times.\n", res[0], res[1]);
|
||||||
|
|
||||||
vTaskDelete(th[0]);
|
vTaskDelete(th[0]);
|
||||||
vTaskDelete(th[1]);
|
vTaskDelete(th[1]);
|
||||||
free(mem[0]);
|
free(mem[0]);
|
||||||
free(mem[1]);
|
free(mem[1]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,31 +80,30 @@ TEST_CASE("PSram cache flush on mmap", "[psram][ignore]")
|
||||||
TEST_CASE("PSram cache flush on write/read", "[psram][ignore]")
|
TEST_CASE("PSram cache flush on write/read", "[psram][ignore]")
|
||||||
{
|
{
|
||||||
void *mem[2];
|
void *mem[2];
|
||||||
res[0]=0; res[1]=0;
|
res[0]=0; res[1]=0;
|
||||||
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
||||||
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
|
||||||
TaskHandle_t th[2];
|
TaskHandle_t th[2];
|
||||||
printf("Creating tasks\n");
|
printf("Creating tasks\n");
|
||||||
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
|
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
|
||||||
xTaskCreatePinnedToCore(tstMem , "tsktwo" , 2048, mem[1], 3, &th[1], 1);
|
xTaskCreatePinnedToCore(tstMem , "tsktwo" , 2048, mem[1], 3, &th[1], 1);
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
printf("Erasing sector...\n");
|
printf("Erasing sector...\n");
|
||||||
spi_flash_erase_sector(FLASHPOS/4096);
|
spi_flash_erase_sector(FLASHPOS/4096);
|
||||||
printf("Erased.\n");
|
printf("Erased.\n");
|
||||||
for (int i=0; i<CYCLES; i++) {
|
for (int i=0; i<CYCLES; i++) {
|
||||||
printf("%d/%d\n", i, CYCLES);
|
printf("%d/%d\n", i, CYCLES);
|
||||||
spi_flash_write(FLASHPOS, buf, 512);
|
spi_flash_write(FLASHPOS, buf, 512);
|
||||||
spi_flash_read(i, buf, 512);
|
spi_flash_read(i, buf, 512);
|
||||||
vTaskDelay(1);
|
vTaskDelay(1);
|
||||||
//if ((i%31)==0)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
printf("Checked memory %d and %d times.\n", res[0], res[1]);
|
printf("Checked memory %d and %d times.\n", res[0], res[1]);
|
||||||
|
|
||||||
vTaskDelete(th[0]);
|
vTaskDelete(th[0]);
|
||||||
vTaskDelete(th[1]);
|
vTaskDelete(th[1]);
|
||||||
free(mem[0]);
|
free(mem[0]);
|
||||||
free(mem[1]);
|
free(mem[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,7 @@ void *pvReturn = NULL;
|
||||||
pxBlock = xStart.pxNextFreeBlock;
|
pxBlock = xStart.pxNextFreeBlock;
|
||||||
while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) )
|
while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) )
|
||||||
{
|
{
|
||||||
// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock);
|
ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock);
|
||||||
|
|
||||||
#if (configENABLE_MEMORY_DEBUG == 1)
|
#if (configENABLE_MEMORY_DEBUG == 1)
|
||||||
{
|
{
|
||||||
|
@ -419,6 +419,9 @@ uint8_t *puc;
|
||||||
than the block being inserted. */
|
than the block being inserted. */
|
||||||
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
|
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
|
||||||
{
|
{
|
||||||
|
ets_printf("i %p\n", pxIterator);
|
||||||
|
ets_printf("n %p\n", pxIterator->pxNextFreeBlock);
|
||||||
|
|
||||||
/* Nothing to do here, just iterate to the right position. */
|
/* Nothing to do here, just iterate to the right position. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "esp_intr_alloc.h"
|
#include "esp_intr_alloc.h"
|
||||||
#include "esp_spi_flash.h"
|
#include "esp_spi_flash.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_psram.h"
|
||||||
|
|
||||||
static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state);
|
static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state);
|
||||||
static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state);
|
static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state);
|
||||||
|
@ -59,6 +60,13 @@ void spi_flash_op_unlock()
|
||||||
xSemaphoreGive(s_flash_op_mutex);
|
xSemaphoreGive(s_flash_op_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If you're going to modify this, keep in mind that while the flash caches of the pro and app
|
||||||
|
cpu are separate, the psram cache is *not*. If one of the CPUs returns from a flash routine
|
||||||
|
with its cache enabled but the other CPUs cache is not enabled yet, you will have problems
|
||||||
|
when accessing psram from the former CPU.
|
||||||
|
*/
|
||||||
|
|
||||||
void IRAM_ATTR spi_flash_op_block_func(void* arg)
|
void IRAM_ATTR spi_flash_op_block_func(void* arg)
|
||||||
{
|
{
|
||||||
// Disable scheduler on this CPU
|
// Disable scheduler on this CPU
|
||||||
|
@ -76,8 +84,6 @@ void IRAM_ATTR spi_flash_op_block_func(void* arg)
|
||||||
while (!s_flash_op_complete) {
|
while (!s_flash_op_complete) {
|
||||||
// busy loop here and wait for the other CPU to finish flash operation
|
// busy loop here and wait for the other CPU to finish flash operation
|
||||||
}
|
}
|
||||||
// Flash operation is complete, re-enable cache
|
|
||||||
spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
|
|
||||||
// Restore interrupts that aren't located in IRAM
|
// Restore interrupts that aren't located in IRAM
|
||||||
esp_intr_noniram_enable();
|
esp_intr_noniram_enable();
|
||||||
// Re-enable scheduler
|
// Re-enable scheduler
|
||||||
|
@ -110,8 +116,8 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
|
||||||
esp_err_t ret = esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid);
|
esp_err_t ret = esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid);
|
||||||
assert(ret == ESP_OK);
|
assert(ret == ESP_OK);
|
||||||
while (!s_flash_op_can_start) {
|
while (!s_flash_op_can_start) {
|
||||||
// Busy loop and wait for spi_flash_op_block_func to disable cache
|
// Busy loop and wait for spi_flash_op_block_func to run so we can
|
||||||
// on the other CPU
|
// disable cache of the other CPU
|
||||||
}
|
}
|
||||||
// Disable scheduler on the current CPU
|
// Disable scheduler on the current CPU
|
||||||
vTaskSuspendAll();
|
vTaskSuspendAll();
|
||||||
|
@ -121,8 +127,9 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
|
||||||
}
|
}
|
||||||
// Kill interrupts that aren't located in IRAM
|
// Kill interrupts that aren't located in IRAM
|
||||||
esp_intr_noniram_disable();
|
esp_intr_noniram_disable();
|
||||||
// Disable cache on this CPU as well
|
// Disable cache on both CPUs as well
|
||||||
spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
|
spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
|
||||||
|
spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
|
void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
|
||||||
|
@ -135,8 +142,9 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
|
||||||
s_flash_op_cpu = -1;
|
s_flash_op_cpu = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Re-enable cache on this CPU
|
// Re-enable cache on both CPUs
|
||||||
spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
|
spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
|
||||||
|
spi_flash_restore_cache(other_cpuid, s_flash_op_cache_state[other_cpuid]);
|
||||||
|
|
||||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||||
// Scheduler is not running yet — this means we are running on PRO CPU.
|
// Scheduler is not running yet — this means we are running on PRO CPU.
|
||||||
|
|
Loading…
Reference in a new issue