Skip to content

Commit

Permalink
feat(nvram): add support for flash with double-word write unit
Browse files Browse the repository at this point in the history
  • Loading branch information
ssimek committed Nov 16, 2024
1 parent 140e38a commit 9bad4d8
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 91 deletions.
8 changes: 8 additions & 0 deletions targets/all/nvram/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,23 @@ Packed<Block::CheckResult> Block::CheckPagesImpl() const

bool Block::Format(uint32_t gen) const
{
#if NVRAM_FLASH_DOUBLE_WRITE
if (Flash::WriteDouble(&magic, Magic, gen))
#else
if (Flash::WriteWord(&magic, Magic) &&
Flash::WriteWord(&generation, gen))
#endif
{
MYDBG("Formatted sector gen %d @ %08X", gen, this);
return true;
}

#if NVRAM_FLASH_DOUBLE_WRITE
Flash::ShredDouble(&magic);
#else
Flash::ShredWord(&generation);
Flash::ShredWord(&magic);
#endif
MYDBG("ERROR - Failed to format sector gen %d @ %08X", gen, this);
return false;
}
Expand Down
19 changes: 18 additions & 1 deletion targets/all/nvram/Layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,19 @@ constexpr size_t PagesKeptFree = NVRAM_PAGES_KEPT_FREE;
constexpr size_t PagesKeptFree = 4;
#endif

#if NVRAM_FLASH_DOUBLE_WRITE
//! Write alignment
constexpr size_t WriteAlignment = 8;
#else
//! Write alignment
constexpr size_t WriteAlignment = 4;
#endif

//! Align size
constexpr size_t RequiredAligned(size_t size) { return (size + WriteAlignment - 1) & ~(WriteAlignment - 1); }

//! Size of individual pages
constexpr size_t PageSize = (BlockSize - BlockHeader) / PagesPerBlock & ~(sizeof(uintptr_t) - 1);
constexpr size_t PageSize = (BlockSize - BlockHeader) / PagesPerBlock & ~(WriteAlignment - 1);

//! Page header length
constexpr size_t PageHeader = 8;
Expand All @@ -52,4 +63,10 @@ constexpr size_t PagePayload = PageSize - PageHeader;
//! Padding at the end of the block
constexpr size_t BlockPadding = BlockSize - BlockHeader - PagesPerBlock * PageSize;

#if NVRAM_FLASH_DOUBLE_WRITE
inline void _ShredWordOrDouble(const void* ptr) { Flash::ShredDouble(ptr); }
#else
inline void _ShredWordOrDouble(const void* ptr) { Flash::ShredWord(ptr); }
#endif

}
61 changes: 53 additions & 8 deletions targets/all/nvram/Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,12 @@ bool Manager::Initialize(Span area, InitFlags flags)

// mark it for erasure
MYDBG("ERROR - Failed to complete block initialization @ %08X", blk);
#if NVRAM_FLASH_DOUBLE_WRITE
Flash::ShredDouble(&blk->magic);
#else
Flash::ShredWord(&blk->generation);
Flash::ShredWord(&blk->magic);
#endif
}
else
{
Expand All @@ -108,8 +112,7 @@ bool Manager::Initialize(Span area, InitFlags flags)
{
// mark a block with only erasable pages as erasable
MYDBG("WARNING - Block with no used nor free pages found after reset @ %08X", blk);
Flash::ShredWord(&blk->magic);
blocksToErase = true;
EraseBlock(blk);
}
else
{
Expand All @@ -136,8 +139,12 @@ bool Manager::Initialize(Span area, InitFlags flags)
{
// unless marked erasable, there is something wrong with the block (e.g. interrupted erase operation)
MYDBG("WARNING - Corrupted block @ %08X", blk);
#if NVRAM_FLASH_DOUBLE_WRITE
Flash::ShredDouble(&blk->magic);
#else
Flash::ShredWord(&blk->generation);
Flash::ShredWord(&blk->magic);
#endif
blocksToErase = true;
}
}
Expand Down Expand Up @@ -233,8 +240,12 @@ const Page* Manager::NewPage(ID id, uint32_t recordSize)
}

// try to prepare a page
#if NVRAM_FLASH_DOUBLE_WRITE
if (Flash::WriteDouble((const uint32_t*)&free->id, id, w0))
#else
if (Flash::WriteWord(&free->sequence, w0) &&
Flash::WriteWord((const uint32_t*)&free->id, id))
#endif
{
if (recordSize)
{
Expand All @@ -254,7 +265,7 @@ const Page* Manager::NewPage(ID id, uint32_t recordSize)
}

// mark the page as bad
Flash::ShredWord(free);
_ShredWordOrDouble(free);
MYDBG("ERROR - Failed to format page %.4s-%d @ %08X", &id, seq, free);

for (free++; free != free->Block()->end(); free++)
Expand All @@ -265,7 +276,7 @@ const Page* Manager::NewPage(ID id, uint32_t recordSize)
if (free->id == ~0u)
{
MYDBG("Marking corrupted page @ %08X", free);
Flash::ShredWord(free);
_ShredWordOrDouble(free);
}
}

Expand All @@ -286,7 +297,7 @@ const Page* Manager::NewPage(ID id, uint32_t recordSize)
{
// mark the page as bad
MYDBG("Marking corrupted page @ %08X", p);
Flash::ShredWord(&p);
_ShredWordOrDouble(&p);
}
else
{
Expand Down Expand Up @@ -414,7 +425,19 @@ async_def(const Block* block; uint32_t gen)
{
if (f.block->IsErasable())
{
#if NVRAM_FLASH_DOUBLE_WRITE
if (BlockPadding)
{
auto pb = (const Block*)f.block->padding;
f.gen = pb->magic == Block::Magic ? pb->generation : 0;
}
else
{
f.gen = 0;
}
#else
f.gen = f.block->generation;
#endif

for (;;)
{
Expand All @@ -437,8 +460,12 @@ async_def(const Block* block; uint32_t gen)
}

// something has gone wrong, mark block for another erasure attempt
#if NVRAM_FLASH_DOUBLE_WRITE
Flash::ShredDouble(&f.block->magic);
#else
Flash::ShredWord(&f.block->generation);
Flash::ShredWord(&f.block->magic);
#endif
}
}

Expand Down Expand Up @@ -538,15 +565,33 @@ size_t Manager::EraseAll(ID id)

void Manager::ErasePage(const Page* page)
{
Flash::ShredWord(&page->id);
_ShredWordOrDouble(&page->id);

// mark the entire block erasable if it contains only erasable pages
auto* b = page->Block();
if (page->Block()->CheckPages().flags == Block::PagesErasable)
{
Flash::ShredWord(&b->magic);
blocksToErase = true;
EraseBlock(b);
}
}

void Manager::EraseBlock(const Block* block)
{
#if NVRAM_FLASH_DOUBLE_WRITE
if (BlockPadding)
{
// copy header to padding to preserve generation numbering
Flash::WriteDouble(block->padding, block->magic, block->generation);
}
else
{
MYDBG("WARNING - losing block generation number because there is no padding available to preserve it, consider alternate layout");
}
Flash::ShredDouble(&block->magic);
#else
Flash::ShredWord(&block->magic);
#endif
blocksToErase = true;
}

}
2 changes: 2 additions & 0 deletions targets/all/nvram/Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ class Manager
async(EraseBlocks);
//! Marks a page (and, if possible, the block that holds it) for erasure
void ErasePage(const Page* page);
//! Marks a block for erasure
void EraseBlock(const Block* block);
};

extern Manager _manager;
Expand Down
Loading

0 comments on commit 9bad4d8

Please sign in to comment.