@@ -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);
}
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@lst.de> Link: https://lore.kernel.org/linux-mmc/20240122073423.GA25859@lst.de/ Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- drivers/mmc/host/sh_mmcif.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)