From: Christian Speich <[email protected]> When erasing blocks as zero, we can use optimized block functions to achieve this.
These allow us to request a large rage to be zeroed, possible optimizing this operation and freeing disk space for sparsesly stored images. This only is possible when erase-blocks-as-zero=true is used and can provide a significant performance boost. The case where 0xFF is used during erase is as slow as before. Signed-off-by: Christian Speich <[email protected]> Signed-off-by: Bernhard Beschow <[email protected]> --- hw/sd/sd.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index c40097924c..03c51b0291 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1322,6 +1322,26 @@ exit: trace_sdcard_rpmb_write_block(req, lduw_be_p(&sd->rpmb.result.result)); } +/* Requires sd->data to be filled with 0xFF */ +static void sd_erase_ff(SDState *sd, uint64_t addr, size_t len) +{ + int erase_len = 1 << HWBLOCK_SHIFT; + uint64_t erase_addr; + + for (erase_addr = addr; erase_addr < addr + len; erase_addr += erase_len) { + sd_blk_write(sd, sd->data, erase_addr, erase_len); + } +} + +static void sd_blk_erase(SDState *sd, uint64_t addr, size_t len) +{ + if (sd->erase_blocks_as_zero) { + blk_pwrite_zeroes(sd->blk, addr + sd_part_offset(sd), len, 0); + } else { + sd_erase_ff(sd, addr, len); + } +} + static void sd_erase(SDState *sd) { uint64_t erase_start = sd->erase_start; @@ -1329,7 +1349,6 @@ static void sd_erase(SDState *sd) bool sdsc = true; uint64_t wpnum; uint64_t erase_addr; - int erase_len = 1 << HWBLOCK_SHIFT; trace_sdcard_erase(sd->erase_start, sd->erase_end); if (sd->erase_start == INVALID_ADDRESS @@ -1358,24 +1377,28 @@ static void sd_erase(SDState *sd) sd->erase_end = INVALID_ADDRESS; sd->csd[14] |= 0x40; - if (sd->erase_blocks_as_zero) { - memset(sd->data, 0x0, erase_len); - } else { - memset(sd->data, 0xFF, erase_len); + if (!sd->erase_blocks_as_zero) { + memset(sd->data, 0xFF, 1 << HWBLOCK_SHIFT); } - for (erase_addr = erase_start; erase_addr <= erase_end; - erase_addr += erase_len) { - if (sdsc) { - /* Only SDSC cards support write protect groups */ + /* Only SDSC cards support write protect groups */ + if (sdsc) { + for (erase_addr = erase_start; erase_addr <= erase_end; + erase_addr = ROUND_UP(erase_addr + 1, WPGROUP_SIZE)) { + uint64_t wp_group_end = ROUND_UP(erase_addr + 1, WPGROUP_SIZE) - 1; + size_t erase_len = MIN(erase_end, wp_group_end) - erase_addr; + wpnum = sd_addr_to_wpnum(erase_addr); assert(wpnum < sd->wp_group_bits); if (test_bit(wpnum, sd->wp_group_bmap)) { sd->card_status |= WP_ERASE_SKIP; continue; } + + sd_blk_erase(sd, erase_addr, erase_len); } - sd_blk_write(sd, sd->data, erase_addr, erase_len); + } else { + sd_blk_erase(sd, erase_start, erase_end - erase_start); } } -- 2.56.0
