How to reproduce it: 1. The value of "s->blksie" was 0x7200. The bits[14:12] was "111", so the buffer boundary was 0x80000.(512Kbytes). This SDMA buffer boundary was the same as u-boot default value. The bit[11:0] was "001000000000", so the block size was 0x200.(512bytes) 2. The SDMA address was 0x83123456 which was not page aligned and "s->sdmasysad % boundary_chk" was 0x23456. The value of boundary_count was 0x5cbaa.("boundary_chk - (s->sdmasysad % boundary_chk)" --> "(0x80000 - 0x23456)")
However, boundary_count did not align the block size 512 bytes and the SDMA address was not page aligned(0x80000), so the following if-statement never be true, ``` if (((boundary_count + begin) < block_size) && page_aligned) ```` Finally, it caused boundary_count overflow because its data type was uint32_t. Ex: the last boundary_count was 0x1aa and "0x1aa - 0x200" became "0xffffffaa". It is the wrong behavior. To fix it, change to check boundary_count smaller than block size if system address did not page align Signed-off-by: Jamin Lin <jamin_...@aspeedtech.com> --- hw/sd/sdhci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 37875c02c3..f1a329fdaf 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -618,7 +618,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) sdbus_read_data(&s->sdbus, s->fifo_buffer, block_size); } begin = s->data_count; - if (((boundary_count + begin) < block_size) && page_aligned) { + if (((boundary_count + begin) < block_size) && !page_aligned) { s->data_count = boundary_count + begin; boundary_count = 0; } else { @@ -634,7 +634,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) if (s->data_count == block_size) { s->data_count = 0; } - if (page_aligned && boundary_count == 0) { + if (boundary_count == 0) { break; } } @@ -642,7 +642,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) s->prnsts |= SDHC_DOING_WRITE; while (s->blkcnt) { begin = s->data_count; - if (((boundary_count + begin) < block_size) && page_aligned) { + if (((boundary_count + begin) < block_size) && !page_aligned) { s->data_count = boundary_count + begin; boundary_count = 0; } else { @@ -659,7 +659,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) s->blkcnt--; } } - if (page_aligned && boundary_count == 0) { + if (boundary_count == 0) { break; } } -- 2.34.1