Use memory fence when disabling cache to avoid -O2 problems

This commit is contained in:
Dan Halbert 2022-12-29 19:49:40 -05:00
parent a930756c26
commit cc92ce4820
3 changed files with 26 additions and 2 deletions

@ -1 +1 @@
Subproject commit 57133eefeb077f73b5ac17ee044d9feaf566da8e Subproject commit baca4c084334aa8625f525a4032d66a397199ea6

View File

@ -29,8 +29,18 @@
// Turn off cache and invalidate all data in it. // Turn off cache and invalidate all data in it.
void nrf_peripherals_disable_and_clear_cache(void) { void nrf_peripherals_disable_and_clear_cache(void) {
// Memory fence for hardware and compiler reasons. If this routine is inlined, the compiler
// needs to know that everything written out be stored before this is called.
// -O2 optimization needed this on SAMD51. Assuming nRF may have the same issue.
// __sync_synchronize() includes volatile asm(), which tells the compiler not to assume
// state across this call.
__sync_synchronize();
// Disabling cache also invalidates all cache entries. // Disabling cache also invalidates all cache entries.
NRF_NVMC->ICACHECNF &= ~(1 << NVMC_ICACHECNF_CACHEEN_Pos); NRF_NVMC->ICACHECNF &= ~(1 << NVMC_ICACHECNF_CACHEEN_Pos);
// Memory fence for hardware and compiler reasons.
__sync_synchronize();
} }
// Enable cache // Enable cache

View File

@ -58,6 +58,9 @@ static supervisor_allocation *supervisor_cache = NULL;
// Wait until both the write enable and write in progress bits have cleared. // Wait until both the write enable and write in progress bits have cleared.
static bool wait_for_flash_ready(void) { static bool wait_for_flash_ready(void) {
if (flash_device == NULL) {
return false;
}
bool ok = true; bool ok = true;
// Both the write enable and write in progress bits should be low. // Both the write enable and write in progress bits should be low.
if (flash_device->no_ready_bit) { if (flash_device->no_ready_bit) {
@ -192,6 +195,9 @@ static bool copy_block(uint32_t src_address, uint32_t dest_address) {
return true; return true;
} }
#define READ_JEDEC_ID_RETRY_COUNT (100)
// If this fails, flash_device will remain NULL.
void supervisor_flash_init(void) { void supervisor_flash_init(void) {
if (flash_device != NULL) { if (flash_device != NULL) {
return; return;
@ -220,7 +226,11 @@ void supervisor_flash_init(void) {
#else #else
// The response will be 0xff if the flash needs more time to start up. // The response will be 0xff if the flash needs more time to start up.
uint8_t jedec_id_response[3] = {0xff, 0xff, 0xff}; uint8_t jedec_id_response[3] = {0xff, 0xff, 0xff};
while (jedec_id_response[0] == 0xff) { // Response can also be 0x00 if reading before ready. When compiled with `-O2`, typically
// takes three tries to read on Grand Central M4.
size_t count = READ_JEDEC_ID_RETRY_COUNT;
while ((count-- > 0) && (jedec_id_response[0] == 0xff || jedec_id_response[2] == 0x00)) {
spi_flash_read_command(CMD_READ_JEDEC_ID, jedec_id_response, 3); spi_flash_read_command(CMD_READ_JEDEC_ID, jedec_id_response, 3);
} }
for (uint8_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) { for (uint8_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
@ -234,6 +244,7 @@ void supervisor_flash_init(void) {
} }
#endif #endif
if (flash_device == NULL) { if (flash_device == NULL) {
// Flash did not respond. Give up.
return; return;
} }
@ -293,6 +304,9 @@ uint32_t supervisor_flash_get_block_size(void) {
// The total number of available blocks. // The total number of available blocks.
uint32_t supervisor_flash_get_block_count(void) { uint32_t supervisor_flash_get_block_count(void) {
if (flash_device == NULL) {
return 0;
}
// We subtract one erase sector size because we may use it as a staging area // We subtract one erase sector size because we may use it as a staging area
// for writes. // for writes.
return (flash_device->total_size - SPI_FLASH_ERASE_SIZE) / FILESYSTEM_BLOCK_SIZE; return (flash_device->total_size - SPI_FLASH_ERASE_SIZE) / FILESYSTEM_BLOCK_SIZE;