From: Mika Kuoppala <mika.kuoppala@linux.intel.com>
To: intel-xe@lists.freedesktop.org
Cc: simona.vetter@ffwll.ch, matthew.brost@intel.com,
christian.koenig@amd.com, thomas.hellstrom@linux.intel.com,
joonas.lahtinen@linux.intel.com, gustavo.sousa@intel.com,
jan.maslak@intel.com, dominik.karol.piatkowski@intel.com,
rodrigo.vivi@intel.com, andrzej.hajda@intel.com,
matthew.auld@intel.com, maciej.patelczyk@intel.com,
gwan-gyeong.mun@intel.com,
Christoph Manszewski <christoph.manszewski@intel.com>,
Mika Kuoppala <mika.kuoppala@linux.intel.com>
Subject: [PATCH 08/24] drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops
Date: Thu, 30 Apr 2026 13:51:04 +0300 [thread overview]
Message-ID: <20260430105121.712843-9-mika.kuoppala@linux.intel.com> (raw)
In-Reply-To: <20260430105121.712843-1-mika.kuoppala@linux.intel.com>
From: Christoph Manszewski <christoph.manszewski@intel.com>
Make it possible to add and remove per vm debug data, which can be used
to annotate vm ranges (using pseudopaths) or to associate them with
a file which can carry arbitrary debug data (e.g. binary instruction to
code line mapping). The debug data is kept separe from the vmas. Each
address can be associated with only one debug data entry i.e. debug data
entries cannot overlap. Each entry is atomic so to remove it the
creation address and range has to be passed for removal.
For debug data manipulation only the 'op' and 'extensions' field from
'struct drm_xe_vm_bind_op' is used. All required parameters are passed
through 'struct drm_xe_vm_bind_op_ext_debug_data' and a valid instance
should be present in the extension chain pointed by the 'extensions'
field.
Debug data will be accessible through the eudebug event interface,
introduced in the following patch. An alternative way to access debug data
using debugfs, without relying on eudebug, will be proposed as a follow-up
to the eudebug series.
v2: enforce empty path on unmap (Joonas, Mika)
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/Makefile | 1 +
drivers/gpu/drm/xe/xe_debug_data.c | 314 +++++++++++++++++++++++
drivers/gpu/drm/xe/xe_debug_data.h | 22 ++
drivers/gpu/drm/xe/xe_debug_data_types.h | 25 ++
drivers/gpu/drm/xe/xe_vm.c | 157 +++++++++++-
drivers/gpu/drm/xe/xe_vm_types.h | 19 ++
include/uapi/drm/xe_drm.h | 64 +++++
7 files changed, 596 insertions(+), 6 deletions(-)
create mode 100644 drivers/gpu/drm/xe/xe_debug_data.c
create mode 100644 drivers/gpu/drm/xe/xe_debug_data.h
create mode 100644 drivers/gpu/drm/xe/xe_debug_data_types.h
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 7212ceb339ab..97c721cd32aa 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -35,6 +35,7 @@ $(obj)/generated/%_device_wa_oob.c $(obj)/generated/%_device_wa_oob.h: $(obj)/xe
xe-y += xe_bb.o \
xe_bo.o \
xe_bo_evict.o \
+ xe_debug_data.o \
xe_dep_scheduler.o \
xe_devcoredump.o \
xe_device.o \
diff --git a/drivers/gpu/drm/xe/xe_debug_data.c b/drivers/gpu/drm/xe/xe_debug_data.c
new file mode 100644
index 000000000000..3c39b2457d6e
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_data.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2025 Intel Corporation
+ */
+
+#include "xe_debug_data.h"
+#include "xe_debug_data_types.h"
+#include "xe_vm.h"
+
+const char *xe_debug_data_pseudo_path_to_string(u64 pseudopath)
+{
+ switch (pseudopath) {
+ case DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_MODULE_AREA:
+ return "[module_area]";
+ case DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SBA_AREA:
+ return "[sba_area]";
+ case DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SIP_AREA:
+ return "[sip_area]";
+ default:
+ return "[unknown]";
+ }
+}
+
+static bool
+debug_data_overlaps(const struct drm_xe_vm_bind_op_ext_debug_data *a,
+ const struct xe_debug_data *b)
+{
+ const u64 s1 = a->addr;
+ const u64 e1 = a->addr + a->range;
+ const u64 s2 = b->addr;
+ const u64 e2 = b->addr + b->range;
+
+ return (s1 < e2) && (s2 < e1);
+}
+
+static bool
+debug_data_matches(const struct drm_xe_vm_bind_op_ext_debug_data *a,
+ const struct xe_debug_data *b)
+{
+ return (a->addr == b->addr) && (a->range == b->range);
+}
+
+static bool
+debug_data_is_empty(const struct drm_xe_vm_bind_op_ext_debug_data *dd)
+{
+ int i;
+
+ if (dd->flags)
+ return false;
+
+ if (dd->offset)
+ return false;
+
+ for (i = 0; i < PATH_MAX; i++)
+ if (dd->pathname[i])
+ return false;
+
+ return true;
+}
+
+static int xe_debug_data_check_add(struct xe_vm *vm,
+ const struct drm_xe_vm_bind_op_ext_debug_data *ext)
+{
+ struct xe_device *xe = vm->xe;
+ struct xe_debug_data *i;
+
+ mutex_lock(&vm->debug_data.lock);
+ list_for_each_entry(i, &vm->debug_data.list, link) {
+ if (XE_IOCTL_DBG(xe, debug_data_overlaps(ext, i))) {
+ mutex_unlock(&vm->debug_data.lock);
+ return -EINVAL;
+ }
+ }
+ mutex_unlock(&vm->debug_data.lock);
+
+ return 0;
+}
+
+static int xe_debug_data_check_remove(struct xe_vm *vm,
+ const struct drm_xe_vm_bind_op_ext_debug_data *ext)
+{
+ struct xe_device *xe = vm->xe;
+ struct xe_debug_data *i;
+ bool found = false;
+
+ if (XE_IOCTL_DBG(xe, !debug_data_is_empty(ext)))
+ return -EINVAL;
+
+ mutex_lock(&vm->debug_data.lock);
+ list_for_each_entry(i, &vm->debug_data.list, link) {
+ found = debug_data_matches(ext, i);
+ if (found)
+ break;
+ }
+ mutex_unlock(&vm->debug_data.lock);
+
+ if (XE_IOCTL_DBG(xe, !found)) {
+ drm_dbg(&xe->drm, "Debug data to remove not found for addr 0x%llx, range 0x%llx\n",
+ ext->addr, ext->range);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+int xe_debug_data_check_extension(struct xe_vm *vm, u32 operation, u64 extension)
+{
+ const u64 __user * const address = u64_to_user_ptr(extension);
+ struct drm_xe_vm_bind_op_ext_debug_data *ext;
+ struct xe_device *xe = vm->xe;
+ int ret;
+
+ if (XE_IOCTL_DBG(xe, operation != DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA &&
+ operation != DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA))
+ return -EINVAL;
+
+ ext = kzalloc_obj(*ext, GFP_KERNEL);
+ if (!ext)
+ return -ENOMEM;
+
+ if (copy_from_user(ext, address, sizeof(*ext))) {
+ kfree(ext);
+ return -EFAULT;
+ }
+
+ if (XE_IOCTL_DBG(xe, ext->flags & ~DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) ||
+ XE_IOCTL_DBG(xe, ext->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO &&
+ ext->offset != 0) ||
+ XE_IOCTL_DBG(xe, ext->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO &&
+ (ext->pseudopath < DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_MODULE_AREA ||
+ ext->pseudopath > DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SIP_AREA)) ||
+ XE_IOCTL_DBG(xe, !(ext->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) &&
+ strnlen(ext->pathname, PATH_MAX) >= PATH_MAX)) {
+ kfree(ext);
+ return -EINVAL;
+ }
+
+ ret = operation == DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA ?
+ xe_debug_data_check_add(vm, ext) :
+ xe_debug_data_check_remove(vm, ext);
+
+ kfree(ext);
+ return ret;
+}
+
+static int xe_debug_data_add(struct xe_vm *vm, struct xe_vma_op *vma_op,
+ struct drm_xe_vm_bind_op_ext_debug_data *ext)
+{
+ struct xe_debug_data *dd;
+
+ vm_dbg(&vm->xe->drm,
+ "ADD_DEBUG_DATA: addr=0x%016llx, range=0x%016llx, offset=0x%08x, flags=0x%016llx, path=%s\n",
+ ext->addr, ext->range, ext->offset, ext->flags,
+ (ext->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) ?
+ xe_debug_data_pseudo_path_to_string(ext->pseudopath) : ext->pathname);
+
+ dd = kzalloc_obj(*dd, GFP_KERNEL);
+ if (!dd)
+ return -ENOMEM;
+
+ dd->addr = ext->addr;
+ dd->range = ext->range;
+ dd->flags = ext->flags;
+ dd->offset = ext->offset;
+
+ if (ext->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) {
+ dd->pseudopath = ext->pseudopath;
+ } else if (strscpy(dd->pathname, ext->pathname, PATH_MAX) < 0) {
+ kfree(dd);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vm->debug_data.lock);
+ list_add_tail(&dd->link, &vm->debug_data.list);
+ mutex_unlock(&vm->debug_data.lock);
+
+ memcpy(&vma_op->modify_debug_data.debug_data, dd, sizeof(*dd));
+
+ return 0;
+}
+
+static int xe_debug_data_remove(struct xe_vm *vm, struct xe_vma_op *vma_op,
+ struct drm_xe_vm_bind_op_ext_debug_data *ext)
+{
+ struct xe_debug_data *dd;
+
+ vm_dbg(&vm->xe->drm,
+ "REMOVE_DEBUG_DATA: addr=0x%016llx, range=0x%016llx, offset=0x%08x, flags=0x%016llx, path=%s\n",
+ ext->addr, ext->range, ext->offset, ext->flags,
+ (ext->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) ?
+ xe_debug_data_pseudo_path_to_string(ext->pseudopath) : ext->pathname);
+
+ mutex_lock(&vm->debug_data.lock);
+ list_for_each_entry(dd, &vm->debug_data.list, link) {
+ if (dd->addr == ext->addr && dd->range == ext->range) {
+ list_del(&dd->link);
+ memcpy(&vma_op->modify_debug_data.debug_data, dd, sizeof(*dd));
+ kfree(dd);
+ break;
+ }
+ }
+ mutex_unlock(&vm->debug_data.lock);
+
+ return 0;
+}
+
+int xe_debug_data_process_extension(struct xe_vm *vm, struct drm_gpuva_ops *ops, u32 operation,
+ u64 extension)
+{
+ const u64 __user * const address = u64_to_user_ptr(extension);
+ struct drm_xe_vm_bind_op_ext_debug_data *ext;
+ struct xe_vma_op *vma_op;
+ struct drm_gpuva_op *op;
+ int ret;
+
+ ext = kzalloc_obj(*ext, GFP_KERNEL);
+ if (!ext)
+ return -ENOMEM;
+
+ if (copy_from_user(ext, address, sizeof(*ext))) {
+ kfree(ext);
+ return -EFAULT;
+ }
+
+ /* We expect only a single op for debug data */
+ op = drm_gpuva_first_op(ops);
+ if (op != drm_gpuva_last_op(ops))
+ drm_warn(&vm->xe->drm, "NOT POSSIBLE");
+
+ vma_op = gpuva_op_to_vma_op(op);
+
+ if (vma_op->subop == XE_VMA_SUBOP_ADD_DEBUG_DATA)
+ ret = xe_debug_data_add(vm, vma_op, ext);
+ else
+ ret = xe_debug_data_remove(vm, vma_op, ext);
+
+ kfree(ext);
+ return ret;
+}
+
+static int xe_debug_data_op_unwind_add(struct xe_vm *vm, struct xe_vma_op *vma_op)
+{
+ const struct xe_debug_data *op_data = &vma_op->modify_debug_data.debug_data;
+ struct xe_debug_data *dd;
+
+ vm_dbg(&vm->xe->drm,
+ "Reverting debug data add: addr=0x%016llx, range=0x%016llx, offset=0x%08x, flags=0x%016llx, path=%s\n",
+ op_data->addr, op_data->range, op_data->offset, op_data->flags,
+ (op_data->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) ?
+ xe_debug_data_pseudo_path_to_string(op_data->pseudopath) : op_data->pathname);
+
+ mutex_lock(&vm->debug_data.lock);
+ list_for_each_entry(dd, &vm->debug_data.list, link) {
+ if (dd->addr == op_data->addr && dd->range == op_data->range) {
+ list_del(&dd->link);
+ kfree(dd);
+ break;
+ }
+ }
+ mutex_unlock(&vm->debug_data.lock);
+
+ return 0;
+}
+
+static int xe_debug_data_op_unwind_remove(struct xe_vm *vm, struct xe_vma_op *vma_op)
+{
+ const struct xe_debug_data *op_data = &vma_op->modify_debug_data.debug_data;
+ struct xe_debug_data *dd;
+
+ vm_dbg(&vm->xe->drm,
+ "Reverting debug data remove: addr=0x%016llx, range=0x%016llx, offset=0x%08x, flags=0x%016llx, path=%s\n",
+ op_data->addr, op_data->range, op_data->offset, op_data->flags,
+ (op_data->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) ?
+ xe_debug_data_pseudo_path_to_string(op_data->pseudopath) : op_data->pathname);
+
+ dd = kzalloc_obj(*dd, GFP_KERNEL);
+ if (!dd)
+ return -ENOMEM;
+
+ memcpy(dd, op_data, sizeof(*dd));
+
+ mutex_lock(&vm->debug_data.lock);
+ list_add_tail(&dd->link, &vm->debug_data.list);
+ mutex_unlock(&vm->debug_data.lock);
+
+ return 0;
+}
+
+int xe_debug_data_op_unwind(struct xe_vm *vm, struct xe_vma_op *vma_op)
+{
+ switch (vma_op->subop) {
+ case XE_VMA_SUBOP_ADD_DEBUG_DATA:
+ return xe_debug_data_op_unwind_add(vm, vma_op);
+ case XE_VMA_SUBOP_REMOVE_DEBUG_DATA:
+ return xe_debug_data_op_unwind_remove(vm, vma_op);
+ default:
+ drm_err(&vm->xe->drm, "Invalid debug data subop %d\n", vma_op->subop);
+ return -EINVAL;
+ }
+}
+
+int xe_debug_data_destroy(struct xe_vm *vm)
+{
+ struct xe_debug_data *dd, *tmp;
+
+ mutex_lock(&vm->debug_data.lock);
+ list_for_each_entry_safe(dd, tmp, &vm->debug_data.list, link) {
+ list_del(&dd->link);
+ kfree(dd);
+ }
+ mutex_unlock(&vm->debug_data.lock);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/xe/xe_debug_data.h b/drivers/gpu/drm/xe/xe_debug_data.h
new file mode 100644
index 000000000000..3436a7023920
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_data.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2025 Intel Corporation
+ */
+
+#ifndef _XE_DEBUG_DATA_H_
+#define _XE_DEBUG_DATA_H_
+
+#include <linux/types.h>
+
+struct drm_gpuva_ops;
+struct xe_vm;
+struct xe_vma_op;
+
+const char *xe_debug_data_pseudo_path_to_string(u64 pseudopath);
+int xe_debug_data_check_extension(struct xe_vm *vm, u32 operation, u64 extension);
+int xe_debug_data_process_extension(struct xe_vm *vm, struct drm_gpuva_ops *ops, u32 operation,
+ u64 extension);
+int xe_debug_data_op_unwind(struct xe_vm *vm, struct xe_vma_op *vma_op);
+int xe_debug_data_destroy(struct xe_vm *vm);
+
+#endif /* _XE_DEBUG_DATA_H_ */
diff --git a/drivers/gpu/drm/xe/xe_debug_data_types.h b/drivers/gpu/drm/xe/xe_debug_data_types.h
new file mode 100644
index 000000000000..a8b430af2275
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_data_types.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2025 Intel Corporation
+ */
+
+#ifndef _XE_DEBUG_DATA_TYPES_H_
+#define _XE_DEBUG_DATA_TYPES_H_
+
+#include <linux/limits.h>
+#include <linux/list.h>
+#include <linux/types.h>
+
+struct xe_debug_data {
+ struct list_head link;
+ u64 addr;
+ u64 range;
+ u64 flags;
+ u32 offset;
+ union {
+ u64 pseudopath;
+ char pathname[PATH_MAX];
+ };
+};
+
+#endif /* _XE_DEBUG_DATA_TYPES_H_ */
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 456ee3bc4073..9a3980e8422a 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -24,6 +24,7 @@
#include "regs/xe_gtt_defs.h"
#include "xe_assert.h"
#include "xe_bo.h"
+#include "xe_debug_data.h"
#include "xe_device.h"
#include "xe_drm_client.h"
#include "xe_eudebug.h"
@@ -1649,6 +1650,9 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef)
for_each_tile(tile, xe, id)
xe_range_fence_tree_init(&vm->rftree[id]);
+ INIT_LIST_HEAD(&vm->debug_data.list);
+ mutex_init(&vm->debug_data.lock);
+
vm->pt_ops = &xelp_pt_ops;
/*
@@ -1952,6 +1956,8 @@ void xe_vm_close_and_put(struct xe_vm *vm)
for_each_tile(tile, xe, id)
xe_range_fence_tree_fini(&vm->rftree[id]);
+ xe_debug_data_destroy(vm);
+
xe_vm_put(vm);
}
@@ -2301,6 +2307,7 @@ static void prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma,
#if IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)
static void print_op(struct xe_device *xe, struct drm_gpuva_op *op)
{
+ struct xe_vma_op *vma_op;
struct xe_vma *vma;
switch (op->op) {
@@ -2335,6 +2342,12 @@ static void print_op(struct xe_device *xe, struct drm_gpuva_op *op)
vm_dbg(&xe->drm, "PREFETCH: addr=0x%016llx, range=0x%016llx",
(ULL)xe_vma_start(vma), (ULL)xe_vma_size(vma));
break;
+ case DRM_GPUVA_OP_DRIVER:
+ vma_op = gpuva_op_to_vma_op(op);
+ if (vma_op->subop != XE_VMA_SUBOP_ADD_DEBUG_DATA &&
+ vma_op->subop != XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ drm_warn(&xe->drm, "Unexpected vma sub op: %d", vma_op->subop);
+ break;
default:
drm_warn(&xe->drm, "NOT POSSIBLE\n");
}
@@ -2379,12 +2392,13 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
struct xe_bo *bo, u64 bo_offset_or_userptr,
u64 addr, u64 range,
u32 operation, u32 flags,
- u32 prefetch_region, u16 pat_index)
+ u32 prefetch_region, u16 pat_index, u64 extensions)
{
struct drm_gem_object *obj = bo ? &bo->ttm.base : NULL;
struct drm_gpuva_ops *ops;
struct drm_gpuva_op *__op;
struct drm_gpuvm_bo *vm_bo;
+ struct xe_vma_op *vma_op;
u64 range_start = addr;
u64 range_end = addr + range;
int err;
@@ -2438,6 +2452,24 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops,
drm_gpuvm_bo_put(vm_bo);
xe_bo_unlock(bo);
break;
+ case DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA:
+ case DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA:
+ ops = kzalloc(sizeof(*ops), GFP_KERNEL);
+ if (!ops)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&ops->list);
+ vma_op = kzalloc_obj(*vma_op, GFP_KERNEL);
+ if (!vma_op) {
+ kfree(ops);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ vma_op->base.op = DRM_GPUVA_OP_DRIVER;
+ vma_op->subop = operation == DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA ?
+ XE_VMA_SUBOP_ADD_DEBUG_DATA : XE_VMA_SUBOP_REMOVE_DEBUG_DATA;
+ list_add_tail(&vma_op->base.entry, &ops->list);
+ break;
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE\n");
ops = ERR_PTR(-EINVAL);
@@ -2712,6 +2744,11 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
case DRM_GPUVA_OP_PREFETCH:
op->flags |= XE_VMA_OP_COMMITTED;
break;
+ case DRM_GPUVA_OP_DRIVER:
+ if (op->subop != XE_VMA_SUBOP_ADD_DEBUG_DATA &&
+ op->subop != XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ drm_warn(&vm->xe->drm, "Unexpected vma sub op: %d", op->subop);
+ break;
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE\n");
}
@@ -2914,6 +2951,11 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
xe_vma_ops_incr_pt_update_ops(vops, op->tile_mask, 1);
break;
+ case DRM_GPUVA_OP_DRIVER:
+ if (op->subop != XE_VMA_SUBOP_ADD_DEBUG_DATA &&
+ op->subop != XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ drm_warn(&vm->xe->drm, "Unexpected vma sub op: %d", op->subop);
+ break;
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE\n");
}
@@ -2987,6 +3029,13 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
case DRM_GPUVA_OP_PREFETCH:
/* Nothing to do */
break;
+ case DRM_GPUVA_OP_DRIVER:
+ if (op->subop == XE_VMA_SUBOP_ADD_DEBUG_DATA ||
+ op->subop == XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ xe_debug_data_op_unwind(vm, op);
+ else
+ drm_warn(&vm->xe->drm, "Unexpected vma sub op: %d", op->subop);
+ break;
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE\n");
}
@@ -3235,6 +3284,11 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
exec);
break;
}
+ case DRM_GPUVA_OP_DRIVER:
+ if (op->subop != XE_VMA_SUBOP_ADD_DEBUG_DATA &&
+ op->subop != XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ drm_warn(&vm->xe->drm, "Unexpected vma sub op: %d", op->subop);
+ break;
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE\n");
}
@@ -3474,6 +3528,11 @@ static void op_add_ufence(struct xe_vm *vm, struct xe_vma_op *op,
case DRM_GPUVA_OP_PREFETCH:
vma_add_ufence(gpuva_to_vma(op->base.prefetch.va), ufence);
break;
+ case DRM_GPUVA_OP_DRIVER:
+ if (op->subop != XE_VMA_SUBOP_ADD_DEBUG_DATA &&
+ op->subop != XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ drm_warn(&vm->xe->drm, "Unexpected vma sub op: %d", op->subop);
+ break;
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE\n");
}
@@ -3561,6 +3620,79 @@ ALLOW_ERROR_INJECTION(vm_bind_ioctl_ops_execute, ERRNO);
#define XE_64K_PAGE_MASK 0xffffull
#define ALL_DRM_XE_SYNCS_FLAGS (DRM_XE_SYNCS_FLAG_WAIT_FOR_OP)
+#define MAX_USER_EXTENSIONS 16
+
+typedef int (*xe_vm_bind_user_extension_check_fn)(struct xe_vm *vm, u32 operation, u64 extension);
+
+typedef int (*xe_vm_bind_user_extension_process_fn)(struct xe_vm *vm, struct drm_gpuva_ops *ops,
+ u32 operation, u64 extension);
+
+static const xe_vm_bind_user_extension_check_fn vm_bind_extension_check_funcs[] = {
+ [XE_VM_BIND_OP_EXTENSIONS_DEBUG_DATA] = xe_debug_data_check_extension,
+};
+
+static const xe_vm_bind_user_extension_process_fn vm_bind_extension_process_funcs[] = {
+ [XE_VM_BIND_OP_EXTENSIONS_DEBUG_DATA] = xe_debug_data_process_extension,
+};
+
+#define MAX_USER_EXTENSIONS 16
+static int __vm_bind_op_user_extensions(struct xe_vm *vm, struct drm_gpuva_ops *ops,
+ u32 operation, u64 extensions)
+{
+ struct xe_device *xe = vm->xe;
+ int debug_data_count = 0;
+ int ext_count = 0;
+ int err = -1;
+
+ struct drm_xe_user_extension ext;
+
+ while (extensions) {
+ u64 __user *address = u64_to_user_ptr(extensions);
+
+ if (XE_IOCTL_DBG(xe, ++ext_count >= MAX_USER_EXTENSIONS))
+ return -E2BIG;
+
+ err = copy_from_user(&ext, address, sizeof(ext));
+ if (XE_IOCTL_DBG(xe, err))
+ return -EFAULT;
+
+ if (XE_IOCTL_DBG(xe, operation != DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA &&
+ operation != DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA &&
+ ext.name == XE_VM_BIND_OP_EXTENSIONS_DEBUG_DATA) ||
+ XE_IOCTL_DBG(xe, ext.name == XE_VM_BIND_OP_EXTENSIONS_DEBUG_DATA &&
+ ++debug_data_count > 1))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, ext.pad) ||
+ XE_IOCTL_DBG(xe, ext.name > XE_VM_BIND_OP_EXTENSIONS_DEBUG_DATA))
+ return -EINVAL;
+
+ if (!ops)
+ err = vm_bind_extension_check_funcs[ext.name](vm, operation, extensions);
+ else
+ err = vm_bind_extension_process_funcs[ext.name](vm, ops, operation,
+ extensions);
+
+ if (XE_IOCTL_DBG(xe, err))
+ return err;
+
+ extensions = ext.next_extension;
+ }
+
+ return 0;
+}
+
+static int vm_bind_ioctl_check_user_extensions(struct xe_vm *vm, u32 operation, u64 extensions)
+{
+ return __vm_bind_op_user_extensions(vm, NULL, operation, extensions);
+}
+
+static int vm_bind_ioctl_process_user_extensions(struct xe_vm *vm, struct drm_gpuva_ops *ops,
+ u32 operation, u64 extensions)
+{
+ return __vm_bind_op_user_extensions(vm, ops, operation, extensions);
+}
+
static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm,
struct drm_xe_vm_bind *args,
struct drm_xe_vm_bind_op **bind_ops)
@@ -3612,6 +3744,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm,
DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR;
bool is_decompress = flags & DRM_XE_VM_BIND_FLAG_DECOMPRESS;
u16 pat_index = (*bind_ops)[i].pat_index;
+ u64 extensions = (*bind_ops)[i].extensions;
u16 coh_mode;
bool comp_en;
@@ -3641,7 +3774,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm,
goto free_bind_ops;
}
- if (XE_IOCTL_DBG(xe, op > DRM_XE_VM_BIND_OP_PREFETCH) ||
+ if (XE_IOCTL_DBG(xe, op > DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA) ||
XE_IOCTL_DBG(xe, flags & ~SUPPORTED_FLAGS) ||
XE_IOCTL_DBG(xe, obj && (is_null || is_cpu_addr_mirror)) ||
XE_IOCTL_DBG(xe, obj_offset && (is_null ||
@@ -3693,7 +3826,9 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm,
XE_IOCTL_DBG(xe, addr & ~PAGE_MASK) ||
XE_IOCTL_DBG(xe, range & ~PAGE_MASK) ||
XE_IOCTL_DBG(xe, !range &&
- op != DRM_XE_VM_BIND_OP_UNMAP_ALL)) {
+ op != DRM_XE_VM_BIND_OP_UNMAP_ALL &&
+ op != DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA &&
+ op != DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA)) {
err = -EINVAL;
goto free_bind_ops;
}
@@ -3704,6 +3839,10 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm,
err = -EOPNOTSUPP;
goto free_bind_ops;
}
+
+ err = vm_bind_ioctl_check_user_extensions(vm, op, extensions);
+ if (err)
+ goto free_bind_ops;
}
return 0;
@@ -3981,11 +4120,17 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
u64 obj_offset = bind_ops[i].obj_offset;
u32 prefetch_region = bind_ops[i].prefetch_mem_region_instance;
u16 pat_index = bind_ops[i].pat_index;
+ u64 extensions = bind_ops[i].extensions;
ops[i] = vm_bind_ioctl_ops_create(vm, &vops, bos[i], obj_offset,
addr, range, op, flags,
- prefetch_region, pat_index);
- if (IS_ERR(ops[i])) {
+ prefetch_region, pat_index, extensions);
+
+ if (!IS_ERR(ops[i]) && extensions) {
+ err = vm_bind_ioctl_process_user_extensions(vm, ops[i], op, extensions);
+ if (err)
+ goto unwind_ops;
+ } else if (IS_ERR(ops[i])) {
err = PTR_ERR(ops[i]);
ops[i] = NULL;
goto unwind_ops;
@@ -4211,7 +4356,7 @@ struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo,
ops = vm_bind_ioctl_ops_create(vm, &vops, bo, 0, addr, xe_bo_size(bo),
DRM_XE_VM_BIND_OP_MAP, 0, 0,
- xe_cache_pat_idx(vm->xe, cache_lvl));
+ xe_cache_pat_idx(vm->xe, cache_lvl), 0);
if (IS_ERR(ops)) {
err = PTR_ERR(ops);
goto release_vm_lock;
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index 635ed29b9a69..d24e594e7c33 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -15,6 +15,7 @@
#include <linux/mmu_notifier.h>
#include <linux/scatterlist.h>
+#include "xe_debug_data_types.h"
#include "xe_device_types.h"
#include "xe_pt_types.h"
#include "xe_range_fence.h"
@@ -406,6 +407,12 @@ struct xe_vm {
bool batch_invalidate_tlb;
/** @xef: Xe file handle for tracking this VM's drm client */
struct xe_file *xef;
+
+ /** @debug_data: track debug_data mapped to vm */
+ struct {
+ struct list_head list;
+ struct mutex lock;
+ } debug_data;
};
/** struct xe_vma_op_map - VMA map operation */
@@ -479,6 +486,12 @@ struct xe_vma_op_prefetch_range {
struct drm_pagemap *dpagemap;
};
+/** struct xe_vma_op_debug_data - debug data altering operation */
+struct xe_vma_op_modify_debug_data {
+ /** @debug_data: debug data associated with that operation */
+ struct xe_debug_data debug_data;
+};
+
/** enum xe_vma_op_flags - flags for VMA operation */
enum xe_vma_op_flags {
/** @XE_VMA_OP_COMMITTED: VMA operation committed */
@@ -495,6 +508,10 @@ enum xe_vma_subop {
XE_VMA_SUBOP_MAP_RANGE,
/** @XE_VMA_SUBOP_UNMAP_RANGE: Unmap range */
XE_VMA_SUBOP_UNMAP_RANGE,
+ /** @XE_VMA_SUBOP_ADD_DEBUG_DATA: Add debug data to vm */
+ XE_VMA_SUBOP_ADD_DEBUG_DATA,
+ /** @XE_VMA_SUBOP_REMOVE_DEBUG_DATA: Remove debug data from vm */
+ XE_VMA_SUBOP_REMOVE_DEBUG_DATA,
};
/** struct xe_vma_op - VMA operation */
@@ -523,6 +540,8 @@ struct xe_vma_op {
struct xe_vma_op_unmap_range unmap_range;
/** @prefetch_range: VMA prefetch range operation specific data */
struct xe_vma_op_prefetch_range prefetch_range;
+ /** @debug_data: debug_data operation specific data */
+ struct xe_vma_op_modify_debug_data modify_debug_data;
};
};
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index ed53a56ad71b..2d90402d4e4e 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -6,6 +6,8 @@
#ifndef _UAPI_XE_DRM_H_
#define _UAPI_XE_DRM_H_
+#include <linux/limits.h>
+
#include "drm.h"
#if defined(__cplusplus)
@@ -1020,6 +1022,63 @@ struct drm_xe_vm_destroy {
__u64 reserved[2];
};
+/**
+ * struct drm_xe_vm_bind_op_ext_debug_data - debug data extension struct for
+ * :c:type:`drm_xe_vm_bind_op`
+ *
+ * The GPU VM can be annotated by issuing a bind operation with the
+ * :c:member:`drm_xe_vm_bind_op.op` set to %DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA or
+ * %DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA. Each such operation has to provide a
+ * :c:type:`drm_xe_vm_bind_op_ext_debug_data` extension, which describes the
+ * debug data to add or remove.
+ *
+ * This extension can either point to a file that contains relevant debug data
+ * or annotate the VM range with a pseudopath by setting the
+ * %DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO flag and providing one of the supported
+ * pseudopath values:
+ * - %DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_MODULE_AREA
+ * - %DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SBA_AREA
+ * - %DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SIP_AREA
+ *
+ */
+struct drm_xe_vm_bind_op_ext_debug_data {
+ /** @base: Base user extension */
+ struct drm_xe_user_extension base;
+
+ /** @addr: Address of the debug data mapping */
+ __u64 addr;
+
+ /** @range: Range of the debug data mapping */
+ __u64 range;
+
+#define DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO (1 << 0)
+ /** @flags: Debug data flags */
+ __u64 flags;
+
+ /**
+ * @offset: Offset into the debug data file, MBZ when
+ * %DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO is set
+ */
+ __u32 offset;
+
+ /** @reserved: Reserved */
+ __u32 reserved;
+
+ union {
+#define DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_MODULE_AREA 0x1
+#define DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SBA_AREA 0x2
+#define DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SIP_AREA 0x3
+ /**
+ * @pseudopath: Pseudopath used when
+ * %DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO is set
+ */
+ __u64 pseudopath;
+
+ /** @pathname: Path to the debug data file */
+ char pathname[PATH_MAX];
+ };
+};
+
/**
* struct drm_xe_vm_bind_op - run bind operations
*
@@ -1029,6 +1088,8 @@ struct drm_xe_vm_destroy {
* - %DRM_XE_VM_BIND_OP_MAP_USERPTR
* - %DRM_XE_VM_BIND_OP_UNMAP_ALL
* - %DRM_XE_VM_BIND_OP_PREFETCH
+ * - %DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA
+ * - %DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA
*
* and the @flags can be:
* - %DRM_XE_VM_BIND_FLAG_READONLY - Setup the page tables as read-only
@@ -1080,6 +1141,7 @@ struct drm_xe_vm_destroy {
* the memory region advised by madvise.
*/
struct drm_xe_vm_bind_op {
+#define XE_VM_BIND_OP_EXTENSIONS_DEBUG_DATA 0
/** @extensions: Pointer to the first extension struct, if any */
__u64 extensions;
@@ -1173,6 +1235,8 @@ struct drm_xe_vm_bind_op {
#define DRM_XE_VM_BIND_OP_MAP_USERPTR 0x2
#define DRM_XE_VM_BIND_OP_UNMAP_ALL 0x3
#define DRM_XE_VM_BIND_OP_PREFETCH 0x4
+#define DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA 0x5
+#define DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA 0x6
/** @op: Bind operation to perform */
__u32 op;
--
2.43.0
next prev parent reply other threads:[~2026-04-30 10:52 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-30 10:50 [PATCH 00/24] Intel Xe GPU Debug Support (eudebug) v8 Mika Kuoppala
2026-04-30 10:50 ` [PATCH 01/24] drm/xe/eudebug: Introduce eudebug interface Mika Kuoppala
2026-04-30 10:50 ` [PATCH 02/24] drm/xe/eudebug: Add documentation Mika Kuoppala
2026-04-30 10:50 ` [PATCH 03/24] drm/xe/eudebug: Add connection establishment documentation Mika Kuoppala
2026-04-30 10:51 ` [PATCH 04/24] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
2026-04-30 10:51 ` [PATCH 05/24] drm/xe/eudebug: Introduce exec_queue events Mika Kuoppala
2026-04-30 10:51 ` [PATCH 06/24] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
2026-04-30 10:51 ` [PATCH 07/24] drm/xe/eudebug: Mark guc contexts as debuggable Mika Kuoppala
2026-04-30 10:51 ` Mika Kuoppala [this message]
2026-04-30 10:51 ` [PATCH 09/24] drm/xe/eudebug: Introduce vm bind and vm bind debug data events Mika Kuoppala
2026-04-30 10:51 ` [PATCH 10/24] drm/xe/eudebug: Add ufence events with acks Mika Kuoppala
2026-04-30 10:51 ` [PATCH 11/24] drm/xe/eudebug: vm open/pread/pwrite Mika Kuoppala
2026-04-30 10:51 ` [PATCH 12/24] drm/xe/eudebug: userptr vm pread/pwrite Mika Kuoppala
2026-04-30 10:51 ` [PATCH 13/24] drm/xe/eudebug: hw enablement for eudebug Mika Kuoppala
2026-04-30 10:51 ` [PATCH 14/24] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
2026-04-30 10:51 ` [PATCH 15/24] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
2026-04-30 10:51 ` [PATCH 16/24] drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test Mika Kuoppala
2026-04-30 14:16 ` Michal Wajdeczko
2026-04-30 10:51 ` [PATCH 17/24] drm/xe: Implement SR-IOV and eudebug exclusivity Mika Kuoppala
2026-04-30 10:51 ` [PATCH 18/24] drm/xe: Add xe_client_debugfs and introduce debug_data file Mika Kuoppala
2026-04-30 10:51 ` [PATCH 19/24] drm/xe/eudebug: Allow getting eudebug instance during discovery Mika Kuoppala
2026-04-30 10:51 ` [PATCH 20/24] drm/xe/eudebug: Add read/count/compare helper for eu attention Mika Kuoppala
2026-04-30 10:51 ` [PATCH 21/24] drm/xe/vm: Support for adding null page VMA to VM on request Mika Kuoppala
2026-04-30 10:51 ` [PATCH 22/24] drm/xe/eudebug: Introduce EU pagefault handling interface Mika Kuoppala
2026-04-30 19:50 ` Gwan-gyeong Mun
2026-04-30 10:51 ` [PATCH 23/24] drm/xe/eudebug: Enable EU pagefault handling Mika Kuoppala
2026-04-30 10:51 ` [PATCH 24/24] drm/xe/eudebug: Disable SVM in Xe for Eudebug Mika Kuoppala
2026-04-30 19:22 ` Matthew Brost
2026-04-30 11:09 ` ✗ CI.checkpatch: warning for Intel Xe GPU Debug Support (eudebug) v8 Patchwork
2026-04-30 11:10 ` ✓ CI.KUnit: success " Patchwork
2026-04-30 12:06 ` ✓ Xe.CI.BAT: " Patchwork
2026-04-30 22:41 ` ✗ Xe.CI.FULL: failure " Patchwork
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=20260430105121.712843-9-mika.kuoppala@linux.intel.com \
--to=mika.kuoppala@linux.intel.com \
--cc=andrzej.hajda@intel.com \
--cc=christian.koenig@amd.com \
--cc=christoph.manszewski@intel.com \
--cc=dominik.karol.piatkowski@intel.com \
--cc=gustavo.sousa@intel.com \
--cc=gwan-gyeong.mun@intel.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=jan.maslak@intel.com \
--cc=joonas.lahtinen@linux.intel.com \
--cc=maciej.patelczyk@intel.com \
--cc=matthew.auld@intel.com \
--cc=matthew.brost@intel.com \
--cc=rodrigo.vivi@intel.com \
--cc=simona.vetter@ffwll.ch \
--cc=thomas.hellstrom@linux.intel.com \
/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