Properly clear erase-block selection when bigger block is chosen
When we choose to erase a bigger block over many smaller sub blocks,
we should clear the `selected' status of sub blocks recursively. If
not, we risk to miss sub blocks that haven't been consolidated in an
intermediate level of erase blocks.
For instance, considering a flash chip with three erase functions:
32x 4KiB sectors
4x 32KiB blocks
1x 128KiB chip
With the following erase pattern at the lowest, 4KiB level (`x' for
a block that is selected for erase, `.' for one left untouched):
xxx..xxx ..x..x.. xxxxxxxx x.x..... 4KiB
At the intermediate level, we would consolidate those 32KiB blocks
that get more than half of their sub blocks erased:
........ ..x..x.. ........ x.x..... 4KiB
x . x . 32KiB
Still more than half of the flash gets erased, so we would consoli-
date this to a full chip erase:
........ ........ ........ ........ 4KiB
. . . . 32KiB
x 128KiB
The current implementation, however, wouldn't clear the remaining
selected blocks at the 4KiB level.
Change-Id: I90181f9c53ca9aa06d353ba6dd4072efbebc260c
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/161
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/flashprog.c b/flashprog.c
index 859537b..704fd2e 100644
--- a/flashprog.c
+++ b/flashprog.c
@@ -1040,6 +1040,19 @@
return layout_idx;
}
+static void deselect_erase_block_rec(const struct erase_layout *layout, size_t findex, size_t block_num)
+{
+ struct eraseblock_data *const ed = &layout[findex].layout_list[block_num];
+ size_t i;
+
+ if (ed->selected) {
+ ed->selected = false;
+ } else if (findex > 0) {
+ for (i = ed->first_sub_block_index; i <= ed->last_sub_block_index; ++i)
+ deselect_erase_block_rec(layout, findex - 1, i);
+ }
+}
+
/*
* @brief Function to select the list of sectors that need erasing
*
@@ -1083,8 +1096,7 @@
if (bytes > eraseblock_size / 2) {
if (ll->start_addr >= info->region_start && ll->end_addr <= info->region_end) {
- for (j = sub_block_start; j <= sub_block_end; j++)
- layout[findex - 1].layout_list[j].selected = false;
+ deselect_erase_block_rec(layout, findex, block_num);
ll->selected = true;
bytes = eraseblock_size;
}