Use kmap_local_page() instead of sg_virt() to obtain a page from the scatterlist: sg_virt() will not perform bounce buffering if the page happens to be located in high memory, which the driver may or may not be using. This code is a bit asynchronous due to being called repeatedly from an interrupt handler, so it would be great if someone can test this. Suggested-by: Christoph Hellwig <hch@xxxxxx> Link: https://lore.kernel.org/linux-mmc/20240122073423.GA25859@xxxxxx/ Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> --- drivers/mmc/host/sh_mmcif.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 077d711e964e..f9f56d653ff4 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -611,13 +611,27 @@ static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p) if (host->sg_blkidx == data->sg->length) { host->sg_blkidx = 0; + /* Unmap previous sg and map the next one */ + if (host->pio_ptr) { + kunmap_local(host->pio_ptr); + host->pio_ptr = NULL; + } if (++host->sg_idx < data->sg_len) - host->pio_ptr = sg_virt(++data->sg); + host->pio_ptr = kmap_local_page(sg_page(++data->sg)); } else { host->pio_ptr = p; } - return host->sg_idx != data->sg_len; + /* + * We return true of there are more blocks, and false if there is no + * next block. + */ + if (host->sg_idx != data->sg_len) + return true; + /* Unmap the last buffer if any */ + if (host->pio_ptr) + kunmap_local(host->pio_ptr); + return false; } static void sh_mmcif_single_read(struct sh_mmcif_host *host, @@ -669,7 +683,7 @@ static void sh_mmcif_multi_read(struct sh_mmcif_host *host, host->wait_for = MMCIF_WAIT_FOR_MREAD; host->sg_idx = 0; host->sg_blkidx = 0; - host->pio_ptr = sg_virt(data->sg); + host->pio_ptr = kmap_local_page(sg_page(data->sg)); sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); } @@ -749,7 +763,7 @@ static void sh_mmcif_multi_write(struct sh_mmcif_host *host, host->wait_for = MMCIF_WAIT_FOR_MWRITE; host->sg_idx = 0; host->sg_blkidx = 0; - host->pio_ptr = sg_virt(data->sg); + host->pio_ptr = kmap_local_page(sg_page(data->sg)); sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); } -- 2.34.1