Skip to content

Commit 29eeef9

Browse files
authored
Merge pull request #9169 from dhalbert/flash_cache_table-fix
2 parents 50121d0 + 98957cc commit 29eeef9

File tree

1 file changed

+63
-64
lines changed

1 file changed

+63
-64
lines changed

supervisor/shared/external_flash/external_flash.c

Lines changed: 63 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ static const external_flash_device *flash_device = NULL;
5454
// cache.
5555
static uint32_t dirty_mask;
5656

57-
// Table of pointers to each cached block
57+
// Table of pointers to each cached block. Should be zero'd after allocation.
58+
#define BLOCKS_PER_SECTOR (SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE)
59+
#define PAGES_PER_BLOCK (FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE)
60+
#define FLASH_CACHE_TABLE_NUM_ENTRIES (BLOCKS_PER_SECTOR * PAGES_PER_BLOCK)
61+
#define FLASH_CACHE_TABLE_SIZE (FLASH_CACHE_TABLE_NUM_ENTRIES * sizeof (uint8_t *))
5862
static uint8_t **flash_cache_table = NULL;
5963

6064
// Wait until both the write enable and write in progress bits have cleared.
@@ -207,7 +211,7 @@ void supervisor_flash_init(void) {
207211
// Delay to give the SPI Flash time to get going.
208212
// TODO(tannewt): Only do this when we know power was applied vs a reset.
209213
uint16_t max_start_up_delay_us = 0;
210-
for (uint8_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
214+
for (size_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
211215
if (possible_devices[i].start_up_time_us > max_start_up_delay_us) {
212216
max_start_up_delay_us = possible_devices[i].start_up_time_us;
213217
}
@@ -219,7 +223,7 @@ void supervisor_flash_init(void) {
219223
#ifdef EXTERNAL_FLASH_NO_JEDEC
220224
// For NVM that don't have JEDEC response
221225
spi_flash_command(CMD_WAKE);
222-
for (uint8_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
226+
for (size_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
223227
const external_flash_device *possible_device = &possible_devices[i];
224228
flash_device = possible_device;
225229
break;
@@ -234,7 +238,7 @@ void supervisor_flash_init(void) {
234238
while ((count-- > 0) && (jedec_id_response[0] == 0xff || jedec_id_response[2] == 0x00)) {
235239
spi_flash_read_command(CMD_READ_JEDEC_ID, jedec_id_response, 3);
236240
}
237-
for (uint8_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
241+
for (size_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
238242
const external_flash_device *possible_device = &possible_devices[i];
239243
if (jedec_id_response[0] == possible_device->manufacturer_id &&
240244
jedec_id_response[1] == possible_device->memory_type &&
@@ -323,7 +327,7 @@ static bool flush_scratch_flash(void) {
323327
// cached.
324328
bool copy_to_scratch_ok = true;
325329
uint32_t scratch_sector = flash_device->total_size - SPI_FLASH_ERASE_SIZE;
326-
for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
330+
for (size_t i = 0; i < BLOCKS_PER_SECTOR; i++) {
327331
if ((dirty_mask & (1 << i)) == 0) {
328332
copy_to_scratch_ok = copy_to_scratch_ok &&
329333
copy_block(current_sector + i * FILESYSTEM_BLOCK_SIZE,
@@ -338,72 +342,70 @@ static bool flush_scratch_flash(void) {
338342
// Second, erase the current sector.
339343
erase_sector(current_sector);
340344
// Finally, copy the new version into it.
341-
for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
345+
for (size_t i = 0; i < BLOCKS_PER_SECTOR; i++) {
342346
copy_block(scratch_sector + i * FILESYSTEM_BLOCK_SIZE,
343347
current_sector + i * FILESYSTEM_BLOCK_SIZE);
344348
}
345349
return true;
346350
}
347351

352+
// Free all entries in the partially or completely filled flash_cache_table, and then free the table itself.
353+
static void release_ram_cache(void) {
354+
if (flash_cache_table == NULL) {
355+
return;
356+
}
357+
358+
for (size_t i = 0; i < FLASH_CACHE_TABLE_NUM_ENTRIES; i++) {
359+
// Table may not be completely full. Stop at first NULL entry.
360+
if (flash_cache_table[i] == NULL) {
361+
break;
362+
}
363+
port_free(flash_cache_table[i]);
364+
}
365+
port_free(flash_cache_table);
366+
flash_cache_table = NULL;
367+
}
368+
348369
// Attempts to allocate a new set of page buffers for caching a full sector in
349370
// ram. Each page is allocated separately so that the GC doesn't need to provide
350371
// one huge block. We can free it as we write if we want to also.
351372
static bool allocate_ram_cache(void) {
352-
uint8_t blocks_per_sector = SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE;
353-
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
354-
355-
uint32_t table_size = blocks_per_sector * pages_per_block * sizeof(size_t);
356-
// Attempt to allocate outside the heap first.
357-
flash_cache_table = port_malloc(table_size, false);
358-
359-
// Declare i and j outside the loops in case we fail to allocate everything
360-
// we need. In that case we'll give it back.
361-
uint8_t i = 0;
362-
uint8_t j = 0;
363-
bool success = flash_cache_table != NULL;
364-
for (i = 0; i < blocks_per_sector && success; i++) {
365-
for (j = 0; j < pages_per_block && success; j++) {
373+
flash_cache_table = port_malloc(FLASH_CACHE_TABLE_SIZE, false);
374+
if (flash_cache_table == NULL) {
375+
// Not enough space even for the cache table.
376+
return false;
377+
}
378+
379+
// Clear all the entries so it's easy to find the last entry.
380+
memset(flash_cache_table, 0, FLASH_CACHE_TABLE_SIZE);
381+
382+
bool success = true;
383+
for (size_t i = 0; i < BLOCKS_PER_SECTOR && success; i++) {
384+
for (size_t j = 0; j < PAGES_PER_BLOCK && success; j++) {
366385
uint8_t *page_cache = port_malloc(SPI_FLASH_PAGE_SIZE, false);
367386
if (page_cache == NULL) {
368387
success = false;
369388
break;
370389
}
371-
flash_cache_table[i * pages_per_block + j] = page_cache;
390+
flash_cache_table[i * PAGES_PER_BLOCK + j] = page_cache;
372391
}
373392
}
393+
374394
// We couldn't allocate enough so give back what we got.
375395
if (!success) {
376-
// We add 1 so that we delete 0 when i is 1. Going to zero (i >= 0)
377-
// would never stop because i is unsigned.
378-
i++;
379-
for (; i > 0; i--) {
380-
for (; j > 0; j--) {
381-
port_free(flash_cache_table[(i - 1) * pages_per_block + (j - 1)]);
382-
}
383-
j = pages_per_block;
384-
}
385-
port_free(flash_cache_table);
386-
flash_cache_table = NULL;
396+
release_ram_cache();
387397
}
388398
return success;
389399
}
390400

391-
static void release_ram_cache(void) {
392-
uint8_t blocks_per_sector = SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE;
393-
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
394-
for (uint8_t i = 0; i < blocks_per_sector; i++) {
395-
for (uint8_t j = 0; j < pages_per_block; j++) {
396-
uint32_t offset = i * pages_per_block + j;
397-
port_free(flash_cache_table[offset]);
398-
}
399-
}
400-
port_free(flash_cache_table);
401-
flash_cache_table = NULL;
402-
}
403-
404401
// Flush the cached sector from ram onto the flash. We'll free the cache unless
405402
// keep_cache is true.
406403
static bool flush_ram_cache(bool keep_cache) {
404+
if (flash_cache_table == NULL) {
405+
// Nothing to flush because there is no cache.
406+
return true;
407+
}
408+
407409
if (current_sector == NO_SECTOR_LOADED) {
408410
if (!keep_cache) {
409411
release_ram_cache();
@@ -414,13 +416,12 @@ static bool flush_ram_cache(bool keep_cache) {
414416
// we've cached. If we don't do this we'll erase the data during the sector
415417
// erase below.
416418
bool copy_to_ram_ok = true;
417-
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
418-
for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
419+
for (size_t i = 0; i < BLOCKS_PER_SECTOR; i++) {
419420
if ((dirty_mask & (1 << i)) == 0) {
420-
for (uint8_t j = 0; j < pages_per_block; j++) {
421+
for (size_t j = 0; j < PAGES_PER_BLOCK; j++) {
421422
copy_to_ram_ok = read_flash(
422-
current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
423-
flash_cache_table[i * pages_per_block + j],
423+
current_sector + (i * PAGES_PER_BLOCK + j) * SPI_FLASH_PAGE_SIZE,
424+
flash_cache_table[i * PAGES_PER_BLOCK + j],
424425
SPI_FLASH_PAGE_SIZE);
425426
if (!copy_to_ram_ok) {
426427
break;
@@ -438,10 +439,10 @@ static bool flush_ram_cache(bool keep_cache) {
438439
// Second, erase the current sector.
439440
erase_sector(current_sector);
440441
// Lastly, write all the data in ram that we've cached.
441-
for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
442-
for (uint8_t j = 0; j < pages_per_block; j++) {
443-
write_flash(current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
444-
flash_cache_table[i * pages_per_block + j],
442+
for (size_t i = 0; i < BLOCKS_PER_SECTOR; i++) {
443+
for (size_t j = 0; j < PAGES_PER_BLOCK; j++) {
444+
write_flash(current_sector + (i * PAGES_PER_BLOCK + j) * SPI_FLASH_PAGE_SIZE,
445+
flash_cache_table[i * PAGES_PER_BLOCK + j],
445446
SPI_FLASH_PAGE_SIZE);
446447
}
447448
}
@@ -496,15 +497,14 @@ static bool external_flash_read_block(uint8_t *dest, uint32_t block) {
496497

497498
// Mask out the lower bits that designate the address within the sector.
498499
uint32_t this_sector = address & (~(SPI_FLASH_ERASE_SIZE - 1));
499-
uint8_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % (SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE);
500-
uint8_t mask = 1 << (block_index);
500+
size_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % BLOCKS_PER_SECTOR;
501+
uint32_t mask = 1 << (block_index);
501502
// We're reading from the currently cached sector.
502503
if (current_sector == this_sector && (mask & dirty_mask) > 0) {
503504
if (flash_cache_table != NULL) {
504-
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
505-
for (int i = 0; i < pages_per_block; i++) {
505+
for (int i = 0; i < PAGES_PER_BLOCK; i++) {
506506
memcpy(dest + i * SPI_FLASH_PAGE_SIZE,
507-
flash_cache_table[block_index * pages_per_block + i],
507+
flash_cache_table[block_index * PAGES_PER_BLOCK + i],
508508
SPI_FLASH_PAGE_SIZE);
509509
}
510510
return true;
@@ -527,8 +527,8 @@ static bool external_flash_write_block(const uint8_t *data, uint32_t block) {
527527
wait_for_flash_ready();
528528
// Mask out the lower bits that designate the address within the sector.
529529
uint32_t this_sector = address & (~(SPI_FLASH_ERASE_SIZE - 1));
530-
uint8_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % (SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE);
531-
uint8_t mask = 1 << (block_index);
530+
size_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % BLOCKS_PER_SECTOR;
531+
uint32_t mask = 1 << (block_index);
532532
// Flush the cache if we're moving onto a sector or we're writing the
533533
// same block again.
534534
if (current_sector != this_sector || (mask & dirty_mask) > 0) {
@@ -550,9 +550,8 @@ static bool external_flash_write_block(const uint8_t *data, uint32_t block) {
550550
dirty_mask |= mask;
551551
// Copy the block to the appropriate cache.
552552
if (flash_cache_table != NULL) {
553-
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
554-
for (int i = 0; i < pages_per_block; i++) {
555-
memcpy(flash_cache_table[block_index * pages_per_block + i],
553+
for (int i = 0; i < PAGES_PER_BLOCK; i++) {
554+
memcpy(flash_cache_table[block_index * PAGES_PER_BLOCK + i],
556555
data + i * SPI_FLASH_PAGE_SIZE,
557556
SPI_FLASH_PAGE_SIZE);
558557
}

0 commit comments

Comments
 (0)