Hi all,
this implements the last missing bits for softpin aka putting userspace in charge of the GPU virtual address space. This builds on top of the per-process address space series. As this is quite a stack of patches now, I'm providing a git branch [1] with all the necessary patches. Please note that I have not yet worked in the feedback I got for the per-process address space patches.
The corresponding userspace bits can be found at [2]. The Mesa changes always use softpin where possible and now finally allow GC7000 support to work with a non-horrible UAPI interface.
Regards, Lucas
[1] https://git.pengutronix.de/git/lst/linux etnaviv/experimental [2] https://gitlab.freedesktop.org/mesa/mesa/merge_requests/1559
Lucas Stach (3): drm/etnaviv: skip command stream validation on PPAS capable GPUs drm/etnaviv: allow to request specific virtual address for gem mapping drm/etnaviv: implement softpin
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 2 ++ drivers/gpu/drm/etnaviv/etnaviv_gem.c | 4 +-- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 3 ++- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 28 ++++++++++++++++++-- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 9 +++++++ drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 16 +++++++++-- drivers/gpu/drm/etnaviv/etnaviv_mmu.h | 2 +- include/uapi/drm/etnaviv_drm.h | 5 +++- 9 files changed, 61 insertions(+), 10 deletions(-)
With per-process address spaces in place, a rogue process submitting bogus command streams can only hurt itself. There is no need to validate the command stream before execution anymore.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 27a14a270a55..627c80ed63d8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -517,7 +517,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto err_submit_objects;
- if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4, + if ((priv->mmu_global->version != ETNAVIV_IOMMU_V2) && + !etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4, relocs, args->nr_relocs)) { ret = -EINVAL; goto err_submit_objects;
On Fri, 2019-08-02 at 19:29 +0200, Lucas Stach wrote:
With per-process address spaces in place, a rogue process submitting bogus command streams can only hurt itself. There is no need to validate the command stream before execution anymore.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 27a14a270a55..627c80ed63d8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -517,7 +517,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto err_submit_objects;
- if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4,
- if ((priv->mmu_global->version != ETNAVIV_IOMMU_V2) &&
ret = -EINVAL; goto err_submit_objects;!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4, relocs, args->nr_relocs)) {
Reviewed-by: Philipp Zabel p.zabel@pengutronix.de
regards Philipp
Allow the mapping code to request a specific virtual address for the gem mapping. If the virtual address is zero we fall back to the old mode of allocating a virtual address for the mapping.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 2 +- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 16 ++++++++++++++-- drivers/gpu/drm/etnaviv/etnaviv_mmu.h | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 74680c0254b6..5dde3e4c3949 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -308,7 +308,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( mapping->use = 1;
ret = etnaviv_iommu_map_gem(mmu, etnaviv_obj, mmu->global->memory_base, - mapping); + mapping, 0); if (ret < 0) kfree(mapping); else diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index 175e6128c4bc..92f3090b8348 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -120,7 +120,7 @@ struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj); void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj);
struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( - struct drm_gem_object *obj, struct etnaviv_iommu_context *mmu); + struct drm_gem_object *obj, struct etnaviv_iommu_context *mmu, u64 va); void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping);
#endif /* __ETNAVIV_GEM_H__ */ diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index 99c20094295c..c344dde2fa05 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -220,9 +220,16 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context, return ret; }
+static int etnaviv_iommu_insert_exact(struct etnaviv_iommu_context *context, + struct drm_mm_node *node, size_t size, u64 va) +{ + return drm_mm_insert_node_in_range(&context->mm, node, size, 0, 0, va, + va + size, DRM_MM_INSERT_LOW); +} + int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context, struct etnaviv_gem_object *etnaviv_obj, u32 memory_base, - struct etnaviv_vram_mapping *mapping) + struct etnaviv_vram_mapping *mapping, u64 va) { struct sg_table *sgt = etnaviv_obj->sgt; struct drm_mm_node *node; @@ -248,7 +255,12 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context,
node = &mapping->vram_node;
- ret = etnaviv_iommu_find_iova(context, node, etnaviv_obj->base.size); + if (va) + ret = etnaviv_iommu_insert_exact(context, node, + etnaviv_obj->base.size, va); + else + ret = etnaviv_iommu_find_iova(context, node, + etnaviv_obj->base.size); if (ret < 0) goto unlock;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h index 3c219d306eab..e97ce8488286 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h @@ -85,7 +85,7 @@ struct etnaviv_gem_object;
int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context, struct etnaviv_gem_object *etnaviv_obj, u32 memory_base, - struct etnaviv_vram_mapping *mapping); + struct etnaviv_vram_mapping *mapping, u64 va); void etnaviv_iommu_unmap_gem(struct etnaviv_iommu_context *context, struct etnaviv_vram_mapping *mapping);
On Fri, 2019-08-02 at 19:29 +0200, Lucas Stach wrote:
Allow the mapping code to request a specific virtual address for the gem mapping. If the virtual address is zero we fall back to the old mode of allocating a virtual address for the mapping.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
Reviewed-by: Philipp Zabel p.zabel@pengutronix.de
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 2 +- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 16 ++++++++++++++-- drivers/gpu/drm/etnaviv/etnaviv_mmu.h | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-)
[...]
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index 99c20094295c..c344dde2fa05 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -220,9 +220,16 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context, return ret; }
+static int etnaviv_iommu_insert_exact(struct etnaviv_iommu_context *context,
struct drm_mm_node *node, size_t size, u64 va)
+{
- return drm_mm_insert_node_in_range(&context->mm, node, size, 0, 0, va,
va + size, DRM_MM_INSERT_LOW);
We are only looking for an exact match, this could use DRM_MM_INSERT_LOWEST.
regards Philipp
With softpin we allow the userspace to take control over the GPU virtual address space. The new capability is relected by a bump of the minor DRM version. There are a few restrictions for userspace to take into account:
1. The kernel reserves a bit of the address space to implement zero page faulting and mapping of the kernel internal ring buffer. Userspace can query the kernel for the first usable GPU VM address via ETNAVIV_PARAM_SOFTPIN_START_ADDR.
2. We only allow softpin on GPUs, which implement proper process separation via PPAS. If softpin is not available the softpin start address will be set to ~0.
3. Softpin is all or nothing. A submit using softpin must not use any address fixups via relocs.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 2 ++ drivers/gpu/drm/etnaviv/etnaviv_gem.c | 4 ++-- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 1 + drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 25 +++++++++++++++++++- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 9 +++++++ include/uapi/drm/etnaviv_drm.h | 5 +++- 7 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 8bcbd3fb02c6..e2e60cdf8741 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -529,7 +529,7 @@ static struct drm_driver etnaviv_drm_driver = { .desc = "etnaviv DRM", .date = "20151214", .major = 1, - .minor = 2, + .minor = 3, };
/* diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index a488cfdb6bbf..32cfa5a48d42 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -24,6 +24,8 @@ struct etnaviv_gem_object; struct etnaviv_gem_submit; struct etnaviv_iommu_global;
+#define ETNAVIV_SOFTPIN_START_ADDRESS SZ_4M /* must be >= SUBALLOC_SIZE */ + struct etnaviv_file_private { struct etnaviv_iommu_context *mmu; struct drm_sched_entity sched_entity[ETNA_MAX_PIPES]; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 5dde3e4c3949..dd863bd858f8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -248,7 +248,7 @@ void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping) }
struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( - struct drm_gem_object *obj, struct etnaviv_iommu_context *mmu) + struct drm_gem_object *obj, struct etnaviv_iommu_context *mmu, u64 va) { struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); struct etnaviv_vram_mapping *mapping; @@ -308,7 +308,7 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( mapping->use = 1;
ret = etnaviv_iommu_map_gem(mmu, etnaviv_obj, mmu->global->memory_base, - mapping, 0); + mapping, va); if (ret < 0) kfree(mapping); else diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index 92f3090b8348..c64e93a6293b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -77,6 +77,7 @@ static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj)
struct etnaviv_gem_submit_bo { u32 flags; + u64 va; struct etnaviv_gem_object *obj; struct etnaviv_vram_mapping *mapping; struct dma_fence *excl; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 627c80ed63d8..09e38f78753c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -72,6 +72,14 @@ static int submit_lookup_objects(struct etnaviv_gem_submit *submit, }
submit->bos[i].flags = bo->flags; + if (submit->flags & ETNA_SUBMIT_SOFTPIN) { + if (bo->presumed < ETNAVIV_SOFTPIN_START_ADDRESS) { + DRM_ERROR("invalid softpin address\n"); + ret = -EINVAL; + goto out_unlock; + } + submit->bos[i].va = bo->presumed; + }
/* normally use drm_gem_object_lookup(), but for bulk lookup * all under single table_lock just hit object_idr directly: @@ -224,11 +232,16 @@ static int submit_pin_objects(struct etnaviv_gem_submit *submit) struct etnaviv_vram_mapping *mapping;
mapping = etnaviv_gem_mapping_get(&etnaviv_obj->base, - submit->mmu); + submit->mmu, submit->bos[i].va); if (IS_ERR(mapping)) { ret = PTR_ERR(mapping); break; } + + if ((submit->flags & ETNA_SUBMIT_SOFTPIN) && + submit->bos[i].va != mapping->iova) + return -EINVAL; + atomic_inc(&etnaviv_obj->gpu_active);
submit->bos[i].flags |= BO_PINNED; @@ -261,6 +274,10 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, u32 *ptr = stream; int ret;
+ /* Submits using softpin don't blend with relocs */ + if ((submit->flags & ETNA_SUBMIT_SOFTPIN) && nr_relocs != 0) + return -EINVAL; + for (i = 0; i < nr_relocs; i++) { const struct drm_etnaviv_gem_submit_reloc *r = relocs + i; struct etnaviv_gem_submit_bo *bo; @@ -445,6 +462,12 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, return -EINVAL; }
+ if ((args->flags & ETNA_SUBMIT_SOFTPIN) && + priv->mmu_global->version != ETNAVIV_IOMMU_V2) { + DRM_ERROR("softpin requested on incompatible MMU\n"); + return -EINVAL; + } + /* * Copy the command submission and bo array to kernel space in * one go, and do this outside of any locks. diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index a3d0e7adc8bf..696c0f1ec8d7 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -42,6 +42,8 @@ static const struct platform_device_id gpu_ids[] = {
int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) { + struct etnaviv_drm_private *priv = gpu->drm->dev_private; + switch (param) { case ETNAVIV_PARAM_GPU_MODEL: *value = gpu->identity.model; @@ -147,6 +149,13 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) *value = gpu->identity.varyings_count; break;
+ case ETNAVIV_PARAM_SOFTPIN_START_ADDR: + if (priv->mmu_global->version == ETNAVIV_IOMMU_V2) + *value = ETNAVIV_SOFTPIN_START_ADDRESS; + else + *value = ~0ULL; + break; + default: DBG("%s: invalid param: %u", dev_name(gpu->dev), param); return -EINVAL; diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h index 0d5c49dc478c..c5710485650c 100644 --- a/include/uapi/drm/etnaviv_drm.h +++ b/include/uapi/drm/etnaviv_drm.h @@ -73,6 +73,7 @@ struct drm_etnaviv_timespec { #define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18 #define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19 #define ETNAVIV_PARAM_GPU_NUM_VARYINGS 0x1a +#define ETNAVIV_PARAM_SOFTPIN_START_ADDR 0x1b
#define ETNA_MAX_PIPES 4
@@ -177,9 +178,11 @@ struct drm_etnaviv_gem_submit_pmr { #define ETNA_SUBMIT_NO_IMPLICIT 0x0001 #define ETNA_SUBMIT_FENCE_FD_IN 0x0002 #define ETNA_SUBMIT_FENCE_FD_OUT 0x0004 +#define ETNA_SUBMIT_SOFTPIN 0x0008 #define ETNA_SUBMIT_FLAGS (ETNA_SUBMIT_NO_IMPLICIT | \ ETNA_SUBMIT_FENCE_FD_IN | \ - ETNA_SUBMIT_FENCE_FD_OUT) + ETNA_SUBMIT_FENCE_FD_OUT| \ + ETNA_SUBMIT_SOFTPIN) #define ETNA_PIPE_3D 0x00 #define ETNA_PIPE_2D 0x01 #define ETNA_PIPE_VG 0x02
On Fri, 2019-08-02 at 19:29 +0200, Lucas Stach wrote:
With softpin we allow the userspace to take control over the GPU virtual address space. The new capability is relected by a bump of the minor DRM version. There are a few restrictions for userspace to take into account:
- The kernel reserves a bit of the address space to implement zero page
faulting and mapping of the kernel internal ring buffer. Userspace can query the kernel for the first usable GPU VM address via ETNAVIV_PARAM_SOFTPIN_START_ADDR.
- We only allow softpin on GPUs, which implement proper process
separation via PPAS. If softpin is not available the softpin start address will be set to ~0.
- Softpin is all or nothing. A submit using softpin must not use any
address fixups via relocs.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 2 ++ drivers/gpu/drm/etnaviv/etnaviv_gem.c | 4 ++-- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 1 + drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 25 +++++++++++++++++++- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 9 +++++++ include/uapi/drm/etnaviv_drm.h | 5 +++- 7 files changed, 43 insertions(+), 5 deletions(-)
[...]
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h index 0d5c49dc478c..c5710485650c 100644 --- a/include/uapi/drm/etnaviv_drm.h +++ b/include/uapi/drm/etnaviv_drm.h @@ -73,6 +73,7 @@ struct drm_etnaviv_timespec { #define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18 #define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19 #define ETNAVIV_PARAM_GPU_NUM_VARYINGS 0x1a +#define ETNAVIV_PARAM_SOFTPIN_START_ADDR 0x1b
#define ETNA_MAX_PIPES 4
@@ -177,9 +178,11 @@ struct drm_etnaviv_gem_submit_pmr { #define ETNA_SUBMIT_NO_IMPLICIT 0x0001 #define ETNA_SUBMIT_FENCE_FD_IN 0x0002 #define ETNA_SUBMIT_FENCE_FD_OUT 0x0004 +#define ETNA_SUBMIT_SOFTPIN 0x0008 #define ETNA_SUBMIT_FLAGS (ETNA_SUBMIT_NO_IMPLICIT | \ ETNA_SUBMIT_FENCE_FD_IN | \
ETNA_SUBMIT_FENCE_FD_OUT)
ETNA_SUBMIT_FENCE_FD_OUT| \
ETNA_SUBMIT_SOFTPIN)
#define ETNA_PIPE_3D 0x00 #define ETNA_PIPE_2D 0x01 #define ETNA_PIPE_VG 0x02
The presumed field of drm_etnaviv_gem_submit_bo has an elaborate comment on its supposed pre-softpin use in etnaviv_drm.h, maybe that should be updated.
Otherwise,
Reviewed-by: Philipp Zabel p.zabel@pengutronix.de
regards Philipp
dri-devel@lists.freedesktop.org