[PATCH v1 3/5] drm/pagemap: DMA map folios when possible
Matthew Brost
matthew.brost at intel.com
Fri Jul 18 04:21:32 UTC 2025
On Thu, Jul 17, 2025 at 03:38:25PM +0200, Francois Dugast wrote:
> If the page is part of a folio, DMA map the whole folio at once instead of
> mapping individual pages one after the other. For example if 2MB folios
> are used instead of 4KB pages, this reduces the number of DMA mappings by
> 512.
>
> The folio order (and consequently, the size) is persisted in the struct
> drm_pagemap_device_addr to be available at the time of unmapping.
>
> Signed-off-by: Francois Dugast <francois.dugast at intel.com>
> Cc: Matthew Brost <matthew.brost at intel.com>
> ---
> drivers/gpu/drm/drm_pagemap.c | 28 +++++++++++++++++++++-------
> 1 file changed, 21 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
> index 0ed66aaade14..de15d96f6393 100644
> --- a/drivers/gpu/drm/drm_pagemap.c
> +++ b/drivers/gpu/drm/drm_pagemap.c
> @@ -220,20 +220,31 @@ static int drm_pagemap_migrate_map_pages(struct device *dev,
> unsigned long npages,
> enum dma_data_direction dir)
> {
> - unsigned long i;
> + unsigned long i, j;
>
> - for (i = 0; i < npages; ++i) {
> + for (i = 0; i < npages;) {
> struct page *page = migrate_pfn_to_page(migrate_pfn[i]);
> + struct folio *folio;
> + unsigned int order;
>
> if (!page)
> - continue;
> + goto next;
>
> if (WARN_ON_ONCE(is_zone_device_page(page)))
> return -EFAULT;
>
> - device_addr[i].addr = dma_map_page(dev, page, 0, PAGE_SIZE, dir);
> + folio = page_folio(page);
> + order = folio_order(folio);
> + device_addr[i].addr = dma_map_page(dev, page, 0, page_size(page), dir);
> + device_addr[i].order = order;
Again, proto, dir.
> +
> if (dma_mapping_error(dev, device_addr[i].addr))
> return -EFAULT;
> +
> + for (j = 0; j < (0x1 << order) && i+j < npages; j++)
> + device_addr[i+j].addr = device_addr[i].addr + j * PAGE_SIZE;
I wouldn’t do this here. The Xe SVM copy functions expect a fully
populated drm_pagemap_addr, but we can hack around that there for now.
I’d prefer to keep this layer as clean as possible.
With that in mind, I’d update the kernel doc for the copy_to_ram and
copy_from_ram functions to indicate that if drm_pagemap_addr is higher
order, the subsequent entries within the range of that order are
expected to be unpopulated.
> +next:
> + i += 0x1 << order;
I wonder if there's a macro/function in Linux that does (0x1 << order).
If so, I'd use that. If not, add a local one to drm_pagemap.
Matt
> }
>
> return 0;
> @@ -257,11 +268,14 @@ static void drm_pagemap_migrate_unmap_pages(struct device *dev,
> {
> unsigned long i;
>
> - for (i = 0; i < npages; ++i) {
> + for (i = 0; i < npages;) {
> if (!device_addr[i].addr || dma_mapping_error(dev, device_addr[i].addr))
> - continue;
> + goto next;
> +
> + dma_unmap_page(dev, device_addr[i].addr, PAGE_SIZE << device_addr[i].order, dir);
>
> - dma_unmap_page(dev, device_addr[i].addr, PAGE_SIZE, dir);
> +next:
> + i += 0x1 << device_addr[i].order;
> }
> }
>
> --
> 2.43.0
>
More information about the Intel-xe
mailing list