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:
Jeroen Domburg 2017-03-10 17:27:53 +08:00
parent c9a7d21068
commit c09ba35d3b
3 changed files with 61 additions and 51 deletions

View file

@ -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>
@ -29,47 +29,47 @@ This code triggers a psram-related silicon bug in rev0 silicon. The bug is fixed
volatile static int res[2];
void tstMem(void *arg) {
volatile unsigned char *mem=(volatile unsigned char*)arg;
int p=0;
while(1) {
for (int i=0; i<TSTSZ; i++) {
mem[i]=(i^p);
}
// vTaskDelay(1);
for (int i=0; i<TSTSZ; i++) {
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]);
}
}
p++;
res[xPortGetCoreID()]++;
}
volatile unsigned char *mem=(volatile unsigned char*)arg;
int p=0;
while(1) {
for (int i=0; i<TSTSZ; i++) {
mem[i]=(i^p);
}
// vTaskDelay(1);
for (int i=0; i<TSTSZ; i++) {
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]);
}
}
p++;
res[xPortGetCoreID()]++;
}
}
TEST_CASE("PSram cache flush on mmap", "[psram][ignore]")
{
void *mem[2];
res[0]=0; res[1]=0;
res[0]=0; res[1]=0;
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
TaskHandle_t th[2];
printf("Creating tasks\n");
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
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) {
spi_flash_read(i, buf, 512);
vTaskDelay(1);
}
for (int i=0; i<4*1024*1024; i+=512) {
spi_flash_read(i, buf, 512);
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[1]);
free(mem[0]);
free(mem[1]);
vTaskDelete(th[0]);
vTaskDelete(th[1]);
free(mem[0]);
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]")
{
void *mem[2];
res[0]=0; res[1]=0;
res[0]=0; res[1]=0;
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
TaskHandle_t th[2];
printf("Creating tasks\n");
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
xTaskCreatePinnedToCore(tstMem , "tsktwo" , 2048, mem[1], 3, &th[1], 1);
char buf[512];
char buf[512];
printf("Erasing sector...\n");
spi_flash_erase_sector(FLASHPOS/4096);
printf("Erased.\n");
for (int i=0; i<CYCLES; i++) {
printf("%d/%d\n", i, CYCLES);
spi_flash_write(FLASHPOS, buf, 512);
spi_flash_read(i, buf, 512);
vTaskDelay(1);
//if ((i%31)==0)
}
printf("Erasing sector...\n");
spi_flash_erase_sector(FLASHPOS/4096);
printf("Erased.\n");
for (int i=0; i<CYCLES; i++) {
printf("%d/%d\n", i, CYCLES);
spi_flash_write(FLASHPOS, buf, 512);
spi_flash_read(i, buf, 512);
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[1]);
free(mem[0]);
free(mem[1]);
vTaskDelete(th[0]);
vTaskDelete(th[1]);
free(mem[0]);
free(mem[1]);
}

View file

@ -230,7 +230,7 @@ void *pvReturn = NULL;
pxBlock = xStart.pxNextFreeBlock;
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)
{
@ -419,6 +419,9 @@ uint8_t *puc;
than the block being inserted. */
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. */
}

View file

@ -30,6 +30,7 @@
#include "esp_intr_alloc.h"
#include "esp_spi_flash.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_restore_cache(uint32_t cpuid, uint32_t saved_state);
@ -59,6 +60,13 @@ void spi_flash_op_unlock()
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)
{
// Disable scheduler on this CPU
@ -76,8 +84,6 @@ void IRAM_ATTR spi_flash_op_block_func(void* arg)
while (!s_flash_op_complete) {
// 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
esp_intr_noniram_enable();
// 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);
assert(ret == ESP_OK);
while (!s_flash_op_can_start) {
// Busy loop and wait for spi_flash_op_block_func to disable cache
// on the other CPU
// Busy loop and wait for spi_flash_op_block_func to run so we can
// disable cache of the other CPU
}
// Disable scheduler on the current CPU
vTaskSuspendAll();
@ -121,8 +127,9 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
}
// Kill interrupts that aren't located in IRAM
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(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
}
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;
#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(other_cpuid, s_flash_op_cache_state[other_cpuid]);
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
// Scheduler is not running yet — this means we are running on PRO CPU.