mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/1] Workaround for partial huge page unmaps in Panthor
@ 2025-12-13 19:08 Adrián Larumbe
  2025-12-13 19:08 ` [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages Adrián Larumbe
  0 siblings, 1 reply; 5+ messages in thread
From: Adrián Larumbe @ 2025-12-13 19:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: dri-devel, Steven Price, Boris Brezillon, kernel, Adrián Larumbe

This is v3 of [1]. This patch is a workaround for performing partial unmaps of a VM region backed
by huge pages. Since these are now disallowed, the patch makes sure unmaps are done on a backing
page-granularity, and then regions untouched by the VM_BIND unmap operation are restored.

A patch series with IGT tests to validate this functionality is found at [2].

Changelog:
v3:
 - Reworked address logic so that prev and next gpuava_op's va's are used in the calculations
   instead of those of the original unmap vma.
 - Got rid of the return struct from get_map_unmap_intervals() and now reckon panthor_vm_map_pages()
   arguments by fiddlign with the gpuva's respective gem object offsets.
 - Use folio_size() instead of folio_order() because the latter implies page sizes from the
   CPU's MMU perspective, rather than that of the GPU.

v2:
 - Fixed bug caused by confusion between semantics of gpu_va prev and next ops boundaries
   and those of the original vma object.
 - Coalesce all unmap operations into a single one.
 - Refactored and simplified code.

[1] https://lore.kernel.org/dri-devel/20251127035021.624045-1-adrian.larumbe@collabora.com/
[2] https://lore.kernel.org/igt-dev/20251213190205.2435793-1-adrian.larumbe@collabora.com/T/#t


Adrián Larumbe (1):
  drm/panthor: Support partial unmaps of huge pages

 drivers/gpu/drm/panthor/panthor_mmu.c | 66 +++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

--
2.51.2

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages
  2025-12-13 19:08 [PATCH v3 0/1] Workaround for partial huge page unmaps in Panthor Adrián Larumbe
@ 2025-12-13 19:08 ` Adrián Larumbe
  2025-12-14  9:39   ` Boris Brezillon
  2025-12-14  9:48   ` Boris Brezillon
  0 siblings, 2 replies; 5+ messages in thread
From: Adrián Larumbe @ 2025-12-13 19:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: dri-devel, Steven Price, Boris Brezillon, kernel,
	Adrián Larumbe, Liviu Dudau, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter

Commit 33729a5fc0ca ("iommu/io-pgtable-arm: Remove split on unmap
behavior") did away with the treatment of partial unmaps of huge IOPTEs.

In the case of Panthor, that means an attempt to run a VM_BIND unmap
operation on a memory region whose start address and size aren't 2MiB
aligned, in the event it intersects with a huge page, would lead to ARM
IOMMU management code to fail and a warning being raised.

Presently, and for lack of a better alternative, it's best to have
Panthor handle partial unmaps at the driver level, by unmapping entire
huge pages and remapping the difference between them and the requested
unmap region.

This could change in the future when the VM_BIND uAPI is expanded to
enforce huge page alignment and map/unmap operational constraints that
render this code unnecessary.

Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_mmu.c | 66 +++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 183da30fa500..f11340a7f59e 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -2110,6 +2110,44 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv)
 	return 0;
 }
 
+static bool
+iova_mapped_as_huge_page(const struct panthor_vma *vma, u64 addr)
+{
+	const struct page *pg;
+	pgoff_t bo_offset;
+
+	bo_offset = addr - vma->base.va.addr + vma->base.gem.offset;
+	pg = to_panthor_bo(vma->base.gem.obj)->base.pages[bo_offset >> PAGE_SHIFT];
+
+	return (folio_size(page_folio(pg)) >= SZ_2M);
+}
+
+static void
+get_map_unmap_intervals(const struct drm_gpuva_op_remap *op,
+			const struct panthor_vma *unmap_vma,
+			u64 *unmap_start, u64 *unmap_range)
+{
+	u64 aligned_unmap_start, aligned_unmap_end, unmap_end;
+
+	drm_gpuva_op_remap_to_unmap_range(op, unmap_start, unmap_range);
+	unmap_end = *unmap_start + *unmap_range;
+
+	aligned_unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
+	if (op->prev && aligned_unmap_start < *unmap_start &&
+	    op->prev->va.addr <= aligned_unmap_start &&
+	    iova_mapped_as_huge_page(unmap_vma, *unmap_start)) {
+		*unmap_range += *unmap_start - aligned_unmap_start;
+		*unmap_start = aligned_unmap_start;
+	}
+
+	aligned_unmap_end = ALIGN(unmap_end, SZ_2M);
+	if (op->next && aligned_unmap_end > unmap_end &&
+	    op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
+	    iova_mapped_as_huge_page(unmap_vma, unmap_end - 1)) {
+		*unmap_range += aligned_unmap_end - unmap_end;
+	}
+}
+
 static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
 				       void *priv)
 {
@@ -2121,16 +2159,44 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
 	int ret;
 
 	drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range);
+
+	/*
+	 * ARM IOMMU page table management code disallows partial unmaps of huge pages,
+	 * so when a partial unmap is requested, we must first unmap the entire huge
+	 * page and then remap the difference between the huge page minus the requested
+	 * unmap region. Calculating the right offsets and ranges for the different unmap
+	 * and map operations is the responsibility of the following function.
+	 */
+	get_map_unmap_intervals(&op->remap, unmap_vma, &unmap_start, &unmap_range);
+
 	ret = panthor_vm_unmap_pages(vm, unmap_start, unmap_range);
 	if (ret)
 		return ret;
 
 	if (op->remap.prev) {
+		ret = panthor_vm_map_pages(vm, unmap_start,
+					   flags_to_prot(unmap_vma->flags),
+					   to_drm_gem_shmem_obj(op->remap.prev->gem.obj)->sgt,
+					   op->remap.prev->gem.offset +
+					   (unmap_start - op->remap.prev->va.addr),
+					   op->remap.prev->va.addr + op->remap.prev->va.range -
+					   unmap_start);
+		if (ret)
+			return ret;
+
 		prev_vma = panthor_vm_op_ctx_get_vma(op_ctx);
 		panthor_vma_init(prev_vma, unmap_vma->flags);
 	}
 
 	if (op->remap.next) {
+		ret = panthor_vm_map_pages(vm, op->remap.next->va.addr,
+					   flags_to_prot(unmap_vma->flags),
+					   to_drm_gem_shmem_obj(op->remap.next->gem.obj)->sgt,
+					   op->remap.next->gem.offset,
+					   unmap_start + unmap_range - op->remap.next->va.addr);
+		if (ret)
+			return ret;
+
 		next_vma = panthor_vm_op_ctx_get_vma(op_ctx);
 		panthor_vma_init(next_vma, unmap_vma->flags);
 	}
-- 
2.51.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages
  2025-12-13 19:08 ` [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages Adrián Larumbe
@ 2025-12-14  9:39   ` Boris Brezillon
  2025-12-14 11:05     ` Adrián Larumbe
  2025-12-14  9:48   ` Boris Brezillon
  1 sibling, 1 reply; 5+ messages in thread
From: Boris Brezillon @ 2025-12-14  9:39 UTC (permalink / raw)
  To: Adrián Larumbe
  Cc: linux-kernel, dri-devel, Steven Price, kernel, Liviu Dudau,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter

On Sat, 13 Dec 2025 19:08:33 +0000
Adrián Larumbe <adrian.larumbe@collabora.com> wrote:

> Commit 33729a5fc0ca ("iommu/io-pgtable-arm: Remove split on unmap
> behavior") did away with the treatment of partial unmaps of huge IOPTEs.
> 
> In the case of Panthor, that means an attempt to run a VM_BIND unmap
> operation on a memory region whose start address and size aren't 2MiB
> aligned, in the event it intersects with a huge page, would lead to ARM
> IOMMU management code to fail and a warning being raised.
> 
> Presently, and for lack of a better alternative, it's best to have
> Panthor handle partial unmaps at the driver level, by unmapping entire
> huge pages and remapping the difference between them and the requested
> unmap region.
> 
> This could change in the future when the VM_BIND uAPI is expanded to
> enforce huge page alignment and map/unmap operational constraints that
> render this code unnecessary.
> 
> Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
> ---
>  drivers/gpu/drm/panthor/panthor_mmu.c | 66 +++++++++++++++++++++++++++
>  1 file changed, 66 insertions(+)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
> index 183da30fa500..f11340a7f59e 100644
> --- a/drivers/gpu/drm/panthor/panthor_mmu.c
> +++ b/drivers/gpu/drm/panthor/panthor_mmu.c
> @@ -2110,6 +2110,44 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv)
>  	return 0;
>  }
>  
> +static bool
> +iova_mapped_as_huge_page(const struct panthor_vma *vma, u64 addr)
> +{
> +	const struct page *pg;
> +	pgoff_t bo_offset;
> +
> +	bo_offset = addr - vma->base.va.addr + vma->base.gem.offset;
> +	pg = to_panthor_bo(vma->base.gem.obj)->base.pages[bo_offset >> PAGE_SHIFT];
> +
> +	return (folio_size(page_folio(pg)) >= SZ_2M);

nit: you can drop the extra ()

	return folio_size(page_folio(pg)) >= SZ_2M;

> +}
> +
> +static void
> +get_map_unmap_intervals(const struct drm_gpuva_op_remap *op,
> +			const struct panthor_vma *unmap_vma,
> +			u64 *unmap_start, u64 *unmap_range)
> +{
> +	u64 aligned_unmap_start, aligned_unmap_end, unmap_end;
> +
> +	drm_gpuva_op_remap_to_unmap_range(op, unmap_start, unmap_range);
> +	unmap_end = *unmap_start + *unmap_range;
> +
> +	aligned_unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
> +	if (op->prev && aligned_unmap_start < *unmap_start &&
> +	    op->prev->va.addr <= aligned_unmap_start &&
> +	    iova_mapped_as_huge_page(unmap_vma, *unmap_start)) {
> +		*unmap_range += *unmap_start - aligned_unmap_start;
> +		*unmap_start = aligned_unmap_start;
> +	}
> +
> +	aligned_unmap_end = ALIGN(unmap_end, SZ_2M);
> +	if (op->next && aligned_unmap_end > unmap_end &&
> +	    op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
> +	    iova_mapped_as_huge_page(unmap_vma, unmap_end - 1)) {
> +		*unmap_range += aligned_unmap_end - unmap_end;
> +	}
> +}
> +
>  static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
>  				       void *priv)
>  {
> @@ -2121,16 +2159,44 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
>  	int ret;
>  
>  	drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range);
> +
> +	/*
> +	 * ARM IOMMU page table management code disallows partial unmaps of huge pages,
> +	 * so when a partial unmap is requested, we must first unmap the entire huge
> +	 * page and then remap the difference between the huge page minus the requested
> +	 * unmap region. Calculating the right offsets and ranges for the different unmap
> +	 * and map operations is the responsibility of the following function.
> +	 */
> +	get_map_unmap_intervals(&op->remap, unmap_vma, &unmap_start, &unmap_range);

Unfortunately, after 5b8fcf4777e7 ("drm/panthor: Add support for atomic
page table updates"), that's not enough, you also need to extend the
locked region (see [1]).

> +
>  	ret = panthor_vm_unmap_pages(vm, unmap_start, unmap_range);
>  	if (ret)
>  		return ret;
>  
>  	if (op->remap.prev) {
> +		ret = panthor_vm_map_pages(vm, unmap_start,
> +					   flags_to_prot(unmap_vma->flags),
> +					   to_drm_gem_shmem_obj(op->remap.prev->gem.obj)->sgt,
> +					   op->remap.prev->gem.offset +
> +					   (unmap_start - op->remap.prev->va.addr),
> +					   op->remap.prev->va.addr + op->remap.prev->va.range -
> +					   unmap_start);
> +		if (ret)
> +			return ret;
> +
>  		prev_vma = panthor_vm_op_ctx_get_vma(op_ctx);
>  		panthor_vma_init(prev_vma, unmap_vma->flags);
>  	}
>  
>  	if (op->remap.next) {
> +		ret = panthor_vm_map_pages(vm, op->remap.next->va.addr,
> +					   flags_to_prot(unmap_vma->flags),
> +					   to_drm_gem_shmem_obj(op->remap.next->gem.obj)->sgt,
> +					   op->remap.next->gem.offset,
> +					   unmap_start + unmap_range - op->remap.next->va.addr);
> +		if (ret)
> +			return ret;
> +
>  		next_vma = panthor_vm_op_ctx_get_vma(op_ctx);
>  		panthor_vma_init(next_vma, unmap_vma->flags);
>  	}

[1]https://gitlab.freedesktop.org/bbrezillon/linux/-/commit/b4b677796c8c33b5be60184bca099ef8fd8c5548

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages
  2025-12-13 19:08 ` [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages Adrián Larumbe
  2025-12-14  9:39   ` Boris Brezillon
@ 2025-12-14  9:48   ` Boris Brezillon
  1 sibling, 0 replies; 5+ messages in thread
From: Boris Brezillon @ 2025-12-14  9:48 UTC (permalink / raw)
  To: Adrián Larumbe
  Cc: linux-kernel, dri-devel, Steven Price, kernel, Liviu Dudau,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter

On Sat, 13 Dec 2025 19:08:33 +0000
Adrián Larumbe <adrian.larumbe@collabora.com> wrote:

> Commit 33729a5fc0ca ("iommu/io-pgtable-arm: Remove split on unmap
> behavior") did away with the treatment of partial unmaps of huge IOPTEs.
> 
> In the case of Panthor, that means an attempt to run a VM_BIND unmap
> operation on a memory region whose start address and size aren't 2MiB
> aligned, in the event it intersects with a huge page, would lead to ARM
> IOMMU management code to fail and a warning being raised.
> 
> Presently, and for lack of a better alternative, it's best to have
> Panthor handle partial unmaps at the driver level, by unmapping entire
> huge pages and remapping the difference between them and the requested
> unmap region.
> 
> This could change in the future when the VM_BIND uAPI is expanded to
> enforce huge page alignment and map/unmap operational constraints that
> render this code unnecessary.
> 
> Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
> ---
>  drivers/gpu/drm/panthor/panthor_mmu.c | 66 +++++++++++++++++++++++++++
>  1 file changed, 66 insertions(+)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
> index 183da30fa500..f11340a7f59e 100644
> --- a/drivers/gpu/drm/panthor/panthor_mmu.c
> +++ b/drivers/gpu/drm/panthor/panthor_mmu.c
> @@ -2110,6 +2110,44 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv)
>  	return 0;
>  }
>  
> +static bool
> +iova_mapped_as_huge_page(const struct panthor_vma *vma, u64 addr)
> +{
> +	const struct page *pg;
> +	pgoff_t bo_offset;
> +
> +	bo_offset = addr - vma->base.va.addr + vma->base.gem.offset;
> +	pg = to_panthor_bo(vma->base.gem.obj)->base.pages[bo_offset >> PAGE_SHIFT];
> +
> +	return (folio_size(page_folio(pg)) >= SZ_2M);
> +}
> +
> +static void
> +get_map_unmap_intervals(const struct drm_gpuva_op_remap *op,
> +			const struct panthor_vma *unmap_vma,
> +			u64 *unmap_start, u64 *unmap_range)
> +{
> +	u64 aligned_unmap_start, aligned_unmap_end, unmap_end;
> +
> +	drm_gpuva_op_remap_to_unmap_range(op, unmap_start, unmap_range);
> +	unmap_end = *unmap_start + *unmap_range;
> +
> +	aligned_unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
> +	if (op->prev && aligned_unmap_start < *unmap_start &&
> +	    op->prev->va.addr <= aligned_unmap_start &&
> +	    iova_mapped_as_huge_page(unmap_vma, *unmap_start)) {
> +		*unmap_range += *unmap_start - aligned_unmap_start;
> +		*unmap_start = aligned_unmap_start;
> +	}
> +
> +	aligned_unmap_end = ALIGN(unmap_end, SZ_2M);
> +	if (op->next && aligned_unmap_end > unmap_end &&
> +	    op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
> +	    iova_mapped_as_huge_page(unmap_vma, unmap_end - 1)) {
> +		*unmap_range += aligned_unmap_end - unmap_end;
> +	}
> +}
> +
>  static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
>  				       void *priv)
>  {
> @@ -2121,16 +2159,44 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
>  	int ret;
>  
>  	drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range);
> +
> +	/*
> +	 * ARM IOMMU page table management code disallows partial unmaps of huge pages,
> +	 * so when a partial unmap is requested, we must first unmap the entire huge
> +	 * page and then remap the difference between the huge page minus the requested
> +	 * unmap region. Calculating the right offsets and ranges for the different unmap
> +	 * and map operations is the responsibility of the following function.
> +	 */
> +	get_map_unmap_intervals(&op->remap, unmap_vma, &unmap_start, &unmap_range);
> +
>  	ret = panthor_vm_unmap_pages(vm, unmap_start, unmap_range);

This needs to be rebased on drm-misc-next: the panthor_vm_unmap_pages()
prototype has changed there.

>  	if (ret)
>  		return ret;
>  
>  	if (op->remap.prev) {
> +		ret = panthor_vm_map_pages(vm, unmap_start,
> +					   flags_to_prot(unmap_vma->flags),
> +					   to_drm_gem_shmem_obj(op->remap.prev->gem.obj)->sgt,
> +					   op->remap.prev->gem.offset +
> +					   (unmap_start - op->remap.prev->va.addr),
> +					   op->remap.prev->va.addr + op->remap.prev->va.range -
> +					   unmap_start);
> +		if (ret)
> +			return ret;
> +
>  		prev_vma = panthor_vm_op_ctx_get_vma(op_ctx);
>  		panthor_vma_init(prev_vma, unmap_vma->flags);
>  	}
>  
>  	if (op->remap.next) {
> +		ret = panthor_vm_map_pages(vm, op->remap.next->va.addr,
> +					   flags_to_prot(unmap_vma->flags),
> +					   to_drm_gem_shmem_obj(op->remap.next->gem.obj)->sgt,
> +					   op->remap.next->gem.offset,
> +					   unmap_start + unmap_range - op->remap.next->va.addr);
> +		if (ret)
> +			return ret;
> +
>  		next_vma = panthor_vm_op_ctx_get_vma(op_ctx);
>  		panthor_vma_init(next_vma, unmap_vma->flags);
>  	}


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages
  2025-12-14  9:39   ` Boris Brezillon
@ 2025-12-14 11:05     ` Adrián Larumbe
  0 siblings, 0 replies; 5+ messages in thread
From: Adrián Larumbe @ 2025-12-14 11:05 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: linux-kernel, dri-devel, Steven Price, kernel, Liviu Dudau,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter

On 14.12.2025 10:39, Boris Brezillon wrote:
> On Sat, 13 Dec 2025 19:08:33 +0000
> Adrián Larumbe <adrian.larumbe@collabora.com> wrote:
>
> > Commit 33729a5fc0ca ("iommu/io-pgtable-arm: Remove split on unmap
> > behavior") did away with the treatment of partial unmaps of huge IOPTEs.
> >
> > In the case of Panthor, that means an attempt to run a VM_BIND unmap
> > operation on a memory region whose start address and size aren't 2MiB
> > aligned, in the event it intersects with a huge page, would lead to ARM
> > IOMMU management code to fail and a warning being raised.
> >
> > Presently, and for lack of a better alternative, it's best to have
> > Panthor handle partial unmaps at the driver level, by unmapping entire
> > huge pages and remapping the difference between them and the requested
> > unmap region.
> >
> > This could change in the future when the VM_BIND uAPI is expanded to
> > enforce huge page alignment and map/unmap operational constraints that
> > render this code unnecessary.
> >
> > Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
> > ---
> >  drivers/gpu/drm/panthor/panthor_mmu.c | 66 +++++++++++++++++++++++++++
> >  1 file changed, 66 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
> > index 183da30fa500..f11340a7f59e 100644
> > --- a/drivers/gpu/drm/panthor/panthor_mmu.c
> > +++ b/drivers/gpu/drm/panthor/panthor_mmu.c
> > @@ -2110,6 +2110,44 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv)
> >  	return 0;
> >  }
> >
> > +static bool
> > +iova_mapped_as_huge_page(const struct panthor_vma *vma, u64 addr)
> > +{
> > +	const struct page *pg;
> > +	pgoff_t bo_offset;
> > +
> > +	bo_offset = addr - vma->base.va.addr + vma->base.gem.offset;
> > +	pg = to_panthor_bo(vma->base.gem.obj)->base.pages[bo_offset >> PAGE_SHIFT];
> > +
> > +	return (folio_size(page_folio(pg)) >= SZ_2M);
>
> nit: you can drop the extra ()
>
> 	return folio_size(page_folio(pg)) >= SZ_2M;
>
> > +}
> > +
> > +static void
> > +get_map_unmap_intervals(const struct drm_gpuva_op_remap *op,
> > +			const struct panthor_vma *unmap_vma,
> > +			u64 *unmap_start, u64 *unmap_range)
> > +{
> > +	u64 aligned_unmap_start, aligned_unmap_end, unmap_end;
> > +
> > +	drm_gpuva_op_remap_to_unmap_range(op, unmap_start, unmap_range);
> > +	unmap_end = *unmap_start + *unmap_range;
> > +
> > +	aligned_unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
> > +	if (op->prev && aligned_unmap_start < *unmap_start &&
> > +	    op->prev->va.addr <= aligned_unmap_start &&
> > +	    iova_mapped_as_huge_page(unmap_vma, *unmap_start)) {
> > +		*unmap_range += *unmap_start - aligned_unmap_start;
> > +		*unmap_start = aligned_unmap_start;
> > +	}
> > +
> > +	aligned_unmap_end = ALIGN(unmap_end, SZ_2M);
> > +	if (op->next && aligned_unmap_end > unmap_end &&
> > +	    op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
> > +	    iova_mapped_as_huge_page(unmap_vma, unmap_end - 1)) {
> > +		*unmap_range += aligned_unmap_end - unmap_end;
> > +	}
> > +}
> > +
> >  static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
> >  				       void *priv)
> >  {
> > @@ -2121,16 +2159,44 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
> >  	int ret;
> >
> >  	drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range);
> > +
> > +	/*
> > +	 * ARM IOMMU page table management code disallows partial unmaps of huge pages,
> > +	 * so when a partial unmap is requested, we must first unmap the entire huge
> > +	 * page and then remap the difference between the huge page minus the requested
> > +	 * unmap region. Calculating the right offsets and ranges for the different unmap
> > +	 * and map operations is the responsibility of the following function.
> > +	 */
> > +	get_map_unmap_intervals(&op->remap, unmap_vma, &unmap_start, &unmap_range);
>
> Unfortunately, after 5b8fcf4777e7 ("drm/panthor: Add support for atomic
> page table updates"), that's not enough, you also need to extend the
> locked region (see [1]).

Oh yeah, completely forgot about that. Let me handle it and will send out v4 asap.

> > +
> >  	ret = panthor_vm_unmap_pages(vm, unmap_start, unmap_range);
> >  	if (ret)
> >  		return ret;
> >
> >  	if (op->remap.prev) {
> > +		ret = panthor_vm_map_pages(vm, unmap_start,
> > +					   flags_to_prot(unmap_vma->flags),
> > +					   to_drm_gem_shmem_obj(op->remap.prev->gem.obj)->sgt,
> > +					   op->remap.prev->gem.offset +
> > +					   (unmap_start - op->remap.prev->va.addr),
> > +					   op->remap.prev->va.addr + op->remap.prev->va.range -
> > +					   unmap_start);
> > +		if (ret)
> > +			return ret;
> > +
> >  		prev_vma = panthor_vm_op_ctx_get_vma(op_ctx);
> >  		panthor_vma_init(prev_vma, unmap_vma->flags);
> >  	}
> >
> >  	if (op->remap.next) {
> > +		ret = panthor_vm_map_pages(vm, op->remap.next->va.addr,
> > +					   flags_to_prot(unmap_vma->flags),
> > +					   to_drm_gem_shmem_obj(op->remap.next->gem.obj)->sgt,
> > +					   op->remap.next->gem.offset,
> > +					   unmap_start + unmap_range - op->remap.next->va.addr);
> > +		if (ret)
> > +			return ret;
> > +
> >  		next_vma = panthor_vm_op_ctx_get_vma(op_ctx);
> >  		panthor_vma_init(next_vma, unmap_vma->flags);
> >  	}
>
> [1]https://gitlab.freedesktop.org/bbrezillon/linux/-/commit/b4b677796c8c33b5be60184bca099ef8fd8c5548

Adrian Larumbe

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-12-14 11:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-13 19:08 [PATCH v3 0/1] Workaround for partial huge page unmaps in Panthor Adrián Larumbe
2025-12-13 19:08 ` [PATCH v3 1/1] drm/panthor: Support partial unmaps of huge pages Adrián Larumbe
2025-12-14  9:39   ` Boris Brezillon
2025-12-14 11:05     ` Adrián Larumbe
2025-12-14  9:48   ` Boris Brezillon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®