From: Gyeyoung Baek <gye976@gmail.com>
To: "Alessio Belle" <alessio.belle@imgtec.com>,
"Luigi Santivetti" <luigi.santivetti@imgtec.com>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Philipp Stanner" <phasta@kernel.org>,
"Donald Robson" <donald.robson@imgtec.com>,
"Sarah Walker" <sarah.walker@imgtec.com>,
"Matt Coster" <opensource@mtcoster.net>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Randy Dunlap" <rdunlap@infradead.org>
Cc: imagination@lists.freedesktop.org,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
linux-doc@vger.kernel.org, Gyeyoung Baek <gye976@gmail.com>
Subject: [PATCH v2 3/6] drm/imagination: Route map and unmap through pvr_vm_bind()
Date: Sun, 08 Nov 2026 14:16:25 +0900 [thread overview]
Message-ID: <20261108-pvr-vm-bind-v2-3-730103d2cc9a@gmail.com> (raw)
In-Reply-To: <20261108-pvr-vm-bind-v2-0-730103d2cc9a@gmail.com>
Give the VM layer a single kernel-side bind entry point, and move every
existing map and unmap path onto it.
FW mappings and the VM_MAP/VM_UNMAP ioctls each had their own copy of
the same sequence (prepare, lock, execute, clean up). Fold them into one
pvr_vm_bind() taking an array of struct pvr_vm_bind_desc. The VM_BIND
ioctl that follows uses the same entry point.
Before:
pvr_meta_vm_map() ----+
pvr_riscv_vm_map() ---+--> pvr_vm_map()
pvr_ioctl_vm_map() ---+ map_init -> lock -> exec -> unlock -> fini
pvr_meta_vm_unmap() --+
pvr_riscv_vm_unmap() -+--> pvr_vm_unmap_obj()
unmap_init -> lock -> exec -> unlock -> fini
pvr_ioctl_vm_unmap() ----> pvr_vm_unmap()
unmap_init -> lock -> find -> exec
-> unlock -> fini
After:
pvr_meta_vm_map() ----+
pvr_riscv_vm_map() ---+--> pvr_vm_map() ---+
pvr_ioctl_vm_map() ---+ |
+--> pvr_vm_bind()
pvr_meta_vm_unmap() --+ | init -> lock -> exec
pvr_riscv_vm_unmap() -+--> pvr_vm_unmap() -+ -> unlock -> fini
pvr_ioctl_vm_unmap() -+
- pvr_vm_unmap() sets the exact flag of its descriptor, since VM_UNMAP
only removes a mapping that exactly matches the range. An unmap
through pvr_vm_bind() otherwise removes everything in the range,
because the VM_BIND ioctl that follows takes an arbitrary range, like
Vulkan sparse unbinding, rather than a previous binding.
- pvr_vm_unmap_all() is the exception and does not go through
pvr_vm_bind().
- pvr_vm_bind(): with the asynchronous mode the VM_BIND ioctl gains
afterwards, a queued request that fails part way through leaves the
address space in a state nobody can reason about. The VM context is
then marked unusable, and pvr_vm_bind() refuses it.
- pvr_vm_unmap_all(): it empties a VM context, so it has to succeed
whatever state the context is in.
- The only userspace-visible change: VM_UNMAP returns -EINVAL instead of
-ENOENT for an invalid address or size.
Signed-off-by: Gyeyoung Baek <gye976@gmail.com>
---
drivers/gpu/drm/imagination/pvr_fw_meta.c | 6 +-
drivers/gpu/drm/imagination/pvr_fw_riscv.c | 6 +-
drivers/gpu/drm/imagination/pvr_vm.c | 304 +++++++++++++++--------------
drivers/gpu/drm/imagination/pvr_vm.h | 46 ++++-
4 files changed, 205 insertions(+), 157 deletions(-)
diff --git a/drivers/gpu/drm/imagination/pvr_fw_meta.c b/drivers/gpu/drm/imagination/pvr_fw_meta.c
index 38a91dcb66c..a1de51afde1 100644
--- a/drivers/gpu/drm/imagination/pvr_fw_meta.c
+++ b/drivers/gpu/drm/imagination/pvr_fw_meta.c
@@ -542,10 +542,8 @@ pvr_meta_vm_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj)
static void
pvr_meta_vm_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj)
{
- struct pvr_gem_object *pvr_obj = fw_obj->gem;
-
- pvr_vm_unmap_obj(pvr_dev->kernel_vm_ctx, pvr_obj,
- fw_obj->fw_mm_node.start, fw_obj->fw_mm_node.size);
+ pvr_vm_unmap(pvr_dev->kernel_vm_ctx, fw_obj->fw_mm_node.start,
+ fw_obj->fw_mm_node.size);
}
static bool
diff --git a/drivers/gpu/drm/imagination/pvr_fw_riscv.c b/drivers/gpu/drm/imagination/pvr_fw_riscv.c
index cd84635bb88..a22b3f99218 100644
--- a/drivers/gpu/drm/imagination/pvr_fw_riscv.c
+++ b/drivers/gpu/drm/imagination/pvr_fw_riscv.c
@@ -149,10 +149,8 @@ pvr_riscv_vm_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj)
static void
pvr_riscv_vm_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj)
{
- struct pvr_gem_object *pvr_obj = fw_obj->gem;
-
- pvr_vm_unmap_obj(pvr_dev->kernel_vm_ctx, pvr_obj,
- fw_obj->fw_mm_node.start, fw_obj->fw_mm_node.size);
+ pvr_vm_unmap(pvr_dev->kernel_vm_ctx, fw_obj->fw_mm_node.start,
+ fw_obj->fw_mm_node.size);
}
static bool
diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c
index 12ebf0daf88..2f959cd5e90 100644
--- a/drivers/gpu/drm/imagination/pvr_vm.c
+++ b/drivers/gpu/drm/imagination/pvr_vm.c
@@ -21,6 +21,8 @@
#include <linux/gfp_types.h>
#include <linux/kref.h>
#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
#include <linux/stddef.h>
/**
@@ -117,11 +119,6 @@ struct pvr_vm_gpuva {
#define to_pvr_vm_gpuva(va) container_of_const(va, struct pvr_vm_gpuva, base)
-enum pvr_vm_bind_type {
- PVR_VM_BIND_TYPE_MAP,
- PVR_VM_BIND_TYPE_UNMAP,
-};
-
/**
* struct pvr_vm_bind_op - Context of a map/unmap operation.
*/
@@ -132,6 +129,9 @@ struct pvr_vm_bind_op {
/** @pvr_obj: Object associated with mapping (map only). */
struct pvr_gem_object *pvr_obj;
+ /** @exact: See &pvr_vm_bind_desc.exact. */
+ bool exact;
+
/**
* @vm_ctx: VM context where the mapping will be created or destroyed.
*/
@@ -198,6 +198,11 @@ static int pvr_vm_bind_op_exec(struct pvr_vm_bind_op *bind_op)
}
case PVR_VM_BIND_TYPE_UNMAP:
+ if (bind_op->exact &&
+ !drm_gpuva_find(&bind_op->vm_ctx->gpuvm_mgr,
+ bind_op->device_addr, bind_op->size))
+ return -ENOENT;
+
return drm_gpuvm_sm_unmap(&bind_op->vm_ctx->gpuvm_mgr,
bind_op, bind_op->device_addr,
bind_op->size);
@@ -229,9 +234,9 @@ static void pvr_vm_bind_op_fini(struct pvr_vm_bind_op *bind_op)
static int
pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op,
struct pvr_vm_context *vm_ctx,
- struct pvr_gem_object *pvr_obj, u64 offset,
- u64 device_addr, u64 size)
+ const struct pvr_vm_bind_desc *desc)
{
+ struct pvr_gem_object *pvr_obj = desc->obj;
struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj);
const bool is_user = vm_ctx != vm_ctx->pvr_dev->kernel_vm_ctx;
const u64 pvr_obj_size = pvr_gem_object_size(pvr_obj);
@@ -239,17 +244,19 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op,
u64 offset_plus_size;
int err;
- if (check_add_overflow(offset, size, &offset_plus_size))
+ if (check_add_overflow(desc->offset, desc->size, &offset_plus_size))
return -EINVAL;
if (is_user &&
- !pvr_find_heap_containing(vm_ctx->pvr_dev, device_addr, size)) {
+ !pvr_find_heap_containing(vm_ctx->pvr_dev, desc->device_addr,
+ desc->size)) {
return -EINVAL;
}
- if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size) ||
- offset & ~PAGE_MASK || size & ~PAGE_MASK ||
- offset >= pvr_obj_size || offset_plus_size > pvr_obj_size)
+ if (!pvr_device_addr_and_size_are_valid(vm_ctx, desc->device_addr,
+ desc->size) ||
+ desc->offset & ~PAGE_MASK || desc->size & ~PAGE_MASK ||
+ desc->offset >= pvr_obj_size || offset_plus_size > pvr_obj_size)
return -EINVAL;
bind_op->type = PVR_VM_BIND_TYPE_MAP;
@@ -275,7 +282,9 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op,
goto err_bind_op_fini;
bind_op->mmu_op_ctx =
- pvr_mmu_op_context_create(vm_ctx->mmu_ctx, sgt, device_addr, offset, size);
+ pvr_mmu_op_context_create(vm_ctx->mmu_ctx, sgt,
+ desc->device_addr, desc->offset,
+ desc->size);
err = PTR_ERR_OR_ZERO(bind_op->mmu_op_ctx);
if (err) {
bind_op->mmu_op_ctx = NULL;
@@ -283,17 +292,16 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op,
}
bind_op->pvr_obj = pvr_obj;
+ pvr_gem_object_get(pvr_obj);
bind_op->vm_ctx = vm_ctx;
- bind_op->device_addr = device_addr;
- bind_op->size = size;
- bind_op->offset = offset;
+ bind_op->device_addr = desc->device_addr;
+ bind_op->size = desc->size;
+ bind_op->offset = desc->offset;
return 0;
err_bind_op_fini:
pvr_vm_bind_op_fini(bind_op);
- /* Drain what fini() deferred. */
- drm_gpuvm_bo_deferred_cleanup(&vm_ctx->gpuvm_mgr);
return err;
}
@@ -301,12 +309,12 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op,
static int
pvr_vm_bind_op_unmap_init(struct pvr_vm_bind_op *bind_op,
struct pvr_vm_context *vm_ctx,
- struct pvr_gem_object *pvr_obj,
- u64 device_addr, u64 size)
+ const struct pvr_vm_bind_desc *desc)
{
int err;
- if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size))
+ if (!pvr_device_addr_and_size_are_valid(vm_ctx, desc->device_addr,
+ desc->size))
return -EINVAL;
bind_op->type = PVR_VM_BIND_TYPE_UNMAP;
@@ -319,17 +327,18 @@ pvr_vm_bind_op_unmap_init(struct pvr_vm_bind_op *bind_op,
}
bind_op->mmu_op_ctx =
- pvr_mmu_op_context_create(vm_ctx->mmu_ctx, NULL, device_addr, 0, 0);
+ pvr_mmu_op_context_create(vm_ctx->mmu_ctx, NULL,
+ desc->device_addr, 0, 0);
err = PTR_ERR_OR_ZERO(bind_op->mmu_op_ctx);
if (err) {
bind_op->mmu_op_ctx = NULL;
goto err_bind_op_fini;
}
- bind_op->pvr_obj = pvr_obj;
bind_op->vm_ctx = vm_ctx;
- bind_op->device_addr = device_addr;
- bind_op->size = size;
+ bind_op->exact = desc->exact;
+ bind_op->device_addr = desc->device_addr;
+ bind_op->size = desc->size;
return 0;
@@ -683,188 +692,191 @@ void pvr_destroy_vm_contexts_for_file(struct pvr_file *pvr_file)
}
}
-/**
- * pvr_vm_map() - Map a section of physical memory into a section of
- * device-virtual memory.
- * @vm_ctx: Target VM context.
- * @pvr_obj: Target PowerVR memory object.
- * @pvr_obj_offset: Offset into @pvr_obj to map from.
- * @device_addr: Virtual device address at the start of the requested mapping.
- * @size: Size of the requested mapping.
- *
- * No handle is returned to represent the mapping. Instead, callers should
- * remember @device_addr and use that as a handle.
- *
- * Return:
- * * 0 on success,
- * * -%EINVAL if @device_addr is not a valid page-aligned device-virtual
- * address; the region specified by @pvr_obj_offset and @size does not fall
- * entirely within @pvr_obj, or any part of the specified region of @pvr_obj
- * is not device-virtual page-aligned,
- * * Any error encountered while performing internal operations required to
- * destroy the mapping (returned from pvr_vm_gpuva_map or
- * pvr_vm_gpuva_remap).
- */
-int
-pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
- u64 pvr_obj_offset, u64 device_addr, u64 size)
+static int
+pvr_vm_bind_op_init(struct pvr_vm_bind_op *bind_op,
+ struct pvr_vm_context *vm_ctx,
+ const struct pvr_vm_bind_desc *desc)
{
- struct pvr_vm_bind_op bind_op = {0};
+ switch (desc->type) {
+ case PVR_VM_BIND_TYPE_MAP:
+ if (WARN_ON(!desc->obj || desc->exact))
+ return -EINVAL;
- int err = pvr_vm_bind_op_map_init(&bind_op, vm_ctx, pvr_obj,
- pvr_obj_offset, device_addr,
- size);
+ return pvr_vm_bind_op_map_init(bind_op, vm_ctx, desc);
- if (err)
- return err;
+ case PVR_VM_BIND_TYPE_UNMAP:
+ if (WARN_ON(desc->obj))
+ return -EINVAL;
- pvr_gem_object_get(pvr_obj);
+ return pvr_vm_bind_op_unmap_init(bind_op, vm_ctx, desc);
+ }
- mutex_lock(&vm_ctx->lock);
- err = pvr_vm_bind_op_exec(&bind_op);
- mutex_unlock(&vm_ctx->lock);
+ return -EINVAL;
+}
- pvr_vm_bind_op_fini(&bind_op);
- drm_gpuvm_bo_deferred_cleanup(&vm_ctx->gpuvm_mgr);
+/**
+ * pvr_vm_bind_ops_free() - Release an array of prepared bind operations.
+ * @bind_ops: Array to release.
+ * @count: Number of prepared entries in @bind_ops.
+ */
+static void pvr_vm_bind_ops_free(struct pvr_vm_bind_op *bind_ops, u32 count)
+{
+ for (u32 i = 0; i < count; i++)
+ pvr_vm_bind_op_fini(&bind_ops[i]);
- return err;
+ kvfree(bind_ops);
}
/**
- * pvr_vm_unmap_obj_locked() - Unmap an already mapped section of device-virtual
- * memory.
+ * pvr_vm_bind_ops_create() - Prepare an array of bind operations.
* @vm_ctx: Target VM context.
- * @pvr_obj: Target PowerVR memory object.
- * @device_addr: Virtual device address at the start of the target mapping.
- * @size: Size of the target mapping.
+ * @descs: Descriptions of the operations.
+ * @desc_count: Number of entries in @descs.
*
- * Return:
- * * 0 on success,
- * * -%EINVAL if @device_addr is not a valid page-aligned device-virtual
- * address,
- * * Any error encountered while performing internal operations required to
- * destroy the mapping (returned from pvr_vm_gpuva_unmap or
- * pvr_vm_gpuva_remap).
+ * Performs every allocation the operations need, so that applying them cannot
+ * fail for want of memory.
*
- * The vm_ctx->lock must be held when calling this function.
+ * Return: The new array, or an ERR_PTR on failure.
*/
-static int
-pvr_vm_unmap_obj_locked(struct pvr_vm_context *vm_ctx,
- struct pvr_gem_object *pvr_obj,
- u64 device_addr, u64 size)
+static struct pvr_vm_bind_op *
+pvr_vm_bind_ops_create(struct pvr_vm_context *vm_ctx,
+ const struct pvr_vm_bind_desc *descs, u32 desc_count)
{
- struct pvr_vm_bind_op bind_op = {0};
-
- int err = pvr_vm_bind_op_unmap_init(&bind_op, vm_ctx, pvr_obj,
- device_addr, size);
- if (err)
- return err;
+ struct pvr_vm_bind_op *bind_ops;
+ int err;
- pvr_gem_object_get(pvr_obj);
+ bind_ops = kvzalloc_objs(*bind_ops, desc_count, GFP_KERNEL_ACCOUNT);
+ if (!bind_ops)
+ return ERR_PTR(-ENOMEM);
- err = pvr_vm_bind_op_exec(&bind_op);
+ for (u32 prepared = 0; prepared < desc_count; prepared++) {
+ err = pvr_vm_bind_op_init(&bind_ops[prepared], vm_ctx,
+ &descs[prepared]);
+ if (err) {
+ pvr_vm_bind_ops_free(bind_ops, prepared);
+ /* Release the vm_bos that fini() deferred. */
+ drm_gpuvm_bo_deferred_cleanup(&vm_ctx->gpuvm_mgr);
+ return ERR_PTR(err);
+ }
- pvr_vm_bind_op_fini(&bind_op);
+ cond_resched();
+ }
- return err;
+ return bind_ops;
}
/**
- * pvr_vm_unmap_obj() - Unmap an already mapped section of device-virtual
- * memory.
+ * pvr_vm_bind() - Apply a batch of bind operations to a VM context.
* @vm_ctx: Target VM context.
- * @pvr_obj: Target PowerVR memory object.
- * @device_addr: Virtual device address at the start of the target mapping.
- * @size: Size of the target mapping.
+ * @descs: Operations to apply, in array order.
+ * @desc_count: Number of entries in @descs.
+ *
+ * Not atomic: if an operation fails, the earlier ones stay applied.
*
* Return:
- * * 0 on success,
- * * Any error encountered by pvr_vm_unmap_obj_locked.
+ * * 0 on success, or
+ * * A negative error code on failure.
*/
-int
-pvr_vm_unmap_obj(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
- u64 device_addr, u64 size)
+int pvr_vm_bind(struct pvr_vm_context *vm_ctx,
+ const struct pvr_vm_bind_desc *descs, u32 desc_count)
{
- int err;
+ struct pvr_vm_bind_op *bind_ops;
+ int err = 0;
+
+ bind_ops = pvr_vm_bind_ops_create(vm_ctx, descs, desc_count);
+ if (IS_ERR(bind_ops))
+ return PTR_ERR(bind_ops);
mutex_lock(&vm_ctx->lock);
- err = pvr_vm_unmap_obj_locked(vm_ctx, pvr_obj, device_addr, size);
+
+ for (u32 i = 0; !err && i < desc_count; i++)
+ err = pvr_vm_bind_op_exec(&bind_ops[i]);
+
mutex_unlock(&vm_ctx->lock);
+ pvr_vm_bind_ops_free(bind_ops, desc_count);
drm_gpuvm_bo_deferred_cleanup(&vm_ctx->gpuvm_mgr);
return err;
}
/**
- * pvr_vm_unmap() - Unmap an already mapped section of device-virtual memory.
+ * pvr_vm_map() - Map part of an object into a VM context.
+ * @vm_ctx: Target VM context.
+ * @pvr_obj: Target PowerVR memory object.
+ * @pvr_obj_offset: Offset into @pvr_obj to map from.
+ * @device_addr: Virtual device address at the start of the requested mapping.
+ * @size: Size of the requested mapping.
+ *
+ * A wrapper around pvr_vm_bind() with a single map operation.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+int
+pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
+ u64 pvr_obj_offset, u64 device_addr, u64 size)
+{
+ const struct pvr_vm_bind_desc desc = {
+ .type = PVR_VM_BIND_TYPE_MAP,
+ .obj = pvr_obj,
+ .offset = pvr_obj_offset,
+ .device_addr = device_addr,
+ .size = size,
+ };
+
+ return pvr_vm_bind(vm_ctx, &desc, 1);
+}
+
+/**
+ * pvr_vm_unmap() - Remove a mapping from a VM context.
* @vm_ctx: Target VM context.
* @device_addr: Virtual device address at the start of the target mapping.
* @size: Size of the target mapping.
*
+ * A wrapper around pvr_vm_bind() with a single exact unmap operation.
+ *
* Return:
* * 0 on success,
- * * Any error encountered by drm_gpuva_find,
- * * Any error encountered by pvr_vm_unmap_obj_locked.
+ * * -%ENOENT if no mapping starts at @device_addr and spans exactly @size, or
+ * * Any other error returned by pvr_vm_bind().
*/
int
pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size)
{
- struct pvr_gem_object *pvr_obj;
- struct drm_gpuva *va;
- int err;
-
- mutex_lock(&vm_ctx->lock);
-
- va = drm_gpuva_find(&vm_ctx->gpuvm_mgr, device_addr, size);
- if (va) {
- pvr_obj = gem_to_pvr_gem(va->gem.obj);
- err = pvr_vm_unmap_obj_locked(vm_ctx, pvr_obj,
- va->va.addr, va->va.range);
- } else {
- err = -ENOENT;
- }
-
- mutex_unlock(&vm_ctx->lock);
-
- drm_gpuvm_bo_deferred_cleanup(&vm_ctx->gpuvm_mgr);
-
- return err;
+ const struct pvr_vm_bind_desc desc = {
+ .type = PVR_VM_BIND_TYPE_UNMAP,
+ .exact = true,
+ .device_addr = device_addr,
+ .size = size,
+ };
+
+ return pvr_vm_bind(vm_ctx, &desc, 1);
}
/**
* pvr_vm_unmap_all() - Unmap all mappings associated with a VM context.
* @vm_ctx: Target VM context.
*
- * This function ensures that no mappings are left dangling by unmapping them
- * all in order of ascending device-virtual address.
+ * Unmaps the whole device-virtual address space at once.
*/
void
pvr_vm_unmap_all(struct pvr_vm_context *vm_ctx)
{
- u64 addr = vm_ctx->gpuvm_mgr.mm_start;
- u64 end = vm_ctx->gpuvm_mgr.mm_start + vm_ctx->gpuvm_mgr.mm_range;
- u64 va_addr, va_range;
-
- mutex_lock(&vm_ctx->lock);
-
- for (; addr < end; addr = va_addr + va_range) {
- struct pvr_gem_object *pvr_obj;
- struct drm_gpuva *va;
-
- va = drm_gpuva_find_first(&vm_ctx->gpuvm_mgr, addr, end - addr);
- if (!va)
- break;
-
- pvr_obj = gem_to_pvr_gem(va->gem.obj);
- va_addr = va->va.addr;
- va_range = va->va.range;
+ const struct pvr_vm_bind_desc desc = {
+ .type = PVR_VM_BIND_TYPE_UNMAP,
+ .device_addr = vm_ctx->gpuvm_mgr.mm_start,
+ .size = vm_ctx->gpuvm_mgr.mm_range,
+ };
+ struct pvr_vm_bind_op bind_op = {0};
- WARN_ON(pvr_vm_unmap_obj_locked(vm_ctx, pvr_obj, va_addr, va_range));
- }
+ if (WARN_ON(pvr_vm_bind_op_unmap_init(&bind_op, vm_ctx, &desc)))
+ return;
+ mutex_lock(&vm_ctx->lock);
+ WARN_ON(pvr_vm_bind_op_exec(&bind_op));
mutex_unlock(&vm_ctx->lock);
+ pvr_vm_bind_op_fini(&bind_op);
drm_gpuvm_bo_deferred_cleanup(&vm_ctx->gpuvm_mgr);
}
diff --git a/drivers/gpu/drm/imagination/pvr_vm.h b/drivers/gpu/drm/imagination/pvr_vm.h
index b0528dffa7f..bf6d5e802d9 100644
--- a/drivers/gpu/drm/imagination/pvr_vm.h
+++ b/drivers/gpu/drm/imagination/pvr_vm.h
@@ -38,10 +38,50 @@ struct pvr_vm_context *pvr_vm_create_context(struct pvr_device *pvr_dev,
int pvr_vm_map(struct pvr_vm_context *vm_ctx,
struct pvr_gem_object *pvr_obj, u64 pvr_obj_offset,
u64 device_addr, u64 size);
-int pvr_vm_unmap_obj(struct pvr_vm_context *vm_ctx,
- struct pvr_gem_object *pvr_obj,
- u64 device_addr, u64 size);
int pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size);
+
+/**
+ * enum pvr_vm_bind_type - Type of a &struct pvr_vm_bind_desc.
+ * @PVR_VM_BIND_TYPE_MAP: Map @pvr_vm_bind_desc.obj into a device-virtual range.
+ * @PVR_VM_BIND_TYPE_UNMAP: Unmap a device-virtual range.
+ */
+enum pvr_vm_bind_type {
+ PVR_VM_BIND_TYPE_MAP,
+ PVR_VM_BIND_TYPE_UNMAP,
+};
+
+/**
+ * struct pvr_vm_bind_desc - A bind operation, as passed to pvr_vm_bind().
+ */
+struct pvr_vm_bind_desc {
+ /** @type: Map or unmap. */
+ enum pvr_vm_bind_type type;
+
+ /**
+ * @obj: Object to map. Map only; must be %NULL for an unmap.
+ * pvr_vm_bind() does not consume the caller's reference.
+ */
+ struct pvr_gem_object *obj;
+
+ /** @offset: Offset into @obj to begin mapping from. Map only. */
+ u64 offset;
+
+ /**
+ * @exact: Fail with -%ENOENT unless a single mapping spans exactly
+ * the range. Unmap only.
+ */
+ bool exact;
+
+ /** @device_addr: Device-virtual address at the start of the range. */
+ u64 device_addr;
+
+ /** @size: Size of the range. */
+ u64 size;
+};
+
+int pvr_vm_bind(struct pvr_vm_context *vm_ctx,
+ const struct pvr_vm_bind_desc *descs, u32 desc_count);
+
void pvr_vm_unmap_all(struct pvr_vm_context *vm_ctx);
dma_addr_t pvr_vm_get_page_table_root_addr(struct pvr_vm_context *vm_ctx);
--
2.43.0
next prev parent reply other threads:[~2026-11-08 5:16 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-08 5:16 [PATCH v2 0/6] drm/imagination: Add async VM_BIND with sparse mappings Gyeyoung Baek
2026-11-08 5:16 ` [PATCH v2 1/6] drm/imagination: Switch the GPUVM to immediate mode Gyeyoung Baek
2026-11-08 5:16 ` [PATCH v2 2/6] drm/imagination: Stop locking reservations around map and unmap Gyeyoung Baek
2026-11-08 5:16 ` Gyeyoung Baek [this message]
2026-11-08 5:16 ` [PATCH v2 4/6] drm/imagination: Add VM_BIND ioctl Gyeyoung Baek
2026-11-08 5:16 ` [PATCH v2 5/6] drm/imagination: Add asynchronous VM_BIND Gyeyoung Baek
2026-11-08 5:16 ` [PATCH v2 6/6] drm/imagination: Add MAP_SPARSE to VM_BIND Gyeyoung Baek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261108-pvr-vm-bind-v2-3-730103d2cc9a@gmail.com \
--to=gye976@gmail.com \
--cc=airlied@gmail.com \
--cc=alessio.belle@imgtec.com \
--cc=christian.koenig@amd.com \
--cc=corbet@lwn.net \
--cc=donald.robson@imgtec.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=imagination@lists.freedesktop.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=luigi.santivetti@imgtec.com \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=opensource@mtcoster.net \
--cc=phasta@kernel.org \
--cc=rdunlap@infradead.org \
--cc=sarah.walker@imgtec.com \
--cc=simona@ffwll.ch \
--cc=skhan@linuxfoundation.org \
--cc=sumit.semwal@linaro.org \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®