[PATCH] Fix folio conversion in __dma_page_dev_to_cpu()
Matthew Wilcox (Oracle)
willy at infradead.org
Wed Aug 23 12:18:52 PDT 2023
Russell and Marek pointed out some assumptions I was making about how sg
lists work; eg that they are limited to 2GB and that the initial offset
lies within the first page (or at least within the first folio that a
page belongs to). While I think those assumptions are true, it's not
too hard to write a version which does not have those assumptions and
also calculates folio_size() only once per loop iteration.
---
arch/arm/mm/dma-mapping.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 0474840224d9..5409225b4abc 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -695,7 +695,6 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
{
- struct folio *folio = page_folio(page);
phys_addr_t paddr = page_to_phys(page) + off;
/* FIXME: non-speculating: not required */
@@ -710,18 +709,19 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
* Mark the D-cache clean for these pages to avoid extra flushing.
*/
if (dir != DMA_TO_DEVICE && size >= PAGE_SIZE) {
- ssize_t left = size;
+ struct folio *folio = pfn_folio(paddr / PAGE_SIZE);
size_t offset = offset_in_folio(folio, paddr);
- if (offset) {
- left -= folio_size(folio) - offset;
- folio = folio_next(folio);
- }
+ for (;;) {
+ size_t sz = folio_size(folio) - offset;
- while (left >= (ssize_t)folio_size(folio)) {
- left -= folio_size(folio);
- set_bit(PG_dcache_clean, &folio->flags);
- if (!left)
+ if (size < sz)
+ break;
+ if (!offset)
+ set_bit(PG_dcache_clean, &folio->flags);
+ offset = 0;
+ size -= sz;
+ if (!size)
break;
folio = folio_next(folio);
}
--
2.40.1
More information about the linux-arm-kernel
mailing list