* [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size
@ 2024-10-25 20:43 Sui Jingfeng
2024-10-25 20:43 ` [PATCH v2 1/2] drm/etnaviv: Record GPU visible size of GEM BO separately Sui Jingfeng
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Sui Jingfeng @ 2024-10-25 20:43 UTC (permalink / raw)
To: Lucas Stach, Russell King, Christian Gmeiner
Cc: David Airlie, Simona Vetter, etnaviv, dri-devel, linux-kernel,
Sui Jingfeng
Etnaviv assumes that GPU page size is 4KiB, however, when using
softpin capable GPUs on a different CPU page size configuration.
The userspace allocated GPUVA ranges collision, unable to be
inserted to the specified address hole exactly.
For example, when running glmark2-drm:
[kernel space debug log]
etnaviv 0000:03:00.0: Insert bo failed, va: 0xfd38b000, size: 0x4000
etnaviv 0000:03:00.0: Insert bo failed, va: 0xfd38a000, size: 0x4000
[user space debug log]
bo->va = 0xfd38c000, bo->size=0x100000
bo->va = 0xfd38b000, bo->size=0x1000 <-- Insert IOVA fails here.
bo->va = 0xfd38a000, bo->size=0x1000
bo->va = 0xfd389000, bo->size=0x1000
The root cause is that kernel side BO takes up bigger address space
than userspace assumes.
To solve this problem, we first track the GPU visible size of GEM buffer
object, then map and unmap the GEM BOs exactly with respect to its GPUVA
size. Ensure that GPU VA is fully mapped/unmapped, not more and not less.
v2:
- Aligned to the GPU page size (Lucas)
v1:
- No GPUVA range wasting (Lucas)
Link: https://lore.kernel.org/dri-devel/20241004194207.1013744-1-sui.jingfeng@linux.dev/
v0:
Link: https://lore.kernel.org/dri-devel/20240930221706.399139-1-sui.jingfeng@linux.dev/
Sui Jingfeng (2):
drm/etnaviv: Record GPU visible size of GEM BO separately
drm/etnaviv: Map and unmap GPUVA range with respect to the GPUVA size
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 11 ++++----
drivers/gpu/drm/etnaviv/etnaviv_gem.h | 5 ++++
drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 36 +++++++++------------------
3 files changed, 22 insertions(+), 30 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] drm/etnaviv: Record GPU visible size of GEM BO separately
2024-10-25 20:43 [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size Sui Jingfeng
@ 2024-10-25 20:43 ` Sui Jingfeng
2024-10-25 20:43 ` [PATCH v2 2/2] drm/etnaviv: Map and unmap GPUVA range with respect to the GPUVA size Sui Jingfeng
2024-10-28 15:57 ` [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size Lucas Stach
2 siblings, 0 replies; 4+ messages in thread
From: Sui Jingfeng @ 2024-10-25 20:43 UTC (permalink / raw)
To: Lucas Stach, Russell King, Christian Gmeiner
Cc: David Airlie, Simona Vetter, etnaviv, dri-devel, linux-kernel,
Sui Jingfeng
The GPU visible size of a GEM BO is not necessarily PAGE_SIZE aligned,
which happens when CPU page size is not equal to GPU page size. Extra
precious resources such as GPU page tables and GPU TLBs may being paid
because of this but never get used.
Track the size of GPU visible part of GEM BO separately, ensure no
GPUVA range wasting by aligning that size to GPU page size.
Signed-off-by: Sui Jingfeng <sui.jingfeng@linux.dev>
---
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 11 +++++------
drivers/gpu/drm/etnaviv/etnaviv_gem.h | 5 +++++
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 5c0c9d4e3be1..fabcaa3b9b25 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -543,7 +543,7 @@ static const struct drm_gem_object_funcs etnaviv_gem_object_funcs = {
.vm_ops = &vm_ops,
};
-static int etnaviv_gem_new_impl(struct drm_device *dev, u32 flags,
+static int etnaviv_gem_new_impl(struct drm_device *dev, u32 size, u32 flags,
const struct etnaviv_gem_ops *ops, struct drm_gem_object **obj)
{
struct etnaviv_gem_object *etnaviv_obj;
@@ -570,6 +570,7 @@ static int etnaviv_gem_new_impl(struct drm_device *dev, u32 flags,
if (!etnaviv_obj)
return -ENOMEM;
+ etnaviv_obj->size = ALIGN(size, SZ_4K);
etnaviv_obj->flags = flags;
etnaviv_obj->ops = ops;
@@ -590,15 +591,13 @@ int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
struct drm_gem_object *obj = NULL;
int ret;
- size = PAGE_ALIGN(size);
-
- ret = etnaviv_gem_new_impl(dev, flags, &etnaviv_gem_shmem_ops, &obj);
+ ret = etnaviv_gem_new_impl(dev, size, flags, &etnaviv_gem_shmem_ops, &obj);
if (ret)
goto fail;
lockdep_set_class(&to_etnaviv_bo(obj)->lock, &etnaviv_shm_lock_class);
- ret = drm_gem_object_init(dev, obj, size);
+ ret = drm_gem_object_init(dev, obj, PAGE_ALIGN(size));
if (ret)
goto fail;
@@ -627,7 +626,7 @@ int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
struct drm_gem_object *obj;
int ret;
- ret = etnaviv_gem_new_impl(dev, flags, ops, &obj);
+ ret = etnaviv_gem_new_impl(dev, size, flags, ops, &obj);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index a42d260cac2c..687555aae807 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -36,6 +36,11 @@ struct etnaviv_gem_object {
const struct etnaviv_gem_ops *ops;
struct mutex lock;
+ /*
+ * The actual size that is visible to the GPU, not necessarily
+ * PAGE_SIZE aligned, but should be aligned to GPU page size.
+ */
+ u32 size;
u32 flags;
struct list_head gem_node;
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] drm/etnaviv: Map and unmap GPUVA range with respect to the GPUVA size
2024-10-25 20:43 [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size Sui Jingfeng
2024-10-25 20:43 ` [PATCH v2 1/2] drm/etnaviv: Record GPU visible size of GEM BO separately Sui Jingfeng
@ 2024-10-25 20:43 ` Sui Jingfeng
2024-10-28 15:57 ` [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size Lucas Stach
2 siblings, 0 replies; 4+ messages in thread
From: Sui Jingfeng @ 2024-10-25 20:43 UTC (permalink / raw)
To: Lucas Stach, Russell King, Christian Gmeiner
Cc: David Airlie, Simona Vetter, etnaviv, dri-devel, linux-kernel,
Sui Jingfeng
Etnaviv assumes that GPU page size is 4KiB, however, GPUVA ranges collision
when using softpin capable GPUs on a non 4KiB CPU page size configuration.
The root cause is that kernel side BO takes up bigger address space than
userspace expect, the size of backing memory of GEM buffer objects are
required to align to the CPU PAGE_SIZE. Therefore, results in userspace
allocated GPUVA range fails to be inserted to the specified hole exactly.
To solve this problem, record the GPU visiable size of a BO firstly, then
map and unmap the SG entry strictly with respect to the total GPUVA size.
Signed-off-by: Sui Jingfeng <sui.jingfeng@linux.dev>
---
drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 36 +++++++++------------------
1 file changed, 12 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index 1661d589bf3e..a2cd64bd2dc0 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -70,8 +70,10 @@ static int etnaviv_context_map(struct etnaviv_iommu_context *context,
}
static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova,
+ unsigned int va_len,
struct sg_table *sgt, int prot)
-{ struct scatterlist *sg;
+{
+ struct scatterlist *sg;
unsigned int da = iova;
unsigned int i;
int ret;
@@ -81,14 +83,16 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova,
for_each_sgtable_dma_sg(sgt, sg, i) {
phys_addr_t pa = sg_dma_address(sg) - sg->offset;
- size_t bytes = sg_dma_len(sg) + sg->offset;
+ unsigned int da_len = sg_dma_len(sg) + sg->offset;
+ unsigned int bytes = min_t(unsigned int, da_len, va_len);
- VERB("map[%d]: %08x %pap(%zx)", i, iova, &pa, bytes);
+ VERB("map[%d]: %08x %pap(%x)", i, iova, &pa, bytes);
ret = etnaviv_context_map(context, da, pa, bytes, prot);
if (ret)
goto fail;
+ va_len -= bytes;
da += bytes;
}
@@ -104,21 +108,7 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova,
static void etnaviv_iommu_unmap(struct etnaviv_iommu_context *context, u32 iova,
struct sg_table *sgt, unsigned len)
{
- struct scatterlist *sg;
- unsigned int da = iova;
- int i;
-
- for_each_sgtable_dma_sg(sgt, sg, i) {
- size_t bytes = sg_dma_len(sg) + sg->offset;
-
- etnaviv_context_unmap(context, da, bytes);
-
- VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
-
- BUG_ON(!PAGE_ALIGNED(bytes));
-
- da += bytes;
- }
+ etnaviv_context_unmap(context, iova, len);
context->flush_seq++;
}
@@ -131,7 +121,7 @@ static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu_context *context,
lockdep_assert_held(&context->lock);
etnaviv_iommu_unmap(context, mapping->vram_node.start,
- etnaviv_obj->sgt, etnaviv_obj->base.size);
+ etnaviv_obj->sgt, etnaviv_obj->size);
drm_mm_remove_node(&mapping->vram_node);
}
@@ -305,16 +295,14 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context,
node = &mapping->vram_node;
if (va)
- ret = etnaviv_iommu_insert_exact(context, node,
- etnaviv_obj->base.size, va);
+ ret = etnaviv_iommu_insert_exact(context, node, etnaviv_obj->size, va);
else
- ret = etnaviv_iommu_find_iova(context, node,
- etnaviv_obj->base.size);
+ ret = etnaviv_iommu_find_iova(context, node, etnaviv_obj->size);
if (ret < 0)
goto unlock;
mapping->iova = node->start;
- ret = etnaviv_iommu_map(context, node->start, sgt,
+ ret = etnaviv_iommu_map(context, node->start, etnaviv_obj->size, sgt,
ETNAVIV_PROT_READ | ETNAVIV_PROT_WRITE);
if (ret < 0) {
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size
2024-10-25 20:43 [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size Sui Jingfeng
2024-10-25 20:43 ` [PATCH v2 1/2] drm/etnaviv: Record GPU visible size of GEM BO separately Sui Jingfeng
2024-10-25 20:43 ` [PATCH v2 2/2] drm/etnaviv: Map and unmap GPUVA range with respect to the GPUVA size Sui Jingfeng
@ 2024-10-28 15:57 ` Lucas Stach
2 siblings, 0 replies; 4+ messages in thread
From: Lucas Stach @ 2024-10-28 15:57 UTC (permalink / raw)
To: Sui Jingfeng, Russell King, Christian Gmeiner
Cc: David Airlie, Simona Vetter, etnaviv, dri-devel, linux-kernel
Am Samstag, dem 26.10.2024 um 04:43 +0800 schrieb Sui Jingfeng:
> Etnaviv assumes that GPU page size is 4KiB, however, when using
> softpin capable GPUs on a different CPU page size configuration.
> The userspace allocated GPUVA ranges collision, unable to be
> inserted to the specified address hole exactly.
>
>
> For example, when running glmark2-drm:
>
> [kernel space debug log]
>
> etnaviv 0000:03:00.0: Insert bo failed, va: 0xfd38b000, size: 0x4000
> etnaviv 0000:03:00.0: Insert bo failed, va: 0xfd38a000, size: 0x4000
>
> [user space debug log]
>
> bo->va = 0xfd38c000, bo->size=0x100000
> bo->va = 0xfd38b000, bo->size=0x1000 <-- Insert IOVA fails here.
> bo->va = 0xfd38a000, bo->size=0x1000
> bo->va = 0xfd389000, bo->size=0x1000
>
>
> The root cause is that kernel side BO takes up bigger address space
> than userspace assumes.
>
> To solve this problem, we first track the GPU visible size of GEM buffer
> object, then map and unmap the GEM BOs exactly with respect to its GPUVA
> size. Ensure that GPU VA is fully mapped/unmapped, not more and not less.
>
Thanks, series applied to etnaviv/next
> v2:
> - Aligned to the GPU page size (Lucas)
>
> v1:
> - No GPUVA range wasting (Lucas)
> Link: https://lore.kernel.org/dri-devel/20241004194207.1013744-1-sui.jingfeng@linux.dev/
>
> v0:
> Link: https://lore.kernel.org/dri-devel/20240930221706.399139-1-sui.jingfeng@linux.dev/
>
> Sui Jingfeng (2):
> drm/etnaviv: Record GPU visible size of GEM BO separately
> drm/etnaviv: Map and unmap GPUVA range with respect to the GPUVA size
>
> drivers/gpu/drm/etnaviv/etnaviv_gem.c | 11 ++++----
> drivers/gpu/drm/etnaviv/etnaviv_gem.h | 5 ++++
> drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 36 +++++++++------------------
> 3 files changed, 22 insertions(+), 30 deletions(-)
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-10-28 15:57 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-25 20:43 [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size Sui Jingfeng
2024-10-25 20:43 ` [PATCH v2 1/2] drm/etnaviv: Record GPU visible size of GEM BO separately Sui Jingfeng
2024-10-25 20:43 ` [PATCH v2 2/2] drm/etnaviv: Map and unmap GPUVA range with respect to the GPUVA size Sui Jingfeng
2024-10-28 15:57 ` [PATCH v2 0/2] drm/etnaviv: Fix GPUVA range collision when CPU page size is not equal to GPU page size Lucas Stach
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox