diff --git a/erasure_layout.c b/erasure_layout.c index 56841ab32..7f3bb460d 100644 --- a/erasure_layout.c +++ b/erasure_layout.c @@ -189,6 +189,27 @@ static void align_region(const struct erase_layout *layout, struct flashctx *con } } +/* Deselect all the blocks from index_to_deselect and down to the smallest. */ +static void deselect_erase_functions(const struct erase_layout *layout, size_t index_to_deselect, + int sub_block_start, const int sub_block_end) +{ + for (int j = sub_block_start; j <= sub_block_end; j++) + layout[index_to_deselect].layout_list[j].selected = false; + + int block_start_to_deselect = + layout[index_to_deselect].layout_list[sub_block_start].first_sub_block_index; + int block_end_to_deselect = + layout[index_to_deselect].layout_list[sub_block_end].last_sub_block_index; + + if (index_to_deselect) + deselect_erase_functions(layout, + index_to_deselect - 1, + block_start_to_deselect, + block_end_to_deselect); + else + return; // index_to_deselect has already reached 0, the smallest size of block. we are done. +} + /* * @brief Function to select the list of sectors that need erasing * @@ -229,9 +250,17 @@ static void select_erase_functions(struct flashctx *flashctx, const struct erase const int total_blocks = sub_block_end - sub_block_start + 1; if (count == total_blocks) { + /* We are selecting one large block instead, so send opcode once + * instead of sending many smaller ones. + */ if (ll->start_addr >= rstart && ll->end_addr <= rend) { - for (int j = sub_block_start; j <= sub_block_end; j++) - layout[findex - 1].layout_list[j].selected = false; + /* Deselect all smaller blocks covering the same region. */ + deselect_erase_functions(layout, + findex - 1, + sub_block_start, + sub_block_end); + + /* Select large block. */ ll->selected = true; } }