* [PATCH 0/4] drm/panthor: Fix partial unmaps, again
@ 2026-09-17 12:33 Boris Brezillon
2026-09-17 12:33 ` [PATCH 1/4] drm/panthor: Avoid false positives in iova_mapped_as_huge_page() Boris Brezillon
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Boris Brezillon @ 2026-09-17 12:33 UTC (permalink / raw)
To: Steven Price, Liviu Dudau, Adrián Larumbe, Akash Goel
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel,
Boris Brezillon
The first patch is just a theoretical perf improvement to avoid
unnecessary unmap+map caused by false positive returned by
iova_mapped_as_huge_page(). The second patch is a fix for a real
bug when iova_mapped_as_huge_page() is called on an imported BO.
The last 2 patches are just consolidating the logic to make things
clearer.
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
Boris Brezillon (4):
drm/panthor: Avoid false positives in iova_mapped_as_huge_page()
drm/panthor: Fix iova_mapped_as_huge_page() for imported BOs
drm/panthor: Consolidate the is-huge-page-mapping test
drm/panthor: Actually check huge-page mapping on sparse regions
drivers/gpu/drm/panthor/panthor_mmu.c | 100 ++++++++++++++++++++++++----------
1 file changed, 71 insertions(+), 29 deletions(-)
---
base-commit: 5535d5e61a77ad79118ea7665ce1c14f857f0f12
change-id: 20260916-panthor-fix-partial-unmap-a52034f21184
Best regards,
--
Boris Brezillon <boris.brezillon@collabora.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/4] drm/panthor: Avoid false positives in iova_mapped_as_huge_page()
2026-09-17 12:33 [PATCH 0/4] drm/panthor: Fix partial unmaps, again Boris Brezillon
@ 2026-09-17 12:33 ` Boris Brezillon
2026-09-18 16:34 ` Akash Goel
2026-09-17 12:33 ` [PATCH 2/4] drm/panthor: Fix iova_mapped_as_huge_page() for imported BOs Boris Brezillon
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Boris Brezillon @ 2026-09-17 12:33 UTC (permalink / raw)
To: Steven Price, Liviu Dudau, Adrián Larumbe, Akash Goel
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel,
Boris Brezillon
The check on the folio size is actually moot if the BO offset matching
the VA we're checking huge-mapping for is not 2M aligned as well.
This means that we are sometimes returning true when we shouldn't, which
forces an extra unmap+map to deal with block-mapping splits. It's not
a functional bug per-se, because the unmap+map sequence will restore
things in the state we expect them to be, but it's better to properly
optimize those cases.
Note that we now align the VA on 2M address below it otherwise we can't
check the bo_offset alignment (both physical and virtual address need
to be aligned, in addition to the physically contiguous size being 2M,
which the folio size check ensures).
These changes force us to pass the drm_gpuva that's being unmapped
instead of the new mappings that will be created to cover the left/right
sections we remap. This changes makes the logic a lot easier to reason
about, because it doesn't make sense to how things were mapped by
passing the new mappings that are not yet in place.
Fixes: 8e7460eac786 ("drm/panthor: Support partial unmaps of huge pages")
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
drivers/gpu/drm/panthor/panthor_mmu.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 9f63a048df61..b0a7033480e6 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -2295,15 +2295,29 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv)
}
static bool
-iova_mapped_as_huge_page(struct drm_gpuva_op_map *op, u64 addr)
+iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
{
- struct panthor_gem_object *bo = to_panthor_bo(op->gem.obj);
+ struct panthor_gem_object *bo = to_panthor_bo(mapping->gem.obj);
+ u64 aligned_va = ALIGN_DOWN(va, SZ_2M);
const struct page *pg;
pgoff_t bo_offset;
- bo_offset = addr - op->va.addr + op->gem.offset;
+ /* If the 2M-aligned VA is outside the mapping being tested, we know
+ * it's not a huge map.
+ */
+ if (aligned_va < mapping->va.addr)
+ return false;
+
+ bo_offset = aligned_va - mapping->va.addr + mapping->gem.offset;
pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
+ /* In case of shmem backing, we know we can only have a huge mapping
+ * if the bo_offset is 2M aligned, meaning we can skip the folio size
+ * check if it's not the case.
+ */
+ if (!IS_ALIGNED(bo_offset, SZ_2M))
+ return false;
+
return folio_size(page_folio(pg)) >= SZ_2M;
}
@@ -2328,7 +2342,7 @@ unmap_hugepage_align(const struct drm_gpuva_op_remap *op,
*/
if (op->prev && aligned_unmap_start < *unmap_start &&
op->prev->va.addr <= aligned_unmap_start &&
- (is_sparse || iova_mapped_as_huge_page(op->prev, *unmap_start))) {
+ (is_sparse || iova_mapped_as_huge_page(op->unmap->va, *unmap_start))) {
*unmap_range += *unmap_start - aligned_unmap_start;
*unmap_start = aligned_unmap_start;
}
@@ -2338,7 +2352,7 @@ unmap_hugepage_align(const struct drm_gpuva_op_remap *op,
*/
if (op->next && aligned_unmap_end > unmap_end &&
op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
- (is_sparse || iova_mapped_as_huge_page(op->next, unmap_end - 1))) {
+ (is_sparse || iova_mapped_as_huge_page(op->unmap->va, unmap_end - 1))) {
*unmap_range += aligned_unmap_end - unmap_end;
}
}
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/4] drm/panthor: Fix iova_mapped_as_huge_page() for imported BOs
2026-09-17 12:33 [PATCH 0/4] drm/panthor: Fix partial unmaps, again Boris Brezillon
2026-09-17 12:33 ` [PATCH 1/4] drm/panthor: Avoid false positives in iova_mapped_as_huge_page() Boris Brezillon
@ 2026-09-17 12:33 ` Boris Brezillon
2026-09-18 16:35 ` Akash Goel
2026-09-17 12:33 ` [PATCH 3/4] drm/panthor: Consolidate the is-huge-page-mapping test Boris Brezillon
2026-09-17 12:33 ` [PATCH 4/4] drm/panthor: Actually check huge-page mapping on sparse regions Boris Brezillon
3 siblings, 1 reply; 9+ messages in thread
From: Boris Brezillon @ 2026-09-17 12:33 UTC (permalink / raw)
To: Steven Price, Liviu Dudau, Adrián Larumbe, Akash Goel
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel,
Boris Brezillon
Imported BOs have no backing.pages array allocated, leading to a NULL
deref when iova_mapped_as_huge_page() gets called on them.
Implement this check through and sgt walk to reach the position of the
sgt targeted by a VA, and check that the DMA address is properly aligned
and the size remaining in the SG entry is bigger than a huge page.
This is basically matching the logic in vm_map_pages(), with get_pgsize()
being replaced by a simpler test, because we don't care about the pgcount
info.
Reported-by: Akash Goel <akash.goel@arm.com>
Fixes: 8e7460eac786 ("drm/panthor: Support partial unmaps of huge pages")
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
drivers/gpu/drm/panthor/panthor_mmu.c | 44 ++++++++++++++++++++++++++++-------
1 file changed, 36 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index b0a7033480e6..6cef954e2cba 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -2299,7 +2299,6 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
{
struct panthor_gem_object *bo = to_panthor_bo(mapping->gem.obj);
u64 aligned_va = ALIGN_DOWN(va, SZ_2M);
- const struct page *pg;
pgoff_t bo_offset;
/* If the 2M-aligned VA is outside the mapping being tested, we know
@@ -2309,16 +2308,45 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
return false;
bo_offset = aligned_va - mapping->va.addr + mapping->gem.offset;
- pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
- /* In case of shmem backing, we know we can only have a huge mapping
- * if the bo_offset is 2M aligned, meaning we can skip the folio size
- * check if it's not the case.
- */
- if (!IS_ALIGNED(bo_offset, SZ_2M))
+ if (drm_gem_is_imported(&bo->base)) {
+ struct sg_table *sgt = bo->dmap.sgt;
+ struct scatterlist *sgl;
+ unsigned int count;
+
+ /* If this is an imported BO, we have to walk the SGT and
+ * check the dma address/size alignment to determine if it's
+ * a huge map or not.
+ */
+ for_each_sgtable_dma_sg(sgt, sgl, count) {
+ size_t len = sg_dma_len(sgl);
+ dma_addr_t daddr;
+
+ if (len <= bo_offset) {
+ bo_offset -= len;
+ continue;
+ }
+
+ len -= bo_offset;
+ daddr = sg_dma_address(sgl) + bo_offset;
+
+ return IS_ALIGNED(daddr, SZ_2M) &&
+ len >= SZ_2M;
+ }
+
return false;
+ } else {
+ const struct page *pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
- return folio_size(page_folio(pg)) >= SZ_2M;
+ /* In case of shmem backing, we know we can only have a huge mapping
+ * if the bo_offset is 2M aligned, meaning we can skip the folio size
+ * check if it's not the case.
+ */
+ if (!IS_ALIGNED(bo_offset, SZ_2M))
+ return false;
+
+ return folio_size(page_folio(pg)) >= SZ_2M;
+ }
}
static void
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/4] drm/panthor: Consolidate the is-huge-page-mapping test
2026-09-17 12:33 [PATCH 0/4] drm/panthor: Fix partial unmaps, again Boris Brezillon
2026-09-17 12:33 ` [PATCH 1/4] drm/panthor: Avoid false positives in iova_mapped_as_huge_page() Boris Brezillon
2026-09-17 12:33 ` [PATCH 2/4] drm/panthor: Fix iova_mapped_as_huge_page() for imported BOs Boris Brezillon
@ 2026-09-17 12:33 ` Boris Brezillon
2026-09-18 16:39 ` Akash Goel
2026-09-17 12:33 ` [PATCH 4/4] drm/panthor: Actually check huge-page mapping on sparse regions Boris Brezillon
3 siblings, 1 reply; 9+ messages in thread
From: Boris Brezillon @ 2026-09-17 12:33 UTC (permalink / raw)
To: Steven Price, Liviu Dudau, Adrián Larumbe, Akash Goel
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel,
Boris Brezillon
Right now the logic to determine whether a given VA in the drm_gpuva
being unmapped is a huge page mapping or not is scattered
in two functions: unmap_hugepage_align() and
iova_mapped_as_huge_page(). This makes it harder to reason about the
logic being implemented for very little gain (some simple checks being
done twice), so let's consolidate all the checks related to huge page
mapping testing in iova_mapped_as_huge_page() and leave
unmap_hugepage_align() as a simple user of this helper that aligns the
area to unmap based on the return of iova_mapped_as_huge_page().
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
drivers/gpu/drm/panthor/panthor_mmu.c | 57 +++++++++++++++++------------------
1 file changed, 28 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 6cef954e2cba..d2897099763e 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -2301,10 +2301,11 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
u64 aligned_va = ALIGN_DOWN(va, SZ_2M);
pgoff_t bo_offset;
- /* If the 2M-aligned VA is outside the mapping being tested, we know
- * it's not a huge map.
+ /* If the 2M section being tested is crossing the mapping boundary
+ * we know it's not a huge map.
*/
- if (aligned_va < mapping->va.addr)
+ if (aligned_va < mapping->va.addr ||
+ aligned_va + SZ_2M > mapping->va.addr + mapping->va.range)
return false;
bo_offset = aligned_va - mapping->va.addr + mapping->gem.offset;
@@ -2337,10 +2338,21 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
return false;
} else {
const struct page *pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
+ struct panthor_vma *vma = container_of(mapping, struct panthor_vma, base);
+ bool is_sparse = vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE;
- /* In case of shmem backing, we know we can only have a huge mapping
- * if the bo_offset is 2M aligned, meaning we can skip the folio size
- * check if it's not the case.
+ /* If the unmapped VMA stands for a sparse mapping, always
+ * assume the backing storage is a THP, since the overhead of
+ * unmapping 2MiB worth of 4KiB pages and remapping some of
+ * them is offset by the logic of working out whether it's
+ * the opposite case right below.
+ */
+ if (is_sparse)
+ return true;
+
+ /* In case of shmem backing, we know we can only have a huge
+ * mapping if the bo_offset is 2M aligned, meaning we can skip
+ * the folio size check if it's not the case.
*/
if (!IS_ALIGNED(bo_offset, SZ_2M))
return false;
@@ -2353,36 +2365,23 @@ static void
unmap_hugepage_align(const struct drm_gpuva_op_remap *op,
u64 *unmap_start, u64 *unmap_range)
{
- struct panthor_vma *unmap_vma = container_of(op->unmap->va, struct panthor_vma, base);
- bool is_sparse = unmap_vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE;
- u64 aligned_unmap_start, aligned_unmap_end, unmap_end;
-
- unmap_end = *unmap_start + *unmap_range;
- aligned_unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
- aligned_unmap_end = ALIGN(unmap_end, SZ_2M);
+ u64 unmap_end = *unmap_start + *unmap_range;
/* If we're dealing with a huge page, make sure the unmap region is
- * aligned on the start of the page. If the unmapped VMA stands for
- * a sparse mapping, always assume the backing storage is a THP, since
- * the overhead of unmapping 2MiB worth of 4KiB pages and remapping
- * some of them is offset by the logic of working out whether it's
- * the opposite case right below. This also holds true for op->next.
+ * aligned on the start of the page.
*/
- if (op->prev && aligned_unmap_start < *unmap_start &&
- op->prev->va.addr <= aligned_unmap_start &&
- (is_sparse || iova_mapped_as_huge_page(op->unmap->va, *unmap_start))) {
- *unmap_range += *unmap_start - aligned_unmap_start;
- *unmap_start = aligned_unmap_start;
- }
+ if (op->prev && !IS_ALIGNED(*unmap_start, SZ_2M) &&
+ iova_mapped_as_huge_page(op->unmap->va, *unmap_start))
+ *unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
/* If we're dealing with a huge page, make sure the unmap region is
* aligned on the end of the page.
*/
- if (op->next && aligned_unmap_end > unmap_end &&
- op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
- (is_sparse || iova_mapped_as_huge_page(op->unmap->va, unmap_end - 1))) {
- *unmap_range += aligned_unmap_end - unmap_end;
- }
+ if (op->next && !IS_ALIGNED(unmap_end, SZ_2M) &&
+ iova_mapped_as_huge_page(op->unmap->va, unmap_end - 1))
+ unmap_end = ALIGN(unmap_end, SZ_2M);
+
+ *unmap_range = unmap_end - *unmap_start;
}
static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/4] drm/panthor: Actually check huge-page mapping on sparse regions
2026-09-17 12:33 [PATCH 0/4] drm/panthor: Fix partial unmaps, again Boris Brezillon
` (2 preceding siblings ...)
2026-09-17 12:33 ` [PATCH 3/4] drm/panthor: Consolidate the is-huge-page-mapping test Boris Brezillon
@ 2026-09-17 12:33 ` Boris Brezillon
2026-09-18 16:48 ` Akash Goel
3 siblings, 1 reply; 9+ messages in thread
From: Boris Brezillon @ 2026-09-17 12:33 UTC (permalink / raw)
To: Steven Price, Liviu Dudau, Adrián Larumbe, Akash Goel
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel,
Boris Brezillon
With the recent changes to iova_mapped_as_huge_page(), the check for
huge-page mapping of sparse BOs is actually simple:
- for a sparse mapping, we know the BO offset any VA in this regions is
va & (SZ_2M - 1)
- the VA we're searching the BO offset for is the 2M-aligned
aligned_va value
This guarantees that the BO offset to check is always zero in that case.
This is simple enough to let the code check if page 0 is a huge page
and save the unmap+map dance when the dummy BO is not backed by a
a huge page. So let's do that and kill the comment that says it's too
complicated.
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
drivers/gpu/drm/panthor/panthor_mmu.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index d2897099763e..01564d250adf 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -2337,18 +2337,18 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
return false;
} else {
- const struct page *pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
struct panthor_vma *vma = container_of(mapping, struct panthor_vma, base);
bool is_sparse = vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE;
+ const struct page *pg;
- /* If the unmapped VMA stands for a sparse mapping, always
- * assume the backing storage is a THP, since the overhead of
- * unmapping 2MiB worth of 4KiB pages and remapping some of
- * them is offset by the logic of working out whether it's
- * the opposite case right below.
+ /* BO offset on a sparse mapping is chosen so that 2M-aligned
+ * VAs point to the start of the BO. Since aligned_va (the
+ * address we check huge-page against) is 2M-aligned, the BO
+ * offset is guaranteed to be zero.
+ * Check panthor_fix_sparse_map_offset() for more details.
*/
if (is_sparse)
- return true;
+ bo_offset = 0;
/* In case of shmem backing, we know we can only have a huge
* mapping if the bo_offset is 2M aligned, meaning we can skip
@@ -2357,6 +2357,7 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
if (!IS_ALIGNED(bo_offset, SZ_2M))
return false;
+ pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
return folio_size(page_folio(pg)) >= SZ_2M;
}
}
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] drm/panthor: Avoid false positives in iova_mapped_as_huge_page()
2026-09-17 12:33 ` [PATCH 1/4] drm/panthor: Avoid false positives in iova_mapped_as_huge_page() Boris Brezillon
@ 2026-09-18 16:34 ` Akash Goel
0 siblings, 0 replies; 9+ messages in thread
From: Akash Goel @ 2026-09-18 16:34 UTC (permalink / raw)
To: Boris Brezillon, Steven Price, Liviu Dudau, Adrián Larumbe
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel, nd
On 9/17/26 13:33, Boris Brezillon wrote:
> The check on the folio size is actually moot if the BO offset matching
> the VA we're checking huge-mapping for is not 2M aligned as well.
> This means that we are sometimes returning true when we shouldn't, which
> forces an extra unmap+map to deal with block-mapping splits. It's not
> a functional bug per-se, because the unmap+map sequence will restore
> things in the state we expect them to be, but it's better to properly
> optimize those cases.
>
> Note that we now align the VA on 2M address below it otherwise we can't
> check the bo_offset alignment (both physical and virtual address need
> to be aligned, in addition to the physically contiguous size being 2M,
> which the folio size check ensures).
>
> These changes force us to pass the drm_gpuva that's being unmapped
> instead of the new mappings that will be created to cover the left/right
> sections we remap. This changes makes the logic a lot easier to reason
> about, because it doesn't make sense to how things were mapped by
> passing the new mappings that are not yet in place.
>
> Fixes: 8e7460eac786 ("drm/panthor: Support partial unmaps of huge pages")
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
Thanks for this patch.
Looks good to me.
Nice idea to take advantage of the fact that shmem would attempt to
allocate a 2M folio only at 2M aligned offsets into the BO.
Reviewed-by: Akash Goel <akash.goel@arm.com>
> drivers/gpu/drm/panthor/panthor_mmu.c | 24 +++++++++++++++++++-----
> 1 file changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
> index 9f63a048df61..b0a7033480e6 100644
> --- a/drivers/gpu/drm/panthor/panthor_mmu.c
> +++ b/drivers/gpu/drm/panthor/panthor_mmu.c
> @@ -2295,15 +2295,29 @@ static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv)
> }
>
> static bool
> -iova_mapped_as_huge_page(struct drm_gpuva_op_map *op, u64 addr)
> +iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
> {
> - struct panthor_gem_object *bo = to_panthor_bo(op->gem.obj);
> + struct panthor_gem_object *bo = to_panthor_bo(mapping->gem.obj);
> + u64 aligned_va = ALIGN_DOWN(va, SZ_2M);
> const struct page *pg;
> pgoff_t bo_offset;
>
> - bo_offset = addr - op->va.addr + op->gem.offset;
> + /* If the 2M-aligned VA is outside the mapping being tested, we know
> + * it's not a huge map.
> + */
> + if (aligned_va < mapping->va.addr)
> + return false;
> +
> + bo_offset = aligned_va - mapping->va.addr + mapping->gem.offset;
> pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
>
> + /* In case of shmem backing, we know we can only have a huge mapping
> + * if the bo_offset is 2M aligned, meaning we can skip the folio size
> + * check if it's not the case.
> + */
> + if (!IS_ALIGNED(bo_offset, SZ_2M))
> + return false;
> +
> return folio_size(page_folio(pg)) >= SZ_2M;
> }
>
> @@ -2328,7 +2342,7 @@ unmap_hugepage_align(const struct drm_gpuva_op_remap *op,
> */
> if (op->prev && aligned_unmap_start < *unmap_start &&
> op->prev->va.addr <= aligned_unmap_start &&
> - (is_sparse || iova_mapped_as_huge_page(op->prev, *unmap_start))) {
> + (is_sparse || iova_mapped_as_huge_page(op->unmap->va, *unmap_start))) {
> *unmap_range += *unmap_start - aligned_unmap_start;
> *unmap_start = aligned_unmap_start;
> }
> @@ -2338,7 +2352,7 @@ unmap_hugepage_align(const struct drm_gpuva_op_remap *op,
> */
> if (op->next && aligned_unmap_end > unmap_end &&
> op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
> - (is_sparse || iova_mapped_as_huge_page(op->next, unmap_end - 1))) {
> + (is_sparse || iova_mapped_as_huge_page(op->unmap->va, unmap_end - 1))) {
> *unmap_range += aligned_unmap_end - unmap_end;
> }
> }
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/4] drm/panthor: Fix iova_mapped_as_huge_page() for imported BOs
2026-09-17 12:33 ` [PATCH 2/4] drm/panthor: Fix iova_mapped_as_huge_page() for imported BOs Boris Brezillon
@ 2026-09-18 16:35 ` Akash Goel
0 siblings, 0 replies; 9+ messages in thread
From: Akash Goel @ 2026-09-18 16:35 UTC (permalink / raw)
To: Boris Brezillon, Steven Price, Liviu Dudau, Adrián Larumbe
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel, nd
On 9/17/26 13:33, Boris Brezillon wrote:
> Imported BOs have no backing.pages array allocated, leading to a NULL
> deref when iova_mapped_as_huge_page() gets called on them.
>
> Implement this check through and sgt walk to reach the position of the
> sgt targeted by a VA, and check that the DMA address is properly aligned
> and the size remaining in the SG entry is bigger than a huge page.
> This is basically matching the logic in vm_map_pages(), with get_pgsize()
> being replaced by a simpler test, because we don't care about the pgcount
> info.
>
> Reported-by: Akash Goel <akash.goel@arm.com>
> Fixes: 8e7460eac786 ("drm/panthor: Support partial unmaps of huge pages")
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
Many thanks for fixing the issue
Reviewed-by: Akash Goel <akash.goel@arm.com>
> drivers/gpu/drm/panthor/panthor_mmu.c | 44 ++++++++++++++++++++++++++++-------
> 1 file changed, 36 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
> index b0a7033480e6..6cef954e2cba 100644
> --- a/drivers/gpu/drm/panthor/panthor_mmu.c
> +++ b/drivers/gpu/drm/panthor/panthor_mmu.c
> @@ -2299,7 +2299,6 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
> {
> struct panthor_gem_object *bo = to_panthor_bo(mapping->gem.obj);
> u64 aligned_va = ALIGN_DOWN(va, SZ_2M);
> - const struct page *pg;
> pgoff_t bo_offset;
>
> /* If the 2M-aligned VA is outside the mapping being tested, we know
> @@ -2309,16 +2308,45 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
> return false;
>
> bo_offset = aligned_va - mapping->va.addr + mapping->gem.offset;
> - pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
>
> - /* In case of shmem backing, we know we can only have a huge mapping
> - * if the bo_offset is 2M aligned, meaning we can skip the folio size
> - * check if it's not the case.
> - */
> - if (!IS_ALIGNED(bo_offset, SZ_2M))
> + if (drm_gem_is_imported(&bo->base)) {
> + struct sg_table *sgt = bo->dmap.sgt;
> + struct scatterlist *sgl;
> + unsigned int count;
> +
> + /* If this is an imported BO, we have to walk the SGT and
> + * check the dma address/size alignment to determine if it's
> + * a huge map or not.
> + */
> + for_each_sgtable_dma_sg(sgt, sgl, count) {
> + size_t len = sg_dma_len(sgl);
> + dma_addr_t daddr;
> +
> + if (len <= bo_offset) {
> + bo_offset -= len;
> + continue;
> + }
> +
> + len -= bo_offset;
> + daddr = sg_dma_address(sgl) + bo_offset;
> +
> + return IS_ALIGNED(daddr, SZ_2M) &&
> + len >= SZ_2M;
> + }
> +
> return false;
> + } else {
> + const struct page *pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
>
> - return folio_size(page_folio(pg)) >= SZ_2M;
> + /* In case of shmem backing, we know we can only have a huge mapping
> + * if the bo_offset is 2M aligned, meaning we can skip the folio size
> + * check if it's not the case.
> + */
> + if (!IS_ALIGNED(bo_offset, SZ_2M))
> + return false;
> +
> + return folio_size(page_folio(pg)) >= SZ_2M;
> + }
> }
>
> static void
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/4] drm/panthor: Consolidate the is-huge-page-mapping test
2026-09-17 12:33 ` [PATCH 3/4] drm/panthor: Consolidate the is-huge-page-mapping test Boris Brezillon
@ 2026-09-18 16:39 ` Akash Goel
0 siblings, 0 replies; 9+ messages in thread
From: Akash Goel @ 2026-09-18 16:39 UTC (permalink / raw)
To: Boris Brezillon, Steven Price, Liviu Dudau, Adrián Larumbe
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel, nd
On 9/17/26 13:33, Boris Brezillon wrote:
> Right now the logic to determine whether a given VA in the drm_gpuva
> being unmapped is a huge page mapping or not is scattered
> in two functions: unmap_hugepage_align() and
> iova_mapped_as_huge_page(). This makes it harder to reason about the
> logic being implemented for very little gain (some simple checks being
> done twice), so let's consolidate all the checks related to huge page
> mapping testing in iova_mapped_as_huge_page() and leave
> unmap_hugepage_align() as a simple user of this helper that aligns the
> area to unmap based on the return of iova_mapped_as_huge_page().
>
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
Many thanks for this improvement.
Looks good to me. Makes it easier to follow the logic.
Reviewed-by: Akash Goel <akash.goel@arm.com>
> drivers/gpu/drm/panthor/panthor_mmu.c | 57 +++++++++++++++++------------------
> 1 file changed, 28 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
> index 6cef954e2cba..d2897099763e 100644
> --- a/drivers/gpu/drm/panthor/panthor_mmu.c
> +++ b/drivers/gpu/drm/panthor/panthor_mmu.c
> @@ -2301,10 +2301,11 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
> u64 aligned_va = ALIGN_DOWN(va, SZ_2M);
> pgoff_t bo_offset;
>
> - /* If the 2M-aligned VA is outside the mapping being tested, we know
> - * it's not a huge map.
> + /* If the 2M section being tested is crossing the mapping boundary
> + * we know it's not a huge map.
> */
> - if (aligned_va < mapping->va.addr)
> + if (aligned_va < mapping->va.addr ||
> + aligned_va + SZ_2M > mapping->va.addr + mapping->va.range)
> return false;
>
> bo_offset = aligned_va - mapping->va.addr + mapping->gem.offset;
> @@ -2337,10 +2338,21 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
> return false;
> } else {
> const struct page *pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
> + struct panthor_vma *vma = container_of(mapping, struct panthor_vma, base);
> + bool is_sparse = vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE;
>
> - /* In case of shmem backing, we know we can only have a huge mapping
> - * if the bo_offset is 2M aligned, meaning we can skip the folio size
> - * check if it's not the case.
> + /* If the unmapped VMA stands for a sparse mapping, always
> + * assume the backing storage is a THP, since the overhead of
> + * unmapping 2MiB worth of 4KiB pages and remapping some of
> + * them is offset by the logic of working out whether it's
> + * the opposite case right below.
> + */
> + if (is_sparse)
> + return true;
> +
> + /* In case of shmem backing, we know we can only have a huge
> + * mapping if the bo_offset is 2M aligned, meaning we can skip
> + * the folio size check if it's not the case.
> */
> if (!IS_ALIGNED(bo_offset, SZ_2M))
> return false;
> @@ -2353,36 +2365,23 @@ static void
> unmap_hugepage_align(const struct drm_gpuva_op_remap *op,
> u64 *unmap_start, u64 *unmap_range)
> {
> - struct panthor_vma *unmap_vma = container_of(op->unmap->va, struct panthor_vma, base);
> - bool is_sparse = unmap_vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE;
> - u64 aligned_unmap_start, aligned_unmap_end, unmap_end;
> -
> - unmap_end = *unmap_start + *unmap_range;
> - aligned_unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
> - aligned_unmap_end = ALIGN(unmap_end, SZ_2M);
> + u64 unmap_end = *unmap_start + *unmap_range;
>
> /* If we're dealing with a huge page, make sure the unmap region is
> - * aligned on the start of the page. If the unmapped VMA stands for
> - * a sparse mapping, always assume the backing storage is a THP, since
> - * the overhead of unmapping 2MiB worth of 4KiB pages and remapping
> - * some of them is offset by the logic of working out whether it's
> - * the opposite case right below. This also holds true for op->next.
> + * aligned on the start of the page.
> */
> - if (op->prev && aligned_unmap_start < *unmap_start &&
> - op->prev->va.addr <= aligned_unmap_start &&
> - (is_sparse || iova_mapped_as_huge_page(op->unmap->va, *unmap_start))) {
> - *unmap_range += *unmap_start - aligned_unmap_start;
> - *unmap_start = aligned_unmap_start;
> - }
> + if (op->prev && !IS_ALIGNED(*unmap_start, SZ_2M) &&
> + iova_mapped_as_huge_page(op->unmap->va, *unmap_start))
> + *unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M);
>
> /* If we're dealing with a huge page, make sure the unmap region is
> * aligned on the end of the page.
> */
> - if (op->next && aligned_unmap_end > unmap_end &&
> - op->next->va.addr + op->next->va.range >= aligned_unmap_end &&
> - (is_sparse || iova_mapped_as_huge_page(op->unmap->va, unmap_end - 1))) {
> - *unmap_range += aligned_unmap_end - unmap_end;
> - }
> + if (op->next && !IS_ALIGNED(unmap_end, SZ_2M) &&
> + iova_mapped_as_huge_page(op->unmap->va, unmap_end - 1))
> + unmap_end = ALIGN(unmap_end, SZ_2M);
> +
> + *unmap_range = unmap_end - *unmap_start;
> }
>
> static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op,
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/4] drm/panthor: Actually check huge-page mapping on sparse regions
2026-09-17 12:33 ` [PATCH 4/4] drm/panthor: Actually check huge-page mapping on sparse regions Boris Brezillon
@ 2026-09-18 16:48 ` Akash Goel
0 siblings, 0 replies; 9+ messages in thread
From: Akash Goel @ 2026-09-18 16:48 UTC (permalink / raw)
To: Boris Brezillon, Steven Price, Liviu Dudau, Adrián Larumbe
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, dri-devel, linux-kernel, nd
On 9/17/26 13:33, Boris Brezillon wrote:
> With the recent changes to iova_mapped_as_huge_page(), the check for
> huge-page mapping of sparse BOs is actually simple:
>
> - for a sparse mapping, we know the BO offset any VA in this regions is
> va & (SZ_2M - 1)
> - the VA we're searching the BO offset for is the 2M-aligned
> aligned_va value
>
> This guarantees that the BO offset to check is always zero in that case.
>
> This is simple enough to let the code check if page 0 is a huge page
> and save the unmap+map dance when the dummy BO is not backed by a
> a huge page. So let's do that and kill the comment that says it's too
> complicated.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
Thanks for this change.
Looks good to me.
Reviewed-by: Akash Goel <akash.goel@arm.com>
> drivers/gpu/drm/panthor/panthor_mmu.c | 15 ++++++++-------
> 1 file changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
> index d2897099763e..01564d250adf 100644
> --- a/drivers/gpu/drm/panthor/panthor_mmu.c
> +++ b/drivers/gpu/drm/panthor/panthor_mmu.c
> @@ -2337,18 +2337,18 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
>
> return false;
> } else {
> - const struct page *pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
> struct panthor_vma *vma = container_of(mapping, struct panthor_vma, base);
> bool is_sparse = vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE;
> + const struct page *pg;
>
> - /* If the unmapped VMA stands for a sparse mapping, always
> - * assume the backing storage is a THP, since the overhead of
> - * unmapping 2MiB worth of 4KiB pages and remapping some of
> - * them is offset by the logic of working out whether it's
> - * the opposite case right below.
> + /* BO offset on a sparse mapping is chosen so that 2M-aligned
> + * VAs point to the start of the BO. Since aligned_va (the
> + * address we check huge-page against) is 2M-aligned, the BO
> + * offset is guaranteed to be zero.
> + * Check panthor_fix_sparse_map_offset() for more details.
> */
> if (is_sparse)
> - return true;
> + bo_offset = 0;
>
> /* In case of shmem backing, we know we can only have a huge
> * mapping if the bo_offset is 2M aligned, meaning we can skip
> @@ -2357,6 +2357,7 @@ iova_mapped_as_huge_page(struct drm_gpuva *mapping, u64 va)
> if (!IS_ALIGNED(bo_offset, SZ_2M))
> return false;
>
> + pg = bo->backing.pages[bo_offset >> PAGE_SHIFT];
> return folio_size(page_folio(pg)) >= SZ_2M;
> }
> }
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-18 16:49 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-17 12:33 [PATCH 0/4] drm/panthor: Fix partial unmaps, again Boris Brezillon
2026-09-17 12:33 ` [PATCH 1/4] drm/panthor: Avoid false positives in iova_mapped_as_huge_page() Boris Brezillon
2026-09-18 16:34 ` Akash Goel
2026-09-17 12:33 ` [PATCH 2/4] drm/panthor: Fix iova_mapped_as_huge_page() for imported BOs Boris Brezillon
2026-09-18 16:35 ` Akash Goel
2026-09-17 12:33 ` [PATCH 3/4] drm/panthor: Consolidate the is-huge-page-mapping test Boris Brezillon
2026-09-18 16:39 ` Akash Goel
2026-09-17 12:33 ` [PATCH 4/4] drm/panthor: Actually check huge-page mapping on sparse regions Boris Brezillon
2026-09-18 16:48 ` Akash Goel
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®