* [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10
@ 2026-09-03 14:59 Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 01/27] drm/xe/eudebug: Introduce eudebug interface Mika Kuoppala
` (32 more replies)
0 siblings, 33 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
Hi,
This is the v10 patch series for Intel Xe GPU debug support (eudebug).
This series continues from the following previous submissions:
- v1: https://lists.freedesktop.org/archives/intel-xe/2024-July/043605.html
- v2: https://lists.freedesktop.org/archives/intel-xe/2024-October/052260.html
- v3: https://lists.freedesktop.org/archives/intel-xe/2024-December/061476.html
- v4: https://lists.freedesktop.org/archives/intel-xe/2025-August/091645.html
- v5: https://lists.freedesktop.org/archives/intel-xe/2025-October/097859.html
- v6: https://lists.freedesktop.org/archives/intel-xe/2025-December/106405.html
- v7: https://lists.freedesktop.org/archives/intel-xe/2026-February/115750.html
- v8: https://lists.freedesktop.org/archives/intel-xe/2026-April/124147.html
- v9: https://lists.freedesktop.org/archives/intel-xe/2026-June/128834.html
# Series layout: core and page faults
v9 shipped eudebug core only, with EU page fault handling split out to be
sent separately. In v10 the page fault work is included again, but it is
deliberately kept as a distinct block on top of the core:
- Patches 1-19 are eudebug core. This is a self-contained, functional
debugger interface and can be reviewed and merged on its own.
- Patches 20-27 add EU page fault handling on top. They touch xe page
fault and SVM paths, and nothing in patches 1-19 depends on them.
They are posted together for completeness, so that reviewers can see
where the core interface is heading and judge the core design with the
page fault use case in view. Treat the second block as a follow-up series
that happens to be in the same posting.
# Major Changes from v9
Page fault support is back in the series (see above).
Continued to work through Sashiko feedback, plus review comments on v9.
Core eudebug:
- Reworked the eudebug workqueues. Deferred ufence signalling no longer
shares the ordered discovery workqueue, and the per device attention
poller moved off the shared system workqueue onto a device workqueue of
its own. Both were sources of head of line blocking: a client's ufence
signal, which is what releases the debuggee from wait_user_fence, could
queue behind an unrelated client's discovery, and the attention poller
blocks on eudebug.lock across a gt reset.
- Connection lifetime and teardown fixes: wake up after detach taking the
occupied event into account, O_CLOEXEC on the connection fd, hold the
drm_device for the lifetime of the connection, do not silently truncate
the target fd, and reject zero as a target fd.
- Event fifo allocated with GFP_KERNEL_ACCOUNT, resource handles preallocated.
- ufence acks: avoid double signal when the fence is not tracked, clear
the bind ref seqno when there is no debugger or when tracking fails,
and stop referencing the ack after dropping the lock.
- EU control: take runtime pm around hw access, gate SR-IOV, proper
teardown when runtime is not active, and no warn on wrong context.
- Documentation and kernel-doc fixes throughout, including the ioctl_lock
in struct xe_file, which is held across a whole ioctl and therefore
nests outside every lock those ioctls take. The security model DOC now
states which fd acquisition methods the ptrace_may_access() parity
claim actually covers.
Page faults:
Reworked on top of 'Fine grained fault locking, threaded prefetch,
storm cache' series (merged). Added svm support and improved multiple
fault handling.
TODO:
access_process_vm(task, ...) still has the possible race with
execve due to mm changing for task, pointed by Sashiko.
See the relevant code and XXX FIXME in xe_eudebug_vm.c, in
xe_eudebug_vma_access(), and in xe_eudebug_track_userptr_task()
in xe_userptr.h. The most straightforward way to fix this
would be to export access_remote_vm(mm, ...) and then use the
notifier mm for it.
# Supported Hardware
- Lunarlake (LNL)
- Battlemage (BMG)
- Pantherlake (PTL)
The code for this submission can be found at:
https://gitlab.freedesktop.org/miku/kernel/-/tree/eudebug-v10
Tests:
https://gitlab.freedesktop.org/DominikPiatkowski-Intel/igt-gpu-tools/-/tree/eudebug-dev-next
Christoph Manszewski (5):
drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops
drm/xe/eudebug: Introduce vm bind and vm bind debug data events
drm/xe/eudebug_test: Introduce eudebug live tests
drm/xe: Implement SR-IOV and eudebug exclusivity
drm/xe: Add xe_client_debugfs and introduce debug_data file
Dominik Grzegorzek (5):
drm/xe: Add EUDEBUG_ENABLE exec queue property
drm/xe/eudebug: Introduce exec_queue events
drm/xe/eudebug: Add hw enablement
drm/xe/eudebug: Introduce EU control interface
drm/xe/eudebug: Introduce per device attention scan worker
Gwan-gyeong Mun (5):
drm/xe/eudebug: Add read/count/compare helper for eu attention
drm/xe/vm: Support for adding null page VMA to VM on request
drm/xe/vm: Add xe_vm_svm_vma_subtract() to carve out a sub-range from
an SVM VMA
drm/xe/eudebug: Introduce EU pagefault handling interface
drm/xe/eudebug: Enable EU pagefault handling
Maciej Patelczyk (3):
drm/xe/pagefault: export pagefault queue properties
drm/xe: Support for xe_vma_unbind()
drm/xe: export prep_vma_destroy as xe_vm_prep_vma_destroy
Mika Kuoppala (9):
drm/xe/eudebug: Introduce eudebug interface
drm/xe/eudebug: Add documentation
drm/xe/eudebug: Add connection establishment documentation
drm/xe/eudebug: Introduce discovery for resources
drm/xe/eudebug: Mark guc contexts as debuggable
drm/xe: Remove ifdef in DRM_GPUVA_OP_DRIVER svm subop checking
drm/xe/eudebug: Add ufence events with acks
drm/xe/eudebug: Add vm open/pread/pwrite
drm/xe/eudebug: Add userptr vm pread/pwrite
.../ABI/testing/sysfs-driver-intel-xe-eudebug | 21 +
Documentation/gpu/driver-uapi.rst | 2 +
Documentation/gpu/xe/index.rst | 1 +
Documentation/gpu/xe/xe_eudebug.rst | 83 +
MAINTAINERS | 2 +
drivers/gpu/drm/xe/Kconfig | 10 +
drivers/gpu/drm/xe/Makefile | 7 +-
drivers/gpu/drm/xe/abi/guc_actions_abi.h | 5 +
drivers/gpu/drm/xe/abi/guc_klvs_abi.h | 1 +
drivers/gpu/drm/xe/regs/xe_engine_regs.h | 1 +
drivers/gpu/drm/xe/regs/xe_gt_regs.h | 43 +
drivers/gpu/drm/xe/tests/xe_eudebug_test.c | 227 ++
drivers/gpu/drm/xe/tests/xe_live_test_mod.c | 5 +
drivers/gpu/drm/xe/xe_client_debugfs.c | 108 +
drivers/gpu/drm/xe/xe_client_debugfs.h | 17 +
drivers/gpu/drm/xe/xe_debug_data.c | 383 +++
drivers/gpu/drm/xe/xe_debug_data.h | 22 +
drivers/gpu/drm/xe/xe_debug_data_types.h | 25 +
drivers/gpu/drm/xe/xe_device.c | 28 +-
drivers/gpu/drm/xe/xe_device.h | 42 +
drivers/gpu/drm/xe/xe_device_types.h | 57 +
drivers/gpu/drm/xe/xe_eudebug.c | 2514 +++++++++++++++++
drivers/gpu/drm/xe/xe_eudebug.h | 119 +
drivers/gpu/drm/xe/xe_eudebug_hw.c | 730 +++++
drivers/gpu/drm/xe/xe_eudebug_hw.h | 30 +
drivers/gpu/drm/xe/xe_eudebug_pagefault.c | 722 +++++
drivers/gpu/drm/xe/xe_eudebug_pagefault.h | 81 +
drivers/gpu/drm/xe/xe_eudebug_types.h | 284 ++
drivers/gpu/drm/xe/xe_eudebug_vm.c | 501 ++++
drivers/gpu/drm/xe/xe_eudebug_vm.h | 8 +
drivers/gpu/drm/xe/xe_exec_queue.c | 77 +-
drivers/gpu/drm/xe/xe_exec_queue.h | 2 +
drivers/gpu/drm/xe/xe_exec_queue_types.h | 7 +
drivers/gpu/drm/xe/xe_gt_debug.c | 251 ++
drivers/gpu/drm/xe/xe_gt_debug.h | 36 +
drivers/gpu/drm/xe/xe_gt_debug_types.h | 22 +
drivers/gpu/drm/xe/xe_guc.c | 8 +
drivers/gpu/drm/xe/xe_guc.h | 6 +
drivers/gpu/drm/xe/xe_guc_ads.c | 12 +
drivers/gpu/drm/xe/xe_guc_pagefault.c | 10 +-
drivers/gpu/drm/xe/xe_guc_submit.c | 34 +
drivers/gpu/drm/xe/xe_guc_submit.h | 1 +
drivers/gpu/drm/xe/xe_hw_engine.h | 14 +
drivers/gpu/drm/xe/xe_pagefault.c | 150 +-
drivers/gpu/drm/xe/xe_pagefault.h | 10 +
drivers/gpu/drm/xe/xe_pagefault_types.h | 38 +-
drivers/gpu/drm/xe/xe_pt.c | 2 -
drivers/gpu/drm/xe/xe_reg_sr.c | 12 +-
drivers/gpu/drm/xe/xe_reg_sr.h | 4 +-
drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +-
drivers/gpu/drm/xe/xe_rtp.c | 2 +-
drivers/gpu/drm/xe/xe_sync.c | 45 +-
drivers/gpu/drm/xe/xe_sync.h | 7 +-
drivers/gpu/drm/xe/xe_sync_types.h | 29 +-
drivers/gpu/drm/xe/xe_userptr.c | 4 +
drivers/gpu/drm/xe/xe_userptr.h | 32 +
drivers/gpu/drm/xe/xe_vm.c | 491 +++-
drivers/gpu/drm/xe/xe_vm.h | 13 +
drivers/gpu/drm/xe/xe_vm_types.h | 28 +
drivers/gpu/drm/xe/xe_wa_oob.rules | 4 +
include/uapi/drm/xe_drm.h | 89 +
include/uapi/drm/xe_drm_eudebug.h | 416 +++
62 files changed, 7826 insertions(+), 111 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-xe-eudebug
create mode 100644 Documentation/gpu/xe/xe_eudebug.rst
create mode 100644 drivers/gpu/drm/xe/tests/xe_eudebug_test.c
create mode 100644 drivers/gpu/drm/xe/xe_client_debugfs.c
create mode 100644 drivers/gpu/drm/xe/xe_client_debugfs.h
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
create mode 100644 drivers/gpu/drm/xe/xe_eudebug.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug.h
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_hw.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_hw.h
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_pagefault.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_pagefault.h
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_types.h
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_vm.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_vm.h
create mode 100644 drivers/gpu/drm/xe/xe_gt_debug.c
create mode 100644 drivers/gpu/drm/xe/xe_gt_debug.h
create mode 100644 drivers/gpu/drm/xe/xe_gt_debug_types.h
create mode 100644 include/uapi/drm/xe_drm_eudebug.h
--
2.53.0
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v10 01/27] drm/xe/eudebug: Introduce eudebug interface
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:16 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 02/27] drm/xe/eudebug: Add documentation Mika Kuoppala
` (31 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala,
Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
Andi Shyti, Matt Roper, Zbigniew Kempczyński,
Jonathan Cavitt, Christoph Manszewski
Add the eudebug interface to the Xe driver, enabling
user-space debuggers (e.g., GDB) to track and interact with GPU resources
of a DRM client. Debuggers can inspect or modify these resources,
for example, to locate ISA/ELF sections and install breakpoints in a
shader's instruction stream.
A debugger opens a connection to the Xe driver via a DRM ioctl, specifying
the target DRM client's file descriptor. This returns an anonymous file
descriptor for the connection, which can be used to listen for resource
creation/destruction events. The same file descriptor can also be used to
receive hardware state change events and control execution flow by
interrupting EU threads on the GPU (in follow-up patches).
Introduce the eudebug connection and event queuing,
adding VM create/destroy events as a baseline. Additional events and
hardware control for full debugger operation are needed and will be
introduced in follow-up patches.
The resource tracking components are inspired by Maciej Patelczyk's work on
resource handling for i915. Chris Wilson suggested a two-way mapping
approach, which simplifies using the resource map as definitive
bookkeeping for resources relayed to the debugger during the discovery
phase (in a follow-up patch).
v2: - Kconfig support (Matthew)
- ptraced access control (Lucas)
- pass expected event length to user (Zbigniew)
- only track long running VMs
- checkpatch (Tilak)
- include order (Andrzej)
- 32bit fixes (Andrzej)
- cleaner get_task_struct
- remove xa_array and use clients.list for tracking (Mika)
v3: - adapt to removal of clients.lock (Mika)
- create_event cleanup (Christoph)
v4: - add proper header guards (Christoph)
- better read_event fault handling (Christoph, Mika)
- simplify attach (Mika)
- connect using target file descriptors
- avoid event->seqno after queue as it can UAF (Mika)
- use drmm for eudebug_fini (Maciej)
- squash dynamic enable
v6: - drm->authenticated is overzealous for render (Mika)
v7: - struct member documentation (Mika)
- enforce seqno mbz (Mika)
v8: - head->seqno fix (Mika)
- resource alloc and removal cleanup (Mika)
- s/wait_interruptible_timeout/wait_timeout (Mika)
- use fd_install in connect (Mika)
v9: - fix xef vs debugger race (Sashiko)
- assign d->xe early (Sashiko)
- simplify locking (Mika)
- fix pending->len outside lock (Sashiko)
- remove version from connect to address fd_install leak (Sashiko)
- create vm by id to avoid use after free (Sashiko)
- use xe_eudebug_detach on connection error path (Sashiko)
- don't sleep on kzalloc as we can disconnect (Sashiko)
- check if enabled on connection (Sashiko)
- preallocated event fifo for lockless allocs (Sashiko, Mika)
v10:
- wakeup after detach, take account of occupied (Sashiko)
- GFP_ACCOUNT for fifo (Sashiko)
- set O_CLOEXEC on connection fd (Sashiko)
- docstrings (Maciej)
- use guard and __kfree (Mika)
- init_early (Maciej)
- remove unused struct members
- no need to send destroy if vm was not announced (Claude)
- avoid dereference of xef on eu_print (Claude)
- don't silently truncate target fd (Claude)
- preallocate resource handles
- zero as target fd (Claude)
- hold drm_device (Claude)
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Andi Shyti <andi.shyti@linux.intel.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com>
Cc: Andrzej Hajda <andrzej.hajda@intel.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
---
.../ABI/testing/sysfs-driver-intel-xe-eudebug | 21 +
Documentation/gpu/driver-uapi.rst | 2 +
MAINTAINERS | 2 +
drivers/gpu/drm/xe/Kconfig | 10 +
drivers/gpu/drm/xe/Makefile | 3 +
drivers/gpu/drm/xe/xe_device.c | 12 +
drivers/gpu/drm/xe/xe_device_types.h | 30 +
drivers/gpu/drm/xe/xe_eudebug.c | 1068 +++++++++++++++++
drivers/gpu/drm/xe/xe_eudebug.h | 71 ++
drivers/gpu/drm/xe/xe_eudebug_types.h | 131 ++
drivers/gpu/drm/xe/xe_vm.c | 15 +-
include/uapi/drm/xe_drm.h | 23 +
include/uapi/drm/xe_drm_eudebug.h | 101 ++
13 files changed, 1487 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-xe-eudebug
create mode 100644 drivers/gpu/drm/xe/xe_eudebug.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug.h
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_types.h
create mode 100644 include/uapi/drm/xe_drm_eudebug.h
diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-eudebug b/Documentation/ABI/testing/sysfs-driver-intel-xe-eudebug
new file mode 100644
index 000000000000..fa8620001508
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-eudebug
@@ -0,0 +1,21 @@
+What: /sys/bus/pci/drivers/xe/.../enable_eudebug
+Date: August 2026
+KernelVersion: 6.20
+Contact: intel-xe@lists.freedesktop.org
+Description: RW. Controls whether the EU debugger interface is armed for
+ this device.
+
+ Reads back 1 when the interface is enabled and 0 when it is
+ not. Writing a boolean value ("0"/"1", "n"/"y", "off"/"on")
+ enables or disables it. The interface starts out disabled.
+
+ While disabled, DRM_IOCTL_XE_EUDEBUG_CONNECT fails with
+ -EOPNOTSUPP.
+
+ Writing 0 while any debugger connection is still attached
+ fails with -EBUSY.
+
+ This attribute is only present when the driver is built with
+ CONFIG_DRM_XE_EUDEBUG and the interface was set up at probe
+ time. If probe could not set it up, the attribute is absent
+ and the connect ioctl fails with -EOPNOTSUPP.
diff --git a/Documentation/gpu/driver-uapi.rst b/Documentation/gpu/driver-uapi.rst
index 627fc68c7a21..1fbcac949da9 100644
--- a/Documentation/gpu/driver-uapi.rst
+++ b/Documentation/gpu/driver-uapi.rst
@@ -30,6 +30,8 @@ drm/xe uAPI
.. kernel-doc:: include/uapi/drm/xe_drm.h
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+
drm/asahi uAPI
================
diff --git a/MAINTAINERS b/MAINTAINERS
index 6f2a3b56e57d..d20581fd0b75 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13127,11 +13127,13 @@ Q: http://patchwork.freedesktop.org/project/intel-xe/
B: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues
C: irc://irc.oftc.net/xe
T: git https://gitlab.freedesktop.org/drm/xe/kernel.git
+F: Documentation/ABI/testing/sysfs-driver-intel-xe-eudebug
F: Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
F: Documentation/gpu/xe/
F: drivers/gpu/drm/xe/
F: include/drm/intel/
F: include/uapi/drm/xe_drm.h
+F: include/uapi/drm/xe_drm_eudebug.h
INTEL ELKHART LAKE PSE I/O DRIVER
M: Raag Jadav <raag.jadav@intel.com>
diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
index 4d7dcaff2b91..e202448c4583 100644
--- a/drivers/gpu/drm/xe/Kconfig
+++ b/drivers/gpu/drm/xe/Kconfig
@@ -129,6 +129,16 @@ config DRM_XE_FORCE_PROBE
Use "!*" to block the probe of the driver for all known devices.
+config DRM_XE_EUDEBUG
+ bool "Enable gdb debugger support (eudebug)"
+ depends on DRM_XE
+ default y
+ help
+ Choose this option if you want to add support for a debugger (gdb)
+ to attach to a process using Xe and debug its gpu/gpgpu programs.
+ With debugger support, Xe provides an interface for a debugger to
+ track, inspect and modify the resources of that process.
+
menu "drm/Xe Debugging"
depends on DRM_XE
depends on EXPERT
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 67b8b5477639..0631f659e304 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -160,6 +160,9 @@ xe-$(CONFIG_I2C) += xe_i2c.o \
xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
xe-$(CONFIG_DRM_GPUSVM) += xe_userptr.o
+# debugging shaders with gdb (eudebug) support
+xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o
+
# graphics hardware monitoring (HWMON) support
xe-$(CONFIG_HWMON) += xe_hwmon.o
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 8583b2e9ecf4..12c84b7c7758 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -33,6 +33,7 @@
#include "xe_dma_buf.h"
#include "xe_drm_client.h"
#include "xe_drv.h"
+#include "xe_eudebug.h"
#include "xe_exec.h"
#include "xe_exec_queue.h"
#include "xe_force_wake.h"
@@ -111,6 +112,10 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
mutex_init(&xef->exec_queue.lock);
xa_init_flags(&xef->exec_queue.xa, XA_FLAGS_ALLOC1);
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+ INIT_LIST_HEAD(&xef->eudebug.target_link);
+#endif
+
file->driver_priv = xef;
kref_init(&xef->refcount);
@@ -174,6 +179,8 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
guard(xe_pm_runtime)(xe);
+ xe_eudebug_file_close(xef);
+
/*
* No need for exec_queue.lock here as there is no contention for it
* when FD is closing as IOCTLs presumably can't be modifying the
@@ -217,6 +224,7 @@ static const struct drm_ioctl_desc xe_ioctls[] = {
DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(XE_VM_GET_PROPERTY, xe_vm_get_property_ioctl,
DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(XE_EUDEBUG_CONNECT, xe_eudebug_connect_ioctl, DRM_RENDER_ALLOW),
};
static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1117,6 +1125,8 @@ int xe_device_probe(struct xe_device *xe)
if (err)
return err;
+ xe_eudebug_init_early(xe);
+
err = drm_dev_register(&xe->drm, 0);
if (err)
return err;
@@ -1154,6 +1164,8 @@ int xe_device_probe(struct xe_device *xe)
if (err)
goto err_unregister_display;
+ xe_eudebug_init(xe);
+
detect_preproduction_hw(xe);
err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 180d450a6deb..f5a5ff4d8873 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -14,6 +14,7 @@
#include "xe_devcoredump_types.h"
#include "xe_drm_ras_types.h"
+#include "xe_eudebug_types.h"
#include "xe_heci_gsc.h"
#include "xe_late_bind_fw_types.h"
#include "xe_oa_types.h"
@@ -601,6 +602,23 @@ struct xe_device {
atomic_t g2g_test_count;
#endif
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+ /** @eudebug: debugger connection list and globals for device */
+ struct {
+ /** @eudebug.session_count: session counter to track connections */
+ u64 session_count;
+
+ /** @eudebug.cap_state: eudebug capability state */
+ enum xe_eudebug_cap_state cap_state;
+
+ /** @eudebug.targets: this is list for xe_files for each target */
+ struct list_head targets;
+
+ /** @eudebug.lock: protects state and targets */
+ struct mutex lock;
+ } eudebug;
+#endif
+
/* private: */
#if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
@@ -615,6 +633,7 @@ struct xe_device {
spinlock_t lock;
} uncore;
#endif
+
};
/**
@@ -676,6 +695,17 @@ struct xe_file {
/** @refcount: ref count of this xe file */
struct kref refcount;
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+ /** @eudebug: struct to hold eudebug connection specifics */
+ struct {
+ /** @eudebug.debugger: the debugger connection into this xe_file */
+ struct xe_eudebug *debugger;
+
+ /** @eudebug.target_link: link into xe_device.eudebug.targets */
+ struct list_head target_link;
+ } eudebug;
+#endif
};
#endif
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
new file mode 100644
index 000000000000..9fe073f60680
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -0,0 +1,1068 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/uaccess.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_managed.h>
+#include <uapi/drm/xe_drm.h>
+
+#include "xe_assert.h"
+#include "xe_device.h"
+#include "xe_eudebug.h"
+#include "xe_eudebug_types.h"
+#include "xe_macros.h"
+#include "xe_vm.h"
+
+#define cast_event(T, event) container_of((event), typeof(*(T)), base)
+
+static const struct rhashtable_params rhash_res = {
+ .head_offset = offsetof(struct xe_eudebug_handle, rh_head),
+ .key_len = sizeof_field(struct xe_eudebug_handle, key),
+ .key_offset = offsetof(struct xe_eudebug_handle, key),
+ .automatic_shrinking = true,
+};
+
+static struct xe_eudebug_resource *
+resource_from_type(struct xe_eudebug *d, int t)
+{
+ return &d->target.res[t];
+}
+
+static int
+xe_eudebug_resources_init(struct xe_eudebug *d)
+{
+ int ret;
+ int i;
+
+ ret = 0;
+ for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
+ struct xe_eudebug_resource *r = resource_from_type(d, i);
+
+ mutex_init(&r->lock);
+ xa_init_flags(&r->xa, XA_FLAGS_ALLOC1);
+ ret = rhashtable_init(&r->rh, &rhash_res);
+
+ if (ret) {
+ xa_destroy(&r->xa);
+ mutex_destroy(&r->lock);
+ break;
+ }
+ }
+
+ if (!ret)
+ return 0;
+
+ while (i--) {
+ struct xe_eudebug_resource *r = resource_from_type(d, i);
+
+ xa_destroy(&r->xa);
+ rhashtable_destroy(&r->rh);
+ mutex_destroy(&r->lock);
+ }
+
+ return ret;
+}
+
+static void
+xe_eudebug_resources_destroy(struct xe_eudebug *d)
+{
+ unsigned long j;
+ int err;
+ int i;
+
+ for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
+ struct xe_eudebug_resource *r = resource_from_type(d, i);
+ struct xe_eudebug_handle *h;
+
+ mutex_lock(&r->lock);
+ xa_for_each(&r->xa, j, h) {
+ struct xe_eudebug_handle *t;
+
+ err = rhashtable_remove_fast(&r->rh,
+ &h->rh_head,
+ rhash_res);
+ xe_eudebug_assert(d, !err);
+ t = xa_erase(&r->xa, h->id);
+ if (XE_WARN_ON(!t))
+ continue;
+
+ xe_eudebug_assert(d, t == h);
+ kfree(t);
+ }
+ mutex_unlock(&r->lock);
+ }
+
+ for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
+ struct xe_eudebug_resource *r = resource_from_type(d, i);
+
+ rhashtable_destroy(&r->rh);
+ xe_eudebug_assert(d, xa_empty(&r->xa));
+ xa_destroy(&r->xa);
+ mutex_destroy(&r->lock);
+ }
+}
+
+static bool xe_eudebug_detached(struct xe_eudebug *d)
+{
+ return !READ_ONCE(d->target.xef);
+}
+
+static void xe_eudebug_free(struct kref *ref)
+{
+ struct xe_eudebug *d = container_of(ref, typeof(*d), ref);
+
+ xe_assert(d->xe, xe_eudebug_detached(d));
+
+ xe_eudebug_resources_destroy(d);
+ XE_WARN_ON(d->target.xef);
+
+ kvfree(d->events.fifo_buf);
+ kvfree(d->events.staging);
+ kvfree(d->events.pending);
+ kfree(d);
+}
+
+static void xe_eudebug_put(struct xe_eudebug *d)
+{
+ kref_put(&d->ref, xe_eudebug_free);
+}
+
+static bool xe_eudebug_detach(struct xe_eudebug *d,
+ const int err)
+{
+ struct xe_file *target = NULL;
+
+ XE_WARN_ON(err > 0);
+
+ mutex_lock(&d->xe->eudebug.lock);
+ if (d->target.xef) {
+ target = d->target.xef;
+ WRITE_ONCE(d->target.err, err);
+ WRITE_ONCE(d->target.xef, NULL);
+
+ XE_WARN_ON(target->eudebug.debugger != d);
+ target->eudebug.debugger = NULL;
+
+ list_del_init(&target->eudebug.target_link);
+
+ eu_dbg(d, "session %lld detached with %d", d->session, err);
+ }
+ mutex_unlock(&d->xe->eudebug.lock);
+
+ wake_up_all(&d->events.write_done);
+
+ if (target) {
+ xe_eudebug_put(d);
+ xe_file_put(target);
+ }
+
+ return !!target;
+}
+
+#define xe_eudebug_disconnect(_d, _err) ({ \
+ struct xe_eudebug *__disc_d = (_d); \
+ int __disc_err = (_err); \
+ if (xe_eudebug_detach(__disc_d, __disc_err)) { \
+ if (__disc_err == 0 || __disc_err == -ETIMEDOUT) \
+ eu_dbg(__disc_d, "Session closed (%d)", __disc_err); \
+ else \
+ eu_err(__disc_d, "Session disconnected, err = %d (%s:%d)", \
+ __disc_err, __func__, __LINE__); \
+ } \
+})
+
+static int event_fifo_pending(struct xe_eudebug *d,
+ struct drm_xe_eudebug_event **pending)
+{
+ struct drm_xe_eudebug_event *e = d->events.pending;
+ unsigned int len, copied;
+
+ lockdep_assert_held(&d->events.lock);
+
+ *pending = NULL;
+
+ if (xe_eudebug_detached(d))
+ return -ENOTCONN;
+
+ if (d->events.pending_occupied) {
+ *pending = e;
+ return 0;
+ }
+
+ if (kfifo_out_peek(&d->events.fifo, e, sizeof(*e)) < sizeof(*e))
+ return -ENOENT;
+
+ len = e->len;
+ if (len <= sizeof(*e) || len > DRM_XE_EUDEBUG_EVENT_MAX_SIZE) {
+ eu_dbg(d, "bad event len %u", len);
+ return -EIO;
+ }
+
+ copied = kfifo_out(&d->events.fifo, e, len);
+ if (copied != len) {
+ eu_dbg(d, "fifo inconsistency");
+ return -EIO;
+ }
+
+ d->events.pending_occupied = true;
+ *pending = e;
+
+ return 0;
+}
+
+static struct xe_eudebug *
+xe_eudebug_get(struct xe_file *xef)
+{
+ struct xe_device *xe = xef->xe;
+ struct xe_eudebug *d;
+
+ if (READ_ONCE(xe->eudebug.cap_state) == XE_EUDEBUG_CAP_NOT_SUPPORTED)
+ return NULL;
+
+ mutex_lock(&xe->eudebug.lock);
+ d = xef->eudebug.debugger;
+ if (d && !kref_get_unless_zero(&d->ref))
+ d = NULL;
+ mutex_unlock(&xe->eudebug.lock);
+
+ if (d && xe_eudebug_detached(d)) {
+ xe_eudebug_put(d);
+ d = NULL;
+ }
+
+ return d;
+}
+
+static int xe_eudebug_queue_event(struct xe_eudebug *d,
+ struct drm_xe_eudebug_event *event)
+{
+ unsigned int copied;
+
+ lockdep_assert_held(&d->events.lock);
+
+ xe_eudebug_assert(d, event->len > sizeof(struct drm_xe_eudebug_event));
+ xe_eudebug_assert(d, event->type);
+ xe_eudebug_assert(d, event->type != DRM_XE_EUDEBUG_EVENT_READ);
+ xe_eudebug_assert(d, event->len <= DRM_XE_EUDEBUG_EVENT_MAX_SIZE);
+ xe_eudebug_assert(d, event == d->events.staging);
+
+ if (xe_eudebug_detached(d))
+ return -ENOTCONN;
+
+ if (kfifo_avail(&d->events.fifo) < event->len)
+ return -ENOSPC;
+
+ copied = kfifo_in(&d->events.fifo, event, event->len);
+ if (XE_WARN_ON(copied != event->len))
+ return -EIO;
+
+ wake_up_all(&d->events.write_done);
+
+ return 0;
+}
+
+static struct xe_eudebug_handle *
+alloc_handle(const u64 key)
+{
+ struct xe_eudebug_handle *h;
+
+ h = kzalloc_obj(*h, GFP_KERNEL);
+ if (!h)
+ return NULL;
+
+ h->key = key;
+
+ return h;
+}
+
+static struct xe_eudebug_handle *
+__find_handle(struct xe_eudebug_resource *r,
+ const u64 key)
+{
+ struct xe_eudebug_handle *h;
+
+ h = rhashtable_lookup_fast(&r->rh,
+ &key,
+ rhash_res);
+ return h;
+}
+
+static int _xe_eudebug_add_handle(struct xe_eudebug *d,
+ int type,
+ void *p,
+ u64 *seqno)
+{
+ const u64 key = (uintptr_t)p;
+ struct xe_eudebug_resource *r;
+ struct xe_eudebug_handle *h, *o;
+ int id, err;
+
+ if (XE_WARN_ON(!p))
+ return -EINVAL;
+
+ h = alloc_handle(key);
+ if (!h)
+ return -ENOMEM;
+
+ r = resource_from_type(d, type);
+
+ /*
+ * Reserve the id, and the nodes backing it, before taking the lock.
+ * A reserved entry reads back as NULL, so nothing can observe the id
+ * until we store the handle below, and that store is guaranteed to
+ * find the slot already there and so never has to allocate.
+ */
+ err = xa_alloc(&r->xa, &h->id, XA_ZERO_ENTRY, xa_limit_31b, GFP_KERNEL);
+ if (err) {
+ kfree(h);
+ return err;
+ }
+
+ mutex_lock(&r->lock);
+ o = __find_handle(r, key);
+ if (o) {
+ err = -EEXIST;
+ } else {
+ err = rhashtable_insert_fast(&r->rh,
+ &h->rh_head,
+ rhash_res);
+ if (!err) {
+ xa_store(&r->xa, h->id, h, GFP_ATOMIC);
+ if (seqno)
+ *seqno = atomic_long_inc_return(&d->events.seqno);
+ }
+ }
+ id = h->id;
+ mutex_unlock(&r->lock);
+
+ if (err) {
+ xa_erase(&r->xa, id);
+ kfree(h);
+ XE_WARN_ON(err > 0);
+ return err;
+ }
+
+ xe_eudebug_assert(d, id);
+
+ return id;
+}
+
+static int xe_eudebug_add_handle(struct xe_eudebug *d,
+ int type,
+ void *p,
+ u64 *seqno)
+{
+ int ret;
+
+ ret = _xe_eudebug_add_handle(d, type, p, seqno);
+
+ eu_dbg(d, "handle type %d handle %p added: %d\n", type, p, ret);
+
+ return ret;
+}
+
+static int _xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
+ u64 *seqno)
+{
+ const u64 key = (uintptr_t)p;
+ struct xe_eudebug_resource *r;
+ struct xe_eudebug_handle *h, *xa_h;
+ int ret;
+
+ if (XE_WARN_ON(!key))
+ return -EINVAL;
+
+ r = resource_from_type(d, type);
+
+ guard(mutex)(&r->lock);
+ h = __find_handle(r, key);
+ if (!h)
+ return -ENOENT;
+
+ xa_h = xa_load(&r->xa, h->id);
+ if (XE_WARN_ON(!xa_h || xa_h != h))
+ return -EIO;
+
+ ret = rhashtable_remove_fast(&r->rh,
+ &h->rh_head,
+ rhash_res);
+ if (XE_WARN_ON(ret))
+ return -EIO;
+
+ xa_h = xa_erase(&r->xa, h->id);
+ if (XE_WARN_ON(xa_h != h))
+ return -EIO;
+
+ ret = h->id;
+ if (seqno)
+ *seqno = atomic_long_inc_return(&d->events.seqno);
+
+ kfree(h);
+
+ return ret;
+}
+
+static int xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
+ u64 *seqno)
+{
+ int ret;
+
+ ret = _xe_eudebug_remove_handle(d, type, p, seqno);
+
+ eu_dbg(d, "handle type %d handle %p removed: %d\n", type, p, ret);
+
+ return ret;
+}
+
+static struct drm_xe_eudebug_event *
+xe_eudebug_prepare_event(struct xe_eudebug *d, u16 type, u64 seqno, u16 flags,
+ u32 len)
+{
+ const u16 known_flags =
+ DRM_XE_EUDEBUG_EVENT_CREATE |
+ DRM_XE_EUDEBUG_EVENT_DESTROY |
+ DRM_XE_EUDEBUG_EVENT_STATE_CHANGE |
+ DRM_XE_EUDEBUG_EVENT_NEED_ACK;
+ struct drm_xe_eudebug_event *event = d->events.staging;
+
+ lockdep_assert_held(&d->events.lock);
+
+ xe_eudebug_assert(d, type <= XE_EUDEBUG_MAX_EVENT_TYPE);
+ xe_eudebug_assert(d, !(~known_flags & flags));
+ xe_eudebug_assert(d, len > sizeof(*event));
+ xe_eudebug_assert(d, len <= DRM_XE_EUDEBUG_EVENT_MAX_SIZE);
+
+ memset(event, 0, len);
+
+ event->len = len;
+ event->type = type;
+ event->flags = flags;
+ event->seqno = seqno;
+
+ return event;
+}
+
+static int send_vm_event(struct xe_eudebug *d, u32 flags,
+ const u64 vm_handle,
+ const u64 seqno)
+{
+ struct drm_xe_eudebug_event *event;
+ struct drm_xe_eudebug_event_vm *e;
+ int err;
+
+ scoped_guard(spinlock, &d->events.lock) {
+ event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_VM,
+ seqno, flags, sizeof(*e));
+ e = cast_event(e, event);
+ e->vm_handle = vm_handle;
+
+ err = xe_eudebug_queue_event(d, event);
+ }
+
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ return err;
+}
+
+static int vm_create_event(struct xe_eudebug *d, struct xe_vm *vm)
+{
+ int vm_id;
+ u64 seqno;
+ int ret;
+
+ if (!xe_vm_in_lr_mode(vm))
+ return 0;
+
+ vm_id = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
+ if (vm_id < 0)
+ return vm_id;
+
+ ret = send_vm_event(d, DRM_XE_EUDEBUG_EVENT_CREATE, vm_id, seqno);
+ if (ret)
+ eu_dbg(d, "send_vm_event create error %d\n", ret);
+
+ return ret;
+}
+
+static int vm_destroy_event(struct xe_eudebug *d, struct xe_vm *vm)
+{
+ int vm_id;
+ u64 seqno;
+ int ret;
+
+ if (!xe_vm_in_lr_mode(vm))
+ return 0;
+
+ vm_id = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
+ if (vm_id < 0)
+ return vm_id;
+
+ ret = send_vm_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY, vm_id, seqno);
+ if (ret)
+ eu_dbg(d, "send_vm_event destroy error %d\n", ret);
+
+ return ret;
+}
+
+void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm)
+{
+ struct xe_eudebug *d;
+ int err;
+
+ if (!xe_vm_in_lr_mode(vm))
+ return;
+
+ d = xe_eudebug_get(xef);
+ if (!d)
+ return;
+
+ err = vm_create_event(d, vm);
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ xe_eudebug_put(d);
+}
+
+void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
+{
+ struct xe_eudebug *d;
+ int err;
+
+ if (!xe_vm_in_lr_mode(vm))
+ return;
+
+ d = xe_eudebug_get(xef);
+ if (!d)
+ return;
+
+ /*
+ * A vm we never handed out to the debugger needs no destroy event.
+ * Only a genuine bookkeeping inconsistency should drop the session.
+ */
+ err = vm_destroy_event(d, vm);
+ if (err && err != -ENOENT)
+ xe_eudebug_disconnect(d, err);
+
+ xe_eudebug_put(d);
+}
+
+static int add_debugger(struct xe_device *xe, struct xe_eudebug *d,
+ struct drm_file *target)
+{
+ struct xe_file *xef = target->driver_priv;
+
+ guard(mutex)(&xe->eudebug.lock);
+
+ if (!xe_eudebug_is_enabled(xe))
+ return -EOPNOTSUPP;
+
+ if (xef->eudebug.debugger)
+ return -EBUSY;
+
+ d->target.xef = xe_file_get(xef);
+ d->target.pid = xef->pid;
+ kref_get(&d->ref);
+ xef->eudebug.debugger = d;
+
+ XE_WARN_ON(!list_empty(&xef->eudebug.target_link));
+
+ do {
+ d->session = ++xe->eudebug.session_count;
+ } while (!d->session);
+
+ list_add_tail(&xef->eudebug.target_link, &xef->xe->eudebug.targets);
+
+ return 0;
+}
+
+static int
+xe_eudebug_attach(struct xe_device *xe, struct drm_file *parent_file,
+ struct xe_eudebug *d, u64 target_fd)
+{
+ struct file *file __free(fput) = NULL;
+ struct drm_file *drm_file;
+ struct xe_file *target_xef;
+ int ret;
+
+ if (XE_IOCTL_DBG(xe, target_fd > INT_MAX))
+ return -EBADFD;
+
+ file = fget(target_fd);
+ if (XE_IOCTL_DBG(xe, !file))
+ return -EBADFD;
+
+ drm_file = file->private_data;
+ if (XE_IOCTL_DBG(xe, !drm_file))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, parent_file->filp->f_op != file->f_op))
+ return -EINVAL;
+
+ target_xef = drm_file->driver_priv;
+ if (XE_IOCTL_DBG(xe, !target_xef))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, xe != target_xef->xe))
+ return -EINVAL;
+
+ ret = add_debugger(xe, d, drm_file);
+ if (XE_IOCTL_DBG(xe, ret))
+ return ret;
+
+ eu_dbg(d, "session %lld attached to %s", d->session,
+ parent_file == drm_file ? "self" : "remote");
+
+ return 0;
+}
+
+static int xe_eudebug_release(struct inode *inode, struct file *file)
+{
+ struct xe_eudebug *d = file->private_data;
+ struct drm_device *drm = &d->xe->drm;
+
+ xe_eudebug_disconnect(d, 0);
+ xe_eudebug_put(d);
+
+ drm_dev_put(drm);
+
+ return 0;
+}
+
+/*
+ * This is racy as we dont take the lock for read but all the
+ * callsites can handle the race so we can live without lock.
+ */
+__no_kcsan
+static unsigned int
+event_fifo_len(const struct xe_eudebug * const d)
+{
+ return kfifo_len(&d->events.fifo);
+}
+
+static unsigned int
+event_fifo_has_events(struct xe_eudebug *d)
+{
+ /* Allow all waiters to proceed to check their state */
+ if (xe_eudebug_detached(d))
+ return 1;
+
+ if (READ_ONCE(d->events.pending_occupied))
+ return 1;
+
+ return event_fifo_len(d) >
+ sizeof(struct drm_xe_eudebug_event);
+}
+
+static __poll_t xe_eudebug_poll(struct file *file, poll_table *wait)
+{
+ struct xe_eudebug * const d = file->private_data;
+ __poll_t ret = 0;
+
+ poll_wait(file, &d->events.write_done, wait);
+
+ if (xe_eudebug_detached(d)) {
+ ret |= EPOLLHUP;
+ if (READ_ONCE(d->target.err))
+ ret |= EPOLLERR;
+ }
+
+ if (event_fifo_has_events(d))
+ ret |= EPOLLIN;
+
+ return ret;
+}
+
+static void xe_eudebug_reader_clear(struct xe_eudebug *d)
+{
+ if (!d)
+ return;
+
+ clear_bit_unlock(XE_EUDEBUG_READER_ACTIVE, &d->flags);
+}
+
+DEFINE_FREE(reader_active, struct xe_eudebug *, xe_eudebug_reader_clear(_T))
+
+static long xe_eudebug_read_event(struct xe_eudebug *d,
+ const u64 arg,
+ const bool wait)
+{
+ struct xe_device *xe = d->xe;
+ struct drm_xe_eudebug_event __user * const user_orig =
+ u64_to_user_ptr(arg);
+ struct xe_eudebug *reader __free(reader_active) = NULL;
+ struct drm_xe_eudebug_event *event_out __free(kvfree) = NULL;
+ struct drm_xe_eudebug_event user_event;
+ struct drm_xe_eudebug_event *pending;
+ long ret = 0;
+ int pending_len = 0;
+ int fifo_ret;
+
+ if (XE_IOCTL_DBG(xe, copy_from_user(&user_event, user_orig, sizeof(user_event))))
+ return -EFAULT;
+
+ if (XE_IOCTL_DBG(xe, user_event.type != DRM_XE_EUDEBUG_EVENT_READ))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, user_event.len < sizeof(*user_orig)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, user_event.flags))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, user_event.seqno))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, user_event.reserved))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, xe_eudebug_detached(d)))
+ return -ENOTCONN;
+
+ if (test_and_set_bit_lock(XE_EUDEBUG_READER_ACTIVE, &d->flags))
+ return -EBUSY;
+
+ reader = d;
+
+ /* XXX: define wait time in connect arguments ? */
+ if (wait) {
+ ret = wait_event_interruptible_timeout(d->events.write_done,
+ event_fifo_has_events(d),
+ msecs_to_jiffies(5 * 1000));
+
+ if (XE_IOCTL_DBG(xe, ret < 0))
+ return ret;
+ }
+
+ /*
+ * Bounce buffer for the copy out, so that the event can be released
+ * from under events.lock before faulting on the user pointer. An event
+ * larger than what the caller asked for is answered with -EMSGSIZE, so
+ * user_event.len is an upper bound for what we will ever copy.
+ */
+ event_out = kvzalloc(min_t(u32, user_event.len,
+ DRM_XE_EUDEBUG_EVENT_MAX_SIZE), GFP_KERNEL);
+ if (!event_out)
+ return -ENOMEM;
+
+ spin_lock(&d->events.lock);
+ fifo_ret = event_fifo_pending(d, &pending);
+ if (fifo_ret == 0) {
+ if (user_event.len < pending->len) {
+ pending_len = pending->len;
+ ret = -EMSGSIZE;
+ } else if (!access_ok(user_orig, pending->len)) {
+ ret = -EFAULT;
+ } else {
+ memcpy(event_out, pending, pending->len);
+ ret = 0;
+ }
+ } else if (fifo_ret == -ENOENT) {
+ ret = wait ? -ETIMEDOUT : -EAGAIN;
+ } else {
+ ret = fifo_ret; /* -ENOTCONN or -EIO */
+ }
+ spin_unlock(&d->events.lock);
+
+ /* disconnect can sleep, so do it only after dropping the spinlock */
+ if (fifo_ret == -EIO)
+ xe_eudebug_disconnect(d, -EIO);
+
+ if (ret == -EMSGSIZE) {
+ if (XE_IOCTL_DBG(xe, put_user(pending_len, &user_orig->len)))
+ ret = -EFAULT;
+ }
+
+ if (!ret && __copy_to_user(user_orig, event_out, event_out->len))
+ ret = -EFAULT;
+
+ if (!ret) {
+ spin_lock(&d->events.lock);
+ d->events.pending_occupied = false;
+ spin_unlock(&d->events.lock);
+ }
+ eu_dbg(d, "event read=%ld: type=%u, flags=0x%x, seqno=%llu", ret,
+ event_out->type, event_out->flags, event_out->seqno);
+
+ return ret;
+}
+
+/**
+ * xe_eudebug_ioctl - Issue a command to eudebug interface
+ *
+ * @file : eudebug file (returned from connect)
+ * @cmd : cmd
+ * @arg : arguments depending on cmd
+ *
+ * Issue a eudebug command
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static long xe_eudebug_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct xe_eudebug * const d = file->private_data;
+ long ret;
+
+ switch (cmd) {
+ case DRM_XE_EUDEBUG_IOCTL_READ_EVENT:
+ ret = xe_eudebug_read_event(d, arg,
+ !(file->f_flags & O_NONBLOCK));
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .release = xe_eudebug_release,
+ .poll = xe_eudebug_poll,
+ .unlocked_ioctl = xe_eudebug_ioctl,
+ .compat_ioctl = xe_eudebug_ioctl,
+};
+
+static int
+xe_eudebug_connect(struct xe_device *xe,
+ struct drm_file *drm_file,
+ struct drm_xe_eudebug_connect *param)
+{
+ const u64 known_open_flags = 0;
+ struct xe_eudebug *d;
+ struct file *file;
+ int fd, err;
+
+ if (XE_IOCTL_DBG(xe, param->extensions))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, param->flags & ~known_open_flags))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, param->reserved))
+ return -EINVAL;
+
+ if (!xe_eudebug_is_enabled(xe))
+ return -EOPNOTSUPP;
+
+ d = kzalloc_obj(*d, GFP_KERNEL);
+ if (XE_IOCTL_DBG(xe, !d))
+ return -ENOMEM;
+
+ d->xe = xe;
+
+ kref_init(&d->ref);
+ init_waitqueue_head(&d->events.write_done);
+
+ spin_lock_init(&d->events.lock);
+
+ err = xe_eudebug_resources_init(d);
+ if (XE_IOCTL_DBG(xe, err)) {
+ kfree(d);
+ return err;
+ }
+
+ d->events.pending = kvzalloc(DRM_XE_EUDEBUG_EVENT_MAX_SIZE,
+ GFP_KERNEL | __GFP_ACCOUNT);
+ if (!d->events.pending) {
+ err = -ENOMEM;
+ goto err_put;
+ }
+
+ d->events.staging = kvzalloc(DRM_XE_EUDEBUG_EVENT_MAX_SIZE,
+ GFP_KERNEL | __GFP_ACCOUNT);
+ if (!d->events.staging) {
+ err = -ENOMEM;
+ goto err_put;
+ }
+
+ d->events.fifo_buf = kvmalloc(XE_EUDEBUG_FIFO_SIZE,
+ GFP_KERNEL | __GFP_ACCOUNT);
+ if (!d->events.fifo_buf) {
+ err = -ENOMEM;
+ goto err_put;
+ }
+
+ err = kfifo_init(&d->events.fifo, d->events.fifo_buf, XE_EUDEBUG_FIFO_SIZE);
+ if (XE_IOCTL_DBG(xe, err))
+ goto err_put;
+
+ err = xe_eudebug_attach(xe, drm_file, d, param->fd);
+ if (XE_IOCTL_DBG(xe, err))
+ goto err_put;
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fd < 0) {
+ err = fd;
+ goto err_detach;
+ }
+
+ file = anon_inode_getfile("[xe_eudebug]", &fops, d, 0);
+ if (IS_ERR(file)) {
+ err = PTR_ERR(file);
+ goto err_fd;
+ }
+
+ eu_dbg(d, "connected session %lld", d->session);
+
+ drm_dev_get(&xe->drm);
+
+ fd_install(fd, file);
+
+ return fd;
+
+err_fd:
+ put_unused_fd(fd);
+err_detach:
+ xe_eudebug_detach(d, err);
+err_put:
+ xe_eudebug_put(d);
+
+ return err;
+}
+
+void xe_eudebug_file_close(struct xe_file *xef)
+{
+ struct xe_eudebug *d;
+
+ d = xe_eudebug_get(xef);
+ if (d) {
+ xe_eudebug_detach(d, 0);
+ xe_eudebug_put(d);
+ }
+}
+
+bool xe_eudebug_is_enabled(struct xe_device *xe)
+{
+ return READ_ONCE(xe->eudebug.cap_state) == XE_EUDEBUG_CAP_ENABLED;
+}
+
+int xe_eudebug_enable(struct xe_device *xe, bool enable)
+{
+ guard(mutex)(&xe->eudebug.lock);
+
+ if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
+ return -EPERM;
+
+ if (!enable && !list_empty(&xe->eudebug.targets))
+ return -EBUSY;
+
+ if (enable == xe_eudebug_is_enabled(xe))
+ return 0;
+
+ WRITE_ONCE(xe->eudebug.cap_state, enable ?
+ XE_EUDEBUG_CAP_ENABLED : XE_EUDEBUG_CAP_DISABLED);
+
+ return 0;
+}
+
+static ssize_t enable_eudebug_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct xe_device *xe = pdev_to_xe_device(to_pci_dev(dev));
+
+ return sysfs_emit(buf, "%u\n", xe_eudebug_is_enabled(xe));
+}
+
+static ssize_t enable_eudebug_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct xe_device *xe = pdev_to_xe_device(to_pci_dev(dev));
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret)
+ return ret;
+
+ ret = xe_eudebug_enable(xe, enable);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(enable_eudebug);
+
+static void xe_eudebug_sysfs_fini(void *arg)
+{
+ struct xe_device *xe = arg;
+ struct drm_device *dev = &xe->drm;
+
+ sysfs_remove_file(&dev->dev->kobj,
+ &dev_attr_enable_eudebug.attr);
+}
+
+void xe_eudebug_init_early(struct xe_device *xe)
+{
+ struct drm_device *dev = &xe->drm;
+ int err;
+
+ INIT_LIST_HEAD(&xe->eudebug.targets);
+ WRITE_ONCE(xe->eudebug.cap_state, XE_EUDEBUG_CAP_NOT_SUPPORTED);
+
+ err = drmm_mutex_init(dev, &xe->eudebug.lock);
+ if (err)
+ drm_warn(&xe->drm, "eudebug disabled, early init fail: %d\n", err);
+ else
+ WRITE_ONCE(xe->eudebug.cap_state, XE_EUDEBUG_CAP_DISABLED);
+}
+
+void xe_eudebug_init(struct xe_device *xe)
+{
+ struct drm_device *dev = &xe->drm;
+ int err;
+
+ /* early init failed */
+ if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
+ return;
+
+ err = sysfs_create_file(&dev->dev->kobj,
+ &dev_attr_enable_eudebug.attr);
+ if (err)
+ goto out_err;
+
+ err = devm_add_action_or_reset(dev->dev, xe_eudebug_sysfs_fini, xe);
+ if (err)
+ goto out_err;
+
+ WRITE_ONCE(xe->eudebug.cap_state, XE_EUDEBUG_CAP_DISABLED);
+
+ return;
+
+out_err:
+ drm_warn(&xe->drm, "eudebug disabled, init fail: %d\n", err);
+
+ WRITE_ONCE(xe->eudebug.cap_state, XE_EUDEBUG_CAP_NOT_SUPPORTED);
+}
+
+/**
+ * xe_eudebug_connect_ioctl - Connect to eudebug interface
+ * @dev : DRM device
+ * @data : ioctl data, (struct drm_xe_eudebug_connect)
+ * @file : DRM file
+ *
+ * Connect to the eudebug interface.
+ *
+ * Return: eudebug filedesriptor on success, negative error code on failure.
+ *
+ */
+int xe_eudebug_connect_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *file)
+{
+ struct xe_device *xe = to_xe_device(dev);
+ struct drm_xe_eudebug_connect * const param = data;
+
+ return xe_eudebug_connect(xe, file, param);
+}
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
new file mode 100644
index 000000000000..a314cfa26a68
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#ifndef _XE_EUDEBUG_H_
+#define _XE_EUDEBUG_H_
+
+#include <linux/types.h>
+
+struct drm_device;
+struct drm_file;
+struct xe_device;
+struct xe_file;
+struct xe_vm;
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+
+#define XE_EUDEBUG_DBG_STR "eudbg: %lld:%lu:%s (%d/%d) -> (%d): "
+
+#define __eu_print(d, func, fmt, ...) \
+ do { \
+ struct xe_eudebug *__pd = (d); \
+ func(&__pd->xe->drm, XE_EUDEBUG_DBG_STR fmt, \
+ __pd->session, \
+ atomic_long_read(&__pd->events.seqno), \
+ (!READ_ONCE(__pd->target.xef) ? "disconnected" : ""), \
+ current->pid, \
+ task_tgid_nr(current), \
+ __pd->target.pid, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define eu_err(d, fmt, ...) __eu_print(d, drm_err, fmt, ##__VA_ARGS__)
+#define eu_warn(d, fmt, ...) __eu_print(d, drm_warn, fmt, ##__VA_ARGS__)
+#define eu_dbg(d, fmt, ...) __eu_print(d, drm_dbg, fmt, ##__VA_ARGS__)
+
+#define xe_eudebug_assert(d, ...) xe_assert((d)->xe, ##__VA_ARGS__)
+
+int xe_eudebug_connect_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *file);
+
+void xe_eudebug_init(struct xe_device *xe);
+void xe_eudebug_init_early(struct xe_device *xe);
+bool xe_eudebug_is_enabled(struct xe_device *xe);
+
+void xe_eudebug_file_close(struct xe_file *xef);
+
+void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm);
+void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm);
+int xe_eudebug_enable(struct xe_device *xe, bool enable);
+
+#else
+
+static inline int xe_eudebug_connect_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *file) { return -EOPNOTSUPP; }
+
+static inline void xe_eudebug_init(struct xe_device *xe) { }
+static inline void xe_eudebug_init_early(struct xe_device *xe) { }
+static inline bool xe_eudebug_is_enabled(struct xe_device *xe) { return false; }
+
+static inline void xe_eudebug_file_close(struct xe_file *xef) { }
+
+static inline void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm) { }
+static inline void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm) { }
+
+#endif /* CONFIG_DRM_XE_EUDEBUG */
+
+#endif /* _XE_EUDEBUG_H_ */
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
new file mode 100644
index 000000000000..46d78f4f8061
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#ifndef _XE_EUDEBUG_TYPES_H_
+#define _XE_EUDEBUG_TYPES_H_
+
+#include <linux/completion.h>
+#include <linux/kfifo.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/rbtree.h>
+#include <linux/rhashtable.h>
+#include <linux/sizes.h>
+#include <linux/wait.h>
+#include <linux/xarray.h>
+
+#include <uapi/drm/xe_drm_eudebug.h>
+
+struct xe_device;
+
+/**
+ * enum xe_eudebug_cap_state - eudebug capability state
+ *
+ * @XE_EUDEBUG_CAP_NOT_SUPPORTED: eudebug feature support off
+ * @XE_EUDEBUG_CAP_DISABLED: eudebug feature supported but disabled
+ * @XE_EUDEBUG_CAP_ENABLED: eudebug enabled
+ */
+enum xe_eudebug_cap_state {
+ XE_EUDEBUG_CAP_NOT_SUPPORTED = 0,
+ XE_EUDEBUG_CAP_DISABLED,
+ XE_EUDEBUG_CAP_ENABLED,
+};
+
+#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_VM
+
+/**
+ * struct xe_eudebug_handle - eudebug resource handle
+ */
+struct xe_eudebug_handle {
+ /** @key: key value in rhashtable <key:id> */
+ u64 key;
+
+ /** @id: opaque handle id for xarray <id:key> */
+ int id;
+
+ /** @rh_head: rhashtable head */
+ struct rhash_head rh_head;
+};
+
+/**
+ * struct xe_eudebug_resource - Resource map for one resource
+ */
+struct xe_eudebug_resource {
+ /** @lock: protects xa and rh consistency */
+ struct mutex lock;
+
+ /** @xa: xarrays for <id->key> */
+ struct xarray xa;
+
+ /** @rh: rhashtable for <key->id> */
+ struct rhashtable rh;
+};
+
+#define XE_EUDEBUG_RES_TYPE_VM 0
+#define XE_EUDEBUG_RES_TYPE_COUNT (XE_EUDEBUG_RES_TYPE_VM + 1)
+
+/**
+ * struct xe_eudebug - Top level struct for eudebug: the connection
+ */
+struct xe_eudebug {
+ /** @ref: kref counter for this struct */
+ struct kref ref;
+
+ /** @target: debug target specifics */
+ struct {
+ /** @target.xef: the target xe_file that we are debugging
+ * Protected by xe->eudebug.lock.
+ */
+ struct xe_file *xef;
+
+ /** @target.pid: pid of target */
+ pid_t pid;
+
+ /** @target.err: error code on disconnect */
+ int err;
+
+ /** @target.res: resource maps for all types */
+ struct xe_eudebug_resource res[XE_EUDEBUG_RES_TYPE_COUNT];
+ } target;
+
+ /** @xe: the parent device we are serving */
+ struct xe_device *xe;
+
+ /** @session: session number for this connection (for logs) */
+ u64 session;
+
+ /** @flags: state flags */
+ unsigned long flags;
+#define XE_EUDEBUG_READER_ACTIVE 0
+
+ /** @events: kfifo queue of to-be-delivered events */
+ struct {
+ /** @events.lock: guards access to fifo, pending and staging */
+ spinlock_t lock;
+
+#define DRM_XE_EUDEBUG_EVENT_MAX_SIZE SZ_64K
+ /** @events.pending: pending event bounce buffer, preallocated */
+ struct drm_xe_eudebug_event *pending;
+ bool pending_occupied;
+
+ /** @events.staging: write side staging buffer, preallocated */
+ struct drm_xe_eudebug_event *staging;
+
+ /** @events.fifo: queue of events pending */
+ struct kfifo fifo;
+
+ /** @events.fifo_buf: memory for the fifo */
+ void *fifo_buf;
+#define XE_EUDEBUG_FIFO_SIZE SZ_16M
+
+ /** @events.write_done: waitqueue for signalling write to fifo */
+ wait_queue_head_t write_done;
+
+ /** @events.seqno: seqno counter to stamp events for fifo */
+ atomic_long_t seqno;
+ } events;
+};
+
+#endif /* _XE_EUDEBUG_TYPES_H_ */
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 19b3d0be7928..cf7a3c7c51e5 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -26,6 +26,7 @@
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_drm_client.h"
+#include "xe_eudebug.h"
#include "xe_exec_queue.h"
#include "xe_gt.h"
#include "xe_migrate.h"
@@ -2162,10 +2163,18 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data,
args->reserved[0] = xe_bo_main_addr(vm->pt_root[0]->bo, XE_PAGE_SIZE);
#endif
+ /*
+ * Announce to the debugger before the id is published, as from that
+ * point on a concurrent destroy can race us to the resource map.
+ */
+ xe_eudebug_vm_create(xef, vm);
+
/* user id alloc must always be last in ioctl to prevent UAF */
err = xa_alloc(&xef->vm.xa, &id, vm, xa_limit_32b, GFP_KERNEL);
- if (err)
+ if (err) {
+ xe_eudebug_vm_destroy(xef, vm);
goto err_close_and_put;
+ }
args->vm_id = id;
@@ -2200,8 +2209,10 @@ int xe_vm_destroy_ioctl(struct drm_device *dev, void *data,
xa_erase(&xef->vm.xa, args->vm_id);
mutex_unlock(&xef->vm.lock);
- if (!err)
+ if (!err) {
+ xe_eudebug_vm_destroy(xef, vm);
xe_vm_close_and_put(vm);
+ }
return err;
}
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index 509202a7b13e..03cb1181c169 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -110,6 +110,7 @@ extern "C" {
#define DRM_XE_VM_QUERY_MEM_RANGE_ATTRS 0x0d
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY 0x0e
#define DRM_XE_VM_GET_PROPERTY 0x0f
+#define DRM_XE_EUDEBUG_CONNECT 0x10
/* Must be kept compact -- no holes */
@@ -129,6 +130,7 @@ extern "C" {
#define DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_VM_QUERY_MEM_RANGE_ATTRS, struct drm_xe_vm_query_mem_range_attr)
#define DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC_QUEUE_SET_PROPERTY, struct drm_xe_exec_queue_set_property)
#define DRM_IOCTL_XE_VM_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_VM_GET_PROPERTY, struct drm_xe_vm_get_property)
+#define DRM_IOCTL_XE_EUDEBUG_CONNECT DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)
/**
* DOC: Xe IOCTL Extensions
@@ -2618,6 +2620,27 @@ enum drm_xe_ras_error_component {
[DRM_XE_RAS_ERR_COMP_FABRIC] = "fabric", \
}
+/**
+ * struct drm_xe_eudebug_connect - Input of &DRM_IOCTL_XE_EUDEBUG_CONNECT
+ *
+ * This structure is used to connect to an eudebug interface of target drm file.
+ */
+struct drm_xe_eudebug_connect {
+ /** @extensions: Pointer to the first extension struct, if any */
+ __u64 extensions;
+
+ /** @fd: Debug target DRM client fd */
+ __u64 fd;
+
+ /** @flags: Flags, MBZ */
+ __u64 flags;
+
+ /** @reserved: MBZ */
+ __u64 reserved;
+};
+
+#include "xe_drm_eudebug.h"
+
#if defined(__cplusplus)
}
#endif
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
new file mode 100644
index 000000000000..d33b8b371aae
--- /dev/null
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef _UAPI_XE_DRM_EUDEBUG_H_
+#define _UAPI_XE_DRM_EUDEBUG_H_
+
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * DOC: DRM_XE_EUDEBUG_IOCTL_READ_EVENT
+ *
+ * Receive one event from the connection returned by
+ * &DRM_IOCTL_XE_EUDEBUG_CONNECT. The argument is a pointer to a
+ * &struct drm_xe_eudebug_event filled in as described there.
+ *
+ * A connection opened without O_NONBLOCK waits up to five seconds for an
+ * event to arrive. Only one reader at a time is allowed on a connection.
+ *
+ * Return: 0 on success. Negative error code on failure:
+ *
+ * - -EMSGSIZE if the pending event is larger than the supplied len. len is
+ * updated with the size needed and the event stays queued.
+ * - -ETIMEDOUT if the blocking wait expired with no event.
+ * - -EAGAIN if O_NONBLOCK was set and no event was queued.
+ * - -EBUSY if another thread is already reading on this connection.
+ * - -ENOTCONN if the debug target is gone and the queue has been drained.
+ */
+#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
+
+/**
+ * struct drm_xe_eudebug_event - Base type of event delivered by xe_eudebug.
+ *
+ * Base event for xe_eudebug interface.
+ *
+ * For receiving events :c:member:`drm_xe_eudebug_event.type` has to
+ * be DRM_XE_EUDEBUG_EVENT_READ. On return, this is set to the type
+ * of event received. :c:member:`drm_xe_eudebug_event.len` has to be
+ * set to maximum size that can be received. On return, len will be set
+ * to the event size. If the pending event was larger than this size,
+ * -EMSGSIZE is returned instead of 0 and the caller should retry with a larger
+ * allocated receive length.
+ *
+ * :c:member:`drm_xe_eudebug_event.seqno` can be used to form a timeline
+ * as event delivery order does not guarantee event creation
+ * order. Must be set to zero.
+ *
+ * :c:member:`drm_xe_eudebug_event.flags` will indicate if a resource was
+ * created, destroyed, or if its state changed. Must be set to zero.
+ *
+ * If DRM_XE_EUDEBUG_EVENT_NEED_ACK is set, xe_eudebug
+ * will hold the said resource until it is acked by userspace
+ * using the acking ioctl with the seqno of the said event.
+ */
+struct drm_xe_eudebug_event {
+ /** @len: Length */
+ __u32 len;
+
+ /** @type: Type */
+ __u16 type;
+#define DRM_XE_EUDEBUG_EVENT_NONE 0
+#define DRM_XE_EUDEBUG_EVENT_READ 1
+#define DRM_XE_EUDEBUG_EVENT_VM 2
+
+ /** @flags: Flags */
+ __u16 flags;
+#define DRM_XE_EUDEBUG_EVENT_CREATE (1 << 0)
+#define DRM_XE_EUDEBUG_EVENT_DESTROY (1 << 1)
+#define DRM_XE_EUDEBUG_EVENT_STATE_CHANGE (1 << 2)
+#define DRM_XE_EUDEBUG_EVENT_NEED_ACK (1 << 3)
+
+ /** @seqno: Sequence number to form a timeline */
+ __u64 seqno;
+
+ /** @reserved: Reserved field, must be zero. */
+ __u64 reserved;
+};
+
+/**
+ * struct drm_xe_eudebug_event_vm - VM event
+ *
+ * VM event is delivered when vm is created or destroyed.
+ */
+struct drm_xe_eudebug_event_vm {
+ /** @base: base event */
+ struct drm_xe_eudebug_event base;
+
+ /** @vm_handle: unique handle for vm */
+ __u64 vm_handle;
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _UAPI_XE_DRM_EUDEBUG_H_ */
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 02/27] drm/xe/eudebug: Add documentation
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 01/27] drm/xe/eudebug: Introduce eudebug interface Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 03/27] drm/xe/eudebug: Add connection establishment documentation Mika Kuoppala
` (30 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
Add core documentation for connection setup and events.
Follow-up patches can then incrementally add their workings.
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
Documentation/gpu/xe/index.rst | 1 +
Documentation/gpu/xe/xe_eudebug.rst | 45 +++++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_eudebug.c | 19 ++++++++++++
3 files changed, 65 insertions(+)
create mode 100644 Documentation/gpu/xe/xe_eudebug.rst
diff --git a/Documentation/gpu/xe/index.rst b/Documentation/gpu/xe/index.rst
index 0247a255f7e6..8d4abdfe71a7 100644
--- a/Documentation/gpu/xe/index.rst
+++ b/Documentation/gpu/xe/index.rst
@@ -36,3 +36,4 @@ The display, or :ref:`drm-kms`, support for drm/xe is provided by
xe_configfs
xe_gt_stats
xe_sigid
+ xe_eudebug
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
new file mode 100644
index 000000000000..ff7fbc403ebb
--- /dev/null
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -0,0 +1,45 @@
+.. SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+===================================
+Xe EU Debug (eudebug)
+===================================
+
+Overview
+========
+
+The EU Debug (eudebug) subsystem provides an interface for debugging
+Execution Unit (EU) workloads on Intel Xe GPUs, independently from
+CPU process debugging. This enables tools like GDB (via gdbserver-intelgt)
+to debug GPU compute workloads through the Level-Zero Debug API.
+In practice, this means that SYCL/DPC++ workloads submitted by the
+compute-runtime can be debugged interactively at this time.
+
+
+Connection Establishment
+========================
+
+.. kernel-doc:: drivers/gpu/drm/xe/xe_eudebug.c
+ :doc: Connection Establishment
+
+Events
+======
+
+.. kernel-doc:: drivers/gpu/drm/xe/xe_eudebug.c
+ :doc: Events
+
+
+Base Event Header
+-----------------
+
+The debugger receives events by reading from the eudebug file descriptor
+using an read_event ioctl. Every event has :c:type:`drm_xe_eudebug_event`
+as a header
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_event
+
+Resource Event Types
+--------------------
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_event_vm
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 9fe073f60680..f46869ebaf22 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -20,6 +20,25 @@
#include "xe_macros.h"
#include "xe_vm.h"
+/**
+ * DOC: Connection Establishment
+ *
+ * To debug a target DRM client, the debugger must first establish
+ * a connection using :c:type:`drm_xe_eudebug_connect`.
+ *
+ */
+
+/**
+ * DOC: Events
+ *
+ * Resource creation/destruction and hardware state changes are
+ * delivered as events for debugger.
+ *
+ * To read an event, ioctl DRM_XE_EUDEBUG_IOCTL_READ_EVENT command
+ * can be issued with prefilled :c:type:`drm_xe_eudebug_event` as argument.
+ *
+ */
+
#define cast_event(T, event) container_of((event), typeof(*(T)), base)
static const struct rhashtable_params rhash_res = {
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 03/27] drm/xe/eudebug: Add connection establishment documentation
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 01/27] drm/xe/eudebug: Introduce eudebug interface Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 02/27] drm/xe/eudebug: Add documentation Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 04/27] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
` (29 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
Add documentation for connecting to a target DRM Xe client
for debugging.
v2: improved Pipe and Fork documentation (Sashiko)
v10: qualify the ptrace_may_access() parity claim per fd
acquisition method (Claude)
Assisted-by: Claude:claude-opus-5
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
Documentation/gpu/xe/xe_eudebug.rst | 11 ++++
drivers/gpu/drm/xe/xe_eudebug.c | 86 +++++++++++++++++++++++++++++
2 files changed, 97 insertions(+)
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
index ff7fbc403ebb..c21fa7c47ab8 100644
--- a/Documentation/gpu/xe/xe_eudebug.rst
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -21,6 +21,17 @@ Connection Establishment
.. kernel-doc:: drivers/gpu/drm/xe/xe_eudebug.c
:doc: Connection Establishment
+File Descriptor Acquisition Methods
+-----------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/xe/xe_eudebug.c
+ :doc: File Descriptor Acquisition Methods
+
+Security Model
+--------------
+.. kernel-doc:: drivers/gpu/drm/xe/xe_eudebug.c
+ :doc: Security Model
+
Events
======
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index f46869ebaf22..835dbd7309af 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -26,6 +26,92 @@
* To debug a target DRM client, the debugger must first establish
* a connection using :c:type:`drm_xe_eudebug_connect`.
*
+ * The debug target's DRM client file descriptor is passed into the
+ * connect ioctl via :c:member:`drm_xe_eudebug_connect.fd`.
+ * This is the fd that the target process obtained from open('/dev/dri/cardX').
+ *
+ * This file descriptor must be a valid DRM client fd in the debugger's
+ * (calling) process context. For debugging an Xe DRM client in
+ * another process, pidfd_getfd() can be used to acquire a duplicate
+ * of the file descriptor from the target process. See
+ * :ref:`File Descriptor Acquisition Methods <fd_acquisition_methods>` for
+ * details on how to obtain the target's fd.
+ *
+ */
+
+/**
+ * DOC: Security Model
+ *
+ * If you are inside the same process, you can connect to your own DRM client
+ * by simply passing its fd to drm_xe_eudebug_connect.
+ *
+ * For a remote process, possession of that process's DRM client fd is
+ * the capability: the connect ioctl adds no credential check of its own.
+ * What sets the bar is therefore how that fd was obtained.
+ *
+ * Taking an fd from a process that did not offer it goes through
+ * pidfd_getfd(), and the kernel enforces credentials there.
+ * __pidfd_fget() requires ptrace_may_access() with
+ * PTRACE_MODE_ATTACH_REALCREDS, under the target's
+ * signal->exec_update_lock. That is the same check, under the same lock,
+ * that /proc/<pid>/mem takes in mm_access(), so for this path the same
+ * ptrace_may_access() rules apply as in CPU process debugging with gdb.
+ * Most of the acquisition methods below end up here, including those
+ * that only use procfs to discover which fd number to ask for.
+ *
+ * Two methods do not involve ptrace_may_access(), because nothing is
+ * being taken. With SCM_RIGHTS the target sends its own fd over a unix
+ * socket, which is the target consenting. With fork() inheritance the fd
+ * belonged to the debugger before the fork and the child merely
+ * inherited a copy of it.
+ *
+ * See :ref:`File Descriptor Acquisition Methods <fd_acquisition_methods>`.
+ */
+
+/**
+ * DOC: File Descriptor Acquisition Methods
+ * .. _fd_acquisition_methods:
+ *
+ * There are multiple ways to get the target DRM client fd for
+ * another process:
+ *
+ * Unix domain socket
+ * The debugger can receive the DRM client fd from the target via a Unix
+ * domain socket using SCM_RIGHTS ancillary data. This is the standard
+ * mechanism for passing file descriptors between processes, but requires
+ * coordination to establish the socket connection.
+ *
+ * Pipe
+ * The target sends the fd number through a pipe, and the debugger
+ * duplicates it via pidfd_getfd(). This requires coordination between
+ * the processes to establish the pipe and synchronize the transfer.
+ *
+ * Fork
+ * If the debugger spawns the target process via fork(), a DRM client
+ * fd can be shared across the fork boundary — either inherited by the
+ * child from the debugger, or acquired from the child by the debugger
+ * via pidfd_getfd() after the child opens the device. This is useful
+ * when the debugger launches the target directly, similar to how gdb
+ * spawns inferiors.
+ *
+ * Ptrace
+ * The debugger can attach to the target process using ptrace. It can
+ * intercept the return value of the target's open() or drmOpen() call
+ * by inspecting registers at syscall exit to catch the fd when it is
+ * created. Alternatively, if the target has already opened the device,
+ * the debugger can read the target's memory using PTRACE_PEEKDATA to
+ * locate the stored fd value in a known variable or data structure.
+ * Once the fd number is known, pidfd_getfd() can be used to acquire a
+ * duplicate in the debugger's process context.
+ *
+ * Procfs
+ * The debugger can look through /proc/<targetpid>/fd for file descriptors
+ * and inspect /proc/<targetpid>/fdinfo to see which of those
+ * are for an Xe DRM client.
+ *
+ * Brute force
+ * The debugger can traverse /proc/<targetpid>/fd descriptors
+ * and try to connect to each to see if it succeeds.
*/
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 04/27] drm/xe/eudebug: Introduce discovery for resources
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (2 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 03/27] drm/xe/eudebug: Add connection establishment documentation Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:22 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 05/27] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
` (28 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala,
Dominik Grzegorzek
A debugger connection can occur after a client has created
and destroyed an arbitrary number of resources. To support
this, we need to relay all currently existing resources to
the debugger. The client is held on selected ioctls until
this discovery process, executed by a workqueue, is complete.
Based on discovery work by Maciej Patelczyk for the i915 driver.
v2: - use rw_semaphore to block DRM ioctls during discovery (Matthew)
- only lock according to ioctl at play (Dominik)
v4: - s/discovery_lock/ioctl_lock
- change lock to be per xe_file as is connections
v5: - helper to get eudebug instance during discovery (Maciej)
v6: - complete_all even if no client (Sashiko)
- don't flush on detach (Sashiko)
v7: - guard close with ioctl lock (Sashiko)
v8: - discovery lock comment fix (Maciej)
v9: - disconnect on failed discovery (Sashiko)
- avoid close race (Sashiko)
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Co-developed-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Acked-by: Matthew Brost <matthew.brost@intel.com> #locking
---
Documentation/gpu/xe/xe_eudebug.rst | 3 +
drivers/gpu/drm/xe/xe_device.c | 13 ++-
drivers/gpu/drm/xe/xe_device.h | 42 +++++++
drivers/gpu/drm/xe/xe_device_types.h | 15 +++
drivers/gpu/drm/xe/xe_eudebug.c | 156 +++++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_eudebug.h | 4 +
drivers/gpu/drm/xe/xe_eudebug_types.h | 9 +-
drivers/gpu/drm/xe/xe_exec_queue.c | 1 +
drivers/gpu/drm/xe/xe_hw_engine.h | 14 +++
include/uapi/drm/xe_drm_eudebug.h | 26 +++++
10 files changed, 276 insertions(+), 7 deletions(-)
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
index c21fa7c47ab8..e191e2c8ded4 100644
--- a/Documentation/gpu/xe/xe_eudebug.rst
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -54,3 +54,6 @@ Resource Event Types
.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
:identifiers: drm_xe_eudebug_event_vm
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_event_exec_queue
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 12c84b7c7758..01254c73b2c6 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -114,6 +114,7 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
INIT_LIST_HEAD(&xef->eudebug.target_link);
+ init_rwsem(&xef->eudebug.ioctl_lock);
#endif
file->driver_priv = xef;
@@ -238,8 +239,12 @@ static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ACQUIRE(xe_pm_runtime_ioctl, pm)(xe);
ret = ACQUIRE_ERR(xe_pm_runtime_ioctl, &pm);
- if (ret >= 0)
+ if (ret >= 0) {
+ bool lock = xe_eudebug_discovery_lock(file, cmd);
ret = drm_ioctl(file, cmd, arg);
+ if (lock)
+ xe_eudebug_discovery_unlock(file, cmd);
+ }
return ret;
}
@@ -256,8 +261,12 @@ static long xe_drm_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
ACQUIRE(xe_pm_runtime_ioctl, pm)(xe);
ret = ACQUIRE_ERR(xe_pm_runtime_ioctl, &pm);
- if (ret >= 0)
+ if (ret >= 0) {
+ bool lock = xe_eudebug_discovery_lock(file, cmd);
ret = drm_compat_ioctl(file, cmd, arg);
+ if (lock)
+ xe_eudebug_discovery_unlock(file, cmd);
+ }
return ret;
}
diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
index 6d3d6d5eba29..5672709bea35 100644
--- a/drivers/gpu/drm/xe/xe_device.h
+++ b/drivers/gpu/drm/xe/xe_device.h
@@ -7,6 +7,7 @@
#define _XE_DEVICE_H_
#include <drm/drm_util.h>
+#include <drm/drm_ioctl.h>
#include "xe_device_types.h"
#include "xe_gt_types.h"
@@ -297,4 +298,45 @@ static inline bool xe_device_is_admin_only(const struct xe_device *xe)
#define LNL_FLUSH_WORK(wrk__) \
flush_work(wrk__)
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+static inline int xe_eudebug_needs_ioctl_lock(const unsigned int cmd)
+{
+ const unsigned int xe_cmd = DRM_IOCTL_NR(cmd) - DRM_COMMAND_BASE;
+
+ switch (xe_cmd) {
+ case DRM_XE_VM_CREATE:
+ case DRM_XE_VM_DESTROY:
+ case DRM_XE_VM_BIND:
+ case DRM_XE_EXEC_QUEUE_CREATE:
+ case DRM_XE_EXEC_QUEUE_DESTROY:
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline bool xe_eudebug_discovery_lock(struct file *file, unsigned int cmd)
+{
+ struct drm_file *file_priv = file->private_data;
+ struct xe_file *xef = file_priv->driver_priv;
+
+ if (!xe_eudebug_needs_ioctl_lock(cmd))
+ return false;
+
+ down_read(&xef->eudebug.ioctl_lock);
+ return true;
+}
+
+static inline void xe_eudebug_discovery_unlock(struct file *file, unsigned int cmd)
+{
+ struct drm_file *file_priv = file->private_data;
+ struct xe_file *xef = file_priv->driver_priv;
+
+ up_read(&xef->eudebug.ioctl_lock);
+}
+#else
+static inline bool xe_eudebug_discovery_lock(struct file *file, unsigned int cmd) { return false; }
+static inline void xe_eudebug_discovery_unlock(struct file *file, unsigned int cmd) { }
+#endif /* CONFIG_DRM_XE_EUDEBUG */
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index f5a5ff4d8873..a9584634279d 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -616,6 +616,9 @@ struct xe_device {
/** @eudebug.lock: protects state and targets */
struct mutex lock;
+
+ /** @eudebug.discovery_wq: used for client resource discovery */
+ struct workqueue_struct *discovery_wq;
} eudebug;
#endif
@@ -704,6 +707,18 @@ struct xe_file {
/** @eudebug.target_link: link into xe_device.eudebug.targets */
struct list_head target_link;
+
+ /**
+ * @eudebug.ioctl_lock: excludes the ioctls that mutate the
+ * eudebug visible resources of this client, so that a writer
+ * sees a stable set of vms and exec queues. Taken for read
+ * around the whole ioctl by xe_eudebug_discovery_lock(), for
+ * the ioctls named in xe_eudebug_needs_ioctl_lock(), and for
+ * write by resource discovery and by file close. Held across
+ * an entire ioctl, so it nests outside every lock those
+ * ioctls take.
+ */
+ struct rw_semaphore ioctl_lock;
} eudebug;
#endif
};
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 835dbd7309af..7a5b14346e05 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -17,6 +17,8 @@
#include "xe_device.h"
#include "xe_eudebug.h"
#include "xe_eudebug_types.h"
+#include "xe_exec_queue.h"
+#include "xe_hw_engine.h"
#include "xe_macros.h"
#include "xe_vm.h"
@@ -37,6 +39,10 @@
* :ref:`File Descriptor Acquisition Methods <fd_acquisition_methods>` for
* details on how to obtain the target's fd.
*
+ * After a successful connection, all existing resources that the target Xe DRM
+ * client already has are sent as events, as if they had been
+ * created right after the connection. This is referred to as discovery.
+ *
*/
/**
@@ -223,6 +229,8 @@ static void xe_eudebug_free(struct kref *ref)
{
struct xe_eudebug *d = container_of(ref, typeof(*d), ref);
+ WARN_ON(work_pending(&d->discovery_work));
+
xe_assert(d->xe, xe_eudebug_detached(d));
xe_eudebug_resources_destroy(d);
@@ -234,7 +242,7 @@ static void xe_eudebug_free(struct kref *ref)
kfree(d);
}
-static void xe_eudebug_put(struct xe_eudebug *d)
+void xe_eudebug_put(struct xe_eudebug *d)
{
kref_put(&d->ref, xe_eudebug_free);
}
@@ -323,7 +331,7 @@ static int event_fifo_pending(struct xe_eudebug *d,
}
static struct xe_eudebug *
-xe_eudebug_get(struct xe_file *xef)
+__xe_eudebug_get(struct xe_file *xef)
{
struct xe_device *xe = xef->xe;
struct xe_eudebug *d;
@@ -345,6 +353,42 @@ xe_eudebug_get(struct xe_file *xef)
return d;
}
+static struct xe_eudebug *
+_xe_eudebug_get(struct xe_file *xef)
+{
+ struct xe_eudebug *d;
+
+ d = __xe_eudebug_get(xef);
+
+ if (d && !completion_done(&d->discovery)) {
+ xe_eudebug_put(d);
+ return NULL;
+ }
+
+ return d;
+}
+
+static struct xe_eudebug *
+xe_eudebug_get(struct xe_file *xef)
+{
+ lockdep_assert_held(&xef->eudebug.ioctl_lock);
+
+ return _xe_eudebug_get(xef);
+}
+
+struct xe_eudebug *
+xe_eudebug_get_nolock(struct xe_file *xef)
+{
+ return _xe_eudebug_get(xef);
+}
+
+/* Returns eudebug instance even if discovery is running */
+struct xe_eudebug *
+xe_eudebug_get_nolock_with_discovery(struct xe_file *xef)
+{
+ return __xe_eudebug_get(xef);
+}
+
static int xe_eudebug_queue_event(struct xe_eudebug *d,
struct drm_xe_eudebug_event *event)
{
@@ -519,6 +563,8 @@ static int xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
{
int ret;
+ XE_WARN_ON(!completion_done(&d->discovery));
+
ret = _xe_eudebug_remove_handle(d, type, p, seqno);
eu_dbg(d, "handle type %d handle %p removed: %d\n", type, p, ret);
@@ -659,6 +705,87 @@ void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
xe_eudebug_put(d);
}
+static struct xe_file *xe_eudebug_target_get(struct xe_eudebug *d)
+{
+ struct xe_file *xef = NULL;
+
+ mutex_lock(&d->xe->eudebug.lock);
+ if (d->target.xef)
+ xef = xe_file_get(d->target.xef);
+ mutex_unlock(&d->xe->eudebug.lock);
+
+ return xef;
+}
+
+static void discover_client(struct xe_eudebug *d)
+{
+ struct xe_file *xef;
+ struct xe_vm *vm;
+ unsigned long i;
+ unsigned int vm_count = 0;
+ int err = 0;
+
+ xef = xe_eudebug_target_get(d);
+ if (!xef) {
+ complete_all(&d->discovery);
+ return;
+ }
+
+ /*
+ * An xe_eudebug ref is taken for the discovery worker, which holds a
+ * ref to the target xe_file; the xe_file in turn holds the vm and
+ * exec_queue refs.
+ *
+ * All the relevant ioctls that manipulate the xe_file resources eudebug
+ * cares about are gated behind down_read(&xef->eudebug.ioctl_lock).
+ * Thus taking the write lock excludes all those ioctls, which lets us
+ * peek into the resource lists without taking their individual locks.
+ */
+ down_write(&xef->eudebug.ioctl_lock);
+
+ if (xe_eudebug_detached(d))
+ goto out;
+
+ eu_dbg(d, "Discovery start for %lld", d->session);
+
+ /* vm lifetime guaranteed by the ioctl_lock */
+ xa_for_each(&xef->vm.xa, i, vm) {
+ err = vm_create_event(d, vm);
+ if (err)
+ goto out;
+ vm_count++;
+ }
+
+out:
+ complete_all(&d->discovery);
+
+ up_write(&xef->eudebug.ioctl_lock);
+
+ if (vm_count)
+ eu_dbg(d, "Discovery found %u vms",
+ vm_count);
+
+ xe_file_put(xef);
+
+ eu_dbg(d, "Discovery end for %lld: %d", d->session, err);
+
+ if (err < 0)
+ xe_eudebug_disconnect(d, err);
+}
+
+static void discovery_work_fn(struct work_struct *work)
+{
+ struct xe_eudebug *d = container_of(work, typeof(*d),
+ discovery_work);
+
+ if (xe_eudebug_detached(d))
+ complete_all(&d->discovery);
+ else
+ discover_client(d);
+
+ xe_eudebug_put(d);
+}
+
static int add_debugger(struct xe_device *xe, struct xe_eudebug *d,
struct drm_file *target)
{
@@ -917,6 +1044,10 @@ static long xe_eudebug_ioctl(struct file *file,
struct xe_eudebug * const d = file->private_data;
long ret;
+ if (cmd != DRM_XE_EUDEBUG_IOCTL_READ_EVENT &&
+ !completion_done(&d->discovery))
+ return -EBUSY;
+
switch (cmd) {
case DRM_XE_EUDEBUG_IOCTL_READ_EVENT:
ret = xe_eudebug_read_event(d, arg,
@@ -967,9 +1098,11 @@ xe_eudebug_connect(struct xe_device *xe,
kref_init(&d->ref);
init_waitqueue_head(&d->events.write_done);
-
spin_lock_init(&d->events.lock);
+ init_completion(&d->discovery);
+ INIT_WORK(&d->discovery_work, discovery_work_fn);
+
err = xe_eudebug_resources_init(d);
if (XE_IOCTL_DBG(xe, err)) {
kfree(d);
@@ -1017,6 +1150,9 @@ xe_eudebug_connect(struct xe_device *xe,
goto err_fd;
}
+ kref_get(&d->ref); /* for discovery */
+ queue_work(xe->eudebug.discovery_wq, &d->discovery_work);
+
eu_dbg(d, "connected session %lld", d->session);
drm_dev_get(&xe->drm);
@@ -1039,11 +1175,15 @@ void xe_eudebug_file_close(struct xe_file *xef)
{
struct xe_eudebug *d;
- d = xe_eudebug_get(xef);
+ down_write(&xef->eudebug.ioctl_lock);
+
+ d = __xe_eudebug_get(xef);
if (d) {
xe_eudebug_detach(d, 0);
xe_eudebug_put(d);
}
+
+ up_write(&xef->eudebug.ioctl_lock);
}
bool xe_eudebug_is_enabled(struct xe_device *xe)
@@ -1126,12 +1266,20 @@ void xe_eudebug_init_early(struct xe_device *xe)
void xe_eudebug_init(struct xe_device *xe)
{
struct drm_device *dev = &xe->drm;
+ struct workqueue_struct *wq;
int err;
/* early init failed */
if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
return;
+ wq = drmm_alloc_ordered_workqueue(dev, "xe-eudebug-discovery", 0);
+ if (IS_ERR(wq)) {
+ err = PTR_ERR(wq);
+ goto out_err;
+ }
+ xe->eudebug.discovery_wq = wq;
+
err = sysfs_create_file(&dev->dev->kobj,
&dev_attr_enable_eudebug.attr);
if (err)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index a314cfa26a68..2d9b6e23315d 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -51,6 +51,10 @@ void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm);
void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm);
int xe_eudebug_enable(struct xe_device *xe, bool enable);
+struct xe_eudebug *xe_eudebug_get_nolock(struct xe_file *xef);
+struct xe_eudebug *xe_eudebug_get_nolock_with_discovery(struct xe_file *xef);
+void xe_eudebug_put(struct xe_eudebug *d);
+
#else
static inline int xe_eudebug_connect_ioctl(struct drm_device *dev,
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 46d78f4f8061..cc4b5f6f2a3a 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -19,6 +19,7 @@
#include <uapi/drm/xe_drm_eudebug.h>
struct xe_device;
+struct workqueue_struct;
/**
* enum xe_eudebug_cap_state - eudebug capability state
@@ -33,7 +34,7 @@ enum xe_eudebug_cap_state {
XE_EUDEBUG_CAP_ENABLED,
};
-#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_VM
+#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
/**
* struct xe_eudebug_handle - eudebug resource handle
@@ -100,6 +101,12 @@ struct xe_eudebug {
unsigned long flags;
#define XE_EUDEBUG_READER_ACTIVE 0
+ /** @discovery: completion to wait for discovery */
+ struct completion discovery;
+
+ /** @discovery_work: worker to discover resources for target_task */
+ struct work_struct discovery_work;
+
/** @events: kfifo queue of to-be-delivered events */
struct {
/** @events.lock: guards access to fifo, pending and staging */
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index c4213bb9c137..a663c55b386d 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -29,6 +29,7 @@
#include "xe_trace.h"
#include "xe_vm.h"
#include "xe_pxp.h"
+#include "xe_eudebug.h"
/**
* DOC: Execution Queue
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.h b/drivers/gpu/drm/xe/xe_hw_engine.h
index c3ee37f8cfc0..7319ac0bb91e 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.h
+++ b/drivers/gpu/drm/xe/xe_hw_engine.h
@@ -78,4 +78,18 @@ enum xe_force_wake_domains xe_hw_engine_to_fw_domain(struct xe_hw_engine *hwe);
u32 xe_hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg);
+static inline bool xe_engine_supports_eudebug(const enum xe_engine_class ec)
+{
+ if (ec == XE_ENGINE_CLASS_COMPUTE ||
+ ec == XE_ENGINE_CLASS_RENDER)
+ return true;
+
+ return false;
+}
+
+static inline bool xe_hw_engine_has_eudebug(const struct xe_hw_engine *hwe)
+{
+ return xe_engine_supports_eudebug(hwe->class);
+}
+
#endif
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index d33b8b371aae..934afe400330 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -66,6 +66,7 @@ struct drm_xe_eudebug_event {
#define DRM_XE_EUDEBUG_EVENT_NONE 0
#define DRM_XE_EUDEBUG_EVENT_READ 1
#define DRM_XE_EUDEBUG_EVENT_VM 2
+#define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE 3
/** @flags: Flags */
__u16 flags;
@@ -94,6 +95,31 @@ struct drm_xe_eudebug_event_vm {
__u64 vm_handle;
};
+/**
+ * struct drm_xe_eudebug_event_exec_queue - Exec Queue resource event
+ *
+ * Resource creation/destruction event for an Exec Queue
+ */
+struct drm_xe_eudebug_event_exec_queue {
+ /** @base: base event */
+ struct drm_xe_eudebug_event base;
+
+ /** @vm_handle: the vm handle this exec queue belongs to */
+ __u64 vm_handle;
+
+ /** @exec_queue_handle: unique handle for this exec queue */
+ __u64 exec_queue_handle;
+
+ /** @engine_class: engine class for the exec queue */
+ __u32 engine_class;
+
+ /** @width: width of exec queue, how many lrcs (handles) it has */
+ __u32 width;
+
+ /** @lrc_handle: array of lrc handles */
+ __u64 lrc_handle[];
+};
+
#if defined(__cplusplus)
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 05/27] drm/xe: Add EUDEBUG_ENABLE exec queue property
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (3 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 04/27] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:14 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 06/27] drm/xe/eudebug: Introduce exec_queue events Mika Kuoppala
` (27 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Dominik Grzegorzek, Mika Kuoppala
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Introduce an immutable eudebug property for exec_queues,
using a flags value to enable eudebug-specific features. For now, the
engine LRC uses this flag to enable the runalone hardware feature.
Runalone ensures that only one hardware engine in a group
[rcs0, ccs0-3] is active on a tile.
v2: - check CONFIG_DRM_XE_EUDEBUG and LR mode (Matthew)
- disable preempt (Dominik)
- lrc_create remove from engine init
v3: - remove redundant runalone setup (Sashiko)
v4: - deny if pxp is on (Sashiko)
- deny if secondary mq (Sashiko)
- deny if parallel (Sashiko)
- really deny if pxp (Claude)
Assisted-by: Claude:claude-opus-5
Cc: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_exec_queue.c | 63 +++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_exec_queue.h | 2 +
drivers/gpu/drm/xe/xe_exec_queue_types.h | 7 +++
include/uapi/drm/xe_drm.h | 2 +
4 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index a663c55b386d..d13f69eb025c 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -358,6 +358,9 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
if (q->flags & EXEC_QUEUE_FLAG_DISABLE_STATE_CACHE_PERF_FIX)
flags |= XE_LRC_DISABLE_STATE_CACHE_PERF_FIX;
+ if (q->eudebug_flags & EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)
+ flags |= XE_LRC_CREATE_RUNALONE;
+
err = q->ops->init(q);
if (err)
return err;
@@ -991,6 +994,51 @@ static int exec_queue_set_state_cache_perf_fix(struct xe_device *xe, struct xe_e
return 0;
}
+static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
+ u64 value)
+{
+ const u64 known_flags = DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
+
+ if (XE_IOCTL_DBG(xe, (q->class != XE_ENGINE_CLASS_RENDER &&
+ q->class != XE_ENGINE_CLASS_COMPUTE)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, (value & ~known_flags)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, !IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)))
+ return -EOPNOTSUPP;
+
+ if (XE_IOCTL_DBG(xe, !xe_exec_queue_is_lr(q)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, xe_exec_queue_is_parallel(q)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe,
+ !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, !xe_eudebug_is_enabled(xe)))
+ return -EPERM;
+
+ if (XE_IOCTL_DBG(xe, xe_exec_queue_uses_pxp(q)))
+ return -EPERM;
+
+ if (XE_IOCTL_DBG(xe, xe_exec_queue_is_multi_queue_secondary(q)))
+ return -EINVAL;
+
+ q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
+ q->sched_props.preempt_timeout_us = 0;
+
+ return 0;
+}
+
+int xe_exec_queue_is_debuggable(struct xe_exec_queue *q)
+{
+ return q->eudebug_flags & EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
+}
+
typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
struct xe_exec_queue *q,
u64 value);
@@ -1005,6 +1053,7 @@ static const xe_exec_queue_set_property_fn exec_queue_set_property_funcs[] = {
exec_queue_set_multi_queue_priority,
[DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX] =
exec_queue_set_state_cache_perf_fix,
+ [DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG] = exec_queue_set_eudebug,
};
/**
@@ -1077,6 +1126,17 @@ static int exec_queue_user_ext_check(struct xe_exec_queue *q, u64 properties)
(properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE))))
return -EINVAL;
+ /*
+ * A debugger can inspect and modify the EU state and memory of a
+ * debuggable queue, so it must not be combined with protected content.
+ * Test the property mask rather than the queue state, as the extensions
+ * are applied in the order userspace chained them and either one may be
+ * processed first.
+ */
+ if (XE_IOCTL_DBG(xe, (properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG)) &&
+ (properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE))))
+ return -EINVAL;
+
return 0;
}
@@ -1112,7 +1172,8 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe,
ext.property != DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE &&
ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP &&
ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY &&
- ext.property != DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX))
+ ext.property != DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX &&
+ ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG))
return -EINVAL;
idx = array_index_nospec(ext.property, ARRAY_SIZE(exec_queue_set_property_funcs));
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.h b/drivers/gpu/drm/xe/xe_exec_queue.h
index 0225426c57b0..fb090704dd9f 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.h
+++ b/drivers/gpu/drm/xe/xe_exec_queue.h
@@ -162,4 +162,6 @@ int xe_exec_queue_contexts_hwsp_rebase(struct xe_exec_queue *q, void *scratch);
struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q);
struct xe_lrc *xe_exec_queue_get_lrc(struct xe_exec_queue *q, u16 idx);
+int xe_exec_queue_is_debuggable(struct xe_exec_queue *q);
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h
index 95f75d61a647..67c4c974d13d 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue_types.h
+++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h
@@ -154,6 +154,13 @@ struct xe_exec_queue {
*/
unsigned long flags;
+ /**
+ * @eudebug_flags: immutable eudebug flags for this exec queue.
+ * Set up with DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG.
+ */
+#define EXEC_QUEUE_EUDEBUG_FLAG_ENABLE BIT(0)
+ unsigned long eudebug_flags;
+
union {
/** @multi_gt_list: list head for VM bind engines if multi-GT */
struct list_head multi_gt_list;
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index 03cb1181c169..a938a9f095ce 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -1442,6 +1442,8 @@ struct drm_xe_exec_queue_create {
#define DRM_XE_MULTI_GROUP_CREATE (1ull << 63)
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY 5
#define DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX 6
+#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG 7
+#define DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE (1 << 0)
/** @extensions: Pointer to the first extension struct, if any */
__u64 extensions;
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 06/27] drm/xe/eudebug: Introduce exec_queue events
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (4 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 05/27] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 07/27] drm/xe/eudebug: Mark guc contexts as debuggable Mika Kuoppala
` (26 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Dominik Grzegorzek, Mika Kuoppala
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Add events to inform the debugger about the creation and destruction of
exec_queues. Use user engine class types instead of the internal
xe_engine_class enum in exec_queue events. During discovery, only advertise
exec_queues with render or compute class, excluding others.
v2: - Only track long running queues
- Checkpatch (Tilak)
v3: __counted_by added
v4: - use helpers for filtering engines (Mika)
v5: - fix lrc handles memcpy size bug (Mika)
v6: - lookup for create event (Sashiko)
- defer engine class lookup (Sashiko)
- avoid uninitialized read on adding handle (Sashiko)
- too strict warn on q->width check (Sashiko)
- create eudebug eq event early (claude)
Assisted-by: Claude:claude-opus-5
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_eudebug.c | 243 +++++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_eudebug.h | 7 +
drivers/gpu/drm/xe/xe_eudebug_types.h | 4 +-
drivers/gpu/drm/xe/xe_exec_queue.c | 8 +-
4 files changed, 256 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 7a5b14346e05..d70970f70a8b 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -443,6 +443,28 @@ __find_handle(struct xe_eudebug_resource *r,
return h;
}
+static int find_handle(struct xe_eudebug *d,
+ const int type,
+ const void *p)
+{
+ const u64 key = (uintptr_t)p;
+ struct xe_eudebug_resource *r;
+ struct xe_eudebug_handle *h;
+ int id;
+
+ if (XE_WARN_ON(!key))
+ return -EINVAL;
+
+ r = resource_from_type(d, type);
+
+ mutex_lock(&r->lock);
+ h = __find_handle(r, key);
+ id = h ? h->id : -ENOENT;
+ mutex_unlock(&r->lock);
+
+ return id;
+}
+
static int _xe_eudebug_add_handle(struct xe_eudebug *d,
int type,
void *p,
@@ -705,6 +727,209 @@ void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
xe_eudebug_put(d);
}
+static const u16 xe_to_user_engine_class[] = {
+ [XE_ENGINE_CLASS_RENDER] = DRM_XE_ENGINE_CLASS_RENDER,
+ [XE_ENGINE_CLASS_COPY] = DRM_XE_ENGINE_CLASS_COPY,
+ [XE_ENGINE_CLASS_VIDEO_DECODE] = DRM_XE_ENGINE_CLASS_VIDEO_DECODE,
+ [XE_ENGINE_CLASS_VIDEO_ENHANCE] = DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE,
+ [XE_ENGINE_CLASS_COMPUTE] = DRM_XE_ENGINE_CLASS_COMPUTE,
+};
+
+static int send_exec_queue_event(struct xe_eudebug *d, u32 flags,
+ u64 vm_handle, u64 exec_queue_handle,
+ enum xe_engine_class class,
+ u32 width, u64 *lrc_handles, u64 seqno)
+{
+ struct drm_xe_eudebug_event *event;
+ struct drm_xe_eudebug_event_exec_queue *e;
+ const u32 sz = struct_size(e, lrc_handle, width);
+ u32 xe_engine_class;
+ int err;
+
+ if (!xe_engine_supports_eudebug(class))
+ return -EINVAL;
+
+ xe_engine_class = xe_to_user_engine_class[class];
+
+ spin_lock(&d->events.lock);
+ event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE,
+ seqno, flags, sz);
+ e = cast_event(e, event);
+
+ e->vm_handle = vm_handle;
+ e->exec_queue_handle = exec_queue_handle;
+ e->engine_class = xe_engine_class;
+ e->width = width;
+
+ memcpy(e->lrc_handle, lrc_handles, width * sizeof(u64));
+
+ err = xe_eudebug_queue_event(d, event);
+ spin_unlock(&d->events.lock);
+
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ return err;
+}
+
+static int exec_queue_create_event(struct xe_eudebug *d,
+ struct xe_file *xef, struct xe_exec_queue *q)
+{
+ int h_vm, h_queue;
+ u64 h_lrc[XE_HW_ENGINE_MAX_INSTANCE], seqno;
+ int i;
+ int ret;
+
+ if (!xe_exec_queue_is_debuggable(q))
+ return 0;
+
+ h_vm = find_handle(d, XE_EUDEBUG_RES_TYPE_VM, q->vm);
+ if (h_vm < 0)
+ return h_vm;
+
+ if (XE_WARN_ON(q->width > XE_HW_ENGINE_MAX_INSTANCE))
+ return -EINVAL;
+
+ ret = 0;
+ for (i = 0; i < q->width; i++) {
+ ret = _xe_eudebug_add_handle(d,
+ XE_EUDEBUG_RES_TYPE_LRC,
+ q->lrc[i],
+ NULL);
+
+ if (ret < 0)
+ break;
+
+ XE_WARN_ON(!ret);
+
+ h_lrc[i] = ret;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ h_queue = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q, &seqno);
+ if (h_queue < 0)
+ return h_queue;
+
+ /* No need to cleanup for added handles on error as if we fail
+ * we disconnect
+ */
+
+ ret = send_exec_queue_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
+ h_vm, h_queue, q->class,
+ q->width, h_lrc, seqno);
+
+ if (ret)
+ eu_dbg(d, "send_exec_queue_event create error %d", ret);
+
+ return ret;
+}
+
+static int exec_queue_destroy_event(struct xe_eudebug *d,
+ struct xe_file *xef,
+ struct xe_exec_queue *q)
+{
+ int h_vm, h_queue;
+ u64 h_lrc[XE_HW_ENGINE_MAX_INSTANCE], seqno;
+ int i;
+ int ret, err = 0;
+
+ if (!xe_exec_queue_is_debuggable(q))
+ return 0;
+
+ /*
+ * A queue we never handed out to the debugger needs no destroy event.
+ * The queue handle is added last on create, so its presence implies
+ * the lrc handles are there too. Past this point a missing handle
+ * means our resource map and the client have diverged, and that has
+ * to drop the session.
+ */
+ if (find_handle(d, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q) == -ENOENT)
+ return 0;
+
+ h_vm = find_handle(d, XE_EUDEBUG_RES_TYPE_VM, q->vm);
+ if (h_vm < 0)
+ return h_vm;
+
+ if (XE_WARN_ON(q->width > XE_HW_ENGINE_MAX_INSTANCE))
+ return -EINVAL;
+
+ for (i = 0; i < q->width; i++) {
+ ret = _xe_eudebug_remove_handle(d,
+ XE_EUDEBUG_RES_TYPE_LRC,
+ q->lrc[i],
+ NULL);
+ if (ret < 0) {
+ XE_WARN_ON(ret);
+ if (!err)
+ err = ret;
+ h_lrc[i] = 0;
+ continue;
+ }
+
+ XE_WARN_ON(!ret);
+ h_lrc[i] = ret;
+ }
+
+ if (err)
+ return err;
+
+ h_queue = xe_eudebug_remove_handle(d,
+ XE_EUDEBUG_RES_TYPE_EXEC_QUEUE,
+ q,
+ &seqno);
+ if (h_queue < 0)
+ return h_queue;
+
+ ret = send_exec_queue_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY,
+ h_vm, h_queue, q->class,
+ q->width, h_lrc, seqno);
+
+ if (ret)
+ eu_dbg(d, "send_exec_queue_event destroy error %d\n", ret);
+
+ return ret;
+}
+
+void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q)
+{
+ struct xe_eudebug *d;
+ int err;
+
+ if (!xe_engine_supports_eudebug(q->class))
+ return;
+
+ d = xe_eudebug_get(xef);
+ if (!d)
+ return;
+
+ err = exec_queue_create_event(d, xef, q);
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ xe_eudebug_put(d);
+}
+
+void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q)
+{
+ struct xe_eudebug *d;
+ int err;
+
+ if (!xe_engine_supports_eudebug(q->class))
+ return;
+
+ d = xe_eudebug_get(xef);
+ if (!d)
+ return;
+
+ err = exec_queue_destroy_event(d, xef, q);
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ xe_eudebug_put(d);
+}
+
static struct xe_file *xe_eudebug_target_get(struct xe_eudebug *d)
{
struct xe_file *xef = NULL;
@@ -720,9 +945,10 @@ static struct xe_file *xe_eudebug_target_get(struct xe_eudebug *d)
static void discover_client(struct xe_eudebug *d)
{
struct xe_file *xef;
+ struct xe_exec_queue *q;
struct xe_vm *vm;
unsigned long i;
- unsigned int vm_count = 0;
+ unsigned int vm_count = 0, eq_count = 0;
int err = 0;
xef = xe_eudebug_target_get(d);
@@ -756,14 +982,23 @@ static void discover_client(struct xe_eudebug *d)
vm_count++;
}
+ xa_for_each(&xef->exec_queue.xa, i, q) {
+ if (!xe_engine_supports_eudebug(q->class))
+ continue;
+
+ err = exec_queue_create_event(d, xef, q);
+ if (err)
+ goto out;
+ }
+
out:
complete_all(&d->discovery);
up_write(&xef->eudebug.ioctl_lock);
- if (vm_count)
- eu_dbg(d, "Discovery found %u vms",
- vm_count);
+ if (vm_count || eq_count)
+ eu_dbg(d, "Discovery found %u vms, %u exec_queues",
+ vm_count, eq_count);
xe_file_put(xef);
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 2d9b6e23315d..3540f1a798ea 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -13,6 +13,7 @@ struct drm_file;
struct xe_device;
struct xe_file;
struct xe_vm;
+struct xe_exec_queue;
#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
@@ -55,6 +56,9 @@ struct xe_eudebug *xe_eudebug_get_nolock(struct xe_file *xef);
struct xe_eudebug *xe_eudebug_get_nolock_with_discovery(struct xe_file *xef);
void xe_eudebug_put(struct xe_eudebug *d);
+void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q);
+void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q);
+
#else
static inline int xe_eudebug_connect_ioctl(struct drm_device *dev,
@@ -70,6 +74,9 @@ static inline void xe_eudebug_file_close(struct xe_file *xef) { }
static inline void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm) { }
static inline void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm) { }
+static inline void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q) { }
+static inline void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q) { }
+
#endif /* CONFIG_DRM_XE_EUDEBUG */
#endif /* _XE_EUDEBUG_H_ */
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index cc4b5f6f2a3a..59d77998b829 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -65,7 +65,9 @@ struct xe_eudebug_resource {
};
#define XE_EUDEBUG_RES_TYPE_VM 0
-#define XE_EUDEBUG_RES_TYPE_COUNT (XE_EUDEBUG_RES_TYPE_VM + 1)
+#define XE_EUDEBUG_RES_TYPE_EXEC_QUEUE 1
+#define XE_EUDEBUG_RES_TYPE_LRC 2
+#define XE_EUDEBUG_RES_TYPE_COUNT (XE_EUDEBUG_RES_TYPE_LRC + 1)
/**
* struct xe_eudebug - Top level struct for eudebug: the connection
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index d13f69eb025c..12410646d15d 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -1487,10 +1487,14 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
if (eci[0].engine_class != DRM_XE_ENGINE_CLASS_VM_BIND)
xe_vm_add_exec_queue(vm, q);
+ xe_eudebug_exec_queue_create(xef, q);
+
/* user id alloc must always be last in ioctl to prevent UAF */
err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL);
- if (err)
+ if (err) {
+ xe_eudebug_exec_queue_destroy(xef, q);
goto del_hw_engine_group;
+ }
args->exec_queue_id = id;
@@ -1691,6 +1695,8 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
if (q->vm && q->hwe->hw_engine_group)
xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q);
+ xe_eudebug_exec_queue_destroy(xef, q);
+
xe_exec_queue_kill(q);
trace_xe_exec_queue_close(q);
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 07/27] drm/xe/eudebug: Mark guc contexts as debuggable
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (5 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 06/27] drm/xe/eudebug: Introduce exec_queue events Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 08/27] drm/xe: Remove ifdef in DRM_GPUVA_OP_DRIVER svm subop checking Mika Kuoppala
` (25 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala,
Lucas De Marchi, Daniele Ceraolo Spurio, Jan Sokolowski,
Dominik Grzegorzek
Inform the GuC which contexts are debuggable, as their
handling differs from ordinary contexts.
v2: void return, use xe_gt_dbg, no need for lrc (Matt)
v3: add the workaround enabling (Daniele)
v4: version needed to 70.49.4
v5: bail out early before registering eq (Daniele)
v6: export the guc action for future (Mika)
v7: remove redundant xe_gt_info (Sashiko)
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Jan Sokolowski <jan.sokolowski@intel.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
---
drivers/gpu/drm/xe/abi/guc_actions_abi.h | 5 ++++
drivers/gpu/drm/xe/abi/guc_klvs_abi.h | 1 +
drivers/gpu/drm/xe/xe_exec_queue.c | 5 ++++
drivers/gpu/drm/xe/xe_guc.c | 8 ++++++
drivers/gpu/drm/xe/xe_guc.h | 6 +++++
drivers/gpu/drm/xe/xe_guc_ads.c | 12 +++++++++
drivers/gpu/drm/xe/xe_guc_submit.c | 34 ++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_guc_submit.h | 1 +
drivers/gpu/drm/xe/xe_wa_oob.rules | 2 ++
9 files changed, 74 insertions(+)
diff --git a/drivers/gpu/drm/xe/abi/guc_actions_abi.h b/drivers/gpu/drm/xe/abi/guc_actions_abi.h
index f5c9b37038d4..652c4e75ed2b 100644
--- a/drivers/gpu/drm/xe/abi/guc_actions_abi.h
+++ b/drivers/gpu/drm/xe/abi/guc_actions_abi.h
@@ -162,6 +162,7 @@ enum xe_guc_action {
XE_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE = 0x8003,
XE_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED = 0x8004,
XE_GUC_ACTION_NOTIFY_EXCEPTION = 0x8005,
+ XE_GUC_ACTION_EU_KERNEL_DEBUG = 0x8006,
XE_GUC_ACTION_TEST_G2G_SEND = 0xF001,
XE_GUC_ACTION_TEST_G2G_RECV = 0xF002,
XE_GUC_ACTION_LIMIT
@@ -285,4 +286,8 @@ enum xe_guc_g2g_type {
/* invalid type for XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR */
#define XE_GUC_CAT_ERR_TYPE_INVALID 0xdeadbeef
+enum xe_guc_eu_kernel_debug_request_type {
+ XE_GUC_EU_KERNEL_DEBUG_ENABLE = 0x3,
+};
+
#endif
diff --git a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h
index 685c4ef17b73..85570453892c 100644
--- a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h
+++ b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h
@@ -522,6 +522,7 @@ enum xe_guc_klv_ids {
GUC_WA_KLV_WAKE_POWER_DOMAINS_FOR_OUTBOUND_MMIO = 0x900a,
GUC_WA_KLV_RESET_BB_STACK_PTR_ON_VF_SWITCH = 0x900b,
GUC_WA_KLV_RESTORE_UNSAVED_MEDIA_CONTROL_REG = 0x900c,
+ GUC_WA_KLV_RESET_DEP_ENGINES_ON_DEBUG_CTX_SWITCH = 0x900d,
GUC_WA_KLV_CLR_CS_INDIRECT_RING_STATE_IF_IDLE_AT_CTX_REG = 0x900e,
GUC_WA_KLV_REMAP_RANGED_TLB_INV = 0x900f,
GUC_WA_KLV_IGNORE_MMIO_READ_SEM_TOKEN_64 = 0x9010,
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index 12410646d15d..98f32c99a3a3 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -19,6 +19,7 @@
#include "xe_gt.h"
#include "xe_gt_sriov_pf.h"
#include "xe_gt_sriov_vf.h"
+#include "xe_guc.h"
#include "xe_hw_engine_class_sysfs.h"
#include "xe_hw_engine_group.h"
#include "xe_irq.h"
@@ -998,6 +999,7 @@ static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
u64 value)
{
const u64 known_flags = DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
+ struct xe_guc *guc = &q->gt->uc.guc;
if (XE_IOCTL_DBG(xe, (q->class != XE_ENGINE_CLASS_RENDER &&
q->class != XE_ENGINE_CLASS_COMPUTE)))
@@ -1009,6 +1011,9 @@ static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
if (XE_IOCTL_DBG(xe, !IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)))
return -EOPNOTSUPP;
+ if (XE_IOCTL_DBG(xe, !xe_guc_has_debug_contexts(guc)))
+ return -EOPNOTSUPP;
+
if (XE_IOCTL_DBG(xe, !xe_exec_queue_is_lr(q)))
return -EINVAL;
diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c
index c7f8bbd4cb92..2a037aebf569 100644
--- a/drivers/gpu/drm/xe/xe_guc.c
+++ b/drivers/gpu/drm/xe/xe_guc.c
@@ -1918,6 +1918,14 @@ u16 xe_hwe_guc_logical_instance(struct xe_hw_engine *hwe)
return hwe->logical_instance;
}
+bool xe_guc_has_debug_contexts(struct xe_guc *guc)
+{
+ return GUC_FIRMWARE_VER_AT_LEAST(guc,
+ XE_GUC_VER_DEBUG_CONTEXTS_MAJOR,
+ XE_GUC_VER_DEBUG_CONTEXTS_MINOR,
+ XE_GUC_VER_DEBUG_CONTEXTS_PATCH);
+}
+
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
#include "tests/xe_guc_g2g_test.c"
#endif
diff --git a/drivers/gpu/drm/xe/xe_guc.h b/drivers/gpu/drm/xe/xe_guc.h
index 61e3ee19a59b..2d1e1bfd3d3b 100644
--- a/drivers/gpu/drm/xe/xe_guc.h
+++ b/drivers/gpu/drm/xe/xe_guc.h
@@ -29,6 +29,11 @@
#define GUC_FIRMWARE_VER_AT_LEAST(guc, ver...) \
xe_guc_fw_version_at_least((guc), MAKE_GUC_VER_ARGS(ver))
+/* Lowest GuC version that knows how to handle debuggable contexts */
+#define XE_GUC_VER_DEBUG_CONTEXTS_MAJOR 70
+#define XE_GUC_VER_DEBUG_CONTEXTS_MINOR 49
+#define XE_GUC_VER_DEBUG_CONTEXTS_PATCH 4
+
struct drm_printer;
void xe_guc_comm_init_early(struct xe_guc *guc);
@@ -63,6 +68,7 @@ int xe_guc_start(struct xe_guc *guc);
void xe_guc_declare_wedged(struct xe_guc *guc);
bool xe_guc_using_main_gamctrl_queues(struct xe_guc *guc);
bool xe_guc_has_paging_engine(struct xe_guc *guc);
+bool xe_guc_has_debug_contexts(struct xe_guc *guc);
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
int xe_guc_g2g_test_notification(struct xe_guc *guc, u32 *payload, u32 len);
diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c
index ff8eee3831aa..8a6cab7bf0d4 100644
--- a/drivers/gpu/drm/xe/xe_guc_ads.c
+++ b/drivers/gpu/drm/xe/xe_guc_ads.c
@@ -396,6 +396,18 @@ static void guc_waklv_init(struct xe_guc_ads *ads)
GUC_FEATURE_KLV_DISABLE_MULTI_QUEUE);
}
+ if (IS_ENABLED(CONFIG_DRM_XE_EUDEBUG) && XE_GT_WA(gt, 14022766366)) {
+ if (xe_guc_has_debug_contexts(>->uc.guc)) {
+ guc_waklv_enable(ads, NULL, 0, &offset, &remain,
+ GUC_WA_KLV_RESET_DEP_ENGINES_ON_DEBUG_CTX_SWITCH);
+ } else {
+ xe_gt_info(gt, "eudebug needs GuC version %u.%u.%u or greater\n",
+ XE_GUC_VER_DEBUG_CONTEXTS_MAJOR,
+ XE_GUC_VER_DEBUG_CONTEXTS_MINOR,
+ XE_GUC_VER_DEBUG_CONTEXTS_PATCH);
+ }
+ }
+
size = guc_ads_waklv_size(ads) - remain;
if (!size)
return;
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index 99d8c807ff05..18a3ece25c3c 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -1013,6 +1013,37 @@ static u32 xe_hwe_guc_logical_to_submit_mask(struct xe_hw_engine *hwe, u32 logic
return logical_mask;
}
+int xe_guc_action_eu_kernel_debug(struct xe_guc *guc, u32 id, u32 cmd)
+{
+ const u32 action[] = {
+ XE_GUC_ACTION_EU_KERNEL_DEBUG,
+ id,
+ cmd,
+ 0, /* reserved */
+ };
+
+ return xe_guc_ct_send(&guc->ct, action,
+ ARRAY_SIZE(action), 0, 0);
+}
+
+static void set_eu_kernel_debug(struct xe_exec_queue *q)
+{
+ struct xe_guc *guc = exec_queue_to_guc(q);
+ struct xe_gt *gt = guc_to_gt(guc);
+ int ret;
+
+ ret = xe_guc_action_eu_kernel_debug(guc, q->guc->id,
+ XE_GUC_EU_KERNEL_DEBUG_ENABLE);
+
+ if (ret)
+ xe_gt_err_ratelimited(gt,
+ "GuC ctx=%u debug enabling failed with %d",
+ q->guc->id, ret);
+ else
+ xe_gt_dbg(gt,
+ "GuC ctx=%u enabled for debug", q->guc->id);
+}
+
static void register_exec_queue(struct xe_exec_queue *q, int ctx_type)
{
struct xe_guc *guc = exec_queue_to_guc(q);
@@ -1074,6 +1105,9 @@ static void register_exec_queue(struct xe_exec_queue *q, int ctx_type)
if (xe_exec_queue_is_multi_queue_secondary(q))
guc_exec_queue_send_cgp_sync(q, CGP_SYNC_REGISTRATION);
+
+ if (xe_exec_queue_is_debuggable(q))
+ set_eu_kernel_debug(q);
}
static u32 wq_space_until_wrap(struct xe_exec_queue *q)
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.h b/drivers/gpu/drm/xe/xe_guc_submit.h
index ccade320dc69..e7a24f8ecbc5 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.h
+++ b/drivers/gpu/drm/xe/xe_guc_submit.h
@@ -56,5 +56,6 @@ void xe_guc_register_vf_exec_queue(struct xe_exec_queue *q, int ctx_type);
bool xe_guc_has_registered_mlrc_queues(struct xe_guc *guc);
int xe_guc_contexts_hwsp_rebase(struct xe_guc *guc, void *scratch);
+int xe_guc_action_eu_kernel_debug(struct xe_guc *guc, u32 id, u32 cmd);
#endif
diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules
index dd69ad07f7a9..3de46094ab5c 100644
--- a/drivers/gpu/drm/xe/xe_wa_oob.rules
+++ b/drivers/gpu/drm/xe/xe_wa_oob.rules
@@ -72,3 +72,5 @@
16029897822 MEDIA_VERSION(3500)
GRAPHICS_VERSION(3510)
14027054324 GRAPHICS_VERSION(3511)
+14022766366 GRAPHICS_VERSION_RANGE(2001, 2004)
+ GRAPHICS_VERSION_RANGE(3000, 3005)
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 08/27] drm/xe: Remove ifdef in DRM_GPUVA_OP_DRIVER svm subop checking
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (6 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 07/27] drm/xe/eudebug: Mark guc contexts as debuggable Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 09/27] drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops Mika Kuoppala
` (24 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
Always emit the DRM_GPUVA_OP_DRIVER case so the previous break is
effective and we never fall through to the default warning.
This also allows adding more subops in the future without ifdef dancing.
Cc: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
drivers/gpu/drm/xe/xe_pt.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index 5d990c1c3740..b7749eda6490 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -1622,7 +1622,6 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op,
err = vma_check_userptr(vm, gpuva_to_vma(op->base.prefetch.va), pt_update);
}
break;
-#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
case DRM_GPUVA_OP_DRIVER:
if (op->subop == XE_VMA_SUBOP_MAP_RANGE) {
struct xe_svm_range *range = op->map_range.range;
@@ -1637,7 +1636,6 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op,
}
}
break;
-#endif
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE");
}
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 09/27] drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (7 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 08/27] drm/xe: Remove ifdef in DRM_GPUVA_OP_DRIVER svm subop checking Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:22 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 10/27] drm/xe/eudebug: Introduce vm bind and vm bind debug data events Mika Kuoppala
` (23 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Christoph Manszewski, Mika Kuoppala
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 separate 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 the creation address
and range have to be passed in order to remove it.
For debug data manipulation only the 'op' and 'extensions' fields from
'struct drm_xe_vm_bind_op' are 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 to 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)
v3: - fix overflow, deny zero ranges, null str for empty check (Sashiko)
- fix TOCTOUs and list handling issues (Sashiko)
v4: - check full path for zero, overflow check (Sashiko)
- don't unwind failed extensions, use op commit (Sashiko)
- restore removes by relink, remove fallible alloc (Sashiko)
Assisted-by: Claude:claude-opus-4-6
Assisted-by: Claude:claude-opus-5
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 | 383 +++++++++++++++++++++++
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 | 180 ++++++++++-
drivers/gpu/drm/xe/xe_vm_types.h | 28 ++
include/uapi/drm/xe_drm.h | 64 ++++
7 files changed, 697 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 0631f659e304..68dfab1a5c30 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..3708583252dd
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_data.c
@@ -0,0 +1,383 @@
+// 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 const char *
+debug_data_path_str(u64 flags, u64 pseudopath, const char *pathname)
+{
+ return (flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) ?
+ xe_debug_data_pseudo_path_to_string(pseudopath) : pathname;
+}
+
+static bool
+debug_data_overlaps(const struct drm_xe_vm_bind_op_ext_debug_data *a,
+ const struct xe_debug_data *b)
+{
+ u64 a_end, b_end;
+
+ /*
+ * Ranges that wrap u64 are rejected by debug_data_ext_validate()
+ * before we get here, so neither side should ever overflow. Be
+ * defensive anyway and report overlap, which makes callers reject
+ * the bind rather than act on a bogus range.
+ */
+ if (check_add_overflow(a->addr, a->range, &a_end) ||
+ check_add_overflow(b->addr, b->range, &b_end))
+ return true;
+
+ return a->addr < b_end && b->addr < a_end;
+}
+
+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 *ext)
+{
+ return !ext->flags && !ext->offset && !ext->reserved &&
+ mem_is_zero(ext->pathname, sizeof(ext->pathname));
+}
+
+/*
+ * Validate a debug data extension copied from userspace.
+ *
+ * This is the single source of truth for what the extension is allowed
+ * to contain. It is called from the check phase and again from the
+ * commit phase (on a freshly-copied snapshot) so that the kernel never
+ * trusts the result of an earlier copy_from_user(): see Sashiko's TOCTOU
+ * comment on v1.
+ */
+static int
+debug_data_ext_validate(struct xe_device *xe, u32 operation,
+ const struct drm_xe_vm_bind_op_ext_debug_data *ext)
+{
+ u64 end;
+
+ 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;
+
+ if (XE_IOCTL_DBG(xe, ext->reserved))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, check_add_overflow(ext->addr, ext->range, &end)))
+ return -EINVAL;
+
+ /* Remove takes only addr+range; everything else must be zero. */
+ if (operation == DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA) {
+ if (XE_IOCTL_DBG(xe, !debug_data_is_empty(ext)))
+ return -EINVAL;
+ if (XE_IOCTL_DBG(xe, !ext->range))
+ return -EINVAL;
+ return 0;
+ }
+
+ /* Add. */
+ if (XE_IOCTL_DBG(xe, !ext->range))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, ext->flags & ~DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO))
+ return -EINVAL;
+
+ if (ext->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO) {
+ if (XE_IOCTL_DBG(xe, ext->offset))
+ return -EINVAL;
+ if (XE_IOCTL_DBG(xe,
+ ext->pseudopath < DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_MODULE_AREA ||
+ ext->pseudopath > DRM_XE_VM_BIND_DEBUG_DATA_PSEUDO_SIP_AREA))
+ return -EINVAL;
+ } else {
+ if (XE_IOCTL_DBG(xe, strnlen(ext->pathname, sizeof(ext->pathname)) >=
+ sizeof(ext->pathname)))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int xe_debug_data_check_extension(struct xe_vm *vm, u32 operation, u64 extension)
+{
+ const void __user * const address = u64_to_user_ptr(extension);
+ struct drm_xe_vm_bind_op_ext_debug_data *ext;
+ int ret;
+
+ ext = kzalloc_obj(*ext, GFP_KERNEL);
+ if (!ext)
+ return -ENOMEM;
+
+ if (copy_from_user(ext, address, sizeof(*ext))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = debug_data_ext_validate(vm->xe, operation, ext);
+ /*
+ * Intentionally no list walk here: any check we make against
+ * vm->debug_data.list outside the commit critical section can be
+ * invalidated before commit runs (concurrent ioctls). The commit
+ * phase re-validates and re-checks under the list lock; this
+ * function exists only for early rejection of syntactically
+ * malformed input.
+ */
+out:
+ 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, *iter;
+ int ret = 0;
+
+ vm_dbg(&vm->xe->drm,
+ "ADD_DEBUG_DATA: addr=0x%016llx, range=0x%016llx, offset=0x%08llx, flags=0x%016llx, path=%s\n",
+ ext->addr, ext->range, ext->offset, ext->flags,
+ debug_data_path_str(ext->flags, ext->pseudopath, ext->pathname));
+
+ dd = kzalloc_obj(*dd, GFP_KERNEL_ACCOUNT);
+ 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,
+ sizeof(dd->pathname)) == -E2BIG) {
+ /* Defence in depth: validate() should have caught this. */
+ ret = -ENAMETOOLONG;
+ goto err_free;
+ }
+
+ /*
+ * Overlap-check-and-insert atomically under the list lock.
+ * Doing the check in a separate critical section would race
+ * with concurrent adds on the same vm.
+ */
+ mutex_lock(&vm->debug_data.lock);
+ list_for_each_entry(iter, &vm->debug_data.list, link) {
+ if (debug_data_matches(ext, iter)) {
+ ret = -EEXIST;
+ goto err_unlock;
+ }
+ if (debug_data_overlaps(ext, iter)) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ }
+ list_add_tail(&dd->link, &vm->debug_data.list);
+ mutex_unlock(&vm->debug_data.lock);
+
+ /*
+ * Borrowed reference for the unwind path and for the bind event.
+ * The list owns it from here, so this must not be freed through
+ * the op.
+ */
+ vma_op->modify_debug_data.added = dd;
+
+ vma_op->flags |= XE_VMA_OP_COMMITTED;
+
+ return 0;
+
+err_unlock:
+ mutex_unlock(&vm->debug_data.lock);
+err_free:
+ kfree(dd);
+ return ret;
+}
+
+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, *found = NULL;
+
+ vm_dbg(&vm->xe->drm,
+ "REMOVE_DEBUG_DATA: addr=0x%016llx, range=0x%016llx\n",
+ ext->addr, ext->range);
+
+ mutex_lock(&vm->debug_data.lock);
+ list_for_each_entry(dd, &vm->debug_data.list, link) {
+ if (debug_data_matches(ext, dd)) {
+ list_del(&dd->link);
+ found = dd;
+ break;
+ }
+ }
+ mutex_unlock(&vm->debug_data.lock);
+
+ if (!found) {
+ drm_dbg(&vm->xe->drm,
+ "Debug data to remove not found: addr=0x%llx range=0x%llx\n",
+ ext->addr, ext->range);
+ return -ENOENT;
+ }
+
+ vma_op->modify_debug_data.removed = found;
+ vma_op->flags |= XE_VMA_OP_COMMITTED;
+
+ return 0;
+}
+
+int xe_debug_data_process_extension(struct xe_vm *vm, struct drm_gpuva_ops *ops,
+ u32 operation, u64 extension)
+{
+ const void __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))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ /*
+ * Re-validate the freshly-copied extension. The check phase
+ * cannot be trusted: userspace may have mutated the backing
+ * memory between check and commit (TOCTOU). All decisions below
+ * are made against this kernel-local copy.
+ */
+ ret = debug_data_ext_validate(vm->xe, operation, ext);
+ if (ret)
+ goto out;
+
+ op = drm_gpuva_first_op(ops);
+ if (XE_WARN_ON(op != drm_gpuva_last_op(ops))) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ 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 if (vma_op->subop == XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ ret = xe_debug_data_remove(vm, vma_op, ext);
+ else
+ ret = -EINVAL;
+
+out:
+ 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.added;
+ struct xe_debug_data *dd, *found = NULL;
+
+ if (!op_data)
+ return 0;
+
+ vm_dbg(&vm->xe->drm,
+ "Reverting debug data add: addr=0x%016llx, range=0x%016llx, offset=0x%08llx, flags=0x%016llx, path=%s\n",
+ op_data->addr, op_data->range, op_data->offset, op_data->flags,
+ debug_data_path_str(op_data->flags, 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);
+ found = dd;
+ break;
+ }
+ }
+ mutex_unlock(&vm->debug_data.lock);
+
+ if (!found) {
+ /*
+ * Internal invariant: we are unwinding an add that
+ * previously succeeded, so the entry must be on the
+ * list unless somebody else removed it behind our
+ * back. There is no such "somebody else" in the
+ * current locking design.
+ */
+ drm_warn(&vm->xe->drm,
+ "unwind add: entry missing addr=0x%llx range=0x%llx\n",
+ op_data->addr, op_data->range);
+ return -ENOENT;
+ }
+
+ kfree(found);
+ vma_op->modify_debug_data.added = NULL;
+
+ return 0;
+}
+
+static int xe_debug_data_op_unwind_remove(struct xe_vm *vm, struct xe_vma_op *vma_op)
+{
+ struct xe_debug_data *dd = vma_op->modify_debug_data.removed;
+
+ if (!dd)
+ return 0;
+
+ vm_dbg(&vm->xe->drm,
+ "Reverting debug data remove: addr=0x%016llx, range=0x%016llx, offset=0x%08llx, flags=0x%016llx, path=%s\n",
+ dd->addr, dd->range, dd->offset, dd->flags,
+ debug_data_path_str(dd->flags, dd->pseudopath, dd->pathname));
+
+ mutex_lock(&vm->debug_data.lock);
+ list_add_tail(&dd->link, &vm->debug_data.list);
+ mutex_unlock(&vm->debug_data.lock);
+
+ vma_op->modify_debug_data.removed = NULL;
+
+ 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;
+ }
+}
+
+void 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);
+}
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..0c0089a427a0
--- /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);
+void 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..5cb74c63b440
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_data_types.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 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;
+ u64 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 cf7a3c7c51e5..fdc8e66a8ddc 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"
@@ -1391,10 +1392,29 @@ static struct drm_gpuva_op *xe_vm_op_alloc(void)
return &op->base;
}
+static void xe_vm_op_free(struct drm_gpuva_op *__op)
+{
+ struct xe_vma_op *op = gpuva_op_to_vma_op(__op);
+
+ /*
+ * Only REMOVE_DEBUG_DATA ops carry a detached list object here.
+ * modify_debug_data overlaps map/unmap/prefetch in the union, so
+ * it must not be touched for any other op type. NULL-safe: set
+ * only on a committed remove that was not unwound.
+ */
+ if (__op->op == DRM_GPUVA_OP_DRIVER &&
+ (op->subop == XE_VMA_SUBOP_ADD_DEBUG_DATA ||
+ op->subop == XE_VMA_SUBOP_REMOVE_DEBUG_DATA))
+ kfree(op->modify_debug_data.removed);
+
+ kfree(op);
+}
+
static void xe_vm_free(struct drm_gpuvm *gpuvm);
static const struct drm_gpuvm_ops gpuvm_ops = {
.op_alloc = xe_vm_op_alloc,
+ .op_free = xe_vm_op_free,
.vm_bo_validate = xe_gpuvm_validate,
.vm_free = xe_vm_free,
};
@@ -1716,6 +1736,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;
/*
@@ -2017,6 +2040,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);
}
@@ -2354,6 +2379,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) {
@@ -2388,6 +2414,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");
}
@@ -2432,12 +2464,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;
@@ -2494,6 +2527,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);
@@ -2798,6 +2849,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");
}
@@ -3000,6 +3056,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");
}
@@ -3079,6 +3140,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)
+ drm_warn(&vm->xe->drm, "Unexpected vma sub op: %d", op->subop);
+ else if (post_commit)
+ xe_debug_data_op_unwind(vm, op);
+ break;
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE\n");
}
@@ -3433,6 +3501,11 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
}
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");
}
@@ -3673,6 +3746,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");
}
@@ -3760,6 +3838,83 @@ 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,
+};
+
+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;
+ struct drm_xe_user_extension ext;
+ int debug_data_count = 0;
+ int ext_count = 0;
+ int err;
+ u32 idx;
+
+ 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) {
+ idx = array_index_nospec(ext.name,
+ ARRAY_SIZE(vm_bind_extension_check_funcs));
+ err = vm_bind_extension_check_funcs[idx](vm, operation, extensions);
+ } else {
+ idx = array_index_nospec(ext.name,
+ ARRAY_SIZE(vm_bind_extension_process_funcs));
+ err = vm_bind_extension_process_funcs[idx](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)
@@ -3811,6 +3966,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;
@@ -3840,7 +3996,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 ||
@@ -3892,7 +4048,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;
}
@@ -3903,6 +4061,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;
@@ -4180,11 +4342,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;
@@ -4418,7 +4586,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 68588b624212..58afdc733461 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"
@@ -421,6 +422,15 @@ 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 {
+ /** @list: list of debug data items for this vm */
+ struct list_head list;
+
+ /** @lock: guards access to the debug data list */
+ struct mutex lock;
+ } debug_data;
};
/** struct xe_vma_op_map - VMA map operation */
@@ -494,6 +504,18 @@ 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 {
+ /**
+ * @added: entry published on vm->debug_data.list, owned by the
+ * list and only borrowed here. Cleared once unwind frees it.
+ */
+ struct xe_debug_data *added;
+
+ /** @removed: detached from the list, relinked on unbind */
+ struct xe_debug_data *removed;
+};
+
/** enum xe_vma_op_flags - flags for VMA operation */
enum xe_vma_op_flags {
/** @XE_VMA_OP_COMMITTED: VMA operation committed */
@@ -510,6 +532,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 */
@@ -538,6 +564,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 a938a9f095ce..12d9158cb5ae 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
+ */
+ __u64 offset;
+
+ /** @reserved: Reserved */
+ __u64 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.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 10/27] drm/xe/eudebug: Introduce vm bind and vm bind debug data events
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (8 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 09/27] drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:26 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 11/27] drm/xe/eudebug: Add ufence events with acks Mika Kuoppala
` (22 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Christoph Manszewski, Mika Kuoppala
From: Christoph Manszewski <christoph.manszewski@intel.com>
Add events to track the bind ioctl and associated debug data add and
remove operations, as a single bind can involve multiple operations
and may fail mid-process.
Add a bind event to signal to the debugger when a bind operation is
executed. Further add debug data add and remove operations so the
debugger can keep track of regions where they reside. The bind event
is important as we will want to include the ufence event later in the
series and tie it to this bind.
Only deliver bind+operations to the debugger if the vm bind
op execution chain succeeds.
v2: - avoid sending bind if there is no operations (Mika)
- documentation (Christoph, Mika)
v3: - use removed field dd for removing
Assisted-by: Claude:claude-opus-5
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Co-developed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
Documentation/gpu/xe/xe_eudebug.rst | 6 +
drivers/gpu/drm/xe/xe_eudebug.c | 236 +++++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_eudebug.h | 7 +
drivers/gpu/drm/xe/xe_eudebug_types.h | 2 +-
drivers/gpu/drm/xe/xe_vm.c | 4 +
include/uapi/drm/xe_drm_eudebug.h | 86 ++++++++++
6 files changed, 336 insertions(+), 5 deletions(-)
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
index e191e2c8ded4..1f743f1d6f2a 100644
--- a/Documentation/gpu/xe/xe_eudebug.rst
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -57,3 +57,9 @@ Resource Event Types
.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
:identifiers: drm_xe_eudebug_event_exec_queue
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_event_vm_bind
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_event_vm_bind_op_debug_data
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index d70970f70a8b..fe3b2ae06a31 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -14,6 +14,7 @@
#include <uapi/drm/xe_drm.h>
#include "xe_assert.h"
+#include "xe_debug_data_types.h"
#include "xe_device.h"
#include "xe_eudebug.h"
#include "xe_eudebug_types.h"
@@ -930,6 +931,181 @@ void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q)
xe_eudebug_put(d);
}
+static int send_vm_bind_event(struct xe_eudebug *d,
+ struct xe_vm *vm,
+ u64 vm_handle,
+ u32 bind_flags,
+ u32 num_ops, u64 *seqno)
+{
+ struct drm_xe_eudebug_event_vm_bind *e;
+ struct drm_xe_eudebug_event *event;
+ const u32 sz = sizeof(*e);
+ const u32 base_flags = DRM_XE_EUDEBUG_EVENT_STATE_CHANGE;
+ int err;
+
+ *seqno = atomic_long_inc_return(&d->events.seqno);
+
+ spin_lock(&d->events.lock);
+ event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND,
+ *seqno, base_flags, sz);
+ e = cast_event(e, event);
+
+ e->vm_handle = vm_handle;
+ e->flags = bind_flags;
+ e->num_bind_ops = num_ops;
+
+ err = xe_eudebug_queue_event(d, event);
+ spin_unlock(&d->events.lock);
+
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ return err;
+}
+
+static int vm_bind_event(struct xe_eudebug *d,
+ struct xe_vm *vm,
+ u32 flags,
+ u32 num_ops,
+ u64 *seqno)
+{
+ int h_vm;
+
+ h_vm = find_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm);
+ if (h_vm < 0)
+ return h_vm;
+
+ return send_vm_bind_event(d, vm, h_vm, flags,
+ num_ops, seqno);
+}
+
+static int vm_bind_op_event(struct xe_eudebug *d,
+ struct xe_vm *vm,
+ const u32 flags,
+ const u64 bind_ref_seqno,
+ const u64 num_extensions,
+ const struct xe_debug_data *debug_data,
+ u64 *op_seqno)
+{
+ struct drm_xe_eudebug_event_vm_bind_op_debug_data *e;
+ struct drm_xe_eudebug_event *event;
+ const u32 sz = sizeof(*e);
+ int err;
+
+ *op_seqno = atomic_long_inc_return(&d->events.seqno);
+
+ spin_lock(&d->events.lock);
+ event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_DEBUG_DATA,
+ *op_seqno, flags, sz);
+ e = cast_event(e, event);
+
+ e->vm_bind_ref_seqno = bind_ref_seqno;
+ e->num_extensions = num_extensions;
+ e->addr = debug_data->addr;
+ e->range = debug_data->range;
+ e->flags = debug_data->flags;
+ e->offset = debug_data->offset;
+
+ /*
+ * The event and the bind extension size their path buffers with
+ * different constants, so the copy below only stays free of
+ * truncation while the two agree.
+ */
+ BUILD_BUG_ON(sizeof(e->pathname) < sizeof(debug_data->pathname));
+
+ if (debug_data->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO)
+ e->pseudopath = debug_data->pseudopath;
+ else
+ strscpy(e->pathname, debug_data->pathname,
+ DRM_XE_VM_BIND_DEBUG_PATH_MAX);
+
+ err = xe_eudebug_queue_event(d, event);
+ spin_unlock(&d->events.lock);
+
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ return err;
+}
+
+static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
+ const u32 flags, const u64 bind_ref_seqno,
+ const struct xe_debug_data *debug_data)
+{
+ u64 op_seqno;
+
+ return vm_bind_op_event(d, vm, flags, bind_ref_seqno, 0,
+ debug_data, &op_seqno);
+}
+
+void xe_eudebug_vm_bind_execute(struct xe_vm *vm,
+ struct xe_vma_ops *ops)
+{
+ struct xe_eudebug *d;
+ struct xe_vma_op *op;
+ u64 bind_seqno = 0;
+ u32 num_ops;
+ int err;
+
+ if (!xe_vm_in_lr_mode(vm))
+ return;
+
+ d = xe_eudebug_get(vm->xef);
+ if (!d)
+ return;
+
+ num_ops = 0;
+ list_for_each_entry(op, &ops->list, link) {
+ if (op->base.op != DRM_GPUVA_OP_DRIVER)
+ continue;
+
+ if (op->subop == XE_VMA_SUBOP_ADD_DEBUG_DATA ||
+ op->subop == XE_VMA_SUBOP_REMOVE_DEBUG_DATA)
+ num_ops++;
+ }
+
+ lockdep_assert_held(&vm->lock);
+
+ if (!num_ops) {
+ xe_eudebug_put(d);
+ return;
+ }
+
+ err = vm_bind_event(d, vm, 0,
+ num_ops, &bind_seqno);
+ if (err)
+ goto out_err;
+
+ list_for_each_entry(op, &ops->list, link) {
+ const struct xe_debug_data *dd;
+ u32 flags = 0;
+
+ if (op->base.op != DRM_GPUVA_OP_DRIVER)
+ continue;
+
+ if (op->subop == XE_VMA_SUBOP_ADD_DEBUG_DATA) {
+ flags = DRM_XE_EUDEBUG_EVENT_CREATE;
+ dd = op->modify_debug_data.added;
+ } else if (op->subop == XE_VMA_SUBOP_REMOVE_DEBUG_DATA) {
+ flags = DRM_XE_EUDEBUG_EVENT_DESTROY;
+ dd = op->modify_debug_data.removed;
+ }
+
+ if (!flags)
+ continue;
+
+ err = vm_bind_op(d, vm, flags, bind_seqno, dd);
+ if (err)
+ goto out_err;
+ }
+
+out_err:
+ if (err)
+ xe_eudebug_disconnect(d, err);
+
+ xe_eudebug_put(d);
+}
+
static struct xe_file *xe_eudebug_target_get(struct xe_eudebug *d)
{
struct xe_file *xef = NULL;
@@ -942,13 +1118,57 @@ static struct xe_file *xe_eudebug_target_get(struct xe_eudebug *d)
return xef;
}
+static int vm_discover_binds(struct xe_eudebug *d, struct xe_vm *vm)
+{
+ struct xe_debug_data *dd;
+ struct list_head *pos;
+ unsigned int ops, count;
+ u64 ref_seqno;
+ int err;
+
+ /*
+ * Walked without vm->debug_data.lock. The caller holds the target's
+ * eudebug.ioctl_lock for write, and everything that adds to or
+ * removes from this list runs under DRM_XE_VM_BIND, which takes that
+ * same rwsem for read, so the list cannot change under us here.
+ */
+ if (list_empty(&vm->debug_data.list))
+ return 0;
+
+ count = 0;
+ list_for_each(pos, &vm->debug_data.list)
+ count++;
+
+ ops = count;
+ ref_seqno = 0;
+ err = vm_bind_event(d, vm, 0, ops, &ref_seqno);
+ if (err) {
+ eu_dbg(d, "vm_bind_event error %d\n", err);
+ return err;
+ }
+
+ list_for_each_entry(dd, &vm->debug_data.list, link) {
+ err = vm_bind_op(d, vm, DRM_XE_EUDEBUG_EVENT_CREATE, ref_seqno, dd);
+ if (err) {
+ eu_dbg(d, "vm_bind_op error %d\n", err);
+ return err;
+ }
+
+ ops--;
+ }
+
+ XE_WARN_ON(ops);
+
+ return ops ? -EIO : count;
+}
+
static void discover_client(struct xe_eudebug *d)
{
struct xe_file *xef;
struct xe_exec_queue *q;
struct xe_vm *vm;
unsigned long i;
- unsigned int vm_count = 0, eq_count = 0;
+ unsigned int vm_count = 0, eq_count = 0, ops_count = 0;
int err = 0;
xef = xe_eudebug_target_get(d);
@@ -980,6 +1200,12 @@ static void discover_client(struct xe_eudebug *d)
if (err)
goto out;
vm_count++;
+
+ err = vm_discover_binds(d, vm);
+ if (err < 0)
+ goto out;
+
+ ops_count += err;
}
xa_for_each(&xef->exec_queue.xa, i, q) {
@@ -989,6 +1215,8 @@ static void discover_client(struct xe_eudebug *d)
err = exec_queue_create_event(d, xef, q);
if (err)
goto out;
+
+ eq_count++;
}
out:
@@ -996,9 +1224,9 @@ static void discover_client(struct xe_eudebug *d)
up_write(&xef->eudebug.ioctl_lock);
- if (vm_count || eq_count)
- eu_dbg(d, "Discovery found %u vms, %u exec_queues",
- vm_count, eq_count);
+ if (vm_count || eq_count || ops_count)
+ eu_dbg(d, "Discovery found %u vms, %u exec_queues, %u bind_ops",
+ vm_count, eq_count, ops_count);
xe_file_put(xef);
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 3540f1a798ea..d54067fdf2c0 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -10,10 +10,14 @@
struct drm_device;
struct drm_file;
+struct xe_debug_data;
struct xe_device;
struct xe_file;
struct xe_vm;
struct xe_exec_queue;
+struct xe_vma;
+struct xe_vma_ops;
+struct xe_user_fence;
#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
@@ -59,6 +63,8 @@ void xe_eudebug_put(struct xe_eudebug *d);
void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q);
void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q);
+void xe_eudebug_vm_bind_execute(struct xe_vm *vm, struct xe_vma_ops *ops);
+
#else
static inline int xe_eudebug_connect_ioctl(struct drm_device *dev,
@@ -77,6 +83,7 @@ static inline void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
static inline void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q) { }
static inline void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q) { }
+static inline void xe_eudebug_vm_bind_execute(struct xe_vm *vm, struct xe_vma_ops *ops) { }
#endif /* CONFIG_DRM_XE_EUDEBUG */
#endif /* _XE_EUDEBUG_H_ */
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 59d77998b829..80fcda87ac88 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -34,7 +34,7 @@ enum xe_eudebug_cap_state {
XE_EUDEBUG_CAP_ENABLED,
};
-#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
+#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_DEBUG_DATA
/**
* struct xe_eudebug_handle - eudebug resource handle
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index fdc8e66a8ddc..3e6bee8d0708 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3806,6 +3806,10 @@ static struct dma_fence *vm_bind_ioctl_ops_execute(struct xe_vm *vm,
xe_vm_set_validation_exec(vm, &exec);
fence = ops_execute(vm, vops);
xe_vm_set_validation_exec(vm, NULL);
+
+ if (!IS_ERR(fence) || PTR_ERR(fence) == -ENODATA)
+ xe_eudebug_vm_bind_execute(vm, vops);
+
if (IS_ERR(fence)) {
if (PTR_ERR(fence) == -ENODATA)
vm_bind_ioctl_ops_fini(vm, vops, NULL);
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 934afe400330..69f568f7ef0b 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -67,6 +67,8 @@ struct drm_xe_eudebug_event {
#define DRM_XE_EUDEBUG_EVENT_READ 1
#define DRM_XE_EUDEBUG_EVENT_VM 2
#define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE 3
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND 4
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_DEBUG_DATA 5
/** @flags: Flags */
__u16 flags;
@@ -120,6 +122,90 @@ struct drm_xe_eudebug_event_exec_queue {
__u64 lrc_handle[];
};
+/**
+ * struct drm_xe_eudebug_event_vm_bind - VM Bind Event
+ *
+ * When the client (debuggee) calls the vm_bind_ioctl with the
+ * DRM_XE_VM_BIND_OP_[ADD|REMOVE]_DEBUG_DATA operation, the following event
+ * sequence will be created (for the debugger)::
+ *
+ * ┌───────────────────────┐
+ * │ EVENT_VM_BIND ├──────────────────┬─┬┄┐
+ * └───────────────────────┘ │ │ ┊
+ * ┌──────────────────────────────────┐ │ │ ┊
+ * │ EVENT_VM_BIND_OP_DEBUG_DATA #1 ├───┘ │ ┊
+ * └──────────────────────────────────┘ │ ┊
+ * ... │ ┊
+ * ┌──────────────────────────────────┐ │ ┊
+ * │ EVENT_VM_BIND_OP_DEBUG_DATA #n ├─────┘ ┊
+ * └──────────────────────────────────┘ ┊
+ * ┊
+ * ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐ ┊
+ * ┊ EVENT_UFENCE ├┄┄┄┄┄┄┄┘
+ * └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
+ *
+ * All the events below VM_BIND will reference the VM_BIND
+ * they associate with, by field .vm_bind_ref_seqno.
+ */
+struct drm_xe_eudebug_event_vm_bind {
+ /** @base: Base event */
+ struct drm_xe_eudebug_event base;
+
+ /** @vm_handle: VM handle for this bind */
+ __u64 vm_handle;
+
+ /** @flags: Bind specific flags */
+ __u32 flags;
+
+ /** @num_bind_ops: How many [ADD|REMOVE]_DEBUG_DATA operations this bind has */
+ __u32 num_bind_ops;
+};
+
+/**
+ * struct drm_xe_eudebug_event_vm_bind_op_debug_data - VM Bind Op Debug Data Event
+ *
+ * When the target drm client issues a vm bind, each operation of type
+ * %DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA or %DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA
+ * will generate an event of this type. For reference see
+ * :c:type:`drm_xe_vm_bind_op_ext_debug_data`.
+ */
+struct drm_xe_eudebug_event_vm_bind_op_debug_data {
+ /** @base: Base event */
+ struct drm_xe_eudebug_event base;
+
+ /** @vm_bind_ref_seqno: Parent :c:member:`drm_xe_eudebug_event_vm_bind.base.seqno` */
+ __u64 vm_bind_ref_seqno;
+
+ /** @num_extensions: Extension count for this op */
+ __u64 num_extensions;
+
+ /** @addr: Address of the debug data mapping */
+ __u64 addr;
+
+ /** @range: Range of the debug data mapping */
+ __u64 range;
+
+ /** @flags: Debug data flags */
+ __u64 flags;
+
+ /** @offset: Offset into the debug data file */
+ __u64 offset;
+
+ /** @reserved: Reserved, must be zero */
+ __u64 reserved;
+ union {
+ /**
+ * @pseudopath: Pseudopath if
+ * %DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO was set
+ */
+ __u64 pseudopath;
+
+#define DRM_XE_VM_BIND_DEBUG_PATH_MAX 4096
+ /** @pathname: Path to the debug data file */
+ char pathname[DRM_XE_VM_BIND_DEBUG_PATH_MAX];
+ };
+};
+
#if defined(__cplusplus)
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 11/27] drm/xe/eudebug: Add ufence events with acks
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (9 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 10/27] drm/xe/eudebug: Introduce vm bind and vm bind debug data events Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:20 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 12/27] drm/xe/eudebug: Add vm open/pread/pwrite Mika Kuoppala
` (21 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
When the vma is in place, the debugger needs to intercept before
userspace proceeds with the workload, for example to install
a breakpoint in an EU shader.
If the ufence is part of a bind sequence, attach the debugger in
xe_user_fence. When the ufence signal is about to be delivered,
check if this ufence needs to be tracked by the debugger.
If so, stall the delivery of the ufence signal until the
debugger has acked the ufence (event), with the ack ioctl.
v2: - return err instead of 0 to guarantee signalling (Dominik)
- checkpatch (Tilak)
- Kconfig (Mika, Andrzej)
- use lock instead of cmpxchg (Mika)
v4: - improve ref handling and no ufences nodebug binds
v5: - remove overzealous warn_on on bind_ref_seqno (Christoph)
- remove superfluous signalled (Mika)
- fix double free on bind sequence (Mika)
- Don't fill op fields if no debugger (Maciej)
v6: - rework to align with xe_eudebug_bind_execute()
v7: - fix setting signalled before debugger acks (Jan)
v8: - explicit debugger set and clears (Mika)
- take reference for tracking check (Mika)
- fix leak of ref in handle_ack (Mika)
v9: - enforce mbz on user_arg.type (Sashiko)
v10: - avoid double signal if not tracked (Sashiko)
- clear bind ref seqno if no debugger (Sashiko)
- add reserved field
- avoid referencing ack after dropping lock (Claude)
- clear bind ref if tracking fails (Claude)
- use GFP_KERNEL for ack allocation
- don't starve discovery wq (Claude)
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
Documentation/gpu/xe/xe_eudebug.rst | 3 +
drivers/gpu/drm/xe/xe_device_types.h | 3 +
drivers/gpu/drm/xe/xe_eudebug.c | 349 +++++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_eudebug.h | 9 +
drivers/gpu/drm/xe/xe_eudebug_types.h | 11 +-
drivers/gpu/drm/xe/xe_sync.c | 45 ++--
drivers/gpu/drm/xe/xe_sync.h | 7 +-
drivers/gpu/drm/xe/xe_sync_types.h | 29 ++-
include/uapi/drm/xe_drm_eudebug.h | 61 +++++
9 files changed, 490 insertions(+), 27 deletions(-)
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
index 1f743f1d6f2a..db52945714f3 100644
--- a/Documentation/gpu/xe/xe_eudebug.rst
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -63,3 +63,6 @@ Resource Event Types
.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
:identifiers: drm_xe_eudebug_event_vm_bind_op_debug_data
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_event_vm_bind_ufence
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index a9584634279d..c62e774495fd 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -619,6 +619,9 @@ struct xe_device {
/** @eudebug.discovery_wq: used for client resource discovery */
struct workqueue_struct *discovery_wq;
+
+ /** @eudebug.ufence_wq: used for deferred ufence signalling */
+ struct workqueue_struct *ufence_wq;
} eudebug;
#endif
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index fe3b2ae06a31..a1f07db6ad81 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -21,6 +21,7 @@
#include "xe_exec_queue.h"
#include "xe_hw_engine.h"
#include "xe_macros.h"
+#include "xe_sync.h"
#include "xe_vm.h"
/**
@@ -248,6 +249,120 @@ void xe_eudebug_put(struct xe_eudebug *d)
kref_put(&d->ref, xe_eudebug_free);
}
+struct xe_eudebug_ack {
+ struct rb_node rb_node;
+ u64 seqno;
+ u64 ts_insert;
+ struct xe_user_fence *ufence;
+};
+
+#define fetch_ack(x) rb_entry(x, struct xe_eudebug_ack, rb_node)
+
+static int compare_ack(const u64 a, const u64 b)
+{
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+
+ return 0;
+}
+
+static int ack_insert_cmp(struct rb_node * const node,
+ const struct rb_node * const p)
+{
+ return compare_ack(fetch_ack(node)->seqno,
+ fetch_ack(p)->seqno);
+}
+
+static int ack_lookup_cmp(const void * const key,
+ const struct rb_node * const node)
+{
+ return compare_ack(*(const u64 *)key,
+ fetch_ack(node)->seqno);
+}
+
+static struct xe_eudebug_ack *remove_ack(struct xe_eudebug *d, u64 seqno)
+{
+ struct rb_root * const root = &d->acks.tree;
+ struct rb_node *node;
+
+ spin_lock(&d->acks.lock);
+ node = rb_find(&seqno, root, ack_lookup_cmp);
+ if (node)
+ rb_erase(node, root);
+ spin_unlock(&d->acks.lock);
+
+ if (!node)
+ return NULL;
+
+ return rb_entry_safe(node, struct xe_eudebug_ack, rb_node);
+}
+
+static void ufence_signal_worker(struct work_struct *w)
+{
+ struct xe_user_fence * const ufence =
+ container_of(w, struct xe_user_fence, eudebug.worker);
+
+ xe_sync_ufence_signal(ufence);
+
+ xe_sync_ufence_put(ufence);
+}
+
+static void kick_ufence_worker(struct xe_user_fence *f)
+{
+ queue_work(f->xe->eudebug.ufence_wq, &f->eudebug.worker);
+}
+
+static void handle_ack(struct xe_eudebug *d, struct xe_eudebug_ack *ack,
+ bool on_disconnect)
+{
+ struct xe_user_fence *f = ack->ufence;
+ struct xe_eudebug *debugger = NULL;
+ u64 signalled_by;
+ bool signal = false;
+
+ spin_lock(&f->eudebug.lock);
+ if (!f->eudebug.signalled_seqno) {
+ f->eudebug.signalled_seqno = ack->seqno;
+ f->eudebug.bind_ref_seqno = 0;
+ debugger = f->eudebug.debugger;
+ f->eudebug.debugger = NULL;
+ signal = true;
+ }
+ signalled_by = f->eudebug.signalled_seqno;
+ spin_unlock(&f->eudebug.lock);
+
+ if (signal)
+ kick_ufence_worker(f);
+ else
+ xe_sync_ufence_put(f);
+
+ eu_dbg(d, "ACK: seqno=%llu: signalled by %llu (%s) (held %lluus)",
+ ack->seqno, signalled_by,
+ on_disconnect ? "disconnect" : "debugger",
+ ktime_us_delta(ktime_get(), ack->ts_insert));
+
+ kfree(ack);
+
+ if (debugger)
+ xe_eudebug_put(debugger);
+}
+
+static void release_acks(struct xe_eudebug *d)
+{
+ struct xe_eudebug_ack *ack, *n;
+ struct rb_root root;
+
+ spin_lock(&d->acks.lock);
+ root = d->acks.tree;
+ d->acks.tree = RB_ROOT;
+ spin_unlock(&d->acks.lock);
+
+ rbtree_postorder_for_each_entry_safe(ack, n, &root, rb_node)
+ handle_ack(d, ack, true);
+}
+
static bool xe_eudebug_detach(struct xe_eudebug *d,
const int err)
{
@@ -277,6 +392,8 @@ static bool xe_eudebug_detach(struct xe_eudebug *d,
xe_file_put(target);
}
+ release_acks(d);
+
return !!target;
}
@@ -1038,11 +1155,169 @@ static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
debug_data, &op_seqno);
}
+void xe_eudebug_ufence_init(struct xe_user_fence *ufence)
+{
+ spin_lock_init(&ufence->eudebug.lock);
+ ufence->eudebug.debugger = NULL;
+ ufence->eudebug.bind_ref_seqno = 0;
+ ufence->eudebug.signalled_seqno = 0;
+ INIT_WORK(&ufence->eudebug.worker, ufence_signal_worker);
+}
+
+void xe_eudebug_ufence_fini(struct xe_user_fence *ufence)
+{
+ struct xe_eudebug *d;
+
+ XE_WARN_ON(READ_ONCE(ufence->eudebug.bind_ref_seqno));
+
+ d = READ_ONCE(ufence->eudebug.debugger);
+ if (!d)
+ return;
+
+ /* last ref */
+ ufence->eudebug.debugger = NULL;
+
+ xe_eudebug_put(d);
+}
+
+static int xe_eudebug_track_ufence(struct xe_eudebug *d,
+ struct xe_user_fence *f,
+ u64 seqno)
+{
+ struct xe_eudebug_ack *ack;
+ struct rb_node *old;
+
+ ack = kzalloc_obj(*ack, GFP_KERNEL);
+ if (!ack) {
+ eu_dbg(d, "ack allocation fail");
+ return -ENOMEM;
+ }
+
+ ack->seqno = seqno;
+ ack->ts_insert = ktime_get();
+
+ __xe_sync_ufence_get(f);
+
+ scoped_guard(spinlock, &d->acks.lock) {
+ old = rb_find_add(&ack->rb_node,
+ &d->acks.tree, ack_insert_cmp);
+ if (!old)
+ ack->ufence = f;
+ }
+
+ if (!old)
+ return 0;
+
+ xe_sync_ufence_put(f);
+ kfree(ack);
+
+ return -EEXIST;
+}
+
+static int track_ufence(struct xe_eudebug *d,
+ struct xe_user_fence *ufence,
+ bool *tracked)
+{
+ struct drm_xe_eudebug_event *event;
+ struct drm_xe_eudebug_event_vm_bind_ufence *e;
+ const u32 sz = sizeof(*e);
+ const u32 flags = DRM_XE_EUDEBUG_EVENT_CREATE |
+ DRM_XE_EUDEBUG_EVENT_NEED_ACK;
+ u64 seqno;
+ int ret;
+
+ *tracked = false;
+
+ if (XE_WARN_ON(!ufence->eudebug.bind_ref_seqno))
+ return -EINVAL;
+
+ seqno = atomic_long_inc_return(&d->events.seqno);
+
+ ret = xe_eudebug_track_ufence(d, ufence, seqno);
+ if (ret)
+ return ret;
+
+ *tracked = true;
+
+ spin_lock(&d->events.lock);
+ event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+ seqno, flags, sz);
+
+ e = cast_event(e, event);
+ e->vm_bind_ref_seqno = ufence->eudebug.bind_ref_seqno;
+
+ ret = xe_eudebug_queue_event(d, event);
+ spin_unlock(&d->events.lock);
+
+ return ret;
+}
+
+/**
+ * xe_eudebug_ufence_track - Track the ufence for eudebug
+ * @ufence : user fence that might be applicaple to tracking
+ *
+ * If this user fence was part of bind sequence, we need
+ * to track it so that we can hold the client signalling on behalf
+ * of debugger and thus deliver event to debugger.
+ *
+ * Return: true debugger will track, false debugger not interested
+ *
+ */
+bool xe_eudebug_ufence_track(struct xe_user_fence *ufence)
+{
+ struct xe_eudebug *d;
+ bool tracked = false;
+ int ret;
+
+ spin_lock(&ufence->eudebug.lock);
+ d = ufence->eudebug.debugger;
+ if (d && !kref_get_unless_zero(&d->ref))
+ d = NULL;
+
+ if (!d || xe_eudebug_detached(d)) {
+ ufence->eudebug.bind_ref_seqno = 0;
+ ufence->eudebug.signalled_seqno = 0;
+ }
+ spin_unlock(&ufence->eudebug.lock);
+
+ if (!d)
+ return false;
+
+ if (xe_eudebug_detached(d)) {
+ xe_eudebug_put(d);
+ return false;
+ }
+
+ ret = track_ufence(d, ufence, &tracked);
+ if (ret) {
+ /*
+ * If we failed before the ack made it into the tree, the
+ * disconnect below has nothing to release for this fence.
+ * Drop the bind reference here, or the fence destructor
+ * will warn about it still being set.
+ */
+ if (!tracked) {
+ scoped_guard(spinlock, &ufence->eudebug.lock) {
+ ufence->eudebug.bind_ref_seqno = 0;
+ ufence->eudebug.signalled_seqno = 0;
+ }
+ }
+
+ xe_eudebug_disconnect(d, ret);
+ }
+
+ xe_eudebug_put(d);
+
+ return tracked;
+}
+
void xe_eudebug_vm_bind_execute(struct xe_vm *vm,
struct xe_vma_ops *ops)
{
+ struct xe_user_fence *ufence = NULL;
struct xe_eudebug *d;
struct xe_vma_op *op;
+ unsigned int i;
u64 bind_seqno = 0;
u32 num_ops;
int err;
@@ -1054,6 +1329,15 @@ void xe_eudebug_vm_bind_execute(struct xe_vm *vm,
if (!d)
return;
+ for (i = 0; i < ops->num_syncs; i++) {
+ struct xe_sync_entry *se = &ops->syncs[i];
+
+ if (xe_sync_is_ufence(se)) {
+ xe_assert(vm->xe, !ufence);
+ ufence = se->ufence;
+ }
+ }
+
num_ops = 0;
list_for_each_entry(op, &ops->list, link) {
if (op->base.op != DRM_GPUVA_OP_DRIVER)
@@ -1071,7 +1355,8 @@ void xe_eudebug_vm_bind_execute(struct xe_vm *vm,
return;
}
- err = vm_bind_event(d, vm, 0,
+ err = vm_bind_event(d, vm,
+ ufence ? DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE : 0,
num_ops, &bind_seqno);
if (err)
goto out_err;
@@ -1099,6 +1384,14 @@ void xe_eudebug_vm_bind_execute(struct xe_vm *vm,
goto out_err;
}
+ if (ufence) {
+ spin_lock(&ufence->eudebug.lock);
+ kref_get(&d->ref);
+ ufence->eudebug.debugger = d;
+ ufence->eudebug.bind_ref_seqno = bind_seqno;
+ spin_unlock(&ufence->eudebug.lock);
+ }
+
out_err:
if (err)
xe_eudebug_disconnect(d, err);
@@ -1489,6 +1782,42 @@ static long xe_eudebug_read_event(struct xe_eudebug *d,
return ret;
}
+static long
+xe_eudebug_ack_event_ioctl(struct xe_eudebug *d,
+ const u64 arg)
+{
+ struct drm_xe_eudebug_ack __user * const user_ptr =
+ u64_to_user_ptr(arg);
+ struct drm_xe_eudebug_ack user_arg;
+ struct xe_eudebug_ack *ack;
+ struct xe_device *xe = d->xe;
+
+ if (XE_IOCTL_DBG(xe, copy_from_user(&user_arg,
+ user_ptr,
+ sizeof(user_arg))))
+ return -EFAULT;
+
+ if (XE_IOCTL_DBG(xe, user_arg.type))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, user_arg.flags))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, user_arg.reserved))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, xe_eudebug_detached(d)))
+ return -ENOTCONN;
+
+ ack = remove_ack(d, user_arg.seqno);
+ if (XE_IOCTL_DBG(xe, !ack))
+ return -EINVAL;
+
+ handle_ack(d, ack, false);
+
+ return 0;
+}
+
/**
* xe_eudebug_ioctl - Issue a command to eudebug interface
*
@@ -1516,6 +1845,10 @@ static long xe_eudebug_ioctl(struct file *file,
ret = xe_eudebug_read_event(d, arg,
!(file->f_flags & O_NONBLOCK));
break;
+ case DRM_XE_EUDEBUG_IOCTL_ACK_EVENT:
+ ret = xe_eudebug_ack_event_ioctl(d, arg);
+ eu_dbg(d, "ioctl cmd=EVENT_ACK ret=%ld\n", ret);
+ break;
default:
ret = -EINVAL;
}
@@ -1566,6 +1899,9 @@ xe_eudebug_connect(struct xe_device *xe,
init_completion(&d->discovery);
INIT_WORK(&d->discovery_work, discovery_work_fn);
+ spin_lock_init(&d->acks.lock);
+ d->acks.tree = RB_ROOT;
+
err = xe_eudebug_resources_init(d);
if (XE_IOCTL_DBG(xe, err)) {
kfree(d);
@@ -1743,6 +2079,17 @@ void xe_eudebug_init(struct xe_device *xe)
}
xe->eudebug.discovery_wq = wq;
+ wq = alloc_workqueue("xe-eudebug-ufence", WQ_UNBOUND, 0);
+ if (!wq) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ err = drmm_add_action_or_reset(dev, __drmm_workqueue_release, wq);
+ if (err)
+ goto out_err;
+ xe->eudebug.ufence_wq = wq;
+
err = sysfs_create_file(&dev->dev->kobj,
&dev_attr_enable_eudebug.attr);
if (err)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index d54067fdf2c0..48608a061f0c 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -65,6 +65,10 @@ void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q)
void xe_eudebug_vm_bind_execute(struct xe_vm *vm, struct xe_vma_ops *ops);
+void xe_eudebug_ufence_init(struct xe_user_fence *ufence);
+void xe_eudebug_ufence_fini(struct xe_user_fence *ufence);
+bool xe_eudebug_ufence_track(struct xe_user_fence *ufence);
+
#else
static inline int xe_eudebug_connect_ioctl(struct drm_device *dev,
@@ -84,6 +88,11 @@ static inline void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_e
static inline void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q) { }
static inline void xe_eudebug_vm_bind_execute(struct xe_vm *vm, struct xe_vma_ops *ops) { }
+
+static inline void xe_eudebug_ufence_init(struct xe_user_fence *ufence) { }
+static inline void xe_eudebug_ufence_fini(struct xe_user_fence *ufence) { }
+static inline bool xe_eudebug_ufence_track(struct xe_user_fence *ufence) { return false; }
+
#endif /* CONFIG_DRM_XE_EUDEBUG */
#endif /* _XE_EUDEBUG_H_ */
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 80fcda87ac88..12a4921c8400 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -34,7 +34,7 @@ enum xe_eudebug_cap_state {
XE_EUDEBUG_CAP_ENABLED,
};
-#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_DEBUG_DATA
+#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
/**
* struct xe_eudebug_handle - eudebug resource handle
@@ -135,6 +135,15 @@ struct xe_eudebug {
/** @events.seqno: seqno counter to stamp events for fifo */
atomic_long_t seqno;
} events;
+
+ /** @acks: user fence acks tracked by this debugger */
+ struct {
+ /** @acks.lock: guards access to tree */
+ spinlock_t lock;
+
+ /** @acks.tree: pending acks by seqnos */
+ struct rb_root tree;
+ } acks;
};
#endif /* _XE_EUDEBUG_TYPES_H_ */
diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
index 37866768d64c..3c6b241a1221 100644
--- a/drivers/gpu/drm/xe/xe_sync.c
+++ b/drivers/gpu/drm/xe/xe_sync.c
@@ -15,27 +15,20 @@
#include <uapi/drm/xe_drm.h>
#include "xe_device.h"
+#include "xe_eudebug.h"
#include "xe_exec_queue.h"
#include "xe_macros.h"
#include "xe_sched_job_types.h"
-struct xe_user_fence {
- struct xe_device *xe;
- struct kref refcount;
- struct dma_fence_cb cb;
- struct work_struct worker;
- struct mm_struct *mm;
- u64 __user *addr;
- u64 value;
- int signalled;
-};
-
static void user_fence_destroy(struct kref *kref)
{
struct xe_user_fence *ufence = container_of(kref, struct xe_user_fence,
refcount);
mmdrop(ufence->mm);
+
+ xe_eudebug_ufence_fini(ufence);
+
kfree(ufence);
}
@@ -49,7 +42,8 @@ static void user_fence_put(struct xe_user_fence *ufence)
kref_put(&ufence->refcount, user_fence_destroy);
}
-static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
+static struct xe_user_fence *user_fence_create(struct xe_device *xe,
+ u64 addr,
u64 value)
{
struct xe_user_fence *ufence;
@@ -70,14 +64,21 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
ufence->mm = current->mm;
mmgrab(ufence->mm);
+ xe_eudebug_ufence_init(ufence);
+
return ufence;
}
-static void user_fence_worker(struct work_struct *w)
+void xe_sync_ufence_signal(struct xe_user_fence *ufence)
{
- struct xe_user_fence *ufence = container_of(w, struct xe_user_fence, worker);
+ /*
+ * Signal exactly once: both the eudebug ack path and user_fence_worker()
+ * can reach here for a tracked ufence. Waiters are woken only after the
+ * state update, so the UMD can reuse the ufence without hitting -EBUSY.
+ */
+ if (xchg(&ufence->signalled, 1))
+ return;
- WRITE_ONCE(ufence->signalled, 1);
if (mmget_not_zero(ufence->mm)) {
kthread_use_mm(ufence->mm);
if (copy_to_user(ufence->addr, &ufence->value, sizeof(ufence->value)))
@@ -88,11 +89,17 @@ static void user_fence_worker(struct work_struct *w)
drm_dbg(&ufence->xe->drm, "mmget_not_zero() failed, ufence wasn't signaled\n");
}
- /*
- * Wake up waiters only after updating the ufence state, allowing the UMD
- * to safely reuse the same ufence without encountering -EBUSY errors.
- */
wake_up_all(&ufence->xe->ufence_wq);
+}
+
+static void user_fence_worker(struct work_struct *w)
+{
+ struct xe_user_fence *ufence = container_of(w, struct xe_user_fence, worker);
+
+ /* Lets see if debugger wants to track this */
+ if (!xe_eudebug_ufence_track(ufence))
+ xe_sync_ufence_signal(ufence);
+
user_fence_put(ufence);
}
diff --git a/drivers/gpu/drm/xe/xe_sync.h b/drivers/gpu/drm/xe/xe_sync.h
index 6b949194acff..768c0517f104 100644
--- a/drivers/gpu/drm/xe/xe_sync.h
+++ b/drivers/gpu/drm/xe/xe_sync.h
@@ -10,8 +10,12 @@
struct drm_syncobj;
struct xe_device;
-struct xe_exec_queue;
struct xe_file;
+struct xe_exec_queue;
+struct drm_syncobj;
+struct dma_fence;
+struct dma_fence_chain;
+struct drm_xe_sync;
struct xe_sched_job;
struct xe_vm;
@@ -45,5 +49,6 @@ struct xe_user_fence *__xe_sync_ufence_get(struct xe_user_fence *ufence);
struct xe_user_fence *xe_sync_ufence_get(struct xe_sync_entry *sync);
void xe_sync_ufence_put(struct xe_user_fence *ufence);
int xe_sync_ufence_get_status(struct xe_user_fence *ufence);
+void xe_sync_ufence_signal(struct xe_user_fence *ufence);
#endif
diff --git a/drivers/gpu/drm/xe/xe_sync_types.h b/drivers/gpu/drm/xe/xe_sync_types.h
index b88f1833e28c..aa5fff7b89c2 100644
--- a/drivers/gpu/drm/xe/xe_sync_types.h
+++ b/drivers/gpu/drm/xe/xe_sync_types.h
@@ -6,13 +6,32 @@
#ifndef _XE_SYNC_TYPES_H_
#define _XE_SYNC_TYPES_H_
+#include <linux/dma-fence-array.h>
+#include <linux/kref.h>
+#include <linux/spinlock.h>
#include <linux/types.h>
-struct drm_syncobj;
-struct dma_fence;
-struct dma_fence_chain;
-struct drm_xe_sync;
-struct user_fence;
+struct xe_user_fence {
+ struct xe_device *xe;
+ struct kref refcount;
+ struct dma_fence_cb cb;
+ struct work_struct worker;
+ struct mm_struct *mm;
+ u64 __user *addr;
+ u64 value;
+ int signalled;
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+ struct {
+ /** @lock: guards access to eudebug struct members */
+ spinlock_t lock;
+ struct xe_eudebug *debugger;
+ u64 bind_ref_seqno;
+ u64 signalled_seqno;
+ struct work_struct worker;
+ } eudebug;
+#endif
+};
struct xe_sync_entry {
struct drm_syncobj *syncobj;
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 69f568f7ef0b..b99ac815a7c3 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -32,6 +32,7 @@ extern "C" {
* - -ENOTCONN if the debug target is gone and the queue has been drained.
*/
#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
+#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT _IOW('j', 0x1, struct drm_xe_eudebug_ack)
/**
* struct drm_xe_eudebug_event - Base type of event delivered by xe_eudebug.
@@ -69,6 +70,7 @@ struct drm_xe_eudebug_event {
#define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE 3
#define DRM_XE_EUDEBUG_EVENT_VM_BIND 4
#define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_DEBUG_DATA 5
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE 6
/** @flags: Flags */
__u16 flags;
@@ -146,6 +148,24 @@ struct drm_xe_eudebug_event_exec_queue {
*
* All the events below VM_BIND will reference the VM_BIND
* they associate with, by field .vm_bind_ref_seqno.
+ * EVENT_UFENCE will only be included if the client did
+ * attach sync of type UFENCE into its vm_bind_ioctl().
+ *
+ * When EVENT_UFENCE is sent by the driver, all the OPs of
+ * the original VM_BIND are completed and the [addr,range]
+ * contained in them are present and modifiable through the
+ * vm accessors. Accessing [addr, range] before related ufence
+ * event will lead to undefined results as the actual bind
+ * operations are async and the backing storage might not
+ * be there on a moment of receiving the event.
+ *
+ * Client's UFENCE sync will be held by the driver: client's
+ * drm_xe_wait_ufence will not complete and the value of the ufence
+ * won't appear until ufence is acked by the debugger process calling
+ * DRM_XE_EUDEBUG_IOCTL_ACK_EVENT with the event_ufence.base.seqno.
+ * This will signal the fence, .value will update and the wait will
+ * complete allowing the client to continue.
+ *
*/
struct drm_xe_eudebug_event_vm_bind {
/** @base: Base event */
@@ -156,6 +176,7 @@ struct drm_xe_eudebug_event_vm_bind {
/** @flags: Bind specific flags */
__u32 flags;
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE (1 << 0)
/** @num_bind_ops: How many [ADD|REMOVE]_DEBUG_DATA operations this bind has */
__u32 num_bind_ops;
@@ -206,6 +227,46 @@ struct drm_xe_eudebug_event_vm_bind_op_debug_data {
};
};
+/**
+ * struct drm_xe_eudebug_event_vm_bind_ufence - User Fence Event
+ *
+ * When target drm client does vm bind with associated user fence,
+ * this event will be delivered. This event will have
+ * DRM_XE_EUDEBUG_EVENT_NEED_ACK set in :c:member:`drm_xe_eudebug_event.flags`
+ * and upon receiving this event you need to ack it with
+ * DRM_XE_EUDEBUG_IOCTL_ACK_EVENT.
+ *
+ */
+struct drm_xe_eudebug_event_vm_bind_ufence {
+ /** @base: Base event */
+ struct drm_xe_eudebug_event base;
+
+ /** @vm_bind_ref_seqno: Parent :c:member:`drm_xe_eudebug_event_vm_bind.base.seqno` */
+ __u64 vm_bind_ref_seqno;
+};
+
+/**
+ * struct drm_xe_eudebug_ack - Deliver ack for an event
+ *
+ * If event base.flags has DRM_XE_EUDEBUG_EVENT_NEED_ACK set,
+ * then the associated resource processing is held for client and
+ * thus held for the debugger. In order to release the client,
+ * ack needs to be delivered with DRM_XE_EUDEBUG_IOCTL_ACK_EVENT.
+ */
+struct drm_xe_eudebug_ack {
+ /** @type: Type, must be zero */
+ __u32 type;
+
+ /** @flags: Flags, must be zero */
+ __u32 flags;
+
+ /** @seqno: Seqno of event that is to be acked */
+ __u64 seqno;
+
+ /** @reserved: Reserved field, must be zero. */
+ __u64 reserved;
+};
+
#if defined(__cplusplus)
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 12/27] drm/xe/eudebug: Add vm open/pread/pwrite
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (10 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 11/27] drm/xe/eudebug: Add ufence events with acks Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:27 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 13/27] drm/xe/eudebug: Add userptr vm pread/pwrite Mika Kuoppala
` (20 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
The debugger needs access to the client's vm to read and write, for
example to inspect ISA/ELF and set up breakpoints.
Add an ioctl to open the target vm with the debugger client and
vm_handle, and hook up pread/pwrite support.
Open will take a timeout argument so that standard fsync
can be used for explicit flushing between cpu/gpu for
the target vm.
Implement this for bo-backed storage. userptr will
be done in the following patch.
v2: - checkpatch (Maciej)
- 32bit fixes (Andrzej)
- bo_vmap (Mika)
- fix vm leak if can't allocate k_buffer (Mika)
- assert vm write held for vma (Matthew)
v3: - fw ref, ttm_bo_access
- timeout boundary check (Dominik)
- don't try to copy to user on zero bytes (Mika)
v4: - offset as unsigned long (Thomas)
- check XE_VMA_DESTROYED
v5: - drm_dev_put before releasing debugger (Mika)
v6: - stop flushing on first error (Mika)
v7: - deny access on debugger disconnect (Andrzej)
v8: - correct offset calc in ttm_bo_access (Sashiko)
- overzealous warn removed (Sashiko)
- check param.extensions (Sashiko)
- avoid hitting assert (Sashiko)
- fix detach race on open (Claude)
- build assert on ioctl cmd (Claude)
- reject >u32 on vm lookup (Claude)
- allow smaller vmallocs before fail
Assisted-by: Claude:claude-opus-4-8
Cc: Andrzej Hajda <andrzej.hajda@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
Documentation/gpu/xe/xe_eudebug.rst | 6 +
drivers/gpu/drm/xe/Makefile | 2 +-
drivers/gpu/drm/xe/regs/xe_gt_regs.h | 24 ++
drivers/gpu/drm/xe/xe_eudebug.c | 32 +-
drivers/gpu/drm/xe/xe_eudebug.h | 10 +
drivers/gpu/drm/xe/xe_eudebug_vm.c | 456 +++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_eudebug_vm.h | 8 +
include/uapi/drm/xe_drm_eudebug.h | 29 ++
8 files changed, 565 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_vm.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_vm.h
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
index db52945714f3..466d366c1e83 100644
--- a/Documentation/gpu/xe/xe_eudebug.rst
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -66,3 +66,9 @@ Resource Event Types
.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
:identifiers: drm_xe_eudebug_event_vm_bind_ufence
+
+VM Access
+=========
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_vm_open
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 68dfab1a5c30..a37ab5e654aa 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -162,7 +162,7 @@ xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
xe-$(CONFIG_DRM_GPUSVM) += xe_userptr.o
# debugging shaders with gdb (eudebug) support
-xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o
+xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o xe_eudebug_vm.o
# graphics hardware monitoring (HWMON) support
xe-$(CONFIG_HWMON) += xe_hwmon.o
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 48c515d91882..8056d007c23e 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -616,6 +616,30 @@
#define CCS_MODE_CSLICE(cslice, ccs) \
((ccs) << ((cslice) * CCS_MODE_CSLICE_WIDTH))
+#define RCU_ASYNC_FLUSH XE_REG(0x149fc)
+#define RCU_ASYNC_FLUSH_IN_PROGRESS REG_BIT(31)
+#define RCU_ASYNC_FLUSH_ENGINE_ID_SHIFT 28
+#define RCU_ASYNC_FLUSH_ENGINE_ID_DECODE1 REG_BIT(26)
+#define RCU_ASYNC_FLUSH_AMFS REG_BIT(8)
+#define RCU_ASYNC_FLUSH_PREFETCH REG_BIT(7)
+#define RCU_ASYNC_FLUSH_DATA_PORT REG_BIT(6)
+#define RCU_ASYNC_FLUSH_DATA_CACHE REG_BIT(5)
+#define RCU_ASYNC_FLUSH_HDC_PIPELINE REG_BIT(4)
+#define RCU_ASYNC_INVALIDATE_HDC_PIPELINE REG_BIT(3)
+#define RCU_ASYNC_INVALIDATE_CONSTANT_CACHE REG_BIT(2)
+#define RCU_ASYNC_INVALIDATE_TEXTURE_CACHE REG_BIT(1)
+#define RCU_ASYNC_INVALIDATE_INSTRUCTION_CACHE REG_BIT(0)
+#define RCU_ASYNC_FLUSH_AND_INVALIDATE_ALL ( \
+ RCU_ASYNC_FLUSH_AMFS | \
+ RCU_ASYNC_FLUSH_PREFETCH | \
+ RCU_ASYNC_FLUSH_DATA_PORT | \
+ RCU_ASYNC_FLUSH_DATA_CACHE | \
+ RCU_ASYNC_FLUSH_HDC_PIPELINE | \
+ RCU_ASYNC_INVALIDATE_HDC_PIPELINE | \
+ RCU_ASYNC_INVALIDATE_CONSTANT_CACHE | \
+ RCU_ASYNC_INVALIDATE_TEXTURE_CACHE | \
+ RCU_ASYNC_INVALIDATE_INSTRUCTION_CACHE)
+
#define FORCEWAKE_ACK_GT XE_REG(0x130044)
/* Applicable for all FORCEWAKE_DOMAIN and FORCEWAKE_ACK_DOMAIN regs */
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index a1f07db6ad81..188a4c60513c 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -18,6 +18,7 @@
#include "xe_device.h"
#include "xe_eudebug.h"
#include "xe_eudebug_types.h"
+#include "xe_eudebug_vm.h"
#include "xe_exec_queue.h"
#include "xe_hw_engine.h"
#include "xe_macros.h"
@@ -222,7 +223,7 @@ xe_eudebug_resources_destroy(struct xe_eudebug *d)
}
}
-static bool xe_eudebug_detached(struct xe_eudebug *d)
+bool xe_eudebug_detached(struct xe_eudebug *d)
{
return !READ_ONCE(d->target.xef);
}
@@ -712,6 +713,31 @@ static int xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
return ret;
}
+static void *find_resource__unlocked(struct xe_eudebug_resource *r,
+ u32 id)
+{
+ struct xe_eudebug_handle *h;
+
+ h = xa_load(&r->xa, id);
+
+ return h ? (void *)(uintptr_t)h->key : NULL;
+}
+
+struct xe_vm *xe_eudebug_vm_get(struct xe_eudebug *d, u32 id)
+{
+ struct xe_eudebug_resource *r =
+ resource_from_type(d, XE_EUDEBUG_RES_TYPE_VM);
+ struct xe_vm *vm;
+
+ mutex_lock(&r->lock);
+ vm = find_resource__unlocked(r, id);
+ if (vm)
+ xe_vm_get(vm);
+ mutex_unlock(&r->lock);
+
+ return vm;
+}
+
static struct drm_xe_eudebug_event *
xe_eudebug_prepare_event(struct xe_eudebug *d, u16 type, u64 seqno, u16 flags,
u32 len)
@@ -1849,6 +1875,10 @@ static long xe_eudebug_ioctl(struct file *file,
ret = xe_eudebug_ack_event_ioctl(d, arg);
eu_dbg(d, "ioctl cmd=EVENT_ACK ret=%ld\n", ret);
break;
+ case DRM_XE_EUDEBUG_IOCTL_VM_OPEN:
+ ret = xe_eudebug_vm_open_ioctl(d, arg);
+ eu_dbg(d, "ioctl cmd=VM_OPEN ret=%ld\n", ret);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 48608a061f0c..ea370dbfc0aa 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -18,6 +18,7 @@ struct xe_exec_queue;
struct xe_vma;
struct xe_vma_ops;
struct xe_user_fence;
+struct xe_eudebug;
#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
@@ -42,6 +43,10 @@ struct xe_user_fence;
#define xe_eudebug_assert(d, ...) xe_assert((d)->xe, ##__VA_ARGS__)
+#define xe_eudebug_for_each_hw_engine(__hwe, __gt, __id) \
+ for_each_hw_engine(__hwe, __gt, __id) \
+ for_each_if(xe_hw_engine_has_eudebug(__hwe))
+
int xe_eudebug_connect_ioctl(struct drm_device *dev,
void *data,
struct drm_file *file);
@@ -54,12 +59,17 @@ void xe_eudebug_file_close(struct xe_file *xef);
void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm);
void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm);
+
+bool xe_eudebug_detached(struct xe_eudebug *d);
+
int xe_eudebug_enable(struct xe_device *xe, bool enable);
struct xe_eudebug *xe_eudebug_get_nolock(struct xe_file *xef);
struct xe_eudebug *xe_eudebug_get_nolock_with_discovery(struct xe_file *xef);
void xe_eudebug_put(struct xe_eudebug *d);
+struct xe_vm *xe_eudebug_vm_get(struct xe_eudebug *d, u32 vm_id);
+
void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q);
void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q);
diff --git a/drivers/gpu/drm/xe/xe_eudebug_vm.c b/drivers/gpu/drm/xe/xe_eudebug_vm.c
new file mode 100644
index 000000000000..316fe29586b0
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_vm.c
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#include "xe_eudebug_vm.h"
+
+#include <linux/anon_inodes.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+
+#include <drm/drm_drv.h>
+
+#include "xe_bo.h"
+#include "xe_device.h"
+#include "xe_eudebug.h"
+#include "xe_eudebug_types.h"
+#include "xe_force_wake.h"
+#include "xe_gt.h"
+#include "xe_mmio.h"
+#include "xe_vm.h"
+
+#include "regs/xe_gt_regs.h"
+#include "regs/xe_engine_regs.h"
+
+static int xe_eudebug_vma_access(struct xe_vma *vma,
+ const u64 offset_in_vma,
+ void *buf, const size_t len, bool write)
+{
+ struct xe_bo *bo;
+ u64 bytes;
+
+ lockdep_assert_held_write(&xe_vma_vm(vma)->lock);
+
+ if (offset_in_vma >= xe_vma_size(vma))
+ return -EINVAL;
+
+ if (vma->gpuva.flags & XE_VMA_DESTROYED)
+ return -EINVAL;
+
+ bytes = min_t(u64, len, xe_vma_size(vma) - offset_in_vma);
+ if (!bytes)
+ return 0;
+
+ bo = xe_bo_get(xe_vma_bo(vma));
+ if (bo) {
+ const u64 bo_offset = xe_vma_bo_offset(vma) + offset_in_vma;
+ int ret;
+
+ ret = ttm_bo_access(&bo->ttm, bo_offset, buf, bytes, write);
+
+ xe_bo_put(bo);
+
+ return ret;
+ }
+
+ return -EINVAL;
+}
+
+static int xe_eudebug_vm_access(struct xe_vm *vm, const u64 offset,
+ void *buf, const size_t len, bool write)
+{
+ struct xe_vma *vma;
+ int ret;
+
+ down_write(&vm->lock);
+
+ if (offset >= vm->size || len > vm->size - offset) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ vma = xe_vm_find_overlapping_vma(vm, offset, len);
+ if (vma) {
+ u64 vma_local_offset;
+
+ /*
+ * xe_vm_find_overlapping_vma() may return a VMA whose start is
+ * below @offset when the VMA's range still overlaps
+ * [offset, offset+len). Reject anything that doesn't actually
+ * cover @offset itself.
+ */
+ if (offset < xe_vma_start(vma) ||
+ offset >= (xe_vma_start(vma) + xe_vma_size(vma))) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Translate VM-space offset to VMA-local offset. */
+ vma_local_offset = offset - xe_vma_start(vma);
+ ret = xe_eudebug_vma_access(vma, vma_local_offset, buf, len, write);
+ } else {
+ ret = -EINVAL;
+ }
+
+out:
+ up_write(&vm->lock);
+
+ return ret;
+}
+
+struct vm_file {
+ struct xe_eudebug *debugger;
+ struct xe_vm *vm;
+ u64 flags;
+ u64 vm_handle;
+ u64 timeout_us;
+};
+
+static ssize_t __vm_read_write(struct xe_vm *vm,
+ void *bb,
+ char __user *r_buffer,
+ const char __user *w_buffer,
+ const u64 offset,
+ size_t len,
+ const bool write)
+{
+ ssize_t ret;
+
+ if (!len)
+ return 0;
+
+ if (write) {
+ ret = copy_from_user(bb, w_buffer, len);
+ if (ret)
+ return -EFAULT;
+
+ ret = xe_eudebug_vm_access(vm, offset, bb, len, true);
+ if (ret <= 0)
+ return ret;
+
+ len = ret;
+ } else {
+ ret = xe_eudebug_vm_access(vm, offset, bb, len, false);
+ if (ret <= 0)
+ return ret;
+
+ len = ret;
+
+ ret = copy_to_user(r_buffer, bb, len);
+ if (ret)
+ return -EFAULT;
+ }
+
+ return len;
+}
+
+static ssize_t __xe_eudebug_vm_access(struct file *file,
+ char __user *r_buffer,
+ const char __user *w_buffer,
+ size_t count, loff_t *__pos)
+{
+ struct vm_file *vmf = file->private_data;
+ struct xe_eudebug * const d = vmf->debugger;
+ struct xe_device * const xe = d->xe;
+ const bool write = !!w_buffer;
+ struct xe_vm *vm;
+ ssize_t copied = 0;
+ ssize_t bytes_left;
+ ssize_t ret;
+ unsigned long alloc_len;
+ loff_t pos = *__pos;
+ void *k_buffer;
+
+ if (XE_IOCTL_DBG(d->xe, xe_eudebug_detached(d)))
+ return -ENOTCONN;
+
+ if (XE_IOCTL_DBG(xe, write && r_buffer))
+ return -EINVAL;
+
+ vm = xe_eudebug_vm_get(d, vmf->vm_handle);
+ if (XE_IOCTL_DBG(xe, !vm))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, vm != vmf->vm)) {
+ eu_warn(d, "vm_access(%s): vm handle mismatch vm_handle=%llu, flags=0x%llx, pos=%llu, count=%zu\n",
+ write ? "write" : "read",
+ vmf->vm_handle, vmf->flags, pos, count);
+ xe_vm_put(vm);
+ return -EINVAL;
+ }
+
+ if (!count) {
+ xe_vm_put(vm);
+ return 0;
+ }
+
+ if (pos >= vm->size) {
+ xe_vm_put(vm);
+ return write ? -ENOSPC : 0;
+ }
+
+ count = min_t(u64, count, vm->size - pos);
+ bytes_left = count;
+
+ alloc_len = min_t(unsigned long, ALIGN(count, PAGE_SIZE), 64 * SZ_1M);
+ do {
+ k_buffer = vmalloc(alloc_len);
+ if (k_buffer)
+ break;
+
+ alloc_len >>= 1;
+ } while (alloc_len >= PAGE_SIZE);
+
+ if (XE_IOCTL_DBG(xe, !k_buffer)) {
+ xe_vm_put(vm);
+ return -ENOMEM;
+ }
+
+ do {
+ const ssize_t len = min_t(ssize_t, bytes_left, alloc_len);
+
+ ret = __vm_read_write(vm, k_buffer,
+ write ? NULL : r_buffer + copied,
+ write ? w_buffer + copied : NULL,
+ (u64)(pos + copied),
+ len,
+ write);
+ if (ret <= 0)
+ break;
+
+ bytes_left -= ret;
+ copied += ret;
+ } while (bytes_left > 0);
+
+ vfree(k_buffer);
+ xe_vm_put(vm);
+
+ if (XE_WARN_ON(copied < 0))
+ copied = 0;
+
+ *__pos += copied;
+
+ return copied ?: ret;
+}
+
+static ssize_t xe_eudebug_vm_read(struct file *file,
+ char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ return __xe_eudebug_vm_access(file, buffer, NULL, count, pos);
+}
+
+static ssize_t xe_eudebug_vm_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ return __xe_eudebug_vm_access(file, NULL, buffer, count, pos);
+}
+
+static int engine_rcu_flush(struct xe_eudebug *d,
+ struct xe_hw_engine *hwe,
+ unsigned int timeout_us)
+{
+ const struct xe_reg psmi_addr = RING_PSMI_CTL(hwe->mmio_base);
+ struct xe_gt *gt = hwe->gt;
+ unsigned int fw_ref;
+ u32 mask = RCU_ASYNC_FLUSH_AND_INVALIDATE_ALL;
+ u32 psmi_ctrl;
+ u32 id;
+ int ret;
+
+ if (hwe->class == XE_ENGINE_CLASS_RENDER)
+ id = 0;
+ else if (hwe->class == XE_ENGINE_CLASS_COMPUTE)
+ id = hwe->instance + 1;
+ else
+ return -EINVAL;
+
+ if (id < 8)
+ mask |= id << RCU_ASYNC_FLUSH_ENGINE_ID_SHIFT;
+ else
+ mask |= (id - 8) << RCU_ASYNC_FLUSH_ENGINE_ID_SHIFT |
+ RCU_ASYNC_FLUSH_ENGINE_ID_DECODE1;
+
+ fw_ref = xe_force_wake_get(gt_to_fw(gt), hwe->domain);
+ if (!fw_ref)
+ return -ETIMEDOUT;
+
+ /* Prevent concurrent flushes */
+ mutex_lock(&d->xe->eudebug.lock);
+ psmi_ctrl = xe_mmio_read32(>->mmio, psmi_addr);
+ if (!(psmi_ctrl & IDLE_MSG_DISABLE))
+ xe_mmio_write32(>->mmio, psmi_addr,
+ REG_MASKED_FIELD_ENABLE(IDLE_MSG_DISABLE));
+
+ /* XXX: Timeout is per operation but in here we flush previous */
+ ret = xe_mmio_wait32(>->mmio, RCU_ASYNC_FLUSH,
+ RCU_ASYNC_FLUSH_IN_PROGRESS, 0,
+ timeout_us, NULL, false);
+ if (ret)
+ goto out;
+
+ xe_mmio_write32(>->mmio, RCU_ASYNC_FLUSH, mask);
+
+ ret = xe_mmio_wait32(>->mmio, RCU_ASYNC_FLUSH,
+ RCU_ASYNC_FLUSH_IN_PROGRESS, 0,
+ timeout_us, NULL, false);
+out:
+ if (!(psmi_ctrl & IDLE_MSG_DISABLE))
+ xe_mmio_write32(>->mmio, psmi_addr,
+ REG_MASKED_FIELD_DISABLE(IDLE_MSG_DISABLE));
+
+ mutex_unlock(&d->xe->eudebug.lock);
+ xe_force_wake_put(gt_to_fw(gt), fw_ref);
+
+ return ret;
+}
+
+static int xe_eudebug_vm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ struct vm_file *vmf = file->private_data;
+ struct xe_eudebug *d = vmf->debugger;
+ struct xe_gt *gt;
+ int gt_id;
+ int ret = -EINVAL;
+
+ eu_dbg(d, "vm_fsync: vm_handle=%llu, flags=0x%llx, start=%llu, end=%llu datasync=%d\n",
+ vmf->vm_handle, vmf->flags, start, end, datasync);
+
+ if (XE_IOCTL_DBG(d->xe, xe_eudebug_detached(d)))
+ return -ENOTCONN;
+
+ for_each_gt(gt, d->xe, gt_id) {
+ struct xe_hw_engine *hwe;
+ enum xe_hw_engine_id id;
+
+ /* XXX: vm open per engine? */
+ xe_eudebug_for_each_hw_engine(hwe, gt, id) {
+ ret = engine_rcu_flush(d, hwe, vmf->timeout_us);
+ if (ret)
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+static int xe_eudebug_vm_release(struct inode *inode, struct file *file)
+{
+ struct vm_file *vmf = file->private_data;
+ struct xe_eudebug *d = vmf->debugger;
+
+ eu_dbg(d, "vm_release: vm_handle=%llu, flags=0x%llx",
+ vmf->vm_handle, vmf->flags);
+
+ xe_vm_put(vmf->vm);
+ drm_dev_put(&d->xe->drm);
+ xe_eudebug_put(d);
+
+ kfree(vmf);
+
+ return 0;
+}
+
+static const struct file_operations vm_fops = {
+ .owner = THIS_MODULE,
+ .llseek = generic_file_llseek,
+ .read = xe_eudebug_vm_read,
+ .write = xe_eudebug_vm_write,
+ .fsync = xe_eudebug_vm_fsync,
+ .mmap = NULL,
+ .release = xe_eudebug_vm_release,
+};
+
+long xe_eudebug_vm_open_ioctl(struct xe_eudebug *d, unsigned long arg)
+{
+ struct drm_xe_eudebug_vm_open param;
+ struct xe_device * const xe = d->xe;
+ struct vm_file *vmf = NULL;
+ struct xe_vm *vm;
+ struct file *file;
+ long ret = 0;
+ int fd;
+
+ BUILD_BUG_ON(_IOC_SIZE(DRM_XE_EUDEBUG_IOCTL_VM_OPEN) != sizeof(param));
+ BUILD_BUG_ON(!(_IOC_DIR(DRM_XE_EUDEBUG_IOCTL_VM_OPEN) & _IOC_WRITE));
+
+ if (XE_IOCTL_DBG(xe, copy_from_user(¶m, (void __user *)arg, sizeof(param))))
+ return -EFAULT;
+
+ if (XE_IOCTL_DBG(xe, param.flags))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, param.extensions))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, param.vm_handle > U32_MAX))
+ return -EINVAL;
+
+ /*
+ * Resolve the handle while holding the lock that the detach takes.
+ * The map keys vms by pointer without holding a reference, and a
+ * client closing its fd tears its vms down without removing their
+ * handles, so a lookup that races the close would otherwise return
+ * a pointer to freed memory.
+ */
+ scoped_guard(mutex, &xe->eudebug.lock) {
+ if (XE_IOCTL_DBG(xe, xe_eudebug_detached(d)))
+ return -ENOTCONN;
+
+ vm = xe_eudebug_vm_get(d, param.vm_handle);
+ }
+
+ if (XE_IOCTL_DBG(xe, !vm))
+ return -EINVAL;
+
+ vmf = kzalloc_obj(*vmf, GFP_KERNEL);
+ if (XE_IOCTL_DBG(xe, !vmf)) {
+ ret = -ENOMEM;
+ goto out_vm_put;
+ }
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+ if (XE_IOCTL_DBG(xe, fd < 0)) {
+ ret = fd;
+ goto out_free;
+ }
+
+ kref_get(&d->ref);
+ vmf->debugger = d;
+ vmf->vm = vm;
+ vmf->flags = param.flags;
+ vmf->vm_handle = param.vm_handle;
+ vmf->timeout_us = div64_u64(param.timeout_ns, 1000ull);
+
+ file = anon_inode_getfile("[xe_eudebug.vm]", &vm_fops, vmf, O_RDWR);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ XE_IOCTL_DBG(xe, ret);
+ file = NULL;
+ goto out_fd_put;
+ }
+
+ eu_dbg(d, "vm_open: handle=%llu, flags=0x%llx, fd=%d",
+ vmf->vm_handle, vmf->flags, fd);
+
+ drm_dev_get(&xe->drm);
+
+ file->f_mode |= FMODE_PREAD | FMODE_PWRITE |
+ FMODE_READ | FMODE_WRITE | FMODE_LSEEK;
+
+ fd_install(fd, file);
+
+ return fd;
+
+out_fd_put:
+ put_unused_fd(fd);
+ xe_eudebug_put(d);
+out_free:
+ kfree(vmf);
+out_vm_put:
+ xe_vm_put(vm);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/xe/xe_eudebug_vm.h b/drivers/gpu/drm/xe/xe_eudebug_vm.h
new file mode 100644
index 000000000000..b3dc5618a5e6
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_vm.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+struct xe_eudebug;
+
+long xe_eudebug_vm_open_ioctl(struct xe_eudebug *d, unsigned long arg);
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index b99ac815a7c3..12e6197230db 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -33,6 +33,7 @@ extern "C" {
*/
#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT _IOW('j', 0x1, struct drm_xe_eudebug_ack)
+#define DRM_XE_EUDEBUG_IOCTL_VM_OPEN _IOW('j', 0x2, struct drm_xe_eudebug_vm_open)
/**
* struct drm_xe_eudebug_event - Base type of event delivered by xe_eudebug.
@@ -267,6 +268,34 @@ struct drm_xe_eudebug_ack {
__u64 reserved;
};
+/**
+ * struct drm_xe_eudebug_vm_open - Open a target vm
+ *
+ * Open target VM for reading and writing with DRM_XE_EUDEBUG_IOCTL_VM_OPEN.
+ *
+ * File descriptor is returned which can be used with pread and pwrite
+ * to inspect and modify the target VM.
+ *
+ * Multiple operations can be synced with calling fsync(fd). If
+ * timeout_ns was specified, the fsync will timeout if the
+ * VM can't be guaranteed to be in sync. Caller should re-read the
+ * state with pread again.
+ *
+ */
+struct drm_xe_eudebug_vm_open {
+ /** @extensions: Pointer to the first extension struct, if any */
+ __u64 extensions;
+
+ /** @vm_handle: handle of vm to be accessed */
+ __u64 vm_handle;
+
+ /** @flags: flags, must be zero */
+ __u64 flags;
+
+ /** @timeout_ns: Timeout value in nanoseconds */
+ __u64 timeout_ns;
+};
+
#if defined(__cplusplus)
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 13/27] drm/xe/eudebug: Add userptr vm pread/pwrite
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (11 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 12/27] drm/xe/eudebug: Add vm open/pread/pwrite Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:24 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 14/27] drm/xe/eudebug: Add hw enablement Mika Kuoppala
` (19 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala,
Simona Vetter, Dominik Grzegorzek
Implement debugger vm access for userptrs.
When bind is done, take a ref to the current task so that
we know from which vm the address was bound. Then during
debugger pread/pwrite we use this target task as
parameter to access the debuggee vm with access_process_vm().
This is based on suggestions from Simona, Thomas and Joonas.
v2: need to add offset into vma (Dominik)
v3: move code into xe_userptr.c (Mika)
v4: check that task mm has not changed (Claude)
Assisted-by: Claude:claude-opus-4-8
Cc: Simona Vetter <simona@ffwll.ch>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Andrzej Hajda <andrzej.hajda@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_eudebug_vm.c | 45 ++++++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_userptr.c | 4 +++
drivers/gpu/drm/xe/xe_userptr.h | 32 +++++++++++++++++++++
3 files changed, 81 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_eudebug_vm.c b/drivers/gpu/drm/xe/xe_eudebug_vm.c
index 316fe29586b0..42e24c1bc09c 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_vm.c
+++ b/drivers/gpu/drm/xe/xe_eudebug_vm.c
@@ -7,6 +7,7 @@
#include <linux/anon_inodes.h>
#include <linux/fs.h>
+#include <linux/sched/mm.h>
#include <linux/vmalloc.h>
#include <drm/drm_drv.h>
@@ -52,6 +53,50 @@ static int xe_eudebug_vma_access(struct xe_vma *vma,
xe_bo_put(bo);
return ret;
+ } else if (xe_vma_is_userptr(vma)) {
+ struct xe_userptr *userptr = &to_userptr_vma(vma)->userptr;
+ struct mm_struct *mm;
+ int ret;
+
+ if (XE_WARN_ON(!userptr->eudebug.task))
+ return -EINVAL;
+
+ /*
+ * XXX FIXME: access_remote_vm() is the preferred
+ *
+ * access_remote_vm() would fit as userptr notifier has
+ * mm ref so we would not need to carry task ref at all.
+ * But access_remote_vm is not exported. access_process_vm()
+ * is exported so use it instead.
+ *
+ * Going through the task means the address space is resolved
+ * from it on every access, and the task outlives its mm: after
+ * an execve the same task carries a different address space,
+ * and after the thread exits it carries none at all even
+ * though the process and this mapping are still alive.
+ *
+ * Confirm the mm the userptr was bound against is still the
+ * one the task holds, so that a replaced address space is
+ * refused instead of handing the debugger bytes from an
+ * unrelated program. access_process_vm() resolves the mm
+ * again on its own, so this narrows that window rather than
+ * closing it. Keying the access on the mm instead, with
+ * get_user_pages_remote() on userptr->notifier.mm, would
+ * remove the task from the picture entirely.
+ */
+ mm = get_task_mm(userptr->eudebug.task);
+ if (!mm)
+ return -ESRCH;
+
+ ret = mm == userptr->notifier.mm ? 0 : -ESRCH;
+ mmput(mm);
+ if (ret)
+ return ret;
+
+ return access_process_vm(userptr->eudebug.task,
+ xe_vma_userptr(vma) + offset_in_vma,
+ buf, bytes,
+ write ? FOLL_WRITE : 0);
}
return -EINVAL;
diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c
index 90ac141fc12d..4ef078d4f4c3 100644
--- a/drivers/gpu/drm/xe/xe_userptr.c
+++ b/drivers/gpu/drm/xe/xe_userptr.c
@@ -421,6 +421,8 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start,
if (err)
return err;
+ xe_eudebug_track_userptr_task(userptr);
+
return 0;
}
@@ -429,6 +431,8 @@ void xe_userptr_remove(struct xe_userptr_vma *uvma)
struct xe_vm *vm = xe_vma_vm(&uvma->vma);
struct xe_userptr *userptr = &uvma->userptr;
+ xe_eudebug_untrack_userptr_task(userptr);
+
drm_gpusvm_free_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
xe_vma_size(&uvma->vma) >> PAGE_SHIFT);
diff --git a/drivers/gpu/drm/xe/xe_userptr.h b/drivers/gpu/drm/xe/xe_userptr.h
index 2a3cd1b5efbb..b0781618b3f4 100644
--- a/drivers/gpu/drm/xe/xe_userptr.h
+++ b/drivers/gpu/drm/xe/xe_userptr.h
@@ -95,6 +95,12 @@ struct xe_userptr {
#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT)
u32 divisor;
#endif
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+ struct {
+ struct task_struct *task;
+ } eudebug;
+#endif
};
#if IS_ENABLED(CONFIG_DRM_GPUSVM)
@@ -133,4 +139,30 @@ static inline void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma)
{
}
#endif
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+static inline void xe_eudebug_track_userptr_task(struct xe_userptr *userptr)
+{
+ /*
+ * We could use the mm which is on notifier. But
+ * the access_remote_vm() is not exported. Thus
+ * we get reference to task for access_process_vm()
+ */
+ userptr->eudebug.task = get_task_struct(current);
+}
+
+static inline void xe_eudebug_untrack_userptr_task(struct xe_userptr *userptr)
+{
+ put_task_struct(userptr->eudebug.task);
+}
+#else
+static inline void xe_eudebug_track_userptr_task(struct xe_userptr *userptr)
+{
+}
+
+static inline void xe_eudebug_untrack_userptr_task(struct xe_userptr *userptr)
+{
+}
+#endif /* CONFIG_DRM_XE_EUDEBUG */
+
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 14/27] drm/xe/eudebug: Add hw enablement
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (12 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 13/27] drm/xe/eudebug: Add userptr vm pread/pwrite Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:15 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 15/27] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
` (18 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Dominik Grzegorzek, Mika Kuoppala
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
In order to turn on debug capabilities (i.e. breakpoints), TD_CTL
and some other registers need to be programmed. Implement eudebug
mode enabling, including eudebug related workarounds.
v2: Move workarounds to xe_wa_oob. Use reg_sr directly instead of
xe_rtp as it suits better for dynamic manipulation of those register we
do later in the series.
v3: get rid of undefining XE_MCR_REG (Mika)
v4: return if dss_mask is all 0.
v5: remove unused GLOBAL_DEBUG_ENABLE (Sashiko)
v6: - don't leak fw ref, check for zero dss_mask (Sashiko)
- hold runtime for hw access (Sashiko)
- make iter size check byte granularity for safety (Claude)
- simplify xe_reg_sr_add with overwrite (Claude)
- check that bitmap size is aligned to hw (4) (Claude)
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/Makefile | 2 +-
drivers/gpu/drm/xe/regs/xe_gt_regs.h | 19 +++
drivers/gpu/drm/xe/xe_eudebug_hw.c | 72 +++++++++
drivers/gpu/drm/xe/xe_eudebug_hw.h | 23 +++
drivers/gpu/drm/xe/xe_gt_debug.c | 201 ++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_gt_debug.h | 32 ++++
drivers/gpu/drm/xe/xe_reg_sr.c | 12 +-
drivers/gpu/drm/xe/xe_reg_sr.h | 4 +-
drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +-
drivers/gpu/drm/xe/xe_rtp.c | 2 +-
drivers/gpu/drm/xe/xe_wa_oob.rules | 2 +
11 files changed, 364 insertions(+), 7 deletions(-)
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_hw.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_hw.h
create mode 100644 drivers/gpu/drm/xe/xe_gt_debug.c
create mode 100644 drivers/gpu/drm/xe/xe_gt_debug.h
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index a37ab5e654aa..5cdf47f79aa4 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -162,7 +162,7 @@ xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
xe-$(CONFIG_DRM_GPUSVM) += xe_userptr.o
# debugging shaders with gdb (eudebug) support
-xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o xe_eudebug_vm.o
+xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o xe_eudebug_vm.o xe_eudebug_hw.o xe_gt_debug.o
# graphics hardware monitoring (HWMON) support
xe-$(CONFIG_HWMON) += xe_hwmon.o
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 8056d007c23e..7537fc1a9c3f 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -515,10 +515,20 @@
#define DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA REG_BIT(15)
#define CLEAR_OPTIMIZATION_DISABLE REG_BIT(6)
+#define TD_CTL XE_REG_MCR(0xe400)
+#define TD_CTL_FEH_AND_FEE_ENABLE REG_BIT(7) /* forced halt and exception */
+#define TD_CTL_FORCE_EXTERNAL_HALT REG_BIT(6)
+#define TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE REG_BIT(4)
+#define TD_CTL_FORCE_EXCEPTION REG_BIT(3)
+#define TD_CTL_BREAKPOINT_ENABLE REG_BIT(2)
+#define TD_CTL_GLOBAL_DEBUG_ENABLE REG_BIT(0) /* XeHP */
+
#define CACHE_MODE_SS XE_REG_MCR(0xe420, XE_REG_OPTION_MASKED)
#define DISABLE_ECC REG_BIT(5)
#define ENABLE_PREFETCH_INTO_IC REG_BIT(3)
+#define EU_ATT(reg, row) XE_REG_MCR((reg ? 0xe478 : 0xe470) + (row) * 4)
+
#define ROW_CHICKEN4 XE_REG_MCR(0xe48c, XE_REG_OPTION_MASKED)
#define DISABLE_GRF_CLEAR REG_BIT(13)
#define XEHP_DIS_BBL_SYSPIPE REG_BIT(11)
@@ -528,6 +538,8 @@
#define THREAD_EX_ARB_MODE REG_GENMASK(3, 2)
#define THREAD_EX_ARB_MODE_RR_AFTER_DEP REG_FIELD_PREP(THREAD_EX_ARB_MODE, 0x2)
+#define EU_ATT_CLR(reg, row) XE_REG_MCR((reg ? 0xe698 : 0xe490) + (row) * 4)
+
#define ROW_CHICKEN3 XE_REG_MCR(0xe49c, XE_REG_OPTION_MASKED)
#define XE2_EUPEND_CHK_FLUSH_DIS REG_BIT(14)
#define DIS_EU_GRF_POISON_TO_LSC REG_BIT(13)
@@ -546,11 +558,13 @@
#define MDQ_ARBITRATION_MODE REG_BIT(12)
#define STALL_DOP_GATING_DISABLE REG_BIT(5)
#define EARLY_EOT_DIS REG_BIT(1)
+#define STALL_DOP_GATING_DISABLE REG_BIT(5)
#define ROW_CHICKEN2 XE_REG_MCR(0xe4f4, XE_REG_OPTION_MASKED)
#define DISABLE_READ_SUPPRESSION REG_BIT(15)
#define DISABLE_EARLY_READ REG_BIT(14)
#define ENABLE_LARGE_GRF_MODE REG_BIT(12)
+#define XEHPC_DISABLE_BTB REG_BIT(11)
#define PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8)
#define DISABLE_TDL_SVHS_GATING REG_BIT(1)
#define DISABLE_DOP_GATING REG_BIT(0)
@@ -616,6 +630,11 @@
#define CCS_MODE_CSLICE(cslice, ccs) \
((ccs) << ((cslice) * CCS_MODE_CSLICE_WIDTH))
+#define RCU_DEBUG_1 XE_REG(0x14a00)
+#define RCU_DEBUG_1_ENGINE_STATUS REG_GENMASK(2, 0)
+#define RCU_DEBUG_1_RUNALONE_ACTIVE REG_BIT(2)
+#define RCU_DEBUG_1_CONTEXT_ACTIVE REG_BIT(0)
+
#define RCU_ASYNC_FLUSH XE_REG(0x149fc)
#define RCU_ASYNC_FLUSH_IN_PROGRESS REG_BIT(31)
#define RCU_ASYNC_FLUSH_ENGINE_ID_SHIFT 28
diff --git a/drivers/gpu/drm/xe/xe_eudebug_hw.c b/drivers/gpu/drm/xe/xe_eudebug_hw.c
new file mode 100644
index 000000000000..aa31b4c91713
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_hw.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#include "xe_eudebug_hw.h"
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <generated/xe_wa_oob.h>
+
+#include "regs/xe_gt_regs.h"
+#include "regs/xe_engine_regs.h"
+
+#include "xe_eudebug.h"
+#include "xe_eudebug_types.h"
+#include "xe_exec_queue.h"
+#include "xe_exec_queue_types.h"
+#include "xe_force_wake.h"
+#include "xe_gt.h"
+#include "xe_gt_debug.h"
+#include "xe_gt_mcr.h"
+#include "xe_hw_engine.h"
+#include "xe_lrc.h"
+#include "xe_macros.h"
+#include "xe_mmio.h"
+#include "xe_reg_sr.h"
+#include "xe_rtp.h"
+#include "xe_wa.h"
+
+static void add_sr_entry(struct xe_hw_engine *hwe,
+ struct xe_reg_mcr mcr_reg,
+ u32 mask, bool enable)
+{
+ const struct xe_reg_sr_entry sr_entry = {
+ .reg = mcr_reg.__reg,
+ .clr_bits = mask,
+ .set_bits = enable ? mask : 0,
+ .read_mask = mask,
+ };
+
+ xe_reg_sr_add(&hwe->reg_sr, &sr_entry, hwe->gt, true);
+}
+
+void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe, bool enable)
+{
+ struct xe_gt *gt = hwe->gt;
+ struct xe_device *xe = gt_to_xe(gt);
+
+ if (!xe_rtp_match_first_render_or_compute(xe, gt, hwe))
+ return;
+
+ if (XE_GT_WA(gt, 18022722726))
+ add_sr_entry(hwe, ROW_CHICKEN,
+ STALL_DOP_GATING_DISABLE, enable);
+
+ if (XE_GT_WA(gt, 14015474168))
+ add_sr_entry(hwe, ROW_CHICKEN2,
+ XEHPC_DISABLE_BTB,
+ enable);
+
+ if (xe->info.graphics_verx100 >= 1200)
+ add_sr_entry(hwe, TD_CTL,
+ TD_CTL_BREAKPOINT_ENABLE |
+ TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
+ TD_CTL_FEH_AND_FEE_ENABLE,
+ enable);
+
+ if (xe->info.graphics_verx100 >= 1250)
+ add_sr_entry(hwe, TD_CTL,
+ TD_CTL_GLOBAL_DEBUG_ENABLE, enable);
+}
diff --git a/drivers/gpu/drm/xe/xe_eudebug_hw.h b/drivers/gpu/drm/xe/xe_eudebug_hw.h
new file mode 100644
index 000000000000..23dd55fc7ad9
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_hw.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#ifndef _XE_EUDEBUG_HW_H_
+#define _XE_EUDEBUG_HW_H_
+
+#include <linux/types.h>
+
+struct xe_eudebug;
+struct xe_hw_engine;
+struct xe_gt;
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+
+void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe, bool enable);
+
+#else /* CONFIG_DRM_XE_EUDEBUG */
+
+#endif /* CONFIG_DRM_XE_EUDEBUG */
+
+#endif /* _XE_EUDEBUG_HW_H_ */
diff --git a/drivers/gpu/drm/xe/xe_gt_debug.c b/drivers/gpu/drm/xe/xe_gt_debug.c
new file mode 100644
index 000000000000..b20e42e66c5b
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_gt_debug.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "regs/xe_gt_regs.h"
+#include "xe_device.h"
+#include "xe_force_wake.h"
+#include "xe_gt.h"
+#include "xe_gt_topology.h"
+#include "xe_gt_debug.h"
+#include "xe_gt_mcr.h"
+#include "xe_pm.h"
+#include "xe_macros.h"
+
+unsigned int xe_gt_eu_att_regs(struct xe_gt *gt)
+{
+ return (GRAPHICS_VERx100(gt_to_xe(gt)) >= 3000) ? 2u : 1u;
+}
+
+int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
+ int (*fn)(struct xe_gt *gt,
+ void *data,
+ u16 group,
+ u16 instance,
+ bool present),
+ void *data)
+{
+ struct xe_device *xe = gt_to_xe(gt);
+ const enum xe_force_wake_domains fw_domains = XE_FW_GT;
+ xe_dss_mask_t dss_mask;
+ unsigned int dss, fw_ref;
+ u16 group, instance;
+ int ret = 0;
+
+ if (!xe_pm_runtime_get_if_active(xe))
+ return -EIO;
+
+ fw_ref = xe_force_wake_get(gt_to_fw(gt), fw_domains);
+ if (!fw_ref) {
+ ret = -ETIMEDOUT;
+ goto out_pm;
+ }
+
+ bitmap_or(dss_mask, gt->fuse_topo.g_dss_mask, gt->fuse_topo.c_dss_mask,
+ XE_MAX_DSS_FUSE_BITS);
+
+ /* If by any chance dss_mask is all 0s */
+ if (!bitmap_weight(dss_mask, XE_MAX_DSS_FUSE_BITS)) {
+ ret = -EINVAL;
+ goto out_fw;
+ }
+
+ /*
+ * Note: This removes terminating zeros when last dss is fused out!
+ * In order bitmask to be exactly the same as on with i915 we would
+ * need to figure out max dss for given platform, most probably by
+ * querying hwconfig
+ */
+
+ for (dss = 0;
+ dss <= find_last_bit(dss_mask, XE_MAX_DSS_FUSE_BITS);
+ dss++) {
+ xe_gt_mcr_get_dss_steering(gt, dss, &group, &instance);
+
+ ret = fn(gt, data, group, instance, test_bit(dss, dss_mask));
+ if (ret)
+ break;
+ }
+
+out_fw:
+ xe_force_wake_put(gt_to_fw(gt), fw_ref);
+out_pm:
+ xe_pm_runtime_put(xe);
+
+ return ret;
+}
+
+static int read_first_attention_mcr(struct xe_gt *gt, void *data,
+ u16 group, u16 instance, bool present)
+{
+ unsigned int reg, row;
+
+ if (!present)
+ return 0;
+
+ for (reg = 0; reg < xe_gt_eu_att_regs(gt); reg++) {
+ for (row = 0; row < XE_GT_EU_ATT_ROWS; row++) {
+ u32 val;
+
+ val = xe_gt_mcr_unicast_read(gt, EU_ATT(reg, row), group, instance);
+
+ if (val)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#define MAX_EUS_PER_ROW 4u
+#define MAX_THREADS 8u
+
+/**
+ * xe_gt_eu_attention_bitmap_size - query size of the attention bitmask
+ *
+ * @gt: pointer to struct xe_gt
+ *
+ * Return: size in bytes.
+ */
+int xe_gt_eu_attention_bitmap_size(struct xe_gt *gt)
+{
+ xe_dss_mask_t dss_mask;
+
+ bitmap_or(dss_mask, gt->fuse_topo.c_dss_mask,
+ gt->fuse_topo.g_dss_mask, XE_MAX_DSS_FUSE_BITS);
+
+ if (XE_WARN_ON(bitmap_empty(dss_mask, XE_MAX_DSS_FUSE_BITS)))
+ return 0;
+
+ return (find_last_bit(dss_mask, XE_MAX_DSS_FUSE_BITS) + 1) *
+ XE_GT_EU_ATT_ROWS * xe_gt_eu_att_regs(gt) * MAX_THREADS *
+ MAX_EUS_PER_ROW / 8;
+}
+
+struct attn_read_iter {
+ struct xe_gt *gt;
+ unsigned int i;
+ unsigned int size;
+ u8 *bits;
+};
+
+static int read_eu_attentions_mcr(struct xe_gt *gt, void *data,
+ u16 group, u16 instance, bool present)
+{
+ struct attn_read_iter * const iter = data;
+ unsigned int reg, row;
+
+ for (reg = 0; reg < xe_gt_eu_att_regs(gt); reg++) {
+ for (row = 0; row < XE_GT_EU_ATT_ROWS; row++) {
+ u32 val;
+
+ if (iter->i + sizeof(val) > iter->size)
+ return 0;
+
+ if (present)
+ val = xe_gt_mcr_unicast_read(gt, EU_ATT(reg, row), group, instance);
+ else
+ val = 0;
+
+ memcpy(&iter->bits[iter->i], &val, sizeof(val));
+ iter->i += sizeof(val);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * xe_gt_eu_attention_bitmap - query host attention
+ *
+ * @gt: pointer to struct xe_gt
+ *
+ * Return: 0 on success, negative otherwise.
+ */
+int xe_gt_eu_attention_bitmap(struct xe_gt *gt, u8 *bits,
+ unsigned int bitmap_size)
+{
+ struct attn_read_iter iter = {
+ .gt = gt,
+ .i = 0,
+ .size = bitmap_size,
+ .bits = bits
+ };
+
+ /* One u32 of attention state per dss, register and row */
+ BUILD_BUG_ON(MAX_THREADS * MAX_EUS_PER_ROW / 8 != sizeof(u32));
+
+ if (XE_WARN_ON(!IS_ALIGNED(bitmap_size, sizeof(u32))))
+ return -EINVAL;
+
+ return xe_gt_foreach_dss_group_instance(gt, read_eu_attentions_mcr, &iter);
+}
+
+/**
+ * xe_gt_eu_threads_needing_attention - Query host attention
+ *
+ * @gt: pointer to struct xe_gt
+ *
+ * Return: 1 if threads waiting host attention, 0 otherwise.
+ */
+int xe_gt_eu_threads_needing_attention(struct xe_gt *gt)
+{
+ int err;
+
+ err = xe_gt_foreach_dss_group_instance(gt, read_first_attention_mcr, NULL);
+
+ XE_WARN_ON(err < 0);
+
+ return err < 0 ? 0 : err;
+}
diff --git a/drivers/gpu/drm/xe/xe_gt_debug.h b/drivers/gpu/drm/xe/xe_gt_debug.h
new file mode 100644
index 000000000000..9dabe9cc1d25
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_gt_debug.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __XE_GT_DEBUG_
+#define __XE_GT_DEBUG_
+
+#include <linux/bits.h>
+#include <linux/math.h>
+
+struct xe_gt;
+
+#define XE_GT_ATTENTION_TIMEOUT_MS 100
+#define XE_GT_EU_ATT_ROWS 2u
+
+unsigned int xe_gt_eu_att_regs(struct xe_gt *gt);
+
+int xe_gt_eu_threads_needing_attention(struct xe_gt *gt);
+int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
+ int (*fn)(struct xe_gt *gt,
+ void *data,
+ u16 group,
+ u16 instance,
+ bool present),
+ void *data);
+
+int xe_gt_eu_attention_bitmap_size(struct xe_gt *gt);
+int xe_gt_eu_attention_bitmap(struct xe_gt *gt, u8 *bits,
+ unsigned int bitmap_size);
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
index e328f5072557..72919a5612a5 100644
--- a/drivers/gpu/drm/xe/xe_reg_sr.c
+++ b/drivers/gpu/drm/xe/xe_reg_sr.c
@@ -104,7 +104,8 @@ static struct xe_reg sanitize_mcr(struct xe_reg_sr *sr,
int xe_reg_sr_add(struct xe_reg_sr *sr,
const struct xe_reg_sr_entry *e,
- struct xe_gt *gt)
+ struct xe_gt *gt,
+ bool overwrite)
{
unsigned long idx = e->reg.addr;
struct xe_reg_sr_entry *pentry = xa_load(&sr->xa, idx);
@@ -114,15 +115,20 @@ int xe_reg_sr_add(struct xe_reg_sr *sr,
reg = sanitize_mcr(sr, e, gt);
if (pentry) {
- if (!compatible_entries(pentry, e)) {
+ if (!overwrite && !compatible_entries(pentry, e)) {
ret = -EINVAL;
goto fail;
}
pentry->clr_bits |= e->clr_bits;
- pentry->set_bits |= e->set_bits;
pentry->read_mask |= e->read_mask;
+ /* An overwrite with nothing to set clears instead */
+ if (overwrite && !e->set_bits)
+ pentry->set_bits &= ~e->clr_bits;
+ else
+ pentry->set_bits |= e->set_bits;
+
return 0;
}
diff --git a/drivers/gpu/drm/xe/xe_reg_sr.h b/drivers/gpu/drm/xe/xe_reg_sr.h
index d26cf4713383..8231640edb0f 100644
--- a/drivers/gpu/drm/xe/xe_reg_sr.h
+++ b/drivers/gpu/drm/xe/xe_reg_sr.h
@@ -6,6 +6,8 @@
#ifndef _XE_REG_SR_H_
#define _XE_REG_SR_H_
+#include <linux/types.h>
+
/*
* Reg save/restore bookkeeping
*/
@@ -28,7 +30,7 @@ void xe_reg_sr_lrc_check(struct xe_reg_sr *sr,
struct drm_printer *p);
int xe_reg_sr_add(struct xe_reg_sr *sr, const struct xe_reg_sr_entry *e,
- struct xe_gt *gt);
+ struct xe_gt *gt, bool overwrite);
void xe_reg_sr_apply_mmio(struct xe_reg_sr *sr, struct xe_gt *gt);
void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe);
diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c
index cab1b578ca0e..744844f59bd5 100644
--- a/drivers/gpu/drm/xe/xe_reg_whitelist.c
+++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c
@@ -193,7 +193,7 @@ static int whitelist_apply_to_hwe(struct xe_hw_engine *hwe, struct xe_reg_sr *in
}
xe_reg_whitelist_print_entry(&p, 0, reg, entry);
- xe_reg_sr_add(out, &hwe_entry, hwe->gt);
+ xe_reg_sr_add(out, &hwe_entry, hwe->gt, false);
slot++;
}
diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
index 6a8d6ea68f25..56641a72f33f 100644
--- a/drivers/gpu/drm/xe/xe_rtp.c
+++ b/drivers/gpu/drm/xe/xe_rtp.c
@@ -244,7 +244,7 @@ static void rtp_add_sr_entry(const struct xe_rtp_action *action,
sr_entry.reg.addr += mmio_base;
- xe_reg_sr_add(sr, &sr_entry, gt);
+ xe_reg_sr_add(sr, &sr_entry, gt, false);
}
static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry,
diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules
index 3de46094ab5c..40a6a57153a7 100644
--- a/drivers/gpu/drm/xe/xe_wa_oob.rules
+++ b/drivers/gpu/drm/xe/xe_wa_oob.rules
@@ -74,3 +74,5 @@
14027054324 GRAPHICS_VERSION(3511)
14022766366 GRAPHICS_VERSION_RANGE(2001, 2004)
GRAPHICS_VERSION_RANGE(3000, 3005)
+18022722726 GRAPHICS_VERSION_RANGE(1250, 1274)
+14015474168 PLATFORM(PVC)
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 15/27] drm/xe/eudebug: Introduce EU control interface
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (13 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 14/27] drm/xe/eudebug: Add hw enablement Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:34 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 16/27] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
` (17 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Dominik Grzegorzek, Christoph Manszewski, Mika Kuoppala
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Introduce EU control functionality, which allows the EU debugger
to interrupt, resume, and inform about the current state of
EU threads during execution. Provide an abstraction layer,
so that in the future the GuC will only need to provide appropriate
callbacks.
Based on an implementation created by the authors and others in the
i915 driver.
v2: - checkpatch (Maciej)
- lrc index off by one fix (Mika)
- checkpatch (Tilak)
- 32bit fixes (Andrzej, Mika)
- find_resource_get for client (Mika)
v3: - fw ref (Mika)
- attention register naming
v4: - fused off handling (Dominik)
- squash xe3 parts and ptl attentions (Mika)
v5: - s/ioctl_lock/exec_queue.lock to avoid wrong lock order (Mika)
v6: - require seqno MBZ (Mika)
v7: - error return consistency (Mika)
v8: - consolidate boilerplate and lrc sanity check (Mika)
v9: - keep FEE when setting FEH, user_arg reserved (Sashiko)
v10: - take runtime pm for hw access (Sashiko)
- gate sriov (Sashiko)
- more careful logging (Sashiko)
- proper teardown if no runtime active
- don't warn on wrong context (Claude)
- documentation fixes (Claude)
- byte size iter size check for safety (Claude)
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
Documentation/gpu/xe/xe_eudebug.rst | 6 +
drivers/gpu/drm/xe/regs/xe_engine_regs.h | 1 +
drivers/gpu/drm/xe/xe_eudebug.c | 54 ++
drivers/gpu/drm/xe/xe_eudebug.h | 2 +
drivers/gpu/drm/xe/xe_eudebug_hw.c | 646 +++++++++++++++++++++++
drivers/gpu/drm/xe/xe_eudebug_hw.h | 7 +
drivers/gpu/drm/xe/xe_eudebug_types.h | 25 +
include/uapi/drm/xe_drm_eudebug.h | 67 +++
8 files changed, 808 insertions(+)
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
index 466d366c1e83..76f255c7da73 100644
--- a/Documentation/gpu/xe/xe_eudebug.rst
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -72,3 +72,9 @@ VM Access
.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
:identifiers: drm_xe_eudebug_vm_open
+
+EU/HW Control
+=============
+
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_eu_control
diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
index 94033982e694..7987e05a78ae 100644
--- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
@@ -156,6 +156,7 @@
#define IDLE_DELAY REG_GENMASK(20, 0)
#define RING_CURRENT_LRCA(base) XE_REG((base) + 0x240)
+#define CURRENT_LRCA_VALID REG_BIT(0)
#define RING_CONTEXT_CONTROL(base) XE_REG((base) + 0x244, XE_REG_OPTION_MASKED)
#define CTX_CTRL_PXP_ENABLE REG_BIT(10)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 188a4c60513c..ecd6d4c5d63c 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -17,11 +17,14 @@
#include "xe_debug_data_types.h"
#include "xe_device.h"
#include "xe_eudebug.h"
+#include "xe_eudebug_hw.h"
#include "xe_eudebug_types.h"
#include "xe_eudebug_vm.h"
#include "xe_exec_queue.h"
+#include "xe_gt.h"
#include "xe_hw_engine.h"
#include "xe_macros.h"
+#include "xe_pm.h"
#include "xe_sync.h"
#include "xe_vm.h"
@@ -738,6 +741,33 @@ struct xe_vm *xe_eudebug_vm_get(struct xe_eudebug *d, u32 id)
return vm;
}
+struct xe_exec_queue *xe_eudebug_exec_queue_get(struct xe_eudebug *d, u32 id)
+{
+ struct xe_eudebug_resource *r =
+ resource_from_type(d, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE);
+ struct xe_exec_queue *eq;
+
+ mutex_lock(&r->lock);
+ eq = find_resource__unlocked(r, id);
+ if (eq)
+ xe_exec_queue_get(eq);
+ mutex_unlock(&r->lock);
+
+ return eq;
+}
+
+struct xe_lrc *xe_eudebug_find_lrc(struct xe_eudebug *d, u32 id)
+{
+ struct xe_eudebug_resource *r = resource_from_type(d, XE_EUDEBUG_RES_TYPE_LRC);
+ struct xe_lrc *lrc;
+
+ mutex_lock(&r->lock);
+ lrc = find_resource__unlocked(r, id);
+ mutex_unlock(&r->lock);
+
+ return lrc;
+}
+
static struct drm_xe_eudebug_event *
xe_eudebug_prepare_event(struct xe_eudebug *d, u16 type, u64 seqno, u16 flags,
u32 len)
@@ -1879,6 +1909,10 @@ static long xe_eudebug_ioctl(struct file *file,
ret = xe_eudebug_vm_open_ioctl(d, arg);
eu_dbg(d, "ioctl cmd=VM_OPEN ret=%ld\n", ret);
break;
+ case DRM_XE_EUDEBUG_IOCTL_EU_CONTROL:
+ ret = xe_eudebug_eu_control(d, arg);
+ eu_dbg(d, "ioctl cmd=EU_CONTROL ret=%ld\n", ret);
+ break;
default:
ret = -EINVAL;
}
@@ -1979,6 +2013,8 @@ xe_eudebug_connect(struct xe_device *xe,
goto err_fd;
}
+ xe_eudebug_hw_init(d);
+
kref_get(&d->ref); /* for discovery */
queue_work(xe->eudebug.discovery_wq, &d->discovery_work);
@@ -2022,6 +2058,10 @@ bool xe_eudebug_is_enabled(struct xe_device *xe)
int xe_eudebug_enable(struct xe_device *xe, bool enable)
{
+ struct xe_gt *gt;
+ int i;
+ u8 id;
+
guard(mutex)(&xe->eudebug.lock);
if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
@@ -2033,6 +2073,20 @@ int xe_eudebug_enable(struct xe_device *xe, bool enable)
if (enable == xe_eudebug_is_enabled(xe))
return 0;
+ xe_pm_runtime_get(xe);
+ for_each_gt(gt, xe, id) {
+ for (i = 0; i < ARRAY_SIZE(gt->hw_engines); i++) {
+ if (!(gt->info.engine_mask & BIT(i)))
+ continue;
+
+ xe_eudebug_init_hw_engine(>->hw_engines[i], enable);
+ }
+
+ xe_gt_reset_async(gt);
+ flush_work(>->reset.worker);
+ }
+ xe_pm_runtime_put(xe);
+
WRITE_ONCE(xe->eudebug.cap_state, enable ?
XE_EUDEBUG_CAP_ENABLED : XE_EUDEBUG_CAP_DISABLED);
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index ea370dbfc0aa..8a5a10bf7e8b 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -72,6 +72,8 @@ struct xe_vm *xe_eudebug_vm_get(struct xe_eudebug *d, u32 vm_id);
void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q);
void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q);
+struct xe_exec_queue *xe_eudebug_exec_queue_get(struct xe_eudebug *d, u32 id);
+struct xe_lrc *xe_eudebug_find_lrc(struct xe_eudebug *d, u32 id);
void xe_eudebug_vm_bind_execute(struct xe_vm *vm, struct xe_vma_ops *ops);
diff --git a/drivers/gpu/drm/xe/xe_eudebug_hw.c b/drivers/gpu/drm/xe/xe_eudebug_hw.c
index aa31b4c91713..d14e4e4775f2 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_hw.c
+++ b/drivers/gpu/drm/xe/xe_eudebug_hw.c
@@ -24,6 +24,7 @@
#include "xe_lrc.h"
#include "xe_macros.h"
#include "xe_mmio.h"
+#include "xe_pm.h"
#include "xe_reg_sr.h"
#include "xe_rtp.h"
#include "xe_wa.h"
@@ -70,3 +71,648 @@ void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe, bool enable)
add_sr_entry(hwe, TD_CTL,
TD_CTL_GLOBAL_DEBUG_ENABLE, enable);
}
+
+static int read_hw_lrca_fw(struct xe_hw_engine *hwe, u32 *lrc_hw)
+{
+ u32 lrc_reg;
+
+ lrc_reg = xe_hw_engine_mmio_read32(hwe, RING_CURRENT_LRCA(0));
+
+ if (!(lrc_reg & CURRENT_LRCA_VALID))
+ return -ENOENT;
+
+ *lrc_hw = lrc_reg & GENMASK(31, 12);
+
+ return 0;
+}
+
+static int read_hw_lrca(struct xe_hw_engine *hwe, u32 *lrc_hw)
+{
+ unsigned int fw_ref;
+ int ret;
+
+ fw_ref = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
+ if (!fw_ref)
+ return -ETIMEDOUT;
+
+ ret = read_hw_lrca_fw(hwe, lrc_hw);
+
+ xe_force_wake_put(gt_to_fw(hwe->gt), fw_ref);
+
+ return ret;
+}
+
+static bool lrca_equals(u32 a, u32 b)
+{
+ return (a & GENMASK(31, 12)) == (b & GENMASK(31, 12));
+}
+
+static int match_exec_queue_lrca(struct xe_exec_queue *q, u32 lrc_hw)
+{
+ int i;
+
+ for (i = 0; i < q->width; i++)
+ if (lrca_equals(lower_32_bits(xe_lrc_descriptor(q->lrc[i])), lrc_hw))
+ return i;
+
+ return -1;
+}
+
+static int rcu_debug1_engine_index(const struct xe_hw_engine * const hwe)
+{
+ if (hwe->class == XE_ENGINE_CLASS_RENDER) {
+ XE_WARN_ON(hwe->instance);
+ return 0;
+ }
+
+ XE_WARN_ON(hwe->instance > 3);
+
+ return hwe->instance + 1;
+}
+
+static u32 engine_status_xe1(const struct xe_hw_engine * const hwe,
+ u32 rcu_debug1)
+{
+ const unsigned int first = 7;
+ const unsigned int incr = 3;
+ const unsigned int i = rcu_debug1_engine_index(hwe);
+ const unsigned int shift = first + (i * incr);
+
+ return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
+}
+
+static u32 engine_status_xe2(const struct xe_hw_engine * const hwe,
+ u32 rcu_debug1)
+{
+ const unsigned int first = 7;
+ const unsigned int incr = 4;
+ const unsigned int i = rcu_debug1_engine_index(hwe);
+ const unsigned int shift = first + (i * incr);
+
+ return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
+}
+
+static u32 engine_status_xe3(const struct xe_hw_engine * const hwe,
+ u32 rcu_debug1)
+{
+ const unsigned int first = 6;
+ const unsigned int incr = 4;
+ const unsigned int i = rcu_debug1_engine_index(hwe);
+ const unsigned int shift = first + (i * incr);
+
+ return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
+}
+
+static u32 engine_status(const struct xe_hw_engine * const hwe,
+ u32 rcu_debug1)
+{
+ u32 status = 0;
+
+ if (GRAPHICS_VER(gt_to_xe(hwe->gt)) < 20)
+ status = engine_status_xe1(hwe, rcu_debug1);
+ else if (GRAPHICS_VER(gt_to_xe(hwe->gt)) < 30)
+ status = engine_status_xe2(hwe, rcu_debug1);
+ else if (GRAPHICS_VER(gt_to_xe(hwe->gt)) < 35)
+ status = engine_status_xe3(hwe, rcu_debug1);
+ else
+ XE_WARN_ON(GRAPHICS_VER(gt_to_xe(hwe->gt)));
+
+ return status;
+}
+
+static bool engine_has_runalone_set(const struct xe_hw_engine * const hwe,
+ u32 rcu_debug1)
+{
+ return engine_status(hwe, rcu_debug1) & RCU_DEBUG_1_RUNALONE_ACTIVE;
+}
+
+static bool engine_has_context_set(const struct xe_hw_engine * const hwe,
+ u32 rcu_debug1)
+{
+ return engine_status(hwe, rcu_debug1) & RCU_DEBUG_1_CONTEXT_ACTIVE;
+}
+
+static struct xe_hw_engine *get_runalone_active_hw_engine(struct xe_gt *gt)
+{
+ struct xe_hw_engine *hwe, *first = NULL;
+ unsigned int num_active, id, fw_ref;
+ u32 val;
+
+ fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
+ if (!fw_ref) {
+ drm_dbg(>_to_xe(gt)->drm, "eudbg: runalone failed to get force wake\n");
+ return ERR_PTR(-ETIMEDOUT);
+ }
+
+ val = xe_mmio_read32(>->mmio, RCU_DEBUG_1);
+ xe_force_wake_put(gt_to_fw(gt), fw_ref);
+
+ drm_dbg(>_to_xe(gt)->drm, "eudbg: runalone RCU_DEBUG_1 = 0x%08x\n", val);
+
+ num_active = 0;
+ xe_eudebug_for_each_hw_engine(hwe, gt, id) {
+ bool runalone, ctx;
+
+ runalone = engine_has_runalone_set(hwe, val);
+ ctx = engine_has_context_set(hwe, val);
+
+ drm_dbg(>_to_xe(gt)->drm, "eudbg: engine %s: runalone=%s, context=%s\n",
+ hwe->name, runalone ? "active" : "inactive",
+ ctx ? "active" : "inactive");
+
+ /*
+ * On earlier gen12 the context status seems to be idle when
+ * it has raised attention. We have to omit the active bit.
+ */
+ if (IS_DGFX(gt_to_xe(gt)))
+ ctx = true;
+
+ if (runalone && ctx) {
+ num_active++;
+
+ drm_dbg(>_to_xe(gt)->drm, "eudbg: runalone engine %s %s\n",
+ hwe->name, first ? "ignored" : "selected");
+ if (!first)
+ first = hwe;
+ }
+ }
+
+ if (num_active > 1)
+ drm_err(>_to_xe(gt)->drm, "eudbg: %u runalone engines active!\n",
+ num_active);
+
+ if (!first)
+ return ERR_PTR(-ENOENT);
+
+ return first;
+}
+
+static struct xe_exec_queue *active_hwe_to_exec_queue(struct xe_hw_engine *hwe,
+ int *lrc_idx)
+{
+ struct xe_device *xe = gt_to_xe(hwe->gt);
+ struct xe_gt *gt = hwe->gt;
+ struct xe_exec_queue *q, *found = NULL;
+ struct xe_file *xef;
+ unsigned long i;
+ int idx, err;
+ u32 lrc_hw;
+
+ err = read_hw_lrca(hwe, &lrc_hw);
+ if (err)
+ return ERR_PTR(err);
+
+ mutex_lock(&xe->eudebug.lock);
+ list_for_each_entry(xef, &xe->eudebug.targets, eudebug.target_link) {
+ mutex_lock(&xef->exec_queue.lock);
+ xa_for_each(&xef->exec_queue.xa, i, q) {
+ if (q->gt != gt)
+ continue;
+
+ if (q->class != hwe->class)
+ continue;
+
+ if (xe_exec_queue_is_idle(q))
+ continue;
+
+ idx = match_exec_queue_lrca(q, lrc_hw);
+ if (idx < 0)
+ continue;
+
+ found = xe_exec_queue_get(q);
+
+ if (lrc_idx)
+ *lrc_idx = idx;
+
+ break;
+ }
+ mutex_unlock(&xef->exec_queue.lock);
+
+ if (found)
+ break;
+ }
+ mutex_unlock(&xe->eudebug.lock);
+
+ if (!found)
+ return ERR_PTR(-ENOENT);
+
+ /*
+ * The context can switch out while we walk the target list, so
+ * both of these are ordinary outcomes rather than driver bugs.
+ */
+ if (read_hw_lrca(hwe, &lrc_hw)) {
+ xe_exec_queue_put(found);
+ return ERR_PTR(-ENOENT);
+ }
+
+ if (match_exec_queue_lrca(found, lrc_hw) < 0) {
+ xe_exec_queue_put(found);
+ return ERR_PTR(-ENOENT);
+ }
+
+ return found;
+}
+
+struct xe_exec_queue *
+xe_gt_runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
+{
+ struct xe_hw_engine *active;
+
+ active = get_runalone_active_hw_engine(gt);
+ if (IS_ERR(active))
+ return ERR_CAST(active);
+
+ return active_hwe_to_exec_queue(active, lrc_idx);
+}
+
+static int check_lrc_sanity(const struct xe_exec_queue *q,
+ const struct xe_lrc *lrc,
+ const int lrc_idx)
+{
+ if (lrc_idx >= q->width)
+ return -EINVAL;
+
+ if (q->lrc[lrc_idx] != lrc)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int do_eu_control(struct xe_eudebug *d,
+ const struct drm_xe_eudebug_eu_control * const arg,
+ struct drm_xe_eudebug_eu_control __user * const user_ptr)
+{
+ void __user * const bitmask_ptr = u64_to_user_ptr(arg->bitmask_ptr);
+ struct xe_device *xe = d->xe;
+ struct xe_exec_queue *q, *active;
+ struct xe_lrc *lrc;
+ unsigned int hw_attn_size, attn_size;
+ u8 *bits = NULL;
+ u64 seqno;
+ int lrc_idx;
+ int ret;
+
+ if (xe_eudebug_detached(d))
+ return -ENOTCONN;
+
+ /* Accept only hardware reg granularity mask */
+ if (XE_IOCTL_DBG(xe, !IS_ALIGNED(arg->bitmask_size, sizeof(u32))))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, arg->seqno))
+ return -EINVAL;
+
+ q = xe_eudebug_exec_queue_get(d, arg->exec_queue_handle);
+ if (XE_IOCTL_DBG(xe, !q))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, !xe_exec_queue_is_debuggable(q))) {
+ ret = -EINVAL;
+ goto queue_put;
+ }
+
+ lrc = xe_eudebug_find_lrc(d, arg->lrc_handle);
+ if (XE_IOCTL_DBG(xe, !lrc)) {
+ ret = -EINVAL;
+ goto queue_put;
+ }
+
+ if (!xe_pm_runtime_get_if_active(xe)) {
+ ret = -EIO;
+ goto queue_put;
+ }
+
+ active = xe_gt_runalone_active_queue_get(q->gt, &lrc_idx);
+ if (XE_IOCTL_DBG(xe, IS_ERR(active))) {
+ ret = PTR_ERR(active);
+ goto out_pm;
+ }
+
+ if (XE_IOCTL_DBG(xe, q != active)) {
+ ret = -EBUSY;
+ goto active_put;
+ }
+
+ ret = check_lrc_sanity(q, lrc, lrc_idx);
+ if (XE_IOCTL_DBG(xe, ret))
+ goto active_put;
+
+ hw_attn_size = xe_gt_eu_attention_bitmap_size(q->gt);
+ attn_size = arg->bitmask_size;
+
+ if (attn_size > hw_attn_size)
+ attn_size = hw_attn_size;
+
+ if (attn_size > 0) {
+ bits = kmalloc(attn_size, GFP_KERNEL);
+ if (!bits) {
+ ret = -ENOMEM;
+ goto active_put;
+ }
+
+ if (copy_from_user(bits, bitmask_ptr, attn_size)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+ }
+
+ ret = -EINVAL;
+ mutex_lock(&xe->eudebug.lock);
+
+ switch (arg->cmd) {
+ case DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL:
+ /* Make sure we dont promise anything but interrupting all */
+ if (!attn_size)
+ ret = d->ops->interrupt_all(d, active, lrc);
+ else
+ ret = -EINVAL;
+ break;
+ case DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED:
+ ret = d->ops->stopped(d, active, lrc, bits, attn_size);
+ break;
+ case DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME:
+ ret = d->ops->resume(d, active, lrc, bits, attn_size);
+ break;
+ default:
+ break;
+ }
+
+ if (ret == 0)
+ seqno = atomic_long_inc_return(&d->events.seqno);
+
+ mutex_unlock(&xe->eudebug.lock);
+
+ if (ret)
+ goto out_free;
+
+ if (put_user(seqno, &user_ptr->seqno)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ if (copy_to_user(bitmask_ptr, bits, attn_size)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ if (hw_attn_size != arg->bitmask_size)
+ if (put_user(hw_attn_size, &user_ptr->bitmask_size))
+ ret = -EFAULT;
+
+out_free:
+ kfree(bits);
+active_put:
+ xe_exec_queue_put(active);
+out_pm:
+ xe_pm_runtime_put(xe);
+queue_put:
+ xe_exec_queue_put(q);
+
+ return ret;
+}
+
+static int xe_eu_control_interrupt_all(struct xe_eudebug *d,
+ struct xe_exec_queue *active,
+ struct xe_lrc *lrc)
+{
+ unsigned int fw_ref = 0;
+ u32 lrc_hw, lrc_hw_post;
+ u32 td_ctl;
+ int err = -EINVAL;
+
+ fw_ref = xe_force_wake_get(gt_to_fw(active->gt), active->hwe->domain);
+ if (!fw_ref) {
+ err = -ETIMEDOUT;
+ goto out;
+ }
+
+ /* Additional check just before issuing MMIO writes */
+ err = read_hw_lrca_fw(active->hwe, &lrc_hw);
+ if (err)
+ goto out;
+
+ if (!lrca_equals(lower_32_bits(xe_lrc_descriptor(lrc)), lrc_hw)) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ td_ctl = xe_gt_mcr_unicast_read_any(active->gt, TD_CTL);
+
+ /* Halt on next thread dispatch */
+ if (!(td_ctl & TD_CTL_FORCE_EXTERNAL_HALT))
+ xe_gt_mcr_multicast_write(active->gt, TD_CTL,
+ td_ctl | TD_CTL_FORCE_EXTERNAL_HALT);
+ else
+ eu_warn(d, "TD_CTL force external halt bit already set!\n");
+
+ /*
+ * The sleep is needed because some interrupts are ignored
+ * by the HW, hence we allow the HW some time to acknowledge
+ * that.
+ */
+ usleep_range(100, 110);
+
+ /* Halt regardless of thread dependencies */
+ if (!(td_ctl & TD_CTL_FORCE_EXCEPTION))
+ xe_gt_mcr_multicast_write(active->gt, TD_CTL,
+ td_ctl | TD_CTL_FORCE_EXCEPTION |
+ TD_CTL_FORCE_EXTERNAL_HALT);
+ else
+ eu_warn(d, "TD_CTL force exception bit already set!\n");
+
+ usleep_range(100, 110);
+
+ xe_gt_mcr_multicast_write(active->gt, TD_CTL, td_ctl &
+ ~(TD_CTL_FORCE_EXTERNAL_HALT | TD_CTL_FORCE_EXCEPTION));
+
+ /*
+ * In case of stopping wrong ctx emit warning.
+ * Nothing else we can do for now.
+ */
+ if (!read_hw_lrca_fw(active->hwe, &lrc_hw_post) &&
+ !lrca_equals(lrc_hw, lrc_hw_post))
+ eu_warn(d, "interrupted wrong context 0x%08x, wanted 0x%08x\n",
+ lrc_hw_post, lrc_hw);
+
+out:
+ if (fw_ref)
+ xe_force_wake_put(gt_to_fw(active->gt), fw_ref);
+
+ return err;
+}
+
+struct ss_iter {
+ struct xe_eudebug *debugger;
+ unsigned int i;
+
+ unsigned int size;
+ u8 *bits;
+};
+
+static int check_attn_mcr(struct xe_gt *gt, void *data,
+ u16 group, u16 instance, bool present)
+{
+ struct ss_iter *iter = data;
+ struct xe_eudebug *d = iter->debugger;
+ unsigned int reg, row;
+
+ for (reg = 0; reg < xe_gt_eu_att_regs(gt); reg++) {
+ for (row = 0; row < XE_GT_EU_ATT_ROWS; row++) {
+ u32 val, cur = 0;
+
+ if (iter->i + sizeof(val) > iter->size)
+ return 0;
+
+ memcpy(&val, &iter->bits[iter->i], sizeof(val));
+ iter->i += sizeof(val);
+
+ if (present)
+ cur = xe_gt_mcr_unicast_read(gt, EU_ATT(reg, row), group, instance);
+
+ if ((val | cur) != cur) {
+ eu_dbg(d,
+ "WRONG CLEAR (%u:%u:%u:%u) EU_ATT_CLR: 0x%08x; EU_ATT: 0x%08x\n",
+ group, instance, reg, row, val, cur);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int clear_attn_mcr(struct xe_gt *gt, void *data,
+ u16 group, u16 instance, bool present)
+{
+ struct ss_iter *iter = data;
+ struct xe_eudebug *d = iter->debugger;
+ unsigned int reg, row;
+
+ for (reg = 0; reg < xe_gt_eu_att_regs(gt); reg++) {
+ for (row = 0; row < XE_GT_EU_ATT_ROWS; row++) {
+ u32 val;
+
+ if (iter->i + sizeof(val) > iter->size)
+ return 0;
+
+ memcpy(&val, &iter->bits[iter->i], sizeof(val));
+ iter->i += sizeof(val);
+
+ if (!val)
+ continue;
+
+ if (present) {
+ xe_gt_mcr_unicast_write(gt, EU_ATT_CLR(reg, row), val,
+ group, instance);
+
+ eu_dbg(d,
+ "EU_ATT_CLR: (%u:%u:%u:%u): 0x%08x\n",
+ group, instance, reg, row, val);
+ } else {
+ eu_dbg(d,
+ "EU_ATT_CLR: (%u:%u:%u:%u): 0x%08x to fused off dss\n",
+ group, instance, reg, row, val);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int xe_eu_control_resume(struct xe_eudebug *d,
+ struct xe_exec_queue *active,
+ struct xe_lrc *lrc,
+ u8 *bits, unsigned int bitmask_size)
+{
+ struct ss_iter iter = {
+ .debugger = d,
+ .i = 0,
+ .size = bitmask_size,
+ .bits = bits
+ };
+
+ /*
+ * hsdes: 18021122357
+ * We need to avoid clearing attention bits that are not set
+ * in order to avoid the EOT hang on PVC.
+ */
+ if (GRAPHICS_VERx100(d->xe) == 1260) {
+ int err;
+
+ err = xe_gt_foreach_dss_group_instance(active->gt, check_attn_mcr, &iter);
+ if (err)
+ return err;
+
+ iter.i = 0;
+ }
+
+ return xe_gt_foreach_dss_group_instance(active->gt, clear_attn_mcr, &iter);
+}
+
+static int xe_eu_control_stopped(struct xe_eudebug *d,
+ struct xe_exec_queue *active,
+ struct xe_lrc *lrc,
+ u8 *bits, unsigned int bitmask_size)
+{
+ return xe_gt_eu_attention_bitmap(active->gt, bits, bitmask_size);
+}
+
+static const struct xe_eudebug_eu_control_ops eu_control = {
+ .interrupt_all = xe_eu_control_interrupt_all,
+ .stopped = xe_eu_control_stopped,
+ .resume = xe_eu_control_resume,
+};
+
+void xe_eudebug_hw_init(struct xe_eudebug *d)
+{
+ d->ops = &eu_control;
+}
+
+long xe_eudebug_eu_control(struct xe_eudebug *d, const u64 arg)
+{
+ struct drm_xe_eudebug_eu_control __user * const user_ptr =
+ u64_to_user_ptr(arg);
+ struct drm_xe_eudebug_eu_control user_arg;
+ struct xe_device *xe = d->xe;
+ int ret;
+
+ if (XE_IOCTL_DBG(xe, !(_IOC_DIR(DRM_XE_EUDEBUG_IOCTL_EU_CONTROL) & _IOC_WRITE)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, !(_IOC_DIR(DRM_XE_EUDEBUG_IOCTL_EU_CONTROL) & _IOC_READ)))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, _IOC_SIZE(DRM_XE_EUDEBUG_IOCTL_EU_CONTROL) != sizeof(user_arg)))
+ return -EINVAL;
+
+ if (copy_from_user(&user_arg,
+ user_ptr,
+ sizeof(user_arg)))
+ return -EFAULT;
+
+ if (XE_IOCTL_DBG(xe, user_arg.flags))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, user_arg.reserved))
+ return -EINVAL;
+
+ if (XE_IOCTL_DBG(xe, IS_SRIOV_VF(xe)))
+ return -EPERM;
+
+ if (!access_ok(u64_to_user_ptr(user_arg.bitmask_ptr), user_arg.bitmask_size))
+ return -EFAULT;
+
+ eu_dbg(d,
+ "eu_control: cmd=%u, flags=0x%x, exec_queue_handle=%llu, bitmask_size=%u\n",
+ user_arg.cmd, user_arg.flags, user_arg.exec_queue_handle,
+ user_arg.bitmask_size);
+
+ ret = do_eu_control(d, &user_arg, user_ptr);
+
+ eu_dbg(d,
+ "eu_control: cmd=%u, flags=0x%x, exec_queue_handle=%llu, bitmask_size=%u ret=%d\n",
+ user_arg.cmd, user_arg.flags, user_arg.exec_queue_handle,
+ user_arg.bitmask_size, ret);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/xe/xe_eudebug_hw.h b/drivers/gpu/drm/xe/xe_eudebug_hw.h
index 23dd55fc7ad9..489ac99b1529 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_hw.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_hw.h
@@ -14,10 +14,17 @@ struct xe_gt;
#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+void xe_eudebug_hw_init(struct xe_eudebug *d);
void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe, bool enable);
+long xe_eudebug_eu_control(struct xe_eudebug *d, const u64 arg);
+
+struct xe_exec_queue *xe_gt_runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx);
+
#else /* CONFIG_DRM_XE_EUDEBUG */
+static inline void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe, bool enable) { }
+
#endif /* CONFIG_DRM_XE_EUDEBUG */
#endif /* _XE_EUDEBUG_HW_H_ */
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 12a4921c8400..2885882ae415 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -19,7 +19,11 @@
#include <uapi/drm/xe_drm_eudebug.h>
struct xe_device;
+struct xe_eudebug;
+struct xe_hw_engine;
struct workqueue_struct;
+struct xe_exec_queue;
+struct xe_lrc;
/**
* enum xe_eudebug_cap_state - eudebug capability state
@@ -69,6 +73,24 @@ struct xe_eudebug_resource {
#define XE_EUDEBUG_RES_TYPE_LRC 2
#define XE_EUDEBUG_RES_TYPE_COUNT (XE_EUDEBUG_RES_TYPE_LRC + 1)
+/**
+ * struct xe_eudebug_eu_control_ops - interface for eu thread
+ * state control backend
+ */
+struct xe_eudebug_eu_control_ops {
+ /** @interrupt_all: interrupts workload active on given hwe */
+ int (*interrupt_all)(struct xe_eudebug *e, struct xe_exec_queue *q,
+ struct xe_lrc *lrc);
+
+ /** @resume: resumes threads reflected by bitmask active on given hwe */
+ int (*resume)(struct xe_eudebug *e, struct xe_exec_queue *q,
+ struct xe_lrc *lrc, u8 *bitmap, unsigned int bitmap_size);
+
+ /** @stopped: returns bitmap reflecting threads which signal attention */
+ int (*stopped)(struct xe_eudebug *e, struct xe_exec_queue *q,
+ struct xe_lrc *lrc, u8 *bitmap, unsigned int bitmap_size);
+};
+
/**
* struct xe_eudebug - Top level struct for eudebug: the connection
*/
@@ -144,6 +166,9 @@ struct xe_eudebug {
/** @acks.tree: pending acks by seqnos */
struct rb_root tree;
} acks;
+
+ /** @ops: operations for eu_control */
+ const struct xe_eudebug_eu_control_ops *ops;
};
#endif /* _XE_EUDEBUG_TYPES_H_ */
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 12e6197230db..e000d41a5e02 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -34,6 +34,7 @@ extern "C" {
#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT _IOW('j', 0x1, struct drm_xe_eudebug_ack)
#define DRM_XE_EUDEBUG_IOCTL_VM_OPEN _IOW('j', 0x2, struct drm_xe_eudebug_vm_open)
+#define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL _IOWR('j', 0x3, struct drm_xe_eudebug_eu_control)
/**
* struct drm_xe_eudebug_event - Base type of event delivered by xe_eudebug.
@@ -296,6 +297,72 @@ struct drm_xe_eudebug_vm_open {
__u64 timeout_ns;
};
+/**
+ * struct drm_xe_eudebug_eu_control - Control EU states
+ *
+ * Issue commands to execution units in hardware.
+ *
+ * With DRM_XE_EUDEBUG_IOCTL_EU_CONTROL debugger can
+ * interrupt all threads on execution units, query thread
+ * state and resume execution.
+ *
+ * :c:member:`drm_xe_eudebug_eu_control.seqno`
+ * will be updated to the timeline point when
+ * the command was issued.
+ *
+ * :c:member:`drm_xe_eudebug_eu_control.cmd` can
+ * be following:
+ *
+ * *DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL*
+ * will instruct hardware to stop all threads on EUs
+ * for exec_queue:lrc. This command takes no bitmask, so
+ * :c:member:`drm_xe_eudebug_eu_control.bitmask_size`
+ * must be set to zero.
+ *
+ * *DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED*
+ * returns the bitmask for threads that are
+ * in so called attention state.
+ *
+ * *DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME*
+ * resumes the threads whose bit is set in the bitmask.
+ *
+ */
+struct drm_xe_eudebug_eu_control {
+ /** @cmd: Command for execution units */
+#define DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL 0
+#define DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED 1
+#define DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME 2
+ __u32 cmd;
+
+ /** @flags: Flags, must be set to zero */
+ __u32 flags;
+
+ /** @seqno: Seqno, must be set to zero */
+ __u64 seqno;
+
+ /** @exec_queue_handle: Exec queue handle for the command */
+ __u64 exec_queue_handle;
+
+ /** @lrc_handle: LRC handle for the command */
+ __u64 lrc_handle;
+
+ /** @reserved: Reserved field, must be set to zero */
+ __u32 reserved;
+
+ /**
+ * @bitmask_size: Bitmask size in bytes
+ *
+ * Only the leading bytes that fit are used. If this differs from
+ * the size the hardware bitmask needs, it is overwritten with that
+ * size on return, so a short buffer can be grown and the command
+ * retried.
+ */
+ __u32 bitmask_size;
+
+ /** @bitmask_ptr: Bitmask pointer, each bit is one thread */
+ __u64 bitmask_ptr;
+};
+
#if defined(__cplusplus)
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 16/27] drm/xe/eudebug: Introduce per device attention scan worker
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (14 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 15/27] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 17/27] drm/xe/eudebug_test: Introduce eudebug live tests Mika Kuoppala
` (16 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Dominik Grzegorzek, Christoph Manszewski, Mika Kuoppala
From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Scan for EU debugging attention bits periodically to detect if some EU
thread has entered the system routine (SIP) due to EU thread exception.
Make the scanning interval 50 times slower when there is no debugger
connection open. Send an attention event whenever we see attention
with a debugger present. If there is no active debugger connection,
reset.
Based on work by the authors and others who worked on attentions in
i915.
v2: - use xa_array for files
- null ptr deref fix for non-debugged context (Dominik)
- checkpatch (Tilak)
- use discovery_lock during list traversal
v3: - engine status per gen improvements, force_wake ref
- __counted_by (Mika)
v4: - attention register naming (Dominik)
v5: - free event on error (Mika)
v6: - annotate data race on extending the poll interval (Mika)
v7: - sysfs race fix, return error instead of XA_WARN_ON (Sashiko)
- attention_poll_stop to async to avoid deadlock (lockdep)
v8: - don't send if there are no attentions
- stop before cancel (Claude)
- use a device workqueue instead of system_dfl_wq (Maciej, Claude)
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
Documentation/gpu/xe/xe_eudebug.rst | 3 +
drivers/gpu/drm/xe/xe_device_types.h | 9 ++
drivers/gpu/drm/xe/xe_eudebug.c | 214 ++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_eudebug_types.h | 2 +-
include/uapi/drm/xe_drm_eudebug.h | 34 ++++
5 files changed, 261 insertions(+), 1 deletion(-)
diff --git a/Documentation/gpu/xe/xe_eudebug.rst b/Documentation/gpu/xe/xe_eudebug.rst
index 76f255c7da73..29f70b023326 100644
--- a/Documentation/gpu/xe/xe_eudebug.rst
+++ b/Documentation/gpu/xe/xe_eudebug.rst
@@ -67,6 +67,9 @@ Resource Event Types
.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
:identifiers: drm_xe_eudebug_event_vm_bind_ufence
+.. kernel-doc:: include/uapi/drm/xe_drm_eudebug.h
+ :identifiers: drm_xe_eudebug_event_eu_attention
+
VM Access
=========
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index c62e774495fd..90ef9ba684d7 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -622,6 +622,15 @@ struct xe_device {
/** @eudebug.ufence_wq: used for deferred ufence signalling */
struct workqueue_struct *ufence_wq;
+
+ /** @eudebug.attention_wq: used for the attention poll work */
+ struct workqueue_struct *attention_wq;
+
+ /** @eudebug.attention_dwork: attention poll work */
+ struct delayed_work attention_dwork;
+
+ /** @eudebug.send_attentions: handle attentions or ignore */
+ bool send_attentions;
} eudebug;
#endif
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index ecd6d4c5d63c..9cb02024bf51 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -22,6 +22,7 @@
#include "xe_eudebug_vm.h"
#include "xe_exec_queue.h"
#include "xe_gt.h"
+#include "xe_gt_debug.h"
#include "xe_hw_engine.h"
#include "xe_macros.h"
#include "xe_pm.h"
@@ -1928,6 +1929,190 @@ static const struct file_operations fops = {
.compat_ioctl = xe_eudebug_ioctl,
};
+static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q,
+ int lrc_idx, void *bitmap, unsigned int size)
+{
+ struct drm_xe_eudebug_event_eu_attention *e;
+ struct drm_xe_eudebug_event *event;
+ const u32 sz = struct_size(e, bitmask, size);
+ int h_queue, h_lrc;
+ int ret;
+
+ if (lrc_idx < 0 || lrc_idx >= q->width)
+ return -EINVAL;
+
+ h_queue = find_handle(d, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q);
+ if (h_queue < 0)
+ return h_queue;
+
+ h_lrc = find_handle(d, XE_EUDEBUG_RES_TYPE_LRC, q->lrc[lrc_idx]);
+ if (h_lrc < 0)
+ return h_lrc;
+
+ spin_lock(&d->events.lock);
+ event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION, 0,
+ DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, sz);
+
+ event->seqno = atomic_long_inc_return(&d->events.seqno);
+ e = cast_event(e, event);
+ e->exec_queue_handle = h_queue;
+ e->lrc_handle = h_lrc;
+ e->bitmask_size = size;
+
+ memcpy(e->bitmask, bitmap, size);
+ ret = xe_eudebug_queue_event(d, event);
+ spin_unlock(&d->events.lock);
+
+ return ret;
+}
+
+static int xe_send_gt_attention(struct xe_gt *gt, void *bitmap, unsigned int size)
+{
+ struct xe_eudebug *d;
+ struct xe_exec_queue *q;
+ int ret, lrc_idx;
+
+ q = xe_gt_runalone_active_queue_get(gt, &lrc_idx);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
+
+ if (!xe_exec_queue_is_debuggable(q)) {
+ ret = -EPERM;
+ goto err_exec_queue_put;
+ }
+
+ d = xe_eudebug_get_nolock(q->vm->xef);
+ if (!d) {
+ ret = -ENOTCONN;
+ goto err_exec_queue_put;
+ }
+
+ if (!completion_done(&d->discovery)) {
+ eu_dbg(d, "discovery not yet done\n");
+ ret = -EBUSY;
+ goto err_eudebug_put;
+ }
+
+ ret = send_attention_event(d, q, lrc_idx, bitmap, size);
+ if (ret)
+ xe_eudebug_disconnect(d, ret);
+
+err_eudebug_put:
+ xe_eudebug_put(d);
+err_exec_queue_put:
+ xe_exec_queue_put(q);
+
+ return ret;
+}
+
+static int xe_eudebug_handle_gt_attention(struct xe_gt *gt)
+{
+ struct xe_device *xe = gt_to_xe(gt);
+ const u32 size = xe_gt_eu_attention_bitmap_size(gt);
+ int ret;
+ void *bitmask;
+
+ if (!READ_ONCE(xe->eudebug.send_attentions))
+ return 0;
+
+ ret = xe_gt_eu_threads_needing_attention(gt);
+ if (ret <= 0)
+ return ret;
+
+ /* If we fail at this time, assume we manage to send eventually */
+ bitmask = kvzalloc(size, GFP_KERNEL);
+ if (!bitmask)
+ return 0;
+
+ ret = xe_gt_eu_attention_bitmap(gt, bitmask, size);
+ if (ret)
+ goto out;
+
+ if (bitmap_empty(bitmask, size * BITS_PER_BYTE))
+ goto out;
+
+ ret = xe_send_gt_attention(gt, bitmask, size);
+out:
+ kvfree(bitmask);
+
+ /* Discovery in progress, fake it */
+ if (ret == -EBUSY)
+ return 0;
+
+ return ret;
+}
+
+static void handle_attention_fail(struct xe_gt *gt, int gt_id, int ret)
+{
+ /* TODO: error capture */
+ drm_err_ratelimited(>_to_xe(gt)->drm,
+ "gt:%d unable to handle eu attention ret = %d\n",
+ gt_id, ret);
+
+ xe_gt_reset_async(gt);
+}
+
+static void attention_poll_work(struct work_struct *work)
+{
+ struct xe_device *xe = container_of(work, typeof(*xe),
+ eudebug.attention_dwork.work);
+ const unsigned int poll_interval_ms = 100;
+ long delay = msecs_to_jiffies(poll_interval_ms);
+ struct xe_gt *gt;
+ u8 gt_id;
+
+ if (!READ_ONCE(xe->eudebug.send_attentions))
+ return;
+
+ if (xe_pm_runtime_get_if_active(xe)) {
+ for_each_gt(gt, xe, gt_id) {
+ int ret;
+
+ if (gt->info.type != XE_GT_TYPE_MAIN)
+ continue;
+
+ ret = xe_eudebug_handle_gt_attention(gt);
+ if (ret)
+ handle_attention_fail(gt, gt_id, ret);
+ }
+
+ xe_pm_runtime_put(xe);
+ }
+
+ /* Non critical if we get it wrong, just longer delay on race */
+ if (data_race(list_empty(&xe->eudebug.targets)))
+ delay = 5 * HZ;
+
+ if (delay >= HZ)
+ delay = round_jiffies_up_relative(delay);
+
+ if (READ_ONCE(xe->eudebug.send_attentions))
+ queue_delayed_work(xe->eudebug.attention_wq,
+ &xe->eudebug.attention_dwork, delay);
+}
+
+/*
+ * The cancel is deliberately the async one. This runs under
+ * xe->eudebug.lock and attention_poll_work() reaches that same lock
+ * through xe_gt_runalone_active_queue_get(), so waiting for the worker
+ * here would deadlock.
+ *
+ * Clearing send_attentions first is therefore what actually stops the
+ * poll: a worker already past its own requeue check can arm the work one
+ * more time, and that wakeup returns at the top guard without rearming.
+ */
+static void xe_eudebug_attention_poll_stop(struct xe_device *xe)
+{
+ WRITE_ONCE(xe->eudebug.send_attentions, false);
+ cancel_delayed_work(&xe->eudebug.attention_dwork);
+}
+
+static void xe_eudebug_attention_poll_start(struct xe_device *xe)
+{
+ WRITE_ONCE(xe->eudebug.send_attentions, true);
+ mod_delayed_work(xe->eudebug.attention_wq, &xe->eudebug.attention_dwork, 0);
+}
+
static int
xe_eudebug_connect(struct xe_device *xe,
struct drm_file *drm_file,
@@ -2017,6 +2202,7 @@ xe_eudebug_connect(struct xe_device *xe,
kref_get(&d->ref); /* for discovery */
queue_work(xe->eudebug.discovery_wq, &d->discovery_work);
+ xe_eudebug_attention_poll_start(xe);
eu_dbg(d, "connected session %lld", d->session);
@@ -2090,6 +2276,11 @@ int xe_eudebug_enable(struct xe_device *xe, bool enable)
WRITE_ONCE(xe->eudebug.cap_state, enable ?
XE_EUDEBUG_CAP_ENABLED : XE_EUDEBUG_CAP_DISABLED);
+ if (enable)
+ xe_eudebug_attention_poll_start(xe);
+ else
+ xe_eudebug_attention_poll_stop(xe);
+
return 0;
}
@@ -2131,12 +2322,24 @@ static void xe_eudebug_sysfs_fini(void *arg)
&dev_attr_enable_eudebug.attr);
}
+static void xe_eudebug_fini(struct drm_device *dev, void *__unused)
+{
+ struct xe_device *xe = to_xe_device(dev);
+
+ xe_assert(xe, list_empty(&xe->eudebug.targets));
+
+ xe_eudebug_attention_poll_stop(xe);
+ cancel_delayed_work_sync(&xe->eudebug.attention_dwork);
+}
+
void xe_eudebug_init_early(struct xe_device *xe)
{
struct drm_device *dev = &xe->drm;
int err;
INIT_LIST_HEAD(&xe->eudebug.targets);
+ INIT_DELAYED_WORK(&xe->eudebug.attention_dwork, attention_poll_work);
+
WRITE_ONCE(xe->eudebug.cap_state, XE_EUDEBUG_CAP_NOT_SUPPORTED);
err = drmm_mutex_init(dev, &xe->eudebug.lock);
@@ -2174,6 +2377,17 @@ void xe_eudebug_init(struct xe_device *xe)
goto out_err;
xe->eudebug.ufence_wq = wq;
+ wq = drmm_alloc_ordered_workqueue(dev, "xe-eudebug-attn", 0);
+ if (IS_ERR(wq)) {
+ err = PTR_ERR(wq);
+ goto out_err;
+ }
+ xe->eudebug.attention_wq = wq;
+
+ err = drmm_add_action_or_reset(&xe->drm, xe_eudebug_fini, NULL);
+ if (err)
+ goto out_err;
+
err = sysfs_create_file(&dev->dev->kobj,
&dev_attr_enable_eudebug.attr);
if (err)
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 2885882ae415..5d3f190baecd 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -38,7 +38,7 @@ enum xe_eudebug_cap_state {
XE_EUDEBUG_CAP_ENABLED,
};
-#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
+#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
/**
* struct xe_eudebug_handle - eudebug resource handle
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index e000d41a5e02..57ff3d90ac29 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -73,6 +73,7 @@ struct drm_xe_eudebug_event {
#define DRM_XE_EUDEBUG_EVENT_VM_BIND 4
#define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_DEBUG_DATA 5
#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE 6
+#define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION 7
/** @flags: Flags */
__u16 flags;
@@ -363,6 +364,39 @@ struct drm_xe_eudebug_eu_control {
__u64 bitmask_ptr;
};
+/**
+ * struct drm_xe_eudebug_event_eu_attention - EU Attention Event
+ *
+ * Whenever there is any thread in halted/attentions state, this
+ * event will be delivered. The event will be delivered periodically
+ * until there are no attentions detected.
+ *
+ */
+struct drm_xe_eudebug_event_eu_attention {
+ /** @base: base event */
+ struct drm_xe_eudebug_event base;
+
+ /** @exec_queue_handle: Exec queue handle for the attentions */
+ __u64 exec_queue_handle;
+
+ /** @lrc_handle: LRC handle for the attentions */
+ __u64 lrc_handle;
+
+ /**
+ * @flags: Reserved for future use, reads as zero
+ *
+ * Event wide flags are carried in
+ * :c:member:`drm_xe_eudebug_event_eu_attention.base`.
+ */
+ __u32 flags;
+
+ /** @bitmask_size: Bitmask size in bytes for bitmask[] */
+ __u32 bitmask_size;
+
+ /** @bitmask: Attention bits, one per thread */
+ __u8 bitmask[];
+};
+
#if defined(__cplusplus)
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 17/27] drm/xe/eudebug_test: Introduce eudebug live tests
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (15 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 16/27] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 18/27] drm/xe: Implement SR-IOV and eudebug exclusivity Mika Kuoppala
` (15 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Christoph Manszewski, Michal Wajdeczko, Mika Kuoppala
From: Christoph Manszewski <christoph.manszewski@intel.com>
Introduce a kunit test for eudebug. For now it checks the dynamic
application of WAs.
v2: adapt to removal of call_for_each_device (Mika)
v3: s/FW_RENDER/FORCEWAKE_ALL (Mika)
v4: enforce kunit rules and naming (Michal)
v5: restore hw state if enable error (Sashiko)
drop XE_MCR_REG def (Claude)
fail if hw state can't be restored (Claude)
Assisted-by: Claude:claude-opus-4-8
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/tests/xe_eudebug_test.c | 224 ++++++++++++++++++++
drivers/gpu/drm/xe/tests/xe_live_test_mod.c | 5 +
drivers/gpu/drm/xe/xe_eudebug.c | 4 +
3 files changed, 233 insertions(+)
create mode 100644 drivers/gpu/drm/xe/tests/xe_eudebug_test.c
diff --git a/drivers/gpu/drm/xe/tests/xe_eudebug_test.c b/drivers/gpu/drm/xe/tests/xe_eudebug_test.c
new file mode 100644
index 000000000000..a207840fdb91
--- /dev/null
+++ b/drivers/gpu/drm/xe/tests/xe_eudebug_test.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0 AND MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <kunit/visibility.h>
+
+#include "regs/xe_gt_regs.h"
+#include "xe_force_wake.h"
+#include "xe_gt_mcr.h"
+#include "xe_mmio.h"
+#include "tests/xe_kunit_helpers.h"
+#include "tests/xe_pci_test.h"
+#include "tests/xe_test.h"
+
+static const char *reg_to_str(struct xe_reg reg)
+{
+ if (reg.raw == TD_CTL.__reg.raw)
+ return "TD_CTL";
+ else if (reg.raw == ROW_CHICKEN.__reg.raw)
+ return "ROW_CHICKEN";
+ else if (reg.raw == ROW_CHICKEN2.__reg.raw)
+ return "ROW_CHICKEN2";
+ else if (reg.raw == ROW_CHICKEN3.__reg.raw)
+ return "ROW_CHICKEN3";
+ else
+ return "UNKNOWN REG";
+}
+
+static u32 get_reg_mask(struct xe_device *xe, struct xe_reg reg, struct kunit *test)
+{
+ u32 val = 0;
+
+ if (reg.raw == TD_CTL.__reg.raw) {
+ val = TD_CTL_BREAKPOINT_ENABLE |
+ TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
+ TD_CTL_FEH_AND_FEE_ENABLE;
+ if (GRAPHICS_VERx100(xe) >= 1250)
+ val |= TD_CTL_GLOBAL_DEBUG_ENABLE;
+ } else if (reg.raw == ROW_CHICKEN.__reg.raw) {
+ val = STALL_DOP_GATING_DISABLE;
+ } else if (reg.raw == ROW_CHICKEN2.__reg.raw) {
+ val = XEHPC_DISABLE_BTB;
+ } else if (reg.raw == ROW_CHICKEN3.__reg.raw) {
+ val = XE2_EUPEND_CHK_FLUSH_DIS;
+ } else {
+ KUNIT_FAIL(test, "Invalid register selection: 0x%x\n", reg.raw);
+ }
+
+ return val;
+}
+
+static u32 get_reg_expected(struct xe_device *xe, struct xe_reg reg,
+ bool enable_eudebug, struct kunit *test)
+{
+ const u32 reg_mask = get_reg_mask(xe, reg, test);
+ u32 reg_bits = 0;
+
+ /*
+ * XXX ROW_CHICKEN3 is expected set either way, and it is the odd one
+ * out here: xe_eudebug_init_hw_engine() programs ROW_CHICKEN,
+ * ROW_CHICKEN2 and TD_CTL, but never ROW_CHICKEN3.
+ * XE2_EUPEND_CHK_FLUSH_DIS is set by WA 14020338487 in xe_wa.c on all
+ * Xe2 render and compute engines, with no reference to eudebug, so as
+ * written this arm asserts that an unrelated workaround is applied.
+ *
+ * Pending a check against the hardware documentation on whether
+ * eupend flush checking has to stay disabled for eudebug.
+ */
+ if (enable_eudebug || reg.raw == ROW_CHICKEN3.__reg.raw)
+ reg_bits = reg_mask;
+ else
+ reg_bits = 0;
+
+ return reg_bits;
+}
+
+static void check_reg(struct xe_gt *gt, bool enable_eudebug,
+ struct xe_reg reg, struct kunit *test)
+{
+ struct xe_device *xe = gt_to_xe(gt);
+ const u32 reg_bits_expected = get_reg_expected(xe, reg, enable_eudebug, test);
+ const u32 reg_mask = get_reg_mask(xe, reg, test);
+ u32 reg_bits = 0;
+
+ if (reg.mcr)
+ reg_bits = xe_gt_mcr_unicast_read_any(gt, (struct xe_reg_mcr){.__reg = reg});
+ else
+ reg_bits = xe_mmio_read32(>->mmio, reg);
+
+ reg_bits &= reg_mask;
+
+ KUNIT_EXPECT_EQ_MSG(test, reg_bits_expected, reg_bits,
+ "Invalid bits set for %s\n", reg_to_str(reg));
+}
+
+static void __check_regs(struct xe_gt *gt, bool enable_eudebug, struct kunit *test)
+{
+ struct xe_device *xe = gt_to_xe(gt);
+
+ if (GRAPHICS_VERx100(xe) >= 1200)
+ check_reg(gt, enable_eudebug, TD_CTL.__reg, test);
+
+ if (GRAPHICS_VERx100(xe) >= 1250 && GRAPHICS_VERx100(xe) <= 1274)
+ check_reg(gt, enable_eudebug, ROW_CHICKEN.__reg, test);
+
+ if (xe->info.platform == XE_PVC)
+ check_reg(gt, enable_eudebug, ROW_CHICKEN2.__reg, test);
+
+ if (GRAPHICS_VERx100(xe) >= 2000 && GRAPHICS_VERx100(xe) <= 2004)
+ check_reg(gt, enable_eudebug, ROW_CHICKEN3.__reg, test);
+}
+
+static void check_regs(struct xe_device *xe, bool enable_eudebug, struct kunit *test)
+{
+ struct xe_gt *gt;
+ unsigned int fw_ref;
+ u8 id;
+
+ kunit_printk(KERN_DEBUG, test, "Check regs for eudebug %s\n",
+ enable_eudebug ? "enabled" : "disabled");
+
+ for_each_gt(gt, xe, id) {
+ if (xe_gt_is_media_type(gt))
+ continue;
+
+ /* XXX: Figure out per platform proper domain */
+ fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
+ KUNIT_ASSERT_TRUE_MSG(test, fw_ref, "Forcewake failed.\n");
+
+ __check_regs(gt, enable_eudebug, test);
+
+ xe_force_wake_put(gt_to_fw(gt), fw_ref);
+ }
+}
+
+struct eudebug_state_restore {
+ struct xe_device *xe;
+ struct kunit *test;
+ bool enabled;
+};
+
+static void restore_eudebug_state(void *arg)
+{
+ struct eudebug_state_restore *r = arg;
+
+ KUNIT_EXPECT_EQ_MSG(r->test, 0, xe_eudebug_enable(r->xe, r->enabled),
+ "Failed to restore eudebug to %s\n",
+ r->enabled ? "enabled" : "disabled");
+}
+
+static void toggle_reg(struct kunit *test)
+{
+ struct xe_device *xe = test->priv;
+ const bool enable_eudebug = xe_eudebug_is_enabled(xe);
+ struct eudebug_state_restore *restore;
+ int ret;
+
+ /* Covers an SR-IOV VF too, xe_eudebug_init() marks one unsupported */
+ if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
+ kunit_skip(test, "eudebug not supported\n");
+
+ kunit_printk(KERN_DEBUG, test, "Test eudebug WAs for graphics version: %u\n",
+ GRAPHICS_VERx100(xe));
+
+ check_regs(xe, enable_eudebug, test);
+
+ /* Nothing to restore until the first toggle below */
+ restore = kunit_kzalloc(test, sizeof(*restore), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, restore);
+ restore->xe = xe;
+ restore->test = test;
+ restore->enabled = enable_eudebug;
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test, restore_eudebug_state,
+ restore));
+
+ ret = xe_eudebug_enable(xe, !enable_eudebug);
+ if (ret == -EBUSY)
+ kunit_skip(test, "eudebug toggle busy\n");
+ KUNIT_ASSERT_EQ(test, 0, ret);
+
+ check_regs(xe, !enable_eudebug, test);
+
+ ret = xe_eudebug_enable(xe, enable_eudebug);
+ KUNIT_ASSERT_EQ(test, 0, ret);
+ check_regs(xe, enable_eudebug, test);
+}
+
+static bool xe_eudebug_has_regs(struct xe_device *xe)
+{
+ return GRAPHICS_VERx100(xe) >= 1200;
+}
+
+static int xe_eudebug_test_init(struct kunit *test)
+{
+ struct xe_device *xe;
+ int ret;
+
+ ret = xe_kunit_helper_xe_device_live_test_init(test);
+ if (ret)
+ return ret;
+
+ xe = test->priv;
+ kunit_info(test, "running on graphics version: %u\n", GRAPHICS_VERx100(xe));
+
+ if (!xe_eudebug_has_regs(xe))
+ kunit_skip(test, "hardware not supported: 0x%x\n", GRAPHICS_VERx100(xe));
+
+ return 0;
+}
+
+static struct kunit_case xe_eudebug_tests[] = {
+ KUNIT_CASE_PARAM(toggle_reg, xe_pci_live_device_gen_param),
+ {}
+};
+
+VISIBLE_IF_KUNIT
+struct kunit_suite xe_eudebug_test_suite = {
+ .name = "xe_eudebug",
+ .test_cases = xe_eudebug_tests,
+ .init = xe_eudebug_test_init,
+};
+EXPORT_SYMBOL_IF_KUNIT(xe_eudebug_test_suite);
diff --git a/drivers/gpu/drm/xe/tests/xe_live_test_mod.c b/drivers/gpu/drm/xe/tests/xe_live_test_mod.c
index 87cd7db20e5f..6d92aee38509 100644
--- a/drivers/gpu/drm/xe/tests/xe_live_test_mod.c
+++ b/drivers/gpu/drm/xe/tests/xe_live_test_mod.c
@@ -25,6 +25,11 @@ kunit_test_suite(xe_guc_g2g_test_suite);
kunit_test_suite(xe_bo_page_size_alloc_suite);
#endif
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+extern struct kunit_suite xe_eudebug_test_suite;
+kunit_test_suite(xe_eudebug_test_suite);
+#endif
+
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("xe live kunit tests");
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 9cb02024bf51..470246af9810 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -2427,3 +2427,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
return xe_eudebug_connect(xe, file, param);
}
+
+#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
+#include "tests/xe_eudebug_test.c"
+#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 18/27] drm/xe: Implement SR-IOV and eudebug exclusivity
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (16 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 17/27] drm/xe/eudebug_test: Introduce eudebug live tests Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:32 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 19/27] drm/xe: Add xe_client_debugfs and introduce debug_data file Mika Kuoppala
` (14 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Christoph Manszewski, Mika Kuoppala
From: Christoph Manszewski <christoph.manszewski@intel.com>
EU debug functionality relies on access to specific mmio registers.
Since VFs don't have access to those registers and in order to avoid
interference with VFs, make SR-IOV and eudebug functionality exclusive.
I.e. don't allow enabling eudebug in VF mode and don't allow enabling
eudebug when any VFs are enabled. Likewise, don't allow enabling
VFs when eudebug is enabled.
v2: initialize lock early (Sashiko)
v3: say why eudebug was refused (Claude)
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/tests/xe_eudebug_test.c | 3 +++
drivers/gpu/drm/xe/xe_eudebug.c | 24 ++++++++++++++++++++--
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/tests/xe_eudebug_test.c b/drivers/gpu/drm/xe/tests/xe_eudebug_test.c
index a207840fdb91..0ed2de04ba83 100644
--- a/drivers/gpu/drm/xe/tests/xe_eudebug_test.c
+++ b/drivers/gpu/drm/xe/tests/xe_eudebug_test.c
@@ -160,6 +160,9 @@ static void toggle_reg(struct kunit *test)
if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
kunit_skip(test, "eudebug not supported\n");
+ if (IS_SRIOV_VF(xe))
+ kunit_skip(test, "eudebug not available in SR-IOV VF mode\n");
+
kunit_printk(KERN_DEBUG, test, "Test eudebug WAs for graphics version: %u\n",
GRAPHICS_VERx100(xe));
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 470246af9810..2c8d8fc82898 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -26,6 +26,7 @@
#include "xe_hw_engine.h"
#include "xe_macros.h"
#include "xe_pm.h"
+#include "xe_sriov_pf.h"
#include "xe_sync.h"
#include "xe_vm.h"
@@ -2245,6 +2246,7 @@ bool xe_eudebug_is_enabled(struct xe_device *xe)
int xe_eudebug_enable(struct xe_device *xe, bool enable)
{
struct xe_gt *gt;
+ int ret;
int i;
u8 id;
@@ -2259,6 +2261,14 @@ int xe_eudebug_enable(struct xe_device *xe, bool enable)
if (enable == xe_eudebug_is_enabled(xe))
return 0;
+ if (enable && IS_SRIOV_PF(xe)) {
+ ret = xe_sriov_pf_lockdown(xe);
+ if (ret) {
+ drm_dbg(&xe->drm, "Can't enable eudebug: VFs are enabled\n");
+ return ret;
+ }
+ }
+
xe_pm_runtime_get(xe);
for_each_gt(gt, xe, id) {
for (i = 0; i < ARRAY_SIZE(gt->hw_engines); i++) {
@@ -2276,10 +2286,14 @@ int xe_eudebug_enable(struct xe_device *xe, bool enable)
WRITE_ONCE(xe->eudebug.cap_state, enable ?
XE_EUDEBUG_CAP_ENABLED : XE_EUDEBUG_CAP_DISABLED);
- if (enable)
+ if (enable) {
xe_eudebug_attention_poll_start(xe);
- else
+ } else {
+ if (IS_SRIOV_PF(xe))
+ xe_sriov_pf_end_lockdown(xe);
+
xe_eudebug_attention_poll_stop(xe);
+ }
return 0;
}
@@ -2359,6 +2373,11 @@ void xe_eudebug_init(struct xe_device *xe)
if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
return;
+ if (IS_SRIOV_VF(xe)) {
+ drm_info(&xe->drm, "eudebug not available in SR-IOV VF mode\n");
+ goto out_not_supported;
+ }
+
wq = drmm_alloc_ordered_workqueue(dev, "xe-eudebug-discovery", 0);
if (IS_ERR(wq)) {
err = PTR_ERR(wq);
@@ -2404,6 +2423,7 @@ void xe_eudebug_init(struct xe_device *xe)
out_err:
drm_warn(&xe->drm, "eudebug disabled, init fail: %d\n", err);
+out_not_supported:
WRITE_ONCE(xe->eudebug.cap_state, XE_EUDEBUG_CAP_NOT_SUPPORTED);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 19/27] drm/xe: Add xe_client_debugfs and introduce debug_data file
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (17 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 18/27] drm/xe: Implement SR-IOV and eudebug exclusivity Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 20/27] drm/xe/pagefault: export pagefault queue properties Mika Kuoppala
` (13 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun,
Christoph Manszewski, Sunil Khatri, Michal Wajdeczko,
Mika Kuoppala
From: Christoph Manszewski <christoph.manszewski@intel.com>
Create a debug_data file for each xe file/client. It lists all mapped
debug data and mimics '/proc/pid/maps'.
Each line represents a single mapping and has the following format:
<vm id> <begin>-<end> <flags> <offset> <pathname>
v2: trim len in debug_data_read() (Sashiko)
v3: - fix return len, avoid rewind (Sashiko)
- use guard, kdoc, cleanups (Michal)
- drop client ref after seq_file is done (Claude)
Assisted-by: Claude:claude-opus-4-8
Cc: Sunil Khatri <sunil.khatri@amd.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/Makefile | 3 +-
drivers/gpu/drm/xe/xe_client_debugfs.c | 108 +++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_client_debugfs.h | 17 ++++
drivers/gpu/drm/xe/xe_device.c | 3 +
4 files changed, 130 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/xe/xe_client_debugfs.c
create mode 100644 drivers/gpu/drm/xe/xe_client_debugfs.h
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 5cdf47f79aa4..4a882e34bbe8 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -358,7 +358,8 @@ ifeq ($(CONFIG_DRM_FBDEV_EMULATION),y)
endif
ifeq ($(CONFIG_DEBUG_FS),y)
- xe-y += xe_debugfs.o \
+ xe-y += xe_client_debugfs.o \
+ xe_debugfs.o \
xe_gt_debugfs.o \
xe_gt_sriov_vf_debugfs.o \
xe_gt_stats.o \
diff --git a/drivers/gpu/drm/xe/xe_client_debugfs.c b/drivers/gpu/drm/xe/xe_client_debugfs.c
new file mode 100644
index 000000000000..919738c4893b
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_client_debugfs.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "xe_client_debugfs.h"
+#include "xe_debug_data.h"
+#include "xe_debug_data_types.h"
+#include "xe_device.h"
+#include "xe_device_types.h"
+#include "xe_vm_types.h"
+
+static void debug_data_show_vm(struct seq_file *m, unsigned long vm_id,
+ struct xe_vm *vm)
+{
+ struct xe_debug_data *dd;
+
+ guard(mutex)(&vm->debug_data.lock);
+
+ list_for_each_entry(dd, &vm->debug_data.list, link) {
+ /* Format: <vm id> <begin>-<end> <flags> <offset>\t<pathname> */
+ seq_printf(m, "%lu 0x%llx-0x%llx 0x%llx 0x%llx\t",
+ vm_id,
+ dd->addr,
+ dd->addr + dd->range,
+ dd->flags,
+ dd->offset);
+
+ if (dd->flags & DRM_XE_VM_BIND_DEBUG_DATA_FLAG_PSEUDO)
+ seq_puts(m, xe_debug_data_pseudo_path_to_string(dd->pseudopath));
+ else
+ /*
+ * The pathname originates from userspace; escape it the
+ * same way seq_path() does for /proc/pid/maps so that a
+ * newline cannot break the line oriented format.
+ */
+ seq_escape(m, dd->pathname, "\n");
+
+ seq_putc(m, '\n');
+ }
+}
+
+static int debug_data_show(struct seq_file *m, void *data)
+{
+ struct xe_file *xef = m->private;
+ unsigned long vm_id;
+ struct xe_vm *vm;
+
+ guard(mutex)(&xef->vm.lock);
+
+ xa_for_each(&xef->vm.xa, vm_id, vm)
+ debug_data_show_vm(m, vm_id, vm);
+
+ return 0;
+}
+
+static int debug_data_open(struct inode *inode, struct file *file)
+{
+ struct xe_file *xef = inode->i_private;
+ int ret;
+
+ ret = single_open(file, debug_data_show, xef);
+ if (ret)
+ return ret;
+
+ xe_file_get(xef);
+
+ return 0;
+}
+
+static int debug_data_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = file->private_data;
+ struct xe_file *xef = m->private;
+ int ret;
+
+ ret = single_release(inode, file);
+ xe_file_put(xef);
+
+ return ret;
+}
+
+static const struct file_operations debug_data_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_data_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = debug_data_release,
+};
+
+/**
+ * xe_client_debugfs_register() - Register the per-client debugfs files
+ * @xef: The xe file to register the files for
+ *
+ * Create the debugfs entries exposed under the DRM client directory of @xef.
+ * Called from xe_file_open(), after DRM has created the client directory.
+ *
+ * The files are removed by drm_file_free() before ->postclose runs, so they
+ * do not need to be torn down by the driver.
+ */
+void xe_client_debugfs_register(struct xe_file *xef)
+{
+ debugfs_create_file("debug_data", 0444, xef->drm->debugfs_client, xef,
+ &debug_data_fops);
+}
diff --git a/drivers/gpu/drm/xe/xe_client_debugfs.h b/drivers/gpu/drm/xe/xe_client_debugfs.h
new file mode 100644
index 000000000000..1211433a4efe
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_client_debugfs.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_CLIENT_DEBUGFS_H_
+#define _XE_CLIENT_DEBUGFS_H_
+
+struct xe_file;
+
+#ifdef CONFIG_DEBUG_FS
+void xe_client_debugfs_register(struct xe_file *xef);
+#else
+static inline void xe_client_debugfs_register(struct xe_file *xef) { }
+#endif
+
+#endif /* _XE_CLIENT_DEBUGFS_H_ */
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 01254c73b2c6..f901cf7b7301 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -25,6 +25,7 @@
#include "regs/xe_regs.h"
#include "xe_bo.h"
#include "xe_bo_evict.h"
+#include "xe_client_debugfs.h"
#include "xe_configfs.h"
#include "xe_debugfs.h"
#include "xe_defaults.h"
@@ -127,6 +128,8 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
put_task_struct(task);
}
+ xe_client_debugfs_register(xef);
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 20/27] drm/xe/pagefault: export pagefault queue properties
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (18 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 19/27] drm/xe: Add xe_client_debugfs and introduce debug_data file Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 21/27] drm/xe/eudebug: Add read/count/compare helper for eu attention Mika Kuoppala
` (12 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
From: Maciej Patelczyk <maciej.patelczyk@intel.com>
Export pagefault queue related properties for eudebug.
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_pagefault.c | 44 -------------------------
drivers/gpu/drm/xe/xe_pagefault.h | 10 ++++++
drivers/gpu/drm/xe/xe_pagefault_types.h | 34 +++++++++++++++++++
3 files changed, 44 insertions(+), 44 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 2e415995f067..27c3a90e4e73 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -70,49 +70,6 @@
* free state once they are complete.
*/
-/**
- * enum xe_pagefault_alloc_state - lifetime state for a page fault queue entry
- * @XE_PAGEFAULT_ALLOC_STATE_FREE:
- * Entry is unused and may be overwritten by the producer, consumer retry
- * or requeue..
- * @XE_PAGEFAULT_ALLOC_STATE_QUEUED:
- * Entry has been enqueued and may be dequeued by a worker.
- * @XE_PAGEFAULT_ALLOC_STATE_ACTIVE:
- * Entry has been dequeued and is the worker's currently serviced fault.
- * The worker may attach additional faults to it via consumer.next.
- * @XE_PAGEFAULT_ALLOC_STATE_CHAINED:
- * Entry is not independently serviced; it has been chained onto an
- * ACTIVE entry via consumer.next and will be acknowledged when the
- * leading fault completes.
- * @XE_PAGEFAULT_ALLOC_STATE_COUNT:
- * Count of allocation states.
- *
- * The page fault queue provides stable storage for outstanding faults so the
- * IRQ handler can chain new cache hits directly onto a worker's active fault.
- * Because entries may remain referenced outside the consumer dequeue window,
- * the producer must only write into entries in the FREE state.
- *
- * State transitions are protected by the page fault queue lock. Workers return
- * entries to FREE after acknowledging the fault (either as ACTIVE or CHAINED).
- */
-enum xe_pagefault_alloc_state {
- XE_PAGEFAULT_ALLOC_STATE_FREE = 0,
- XE_PAGEFAULT_ALLOC_STATE_QUEUED = 1,
- XE_PAGEFAULT_ALLOC_STATE_CHAINED = 2,
- XE_PAGEFAULT_ALLOC_STATE_ACTIVE = 3,
- XE_PAGEFAULT_ALLOC_STATE_COUNT = 4,
-};
-
-static int xe_pagefault_entry_size(void)
-{
- /*
- * Power of two alignment is not a hardware requirement, rather a
- * software restriction which makes the math for page fault queue
- * management simplier.
- */
- return roundup_pow_of_two(sizeof(struct xe_pagefault));
-}
-
static int xe_pagefault_begin(struct drm_exec *exec, struct xe_vma *vma,
struct xe_vram_region *vram, bool need_vram_move)
{
@@ -295,7 +252,6 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
return err;
}
-#define XE_PAGEFAULT_CACHE_START_INVALID U64_MAX
#define xe_pagefault_cache_start_invalidate(val) \
(val = XE_PAGEFAULT_CACHE_START_INVALID)
diff --git a/drivers/gpu/drm/xe/xe_pagefault.h b/drivers/gpu/drm/xe/xe_pagefault.h
index e9c5d1f03760..83b68a19cc7c 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.h
+++ b/drivers/gpu/drm/xe/xe_pagefault.h
@@ -90,4 +90,14 @@ static inline u64 xe_pagefault_start_addr(struct xe_pagefault *pf)
return pf->consumer.page_addr;
}
+static inline int xe_pagefault_entry_size(void)
+{
+ /*
+ * Power of two alignment is not a hardware requirement, rather a
+ * software restriction which makes the math for page fault queue
+ * management simplier.
+ */
+ return roundup_pow_of_two(sizeof(struct xe_pagefault));
+}
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h
index efeba5c3a58b..f99b4e22441c 100644
--- a/drivers/gpu/drm/xe/xe_pagefault_types.h
+++ b/drivers/gpu/drm/xe/xe_pagefault_types.h
@@ -149,6 +149,39 @@ struct xe_pagefault {
} producer;
};
+/**
+ * enum xe_pagefault_alloc_state - lifetime state for a page fault queue entry
+ * @XE_PAGEFAULT_ALLOC_STATE_FREE:
+ * Entry is unused and may be overwritten by the producer, consumer retry
+ * or requeue..
+ * @XE_PAGEFAULT_ALLOC_STATE_QUEUED:
+ * Entry has been enqueued and may be dequeued by a worker.
+ * @XE_PAGEFAULT_ALLOC_STATE_ACTIVE:
+ * Entry has been dequeued and is the worker's currently serviced fault.
+ * The worker may attach additional faults to it via consumer.next.
+ * @XE_PAGEFAULT_ALLOC_STATE_CHAINED:
+ * Entry is not independently serviced; it has been chained onto an
+ * ACTIVE entry via consumer.next and will be acknowledged when the
+ * leading fault completes.
+ * @XE_PAGEFAULT_ALLOC_STATE_COUNT:
+ * Maximum enum value.
+ *
+ * The page fault queue provides stable storage for outstanding faults so the
+ * IRQ handler can chain new cache hits directly onto a worker's active fault.
+ * Because entries may remain referenced outside the consumer dequeue window,
+ * the producer must only write into entries in the FREE state.
+ *
+ * State transitions are protected by the page fault queue lock. Workers return
+ * entries to FREE after acknowledging the fault (either as ACTIVE or CHAINED).
+ */
+enum xe_pagefault_alloc_state {
+ XE_PAGEFAULT_ALLOC_STATE_FREE = 0,
+ XE_PAGEFAULT_ALLOC_STATE_QUEUED = 1,
+ XE_PAGEFAULT_ALLOC_STATE_CHAINED = 2,
+ XE_PAGEFAULT_ALLOC_STATE_ACTIVE = 3,
+ XE_PAGEFAULT_ALLOC_STATE_COUNT = 4,
+};
+
/**
* struct xe_pagefault_queue - Xe pagefault queue (consumer)
*
@@ -188,6 +221,7 @@ struct xe_pagefault_work {
* Protected by the page fault queue lock.
*/
struct {
+#define XE_PAGEFAULT_CACHE_START_INVALID U64_MAX
/** @cache.start: Start address of the current page fault */
u64 start;
/** @cache.end: End address of the current page fault */
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 21/27] drm/xe/eudebug: Add read/count/compare helper for eu attention
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (19 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 20/27] drm/xe/pagefault: export pagefault queue properties Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:31 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 22/27] drm/xe/vm: Support for adding null page VMA to VM on request Mika Kuoppala
` (11 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
From: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Add xe_eu_attentions structure to capture and store eu attention bits.
Add a function to count the number of eu threads that have turned on from
eu attentions, and add a function to count the number of eu threads that
have changed on a state between eu attentions.
v2: fix array size calculation (Christoph)
v3: remote timestamp (Maciej)
v4: settle time (Maciej)
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_gt_debug.c | 50 ++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_gt_debug.h | 6 +++-
drivers/gpu/drm/xe/xe_gt_debug_types.h | 22 ++++++++++++
3 files changed, 77 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/xe/xe_gt_debug_types.h
diff --git a/drivers/gpu/drm/xe/xe_gt_debug.c b/drivers/gpu/drm/xe/xe_gt_debug.c
index b20e42e66c5b..bff78c0b232a 100644
--- a/drivers/gpu/drm/xe/xe_gt_debug.c
+++ b/drivers/gpu/drm/xe/xe_gt_debug.c
@@ -3,12 +3,15 @@
* Copyright © 2023 Intel Corporation
*/
+#include <linux/delay.h>
+
#include "regs/xe_gt_regs.h"
#include "xe_device.h"
#include "xe_force_wake.h"
#include "xe_gt.h"
#include "xe_gt_topology.h"
#include "xe_gt_debug.h"
+#include "xe_gt_debug_types.h"
#include "xe_gt_mcr.h"
#include "xe_pm.h"
#include "xe_macros.h"
@@ -199,3 +202,50 @@ int xe_gt_eu_threads_needing_attention(struct xe_gt *gt)
return err < 0 ? 0 : err;
}
+
+static inline unsigned int
+xe_eu_attentions_count(const struct xe_eu_attentions *a)
+{
+ return bitmap_weight((void *)a->att, a->size * BITS_PER_BYTE);
+}
+
+void xe_gt_eu_attentions_read(struct xe_gt *gt,
+ struct xe_eu_attentions *a,
+ const unsigned int settle_time_ms)
+{
+ unsigned int attn, prev = 0;
+ ktime_t end, now;
+
+ now = ktime_get_raw();
+ /* Initially wait longer for attentions to appear */
+ end = ktime_add_ms(now, settle_time_ms * 10);
+
+ a->size = min_t(int,
+ xe_gt_eu_attention_bitmap_size(gt),
+ sizeof(a->att));
+
+ do {
+ if (xe_gt_eu_attention_bitmap(gt, a->att, a->size) < 0)
+ return;
+
+ if (!settle_time_ms)
+ break;
+
+ attn = xe_eu_attentions_count(a);
+
+ now = ktime_get_raw();
+
+ if (attn > prev) {
+ prev = attn;
+ end = ktime_add_ms(now, settle_time_ms);
+ }
+
+ udelay(15);
+
+ /*
+ * XXX We are gathering data for production SIP to find
+ * the upper limit of settle time. For now, we wait full
+ * timeout value regardless.
+ */
+ } while ((attn < a->size * 8) && ktime_before(now, end));
+}
diff --git a/drivers/gpu/drm/xe/xe_gt_debug.h b/drivers/gpu/drm/xe/xe_gt_debug.h
index 9dabe9cc1d25..70794d246e35 100644
--- a/drivers/gpu/drm/xe/xe_gt_debug.h
+++ b/drivers/gpu/drm/xe/xe_gt_debug.h
@@ -9,9 +9,10 @@
#include <linux/bits.h>
#include <linux/math.h>
+struct xe_eu_attentions;
struct xe_gt;
-#define XE_GT_ATTENTION_TIMEOUT_MS 100
+#define XE_GT_ATTENTION_TIMEOUT_MS 150
#define XE_GT_EU_ATT_ROWS 2u
unsigned int xe_gt_eu_att_regs(struct xe_gt *gt);
@@ -29,4 +30,7 @@ int xe_gt_eu_attention_bitmap_size(struct xe_gt *gt);
int xe_gt_eu_attention_bitmap(struct xe_gt *gt, u8 *bits,
unsigned int bitmap_size);
+void xe_gt_eu_attentions_read(struct xe_gt *gt,
+ struct xe_eu_attentions *a,
+ const unsigned int settle_time_ms);
#endif
diff --git a/drivers/gpu/drm/xe/xe_gt_debug_types.h b/drivers/gpu/drm/xe/xe_gt_debug_types.h
new file mode 100644
index 000000000000..f24eed15cf7c
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_gt_debug_types.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2025 Intel Corporation
+ */
+
+#ifndef __XE_GT_DEBUG_TYPES_
+#define __XE_GT_DEBUG_TYPES_
+
+#include <linux/types.h>
+
+#define XE_GT_EU_ATT_ROWS 2u
+#define XE_GT_EU_ATT_MAX_THREADS 16
+#define XE_GT_EU_MAX_NUM 1024
+
+struct xe_eu_attentions {
+ u8 att[XE_GT_EU_MAX_NUM *
+ XE_GT_EU_ATT_ROWS *
+ XE_GT_EU_ATT_MAX_THREADS/8];
+ unsigned int size;
+};
+
+#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 22/27] drm/xe/vm: Support for adding null page VMA to VM on request
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (20 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 21/27] drm/xe/eudebug: Add read/count/compare helper for eu attention Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 23/27] drm/xe/vm: Add xe_vm_svm_vma_subtract() to carve out a sub-range from an SVM VMA Mika Kuoppala
` (10 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Oak Zeng,
Niranjana Vishwanathapura, Stuart Summers, Bruce Chang,
Mika Kuoppala
From: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
The XE2 (and PVC) HW has a limitation that the pagefault due to invalid
access will halt the corresponding EUs. So, in order to activate the
debugger, kmd needs to install the temporal page to unhalt the EUs.
Plan to be used for pagefault handling when the EU debugger is running.
The idea is to install a null page vma if the pagefault is from an invalid
access. After installing null page pte, the user debugger can continue to
run/inspect without causing a fatal failure or reset and stop.
Based on Bruce's implementation [1].
[1] https://lore.kernel.org/intel-xe/20230829231648.4438-1-yu.bruce.chang@intel.com/
v2: s/NULL_VMA/DRM_GPUVA_SPARSE (Mika)
v3: use ERR_CAST as we dont return null (Mika)
v4: export vma insert/remove/destroy for eudebug needs (Maciej)
Cc: Oak Zeng <oak.zeng@intel.com>
Cc: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Cc: Stuart Summers <stuart.summers@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Co-developed-by: Bruce Chang <yu.bruce.chang@intel.com>
Signed-off-by: Bruce Chang <yu.bruce.chang@intel.com>
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
drivers/gpu/drm/xe/xe_vm.c | 42 ++++++++++++++++++++++++++++++++++++--
drivers/gpu/drm/xe/xe_vm.h | 5 +++++
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 3e6bee8d0708..1002d2f343b8 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1259,7 +1259,7 @@ static void xe_vm_assert_write_mode_or_garbage_collector(struct xe_vm *vm)
lockdep_is_held_type(&vm->svm.garbage_collector.lock, 0)));
}
-static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
+void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
{
struct xe_vm *vm = xe_vma_vm(vma);
struct xe_bo *bo = xe_vma_bo(vma);
@@ -1355,7 +1355,7 @@ xe_vm_find_overlapping_vma(struct xe_vm *vm, u64 start, u64 range)
return gpuva ? gpuva_to_vma(gpuva) : NULL;
}
-static int xe_vm_insert_vma(struct xe_vm *vm, struct xe_vma *vma)
+int xe_vm_insert_vma(struct xe_vm *vm, struct xe_vma *vma)
{
int err;
@@ -5312,3 +5312,41 @@ void xe_vm_remove_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
}
up_write(&vm->exec_queues.lock);
}
+
+struct xe_vma *xe_vm_create_null_vma(struct xe_vm *vm, u64 addr)
+{
+ struct xe_vma_mem_attr default_attr = {
+ .preferred_loc = {
+ .devmem_fd = DRM_XE_PREFERRED_LOC_DEFAULT_DEVICE,
+ .migration_policy = DRM_XE_MIGRATE_ALL_PAGES,
+ },
+ .atomic_access = DRM_XE_ATOMIC_UNDEFINED,
+ .default_pat_index = vm->xe->pat.idx[XE_CACHE_NONE],
+ .pat_index = vm->xe->pat.idx[XE_CACHE_NONE],
+ };
+ struct xe_vma *vma;
+ u32 page_size;
+ int err;
+
+ if (xe_vm_is_closed_or_banned(vm))
+ return ERR_PTR(-ENOENT);
+
+ page_size = vm->flags & XE_VM_FLAG_64K ? SZ_64K : SZ_4K;
+ vma = xe_vma_create(vm, NULL, 0, addr, addr + page_size - 1,
+ &default_attr, DRM_GPUVA_SPARSE);
+ if (IS_ERR(vma))
+ return ERR_CAST(vma);
+
+ err = xe_vm_insert_vma(vm, vma);
+ if (err) {
+ xe_vma_destroy_late(vma);
+ return ERR_PTR(err);
+ }
+
+ return vma;
+}
+
+void xe_vm_destroy_vma(struct xe_vma *vma)
+{
+ xe_vma_destroy_late(vma);
+}
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index c5b900f38ded..07e8c576abc7 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -436,4 +436,9 @@ static inline struct drm_exec *xe_vm_validation_exec(struct xe_vm *vm)
((READ_ONCE(tile_present) & ~READ_ONCE(tile_invalidated)) & BIT((tile)->id))
void xe_vma_mem_attr_copy(struct xe_vma_mem_attr *to, struct xe_vma_mem_attr *from);
+
+int xe_vm_insert_vma(struct xe_vm *vm, struct xe_vma *vma);
+struct xe_vma *xe_vm_create_null_vma(struct xe_vm *vm, u64 addr);
+void xe_vm_destroy_vma(struct xe_vma *vma);
+void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence);
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 23/27] drm/xe/vm: Add xe_vm_svm_vma_subtract() to carve out a sub-range from an SVM VMA
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (21 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 22/27] drm/xe/vm: Support for adding null page VMA to VM on request Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 24/27] drm/xe: Support for xe_vma_unbind() Mika Kuoppala
` (9 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
From: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
When the EU debugger page fault handler needs to install a NULL (sparse)
VMA at an address that is currently covered by a large SVM
cpu-addr-mirror VMA, the SVM VMA must first be trimmed to leave a hole
at the faulted address. There was no helper to do this in a
semantically clean way, so add one.
xe_vm_svm_vma_subtract() removes the address range [sub_start, sub_end)
from an existing VMA according to three cases:
1) No overlap: [sub_start, sub_end) lies entirely outside the VMA.
Return -EINVAL; the caller's invariants are violated.
2) Full coverage: [sub_start, sub_end) covers the entire VMA.
Remove and destroy the VMA in one step.
3) Partial overlap: [sub_start, sub_end) overlaps only part of the VMA.
The original VMA is removed and destroyed, and the non-overlapping
head region [vma_start, overlap_start) and/or tail region
[overlap_end, vma_end) are re-created as new VMAs via
xe_vma_create() + xe_vm_insert_vma(). The new VMAs inherit the
original VMA's memory attributes and its XE_VMA_CREATE_MASK
creation flags, so properties such as XE_VMA_SYSTEM_ALLOCATOR is
preserved.
Note on address conventions: xe_vma_end() returns an exclusive end
address, and sub_end is likewise exclusive, consistent with the rest of
the VM code. xe_vma_create() however takes an inclusive end address, so
the head and tail VMAs are passed overlap_start - 1 and vma_end - 1
respectively.
The function requires vm->lock to be held for write by the caller, which
is already the case in all page-fault service paths.
xe_vm_svm_vma_subtract() is intended to be called from the EU debugger
page fault path (xe_pagefault.c) when xe_svm_handle_pagefault() returns
-ENOENT for a faulted address inside a cpu-addr-mirror VMA, indicating
that no CPU mm VMA backs that address.
The xe_vm_svm_vma_subtract() returns vma that represents subtracted
vma with attributes copied from original one. It shall be reinserted
then page fault is handled.
Assisted-by: GitHub Copilot:claude-opus-4.6
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_vm.c | 139 +++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_vm.h | 3 +
2 files changed, 142 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 1002d2f343b8..73490a10bdc0 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -5350,3 +5350,142 @@ void xe_vm_destroy_vma(struct xe_vma *vma)
{
xe_vma_destroy_late(vma);
}
+
+/**
+ * xe_vm_svm_vma_subtract() - Subtract an address range from an existing SVM VMA
+ * @vm: The xe_vm the @vma belongs to
+ * @vma: Target SVM VMA from which a sub-range will be removed
+ * @sub_start: Start address of the range to subtract (inclusive)
+ * @sub_end: End address of the range to subtract (exclusive)
+ *
+ * Behavior:
+ * 1) If [sub_start, sub_end) does not overlap @vma at all, return -EINVAL.
+ * 2) If [sub_start, sub_end) fully covers @vma, the entire VMA is removed.
+ * 3) If [sub_start, sub_end) partially overlaps @vma, only the overlapping
+ * portion is removed. The remaining non-overlapping head and/or tail
+ * regions are re-inserted as new VMAs that inherit the original VMA's
+ * memory attributes and creation flags.
+ *
+ * Locking: Caller must hold vm->lock for write.
+ *
+ * Return: pointer to vma which is the subtracted hole in SVM mapping
+ * or error on failure
+ */
+struct xe_vma *xe_vm_svm_vma_subtract(struct xe_vm *vm, struct xe_vma *vma,
+ u64 sub_start, u64 sub_end)
+{
+ u64 vma_start = xe_vma_start(vma);
+ u64 vma_end = xe_vma_end(vma); /* exclusive */
+ u64 overlap_start, overlap_end; /* overlap range, end is exclusive */
+ u64 start, end;
+ struct xe_vma_mem_attr attr = {};
+ struct xe_vma *rvma = NULL;
+ struct xe_vma *prev_vma = NULL;
+ struct xe_vma *next_vma = NULL;
+ unsigned int flags;
+ int err = 0;
+
+ lockdep_assert_held_write(&vm->lock);
+
+ /* Reject obviously invalid input range. */
+ if (sub_start >= sub_end)
+ return ERR_PTR(-EINVAL);
+
+ /* 1) No overlap with the existing VMA. */
+ if (sub_end <= vma_start || sub_start >= vma_end)
+ return ERR_PTR(-EINVAL);
+
+ /* Compute the actual overlapping region clipped to the VMA. */
+ overlap_start = max(sub_start, vma_start);
+ overlap_end = min(sub_end, vma_end);
+
+ start = vma_start;
+ end = vma_end;
+ /*
+ * Preserve the original VMA's memory attributes (with proper refcount
+ * handling on dpagemap) and creation flags before destroying it, then
+ * re-insert the non-overlapping head/tail regions as new VMAs.
+ */
+ xe_vma_mem_attr_copy(&attr, &vma->attr);
+ flags = vma->gpuva.flags & XE_VMA_CREATE_MASK;
+
+ xe_vm_remove_vma(vm, vma);
+ /* 2) Subtract range fully covers the VMA -> remove it entirely. */
+ if (overlap_start == vma_start && overlap_end == vma_end)
+ goto out;
+
+ /*
+ * 3) Partial overlap.
+ *
+ * Head region: [vma_start, overlap_start)
+ */
+ if (vma_start < overlap_start) {
+ /* xe_vma_create() takes an inclusive end address. */
+ prev_vma = xe_vma_create(vm, NULL, 0, vma_start,
+ overlap_start - 1, &attr, flags);
+ if (IS_ERR(prev_vma)) {
+ err = PTR_ERR(prev_vma);
+ prev_vma = NULL;
+ goto err;
+ }
+
+ err = xe_vm_insert_vma(vm, prev_vma);
+ if (err) {
+ xe_vma_destroy_late(prev_vma);
+ prev_vma = NULL;
+ goto err;
+ }
+ start = overlap_start;
+ }
+
+ /* Tail region: [overlap_end, vma_end) */
+ if (overlap_end < vma_end) {
+ next_vma = xe_vma_create(vm, NULL, 0, overlap_end, vma_end - 1,
+ &attr, flags);
+ if (IS_ERR(next_vma)) {
+ err = PTR_ERR(next_vma);
+ next_vma = NULL;
+ goto err;
+ }
+
+ err = xe_vm_insert_vma(vm, next_vma);
+ if (err) {
+ xe_vma_destroy_late(next_vma);
+ next_vma = NULL;
+ goto err;
+ }
+ end = overlap_end;
+ }
+
+out:
+ rvma = xe_vma_create(vm, NULL, 0,
+ start, end - 1,
+ &attr,
+ flags);
+ if (IS_ERR(rvma)) {
+ err = PTR_ERR(rvma);
+ goto err;
+ }
+ xe_vma_destroy_unlocked(vma);
+ xe_vma_mem_attr_fini(&attr);
+ return rvma;
+
+err:
+ xe_vma_mem_attr_fini(&attr);
+
+ if (prev_vma) {
+ xe_vm_remove_vma(vm, prev_vma);
+ xe_vma_destroy_unlocked(prev_vma);
+ }
+ if (next_vma) {
+ xe_vm_remove_vma(vm, next_vma);
+ xe_vma_destroy_unlocked(next_vma);
+ }
+
+ if (xe_vm_insert_vma(vm, vma)) {
+ xe_vma_destroy_unlocked(vma);
+ xe_vm_kill(vm, true);
+ }
+
+ return ERR_PTR(err);
+}
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index 07e8c576abc7..6ff14fbce7a6 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -441,4 +441,7 @@ int xe_vm_insert_vma(struct xe_vm *vm, struct xe_vma *vma);
struct xe_vma *xe_vm_create_null_vma(struct xe_vm *vm, u64 addr);
void xe_vm_destroy_vma(struct xe_vma *vma);
void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence);
+
+struct xe_vma *xe_vm_svm_vma_subtract(struct xe_vm *vm, struct xe_vma *vma, u64 sub_start,
+ u64 sub_end);
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 24/27] drm/xe: Support for xe_vma_unbind()
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (22 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 23/27] drm/xe/vm: Add xe_vm_svm_vma_subtract() to carve out a sub-range from an SVM VMA Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 25/27] drm/xe: export prep_vma_destroy as xe_vm_prep_vma_destroy Mika Kuoppala
` (8 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
From: Maciej Patelczyk <maciej.patelczyk@intel.com>
Introduced a API to single VMA unbind from VM.
New function xe_vma_unbind() added.
Assisted-by: GitHub Copilot CLI:claude-opus-4.7
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_vm.c | 84 ++++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_vm.h | 3 ++
2 files changed, 87 insertions(+)
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 73490a10bdc0..83cc94aabe59 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1066,6 +1066,90 @@ struct dma_fence *xe_vm_range_unbind(struct xe_vm *vm,
return fence;
}
+static void xe_vm_populate_unbind(struct xe_vma_op *op,
+ struct xe_vma *vma,
+ u8 tile_mask)
+{
+ INIT_LIST_HEAD(&op->link);
+ op->tile_mask = tile_mask;
+ op->base.op = DRM_GPUVA_OP_UNMAP;
+ op->base.unmap.va = &vma->gpuva;
+ op->base.unmap.keep = false;
+}
+
+static int xe_vm_ops_add_unbind(struct xe_vma_ops *vops,
+ struct xe_vma *vma,
+ u8 tile_mask)
+{
+ struct xe_vma_op *op;
+
+ op = kzalloc_obj(*op);
+ if (!op)
+ return -ENOMEM;
+
+ xe_vm_populate_unbind(op, vma, tile_mask);
+ list_add_tail(&op->link, &vops->list);
+ xe_vma_ops_incr_pt_update_ops(vops, tile_mask, 1);
+
+ return 0;
+}
+
+/**
+ * xe_vma_unbind() - Unbind a vma from GPU page tables.
+ * @vm: The VM which the vma belongs to.
+ * @vma: The vma to be unbinded.
+ * @tile_mask: tiles for unbind.
+ *
+ * Return: dma fence for unbind to signal completion on success, ERR_PTR on
+ * failure
+ */
+
+struct dma_fence *xe_vma_unbind(struct xe_vm *vm, struct xe_vma *vma,
+ u8 tile_mask)
+{
+ struct dma_fence *fence = NULL;
+ struct xe_vma_ops vops;
+ struct xe_vma_op *op, *next_op;
+ struct xe_tile *tile;
+ u8 id;
+ int err;
+
+ lockdep_assert_held_write(&vm->lock);
+ xe_vm_assert_held(vm);
+ xe_assert(vm->xe, xe_vm_in_fault_mode(vm));
+
+ if (!vma->tile_present)
+ return dma_fence_get_stub();
+
+ xe_vma_ops_init(&vops, vm, NULL, NULL, 0);
+ for_each_tile(tile, vm->xe, id) {
+ vops.pt_update_ops[id].wait_vm_bookkeep = true;
+ vops.pt_update_ops[tile->id].q =
+ xe_migrate_exec_queue(tile->migrate);
+ }
+
+ err = xe_vm_ops_add_unbind(&vops, vma, tile_mask);
+ if (err)
+ return ERR_PTR(err);
+
+ err = xe_vma_ops_alloc(&vops, false);
+ if (err) {
+ fence = ERR_PTR(err);
+ goto free_ops;
+ }
+
+ fence = ops_execute(vm, &vops);
+
+free_ops:
+ list_for_each_entry_safe(op, next_op, &vops.list, link) {
+ list_del(&op->link);
+ kfree(op);
+ }
+ xe_vma_ops_fini(&vops);
+
+ return fence;
+}
+
static void xe_vma_mem_attr_fini(struct xe_vma_mem_attr *attr)
{
drm_pagemap_put(attr->preferred_loc.dpagemap);
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index 6ff14fbce7a6..5dc15b6bbcdd 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -249,6 +249,9 @@ struct dma_fence *xe_vm_range_rebind(struct xe_vm *vm,
u8 tile_mask);
struct dma_fence *xe_vm_range_unbind(struct xe_vm *vm,
struct xe_svm_range *range);
+struct dma_fence *xe_vma_unbind(struct xe_vm *vm,
+ struct xe_vma *vma,
+ u8 tile_mask);
int xe_vm_invalidate_vma(struct xe_vma *vma);
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 25/27] drm/xe: export prep_vma_destroy as xe_vm_prep_vma_destroy
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (23 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 24/27] drm/xe: Support for xe_vma_unbind() Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 26/27] drm/xe/eudebug: Introduce EU pagefault handling interface Mika Kuoppala
` (7 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
From: Maciej Patelczyk <maciej.patelczyk@intel.com>
Rename and export helper function for wider usage.
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_vm.c | 27 ++++++++++++++++++---------
drivers/gpu/drm/xe/xe_vm.h | 2 ++
2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 83cc94aabe59..cfe4b6f97dd0 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -2447,8 +2447,17 @@ static const u32 region_to_mem_type[] = {
XE_PL_VRAM1,
};
-static void prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma,
- bool post_commit)
+/**
+ * xe_vm_prep_vma_destroy - Prepare vma to be destroyed.
+ * @vm : the vm vma belongs to
+ * @vma: vma to be removed
+ * @post_commit: if to remove vma from gpuvm tree
+ *
+ * Marks vma as destroyed and if post_commit is true
+ * also removes it from gpuvm tree.
+ */
+void xe_vm_prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma,
+ bool post_commit)
{
xe_svm_notifier_lock(vm);
vma->gpuva.flags |= XE_VMA_DESTROYED;
@@ -2803,7 +2812,7 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op,
if (!bo->vm) {
err = add_preempt_fences(vm, bo);
if (err) {
- prep_vma_destroy(vm, vma, false);
+ xe_vm_prep_vma_destroy(vm, vma, false);
xe_vma_destroy(vma, NULL);
}
}
@@ -2830,7 +2839,7 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op,
}
}
if (err) {
- prep_vma_destroy(vm, vma, false);
+ xe_vm_prep_vma_destroy(vm, vma, false);
xe_vma_destroy_unlocked(vma);
vma = ERR_PTR(err);
}
@@ -2891,7 +2900,7 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
xe_vm_assert_write_mode_or_garbage_collector(vm);
- prep_vma_destroy(vm, gpuva_to_vma(op->base.remap.unmap->va),
+ xe_vm_prep_vma_destroy(vm, gpuva_to_vma(op->base.remap.unmap->va),
true);
op->flags |= XE_VMA_OP_COMMITTED;
@@ -2927,7 +2936,7 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
case DRM_GPUVA_OP_UNMAP:
xe_vm_assert_write_mode_or_garbage_collector(vm);
- prep_vma_destroy(vm, gpuva_to_vma(op->base.unmap.va), true);
+ xe_vm_prep_vma_destroy(vm, gpuva_to_vma(op->base.unmap.va), true);
op->flags |= XE_VMA_OP_COMMITTED;
break;
case DRM_GPUVA_OP_PREFETCH:
@@ -3168,7 +3177,7 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
xe_vm_assert_write_mode_or_garbage_collector(vm);
if (op->map.vma) {
- prep_vma_destroy(vm, op->map.vma, post_commit);
+ xe_vm_prep_vma_destroy(vm, op->map.vma, post_commit);
xe_vma_destroy_unlocked(op->map.vma);
}
break;
@@ -3194,11 +3203,11 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
xe_vm_assert_write_mode_or_garbage_collector(vm);
if (op->remap.prev) {
- prep_vma_destroy(vm, op->remap.prev, prev_post_commit);
+ xe_vm_prep_vma_destroy(vm, op->remap.prev, prev_post_commit);
xe_vma_destroy_unlocked(op->remap.prev);
}
if (op->remap.next) {
- prep_vma_destroy(vm, op->remap.next, next_post_commit);
+ xe_vm_prep_vma_destroy(vm, op->remap.next, next_post_commit);
xe_vma_destroy_unlocked(op->remap.next);
}
if (vma) {
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index 5dc15b6bbcdd..bb1c37e9a608 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -442,6 +442,8 @@ void xe_vma_mem_attr_copy(struct xe_vma_mem_attr *to, struct xe_vma_mem_attr *fr
int xe_vm_insert_vma(struct xe_vm *vm, struct xe_vma *vma);
struct xe_vma *xe_vm_create_null_vma(struct xe_vm *vm, u64 addr);
+void xe_vm_prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma,
+ bool post_commit);
void xe_vm_destroy_vma(struct xe_vma *vma);
void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence);
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 26/27] drm/xe/eudebug: Introduce EU pagefault handling interface
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (24 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 25/27] drm/xe: export prep_vma_destroy as xe_vm_prep_vma_destroy Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:43 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 27/27] drm/xe/eudebug: Enable EU pagefault handling Mika Kuoppala
` (6 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
From: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
The XE2 (and PVC) HW has a limitation that the pagefault due to invalid
access will halt the corresponding EUs. To solve this problem, introduce
EU pagefault handling functionality, which allows to unhalt pagefaulted
eu threads and to EU debugger to get inform about the eu attentions state
of EU threads during execution.
If a pagefault occurs, send the DRM_XE_EUDEBUG_EVENT_PAGEFAULT event
after handling the pagefault. The pagefault eudebug event follows
the newly added drm_xe_eudebug_event_pagefault type.
When a pagefault occurs, it prevents to send the
DRM_XE_EUDEBUG_EVENT_EU_ATTENTION event to the client during pagefault
handling.
The page fault event delivery follows the below policy.
(1) If EU Debugger discovery has completed and pagefaulted eu threads turn
on attention bit then pagefault handler delivers pagefault event
directly.
(2) If a pagefault occurs during eu debugger discovery process, pagefault
handler queues a pagefault event and sends the queued event when
discovery has completed and pagefaulted eu threads turn on attention
bit.
(3) The pagefault handling procedure is started when first pagefault
occurs and it will end when the last is handled. It means that
no worker handles currently pagefault and no pagefault is in the queue.
The start and end is handled by eudebug. All pagefaults in between
have simplified handing by inserting temporary NULL VMA and ACK.
If multiple eu threads are running and a pagefault occurs due to accessing
the same or other invalid address, send a single pagefault event
(DRM_XE_EUDEBUG_EVENT_PAGEFAULT type) to the user debugger instead of a
pagefault event for each of the multiple eu threads.
As the attention scan worker send the eu attention event whenever the
attention bit is turned on, user debugger receives attenion event
immediately after pagefault event.
In this case, the page-fault event always precedes the attention event.
When the user debugger receives an attention event after a pagefault event,
it can detect whether additional breakpoints or interrupts occur in
addition to the existing pagefault by comparing the eu threads where the
pagefault occurred with the eu threads where the attention bit is newly
enabled.
v2: use only force exception (Joonas, Mika)
v3: rebased on v4 (Mika)
v4: streamline uapi, cleanups (Mika)
v5: struct member documentation (Mika)
v6: fault to fault_type (Mika)
v7: pagefault rework (Maciej)
v8: get debugger reference on signalling (Mika)
v9: pagefault storm adaptation and fixes (Maciej, Sashiko)
v10: - rebased on eudebug v9
- reworked flow to support multiple pagefault processing
Assisted-by: sashiko
Assisted-by: GitHub Copilot CLI:claude-opus-4.7
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Gustavo Sousa <gustavo.sousa@intel.com>
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: Jan Maślak <jan.maslak@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/Makefile | 2 +-
drivers/gpu/drm/xe/xe_eudebug.c | 125 +++-
drivers/gpu/drm/xe/xe_eudebug.h | 9 +
drivers/gpu/drm/xe/xe_eudebug_hw.c | 14 +-
drivers/gpu/drm/xe/xe_eudebug_pagefault.c | 699 ++++++++++++++++++++++
drivers/gpu/drm/xe/xe_eudebug_pagefault.h | 79 +++
drivers/gpu/drm/xe/xe_eudebug_types.h | 107 +++-
drivers/gpu/drm/xe/xe_pagefault_types.h | 1 +
include/uapi/drm/xe_drm_eudebug.h | 12 +
9 files changed, 1013 insertions(+), 35 deletions(-)
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_pagefault.c
create mode 100644 drivers/gpu/drm/xe/xe_eudebug_pagefault.h
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 4a882e34bbe8..b5da138fd26e 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -162,7 +162,7 @@ xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
xe-$(CONFIG_DRM_GPUSVM) += xe_userptr.o
# debugging shaders with gdb (eudebug) support
-xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o xe_eudebug_vm.o xe_eudebug_hw.o xe_gt_debug.o
+xe-$(CONFIG_DRM_XE_EUDEBUG) += xe_eudebug.o xe_eudebug_vm.o xe_eudebug_hw.o xe_eudebug_pagefault.o xe_gt_debug.o
# graphics hardware monitoring (HWMON) support
xe-$(CONFIG_HWMON) += xe_hwmon.o
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 2c8d8fc82898..cbe32ec4f244 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -19,11 +19,15 @@
#include "xe_eudebug.h"
#include "xe_eudebug_hw.h"
#include "xe_eudebug_types.h"
+#include "xe_eudebug_pagefault.h"
#include "xe_eudebug_vm.h"
#include "xe_exec_queue.h"
+#include "xe_force_wake.h"
#include "xe_gt.h"
#include "xe_gt_debug.h"
+#include "xe_gt_mcr.h"
#include "xe_hw_engine.h"
+#include "regs/xe_gt_regs.h"
#include "xe_macros.h"
#include "xe_pm.h"
#include "xe_sriov_pf.h"
@@ -241,12 +245,25 @@ static void xe_eudebug_free(struct kref *ref)
xe_assert(d->xe, xe_eudebug_detached(d));
+ xe_eudebug_pagefault_fini(d);
xe_eudebug_resources_destroy(d);
+ mutex_destroy(&d->pf.lock);
XE_WARN_ON(d->target.xef);
kvfree(d->events.fifo_buf);
kvfree(d->events.staging);
kvfree(d->events.pending);
+
+ /*
+ * This should be finalized in detach.
+ * Warn if there is a leftover due to race
+ */
+ WARN_ON(d->pf.fence);
+ if (d->pf.fence) {
+ dma_fence_signal(d->pf.fence);
+ dma_fence_put(d->pf.fence);
+ }
+
kfree(d);
}
@@ -394,6 +411,7 @@ static bool xe_eudebug_detach(struct xe_eudebug *d,
wake_up_all(&d->events.write_done);
if (target) {
+ xe_eudebug_pagefault_signal(d);
xe_eudebug_put(d);
xe_file_put(target);
}
@@ -1930,11 +1948,12 @@ static const struct file_operations fops = {
.compat_ioctl = xe_eudebug_ioctl,
};
-static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q,
- int lrc_idx, void *bitmap, unsigned int size)
+static int
+send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, int lrc_idx)
{
struct drm_xe_eudebug_event_eu_attention *e;
struct drm_xe_eudebug_event *event;
+ const u32 size = xe_gt_eu_attention_bitmap_size(q->gt);
const u32 sz = struct_size(e, bitmask, size);
int h_queue, h_lrc;
int ret;
@@ -1960,14 +1979,18 @@ static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q,
e->lrc_handle = h_lrc;
e->bitmask_size = size;
- memcpy(e->bitmask, bitmap, size);
- ret = xe_eudebug_queue_event(d, event);
+ ret = xe_gt_eu_attention_bitmap(q->gt, &e->bitmask[0], e->bitmask_size);
+
+ if (!ret && !bitmap_empty((unsigned long *)&e->bitmask[0],
+ e->bitmask_size * BITS_PER_BYTE))
+ ret = xe_eudebug_queue_event(d, event);
+
spin_unlock(&d->events.lock);
return ret;
}
-static int xe_send_gt_attention(struct xe_gt *gt, void *bitmap, unsigned int size)
+static int xe_send_gt_attention(struct xe_gt *gt)
{
struct xe_eudebug *d;
struct xe_exec_queue *q;
@@ -1982,7 +2005,7 @@ static int xe_send_gt_attention(struct xe_gt *gt, void *bitmap, unsigned int siz
goto err_exec_queue_put;
}
- d = xe_eudebug_get_nolock(q->vm->xef);
+ d = xe_eudebug_get_nolock_with_discovery(q->vm->xef);
if (!d) {
ret = -ENOTCONN;
goto err_exec_queue_put;
@@ -1994,7 +2017,7 @@ static int xe_send_gt_attention(struct xe_gt *gt, void *bitmap, unsigned int siz
goto err_eudebug_put;
}
- ret = send_attention_event(d, q, lrc_idx, bitmap, size);
+ ret = send_attention_event(d, q, lrc_idx);
if (ret)
xe_eudebug_disconnect(d, ret);
@@ -2009,32 +2032,12 @@ static int xe_send_gt_attention(struct xe_gt *gt, void *bitmap, unsigned int siz
static int xe_eudebug_handle_gt_attention(struct xe_gt *gt)
{
struct xe_device *xe = gt_to_xe(gt);
- const u32 size = xe_gt_eu_attention_bitmap_size(gt);
int ret;
- void *bitmask;
if (!READ_ONCE(xe->eudebug.send_attentions))
return 0;
- ret = xe_gt_eu_threads_needing_attention(gt);
- if (ret <= 0)
- return ret;
-
- /* If we fail at this time, assume we manage to send eventually */
- bitmask = kvzalloc(size, GFP_KERNEL);
- if (!bitmask)
- return 0;
-
- ret = xe_gt_eu_attention_bitmap(gt, bitmask, size);
- if (ret)
- goto out;
-
- if (bitmap_empty(bitmask, size * BITS_PER_BYTE))
- goto out;
-
- ret = xe_send_gt_attention(gt, bitmask, size);
-out:
- kvfree(bitmask);
+ ret = xe_send_gt_attention(gt);
/* Discovery in progress, fake it */
if (ret == -EBUSY)
@@ -2053,6 +2056,53 @@ static void handle_attention_fail(struct xe_gt *gt, int gt_id, int ret)
xe_gt_reset_async(gt);
}
+int xe_eudebug_send_pagefault_event(struct xe_eudebug *d,
+ struct xe_eudebug_pagefault *pf)
+{
+ struct drm_xe_eudebug_event_pagefault *ep;
+ struct drm_xe_eudebug_event *event;
+ int h_queue, h_lrc;
+ u32 size = xe_gt_eu_attention_bitmap_size(pf->q->gt) * 3;
+ u32 sz = struct_size(ep, bitmask, size);
+ int ret;
+
+ XE_WARN_ON(pf->lrc_idx < 0 || pf->lrc_idx >= pf->q->width);
+
+ XE_WARN_ON(!xe_exec_queue_is_debuggable(pf->q));
+
+ h_queue = find_handle(d, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, pf->q);
+ if (h_queue < 0)
+ return h_queue;
+
+ h_lrc = find_handle(d, XE_EUDEBUG_RES_TYPE_LRC, pf->q->lrc[pf->lrc_idx]);
+ if (h_lrc < 0)
+ return h_lrc;
+
+ spin_lock(&d->events.lock);
+ event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_PAGEFAULT, 0,
+ DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, sz);
+
+
+ ep = cast_event(ep, event);
+ ep->exec_queue_handle = h_queue;
+ ep->lrc_handle = h_lrc;
+ ep->bitmask_size = size;
+ ep->pagefault_address = pf->fault.addr;
+
+ memcpy(ep->bitmask, pf->attentions.before.att, pf->attentions.before.size);
+ memcpy(ep->bitmask + pf->attentions.before.size,
+ pf->attentions.after.att, pf->attentions.after.size);
+ memcpy(ep->bitmask + pf->attentions.before.size + pf->attentions.after.size,
+ pf->attentions.resolved.att, pf->attentions.resolved.size);
+
+ event->seqno = atomic_long_inc_return(&d->events.seqno);
+
+ ret = xe_eudebug_queue_event(d, event);
+ spin_unlock(&d->events.lock);
+
+ return ret;
+}
+
static void attention_poll_work(struct work_struct *work)
{
struct xe_device *xe = container_of(work, typeof(*xe),
@@ -2072,8 +2122,14 @@ static void attention_poll_work(struct work_struct *work)
if (gt->info.type != XE_GT_TYPE_MAIN)
continue;
- ret = xe_eudebug_handle_gt_attention(gt);
- if (ret)
+ if (!xe_gt_eu_threads_needing_attention(gt))
+ continue;
+
+ ret = xe_eudebug_handle_pagefaults(gt);
+ if (!ret)
+ ret = xe_eudebug_handle_gt_attention(gt);
+
+ if (ret && ret != -EBUSY)
handle_attention_fail(gt, gt_id, ret);
}
@@ -2102,13 +2158,13 @@ static void attention_poll_work(struct work_struct *work)
* poll: a worker already past its own requeue check can arm the work one
* more time, and that wakeup returns at the top guard without rearming.
*/
-static void xe_eudebug_attention_poll_stop(struct xe_device *xe)
+void xe_eudebug_attention_poll_stop(struct xe_device *xe)
{
WRITE_ONCE(xe->eudebug.send_attentions, false);
cancel_delayed_work(&xe->eudebug.attention_dwork);
}
-static void xe_eudebug_attention_poll_start(struct xe_device *xe)
+void xe_eudebug_attention_poll_start(struct xe_device *xe)
{
WRITE_ONCE(xe->eudebug.send_attentions, true);
mod_delayed_work(xe->eudebug.attention_wq, &xe->eudebug.attention_dwork, 0);
@@ -2143,6 +2199,8 @@ xe_eudebug_connect(struct xe_device *xe,
d->xe = xe;
kref_init(&d->ref);
+ mutex_init(&d->pf.lock);
+ INIT_LIST_HEAD(&d->pf.pagefaults);
init_waitqueue_head(&d->events.write_done);
spin_lock_init(&d->events.lock);
@@ -2152,6 +2210,9 @@ xe_eudebug_connect(struct xe_device *xe,
spin_lock_init(&d->acks.lock);
d->acks.tree = RB_ROOT;
+ d->pf.active = 0;
+ d->pf.first = NULL;
+
err = xe_eudebug_resources_init(d);
if (XE_IOCTL_DBG(xe, err)) {
kfree(d);
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 8a5a10bf7e8b..2bad3e7f8b8c 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -13,12 +13,14 @@ struct drm_file;
struct xe_debug_data;
struct xe_device;
struct xe_file;
+struct xe_gt;
struct xe_vm;
struct xe_exec_queue;
struct xe_vma;
struct xe_vma_ops;
struct xe_user_fence;
struct xe_eudebug;
+struct xe_eudebug_pagefault;
#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
@@ -66,6 +68,7 @@ int xe_eudebug_enable(struct xe_device *xe, bool enable);
struct xe_eudebug *xe_eudebug_get_nolock(struct xe_file *xef);
struct xe_eudebug *xe_eudebug_get_nolock_with_discovery(struct xe_file *xef);
+
void xe_eudebug_put(struct xe_eudebug *d);
struct xe_vm *xe_eudebug_vm_get(struct xe_eudebug *d, u32 vm_id);
@@ -81,6 +84,12 @@ void xe_eudebug_ufence_init(struct xe_user_fence *ufence);
void xe_eudebug_ufence_fini(struct xe_user_fence *ufence);
bool xe_eudebug_ufence_track(struct xe_user_fence *ufence);
+int xe_eudebug_send_pagefault_event(struct xe_eudebug *d,
+ struct xe_eudebug_pagefault *pf);
+
+void xe_eudebug_attention_poll_stop(struct xe_device *xe);
+void xe_eudebug_attention_poll_start(struct xe_device *xe);
+
#else
static inline int xe_eudebug_connect_ioctl(struct drm_device *dev,
diff --git a/drivers/gpu/drm/xe/xe_eudebug_hw.c b/drivers/gpu/drm/xe/xe_eudebug_hw.c
index d14e4e4775f2..a246a9905bc8 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_hw.c
+++ b/drivers/gpu/drm/xe/xe_eudebug_hw.c
@@ -345,6 +345,7 @@ static int do_eu_control(struct xe_eudebug *d,
void __user * const bitmask_ptr = u64_to_user_ptr(arg->bitmask_ptr);
struct xe_device *xe = d->xe;
struct xe_exec_queue *q, *active;
+ struct dma_fence *pf_fence;
struct xe_lrc *lrc;
unsigned int hw_attn_size, attn_size;
u8 *bits = NULL;
@@ -416,8 +417,19 @@ static int do_eu_control(struct xe_eudebug *d,
}
}
- ret = -EINVAL;
mutex_lock(&xe->eudebug.lock);
+ do {
+ pf_fence = dma_fence_get(d->pf.fence);
+ if (pf_fence) {
+ mutex_unlock(&xe->eudebug.lock);
+ ret = dma_fence_wait(pf_fence, true);
+ dma_fence_put(pf_fence);
+ if (ret)
+ goto out_free;
+ mutex_lock(&xe->eudebug.lock);
+ }
+ } while (pf_fence);
+ ret = -EINVAL;
switch (arg->cmd) {
case DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL:
diff --git a/drivers/gpu/drm/xe/xe_eudebug_pagefault.c b/drivers/gpu/drm/xe/xe_eudebug_pagefault.c
new file mode 100644
index 000000000000..5ad37e757f69
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_pagefault.c
@@ -0,0 +1,699 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#include "xe_eudebug_pagefault.h"
+
+#include <linux/delay.h>
+
+#include "xe_exec_queue.h"
+#include "xe_pagefault.h"
+#include "xe_eudebug.h"
+#include "xe_eudebug_hw.h"
+#include "xe_force_wake.h"
+#include "xe_gt_debug.h"
+#include "xe_gt_mcr.h"
+#include "regs/xe_gt_regs.h"
+#include "xe_vm.h"
+
+/**
+ * DOC: EU Debug page fault workaround
+ *
+ * When shader generates an unresolvable page fault for client under debug
+ * then eudebug performs following steps:
+ * - Attention register is read to get current state of hw threads ('before').
+ * - TD_CTL_FORCE_EXCEPTION is set to halt all currently running hw threads
+ * ('after'). Threads that caused page fault(s) are halted by HW and will
+ * not appread in 'after' bitmask.
+ * - Page fault is ACKed to GuC.
+ * - All other page faults for a matching VM are processed with optional
+ * temporary null VMA insertion before and removal after processing.
+ * - When there are no more matching page faults in a queue and worker's
+ * cache then:
+ * - attention register is read to get 'resolved' bitmask.
+ * - TD_CTL_FORCE_EXCEPTION is cleared
+ * - null vma is removed
+ * - event to UMD is send.
+ *
+ * Single EUDebug pagefault event reports only first page fault however it
+ * 'handles' them all so the bitmask may contain many aggregated page faults
+ * and UMD shall check all threads that transitioned from 0 ('after') to 1
+ * ('resolved').
+ *
+ * It is assumed that only client under debug is actively running (runalone
+ * mode).
+ */
+
+static struct xe_gt *
+epf_to_gt(struct xe_eudebug_pagefault *epf)
+{
+ return epf->q->gt;
+}
+
+static const char *
+pagefault_get_driver_name(struct dma_fence *dma_fence)
+{
+ return "xe";
+}
+
+static const char *
+pagefault_fence_get_timeline_name(struct dma_fence *dma_fence)
+{
+ return "eudebug_pagefault_fence";
+}
+
+static const struct dma_fence_ops pagefault_fence_ops = {
+ .get_driver_name = pagefault_get_driver_name,
+ .get_timeline_name = pagefault_fence_get_timeline_name,
+};
+
+struct pagefault_fence {
+ struct dma_fence base;
+ spinlock_t lock;
+};
+
+static struct pagefault_fence *pagefault_fence_create(void)
+{
+ struct pagefault_fence *fence;
+
+ fence = kzalloc_obj(*fence, GFP_KERNEL);
+ if (fence == NULL)
+ return NULL;
+
+ spin_lock_init(&fence->lock);
+ dma_fence_init(&fence->base, &pagefault_fence_ops, &fence->lock,
+ dma_fence_context_alloc(1), 1);
+
+ return fence;
+}
+
+static void pagefault_set_private(struct xe_pagefault *pf,
+ struct xe_eudebug_pagefault *epf)
+{
+ u64 private;
+
+ epf->private = pf->producer.private;
+ private = (u64)epf | XE_EUDEBUG_PAGEFAULT_PRIVATE_EUDEBUG;
+ pf->producer.private = (void *)private;
+}
+
+void xe_eudebug_pagefault_set_private(struct xe_pagefault *pf,
+ struct xe_vm *vm)
+{
+ struct xe_eudebug_pagefault *epf;
+ struct xe_eudebug *d;
+
+ if (!xe_eudebug_is_enabled(vm->xe))
+ return;
+
+ /* Could be a retry from -EAGAIN handler error */
+ if ((u64)pf->producer.private & XE_EUDEBUG_PAGEFAULT_PRIVATE_EUDEBUG)
+ return;
+
+ d = xe_eudebug_get_nolock_with_discovery(vm->xef);
+ if (!d)
+ return;
+
+ mutex_lock(&d->xe->eudebug.lock);
+ epf = d->pf.first;
+ if (epf && pf->consumer.asid == d->pf.asid)
+ d->pf.active++;
+ else
+ epf = NULL;
+ mutex_unlock(&d->xe->eudebug.lock);
+
+ if (epf)
+ pagefault_set_private(pf, epf);
+
+ xe_eudebug_put(d);
+}
+
+void *xe_eudebug_pagefault_get_private(void *private)
+{
+ if ((u64)private & XE_EUDEBUG_PAGEFAULT_PRIVATE_EUDEBUG) {
+ struct xe_eudebug_pagefault *epf = (void *)((u64)private &
+ ~XE_EUDEBUG_PAGEFAULT_PRIVATE_EUDEBUG);
+ return epf->private;
+ }
+ return private;
+}
+
+int
+xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf)
+{
+ struct pagefault_fence *pf_fence;
+ struct xe_eudebug_pagefault *epf;
+ struct xe_gt *gt = pf->gt;
+ struct xe_exec_queue *q;
+ struct dma_fence *fence;
+ struct xe_eudebug *d;
+ unsigned long tdctl_timeout;
+ unsigned int fw_ref;
+ int lrc_idx;
+ u32 td_ctl;
+
+ if (!xe_eudebug_is_enabled(vm->xe))
+ return -EOPNOTSUPP;
+
+ d = xe_eudebug_get_nolock_with_discovery(vm->xef);
+ if (!d)
+ return -ENOENT;
+
+ q = xe_gt_runalone_active_queue_get(gt, &lrc_idx);
+ if (IS_ERR(q))
+ goto err_put_eudebug;
+
+ if (XE_WARN_ON(q->vm != vm))
+ goto err_put_exec_queue;
+
+ if (!xe_exec_queue_is_debuggable(q))
+ goto err_put_exec_queue;
+
+ /**
+ * Check if there is an active pagefault.
+ * If so, attach original epf to current pagefault and leave.
+ */
+ mutex_lock(&d->xe->eudebug.lock);
+ if (d->pf.active || d->pf.first) {
+ epf = kzalloc_obj(*epf, GFP_KERNEL);
+ if (!epf) {
+ mutex_unlock(&d->xe->eudebug.lock);
+ goto err_put_exec_queue;
+ }
+ d->pf.active++;
+ goto out_set_epf;
+ }
+
+ fw_ref = xe_force_wake_get(gt_to_fw(gt), q->hwe->domain);
+ if (!fw_ref)
+ goto err_put_exec_queue_unlock;
+
+ /*
+ * If there is no debug functionality (TD_CTL_GLOBAL_DEBUG_ENABLE, etc.),
+ * don't proceed pagefault routine for eu debugger.
+ */
+ td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+ if (!(td_ctl & TD_CTL_GLOBAL_DEBUG_ENABLE))
+ goto err_put_fw;
+
+ epf = kzalloc_obj(*epf, GFP_KERNEL);
+ if (!epf)
+ goto err_put_fw;
+
+ /* Will be enabled when d->pf.first is released */
+ xe_eudebug_attention_poll_stop(gt_to_xe(gt));
+
+ do {
+ fence = dma_fence_get(d->pf.fence);
+ if (fence) {
+ mutex_unlock(&d->xe->eudebug.lock);
+ dma_fence_wait(fence, true);
+ dma_fence_put(fence);
+ mutex_lock(&d->xe->eudebug.lock);
+ }
+ } while (fence);
+
+ pf_fence = pagefault_fence_create();
+ if (!pf_fence)
+ goto err_fence;
+
+ d->pf.fence = &pf_fence->base;
+
+ INIT_LIST_HEAD(&epf->link);
+
+ xe_gt_eu_attentions_read(gt, &epf->attentions.before, 0);
+
+ if (td_ctl & TD_CTL_FORCE_EXCEPTION)
+ eu_warn(d, "force exception already set!");
+
+ tdctl_timeout = jiffies + msecs_to_jiffies(XE_GT_ATTENTION_TIMEOUT_MS);
+ /* Halt regardless of thread dependencies */
+ do {
+ xe_gt_mcr_multicast_write(gt, TD_CTL,
+ td_ctl | TD_CTL_FORCE_EXCEPTION);
+ usleep_range(200, 220);
+ td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+
+ if (!(td_ctl & TD_CTL_FORCE_EXCEPTION) &&
+ time_after(jiffies, tdctl_timeout)) {
+ eu_err(d, "Failed to set Force Exception. Pagefault failed");
+ goto err_tdctl;
+ }
+ } while (!(td_ctl & TD_CTL_FORCE_EXCEPTION));
+
+ xe_gt_eu_attentions_read(gt, &epf->attentions.after,
+ XE_GT_ATTENTION_TIMEOUT_MS);
+
+ xe_force_wake_put(gt_to_fw(gt), fw_ref);
+
+out_set_epf:
+ /*
+ * xe_exec_queue_put() will be called from destroy_pagefault()
+ * or handle_pagefault()
+ */
+ epf->q = q;
+ epf->d = d; /* Ref is taken and will not be dropped here */
+ if (!d->pf.first) {
+ d->pf.first = epf;
+ d->pf.active++;
+ d->pf.asid = pf->consumer.asid;
+ }
+ mutex_unlock(&d->xe->eudebug.lock);
+
+ epf->lrc_idx = lrc_idx;
+ epf->fault.addr = pf->consumer.page_addr;
+ epf->fault.type_level = pf->consumer.fault_type_level;
+ epf->fault.access_type = pf->consumer.access_type;
+
+ pagefault_set_private(pf, epf);
+
+ return 0;
+
+err_tdctl:
+ dma_fence_put(d->pf.fence);
+ d->pf.fence = NULL;
+err_fence:
+ xe_eudebug_attention_poll_start(gt_to_xe(gt));
+ kfree(epf);
+err_put_fw:
+ xe_force_wake_put(gt_to_fw(gt), fw_ref);
+err_put_exec_queue_unlock:
+ mutex_unlock(&d->xe->eudebug.lock);
+err_put_exec_queue:
+ xe_exec_queue_put(q);
+err_put_eudebug:
+ xe_eudebug_put(d);
+
+ return -EINVAL;
+}
+
+static struct xe_eudebug_pagefault *_get_epf(void *private)
+{
+ if ((u64)private & XE_EUDEBUG_PAGEFAULT_PRIVATE_EUDEBUG)
+ return (struct xe_eudebug_pagefault *)((u64)private &
+ ~XE_EUDEBUG_PAGEFAULT_PRIVATE_EUDEBUG);
+
+ return NULL;
+
+}
+static struct xe_eudebug_pagefault *xe_eudebug_get_epf(struct xe_pagefault *pf)
+{
+ return _get_epf(pf->producer.private);
+}
+
+struct xe_vma *xe_eudebug_create_vma(struct xe_vm *vm, struct xe_pagefault *pf)
+{
+ u64 addr;
+ size_t align;
+ struct xe_vma *vma = NULL;
+ struct xe_eudebug_pagefault *epf = xe_eudebug_get_epf(pf);
+
+ align = vm->flags & XE_VM_FLAG_64K ? SZ_64K : SZ_4K;
+ addr = ALIGN_DOWN(pf->consumer.page_addr, align);
+ vma = xe_vm_create_null_vma(vm, addr);
+ if (IS_ERR(vma))
+ return vma;
+
+ epf->null_vma = vma;
+ return vma;
+}
+
+static void eudebug_destroy_vma(struct xe_vm *vm, struct xe_vma *vma)
+{
+ struct dma_fence *fence;
+
+ xe_vm_lock(vm, false);
+ xe_vm_prep_vma_destroy(vm, vma, true);
+
+ fence = xe_vma_unbind(vm, vma, vma->tile_present);
+ if (IS_ERR(fence)) {
+ drm_err(&vm->xe->drm,
+ "eudebug: failed to unbind temporary NULL vma. Err = %ld\n",
+ PTR_ERR(fence));
+ fence = NULL;
+ } else {
+ dma_fence_wait(fence, true);
+ }
+
+ xe_vma_destroy(vma, fence);
+ if (fence)
+ dma_fence_put(fence);
+ xe_vm_unlock(vm);
+}
+
+static void destroy_pagefault(struct xe_eudebug_pagefault *epf)
+{
+ if (epf->d && epf == epf->d->pf.first)
+ epf->d->pf.first = NULL;
+
+ if (epf->null_vma) {
+ lockdep_assert_held(&epf->q->vm->lock);
+ eudebug_destroy_vma(epf->q->vm, epf->null_vma);
+ }
+
+ xe_exec_queue_put(epf->q);
+ if (epf->d)
+ xe_eudebug_put(epf->d);
+ kfree(epf);
+}
+
+static void queue_pagefault(struct xe_eudebug *d,
+ struct xe_eudebug_pagefault *epf)
+{
+ lockdep_assert_held(&epf->q->vm->lock);
+
+ mutex_lock(&d->pf.lock);
+
+ if (epf->null_vma) {
+ eudebug_destroy_vma(epf->q->vm, epf->null_vma);
+ epf->null_vma = NULL;
+ }
+
+ list_add_tail(&epf->link, &d->pf.pagefaults);
+ mutex_unlock(&d->pf.lock);
+
+ /* Queued is equivalent of sent. Drop references */
+ xe_eudebug_put(epf->d);
+ epf->d = NULL;
+}
+
+static void
+xe_eudebug_pagefault_process(struct xe_eudebug_pagefault *epf)
+{
+ struct xe_gt *gt = epf_to_gt(epf);
+
+ xe_gt_eu_attentions_read(gt, &epf->attentions.resolved,
+ XE_GT_ATTENTION_TIMEOUT_MS);
+}
+
+static int send_queued_pagefaults(struct xe_eudebug *d)
+{
+ struct xe_eudebug_pagefault *epf, *epf_temp;
+ int ret = 0;
+
+ mutex_lock(&d->pf.lock);
+ list_for_each_entry_safe(epf, epf_temp, &d->pf.pagefaults, link) {
+ ret = xe_eudebug_send_pagefault_event(d, epf);
+
+ if (ret == -ENOSPC) {
+ ret = 0;
+ break;
+ }
+
+ list_del(&epf->link);
+
+ destroy_pagefault(epf);
+
+ if (ret)
+ break;
+ }
+ mutex_unlock(&d->pf.lock);
+ return ret;
+}
+
+/*
+ * Fills up the 'resolved' bitmask.
+ * Clears FEE and singlas the pagefault fence.
+ * In the end event is send or internally queued.
+ *
+ * Returns 0 if epf shall not be destroyed (event was queued).
+ */
+static int
+eudebug_pagefault_finalize(struct xe_eudebug_pagefault *epf, int err)
+{
+ struct xe_gt *gt = epf_to_gt(epf);
+ struct xe_eudebug *d;
+ unsigned long tdctl_timeout;
+ unsigned int fw_ref;
+ bool queued = false;
+ u32 td_ctl, ret = 0;
+
+ fw_ref = xe_force_wake_get(gt_to_fw(gt), epf->q->hwe->domain);
+ if (!fw_ref) {
+ struct xe_device *xe = gt_to_xe(gt);
+
+ drm_warn(&xe->drm, "Forcewake fail: Can not recover TD_CTL");
+ } else {
+ td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+ tdctl_timeout = jiffies + msecs_to_jiffies(XE_GT_ATTENTION_TIMEOUT_MS);
+ do {
+ xe_gt_mcr_multicast_write(gt, TD_CTL, td_ctl &
+ ~(TD_CTL_FORCE_EXCEPTION));
+ usleep_range(200, 220);
+ td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+
+ if ((td_ctl & TD_CTL_FORCE_EXCEPTION) &&
+ time_after(jiffies, tdctl_timeout)) {
+ eu_err(epf->d, "Failed to clear Force Exception!!!");
+ break;
+ }
+ } while (td_ctl & TD_CTL_FORCE_EXCEPTION);
+ xe_force_wake_put(gt_to_fw(gt), fw_ref);
+ }
+
+ d = epf->d;
+
+ if (!err) {
+ if (completion_done(&d->discovery)) {
+ /* Just in case there was a discovery */
+ ret = send_queued_pagefaults(d);
+ if (!ret) {
+ ret = xe_eudebug_send_pagefault_event(d, epf);
+ if (ret == -ENOSPC) {
+ queue_pagefault(d, epf);
+ queued = true;
+ ret = 0;
+ }
+ }
+
+ } else {
+ queue_pagefault(d, epf);
+ queued = true;
+ }
+ }
+
+ if (d->pf.fence) {
+ dma_fence_signal(d->pf.fence);
+ dma_fence_put(d->pf.fence);
+ d->pf.fence = NULL;
+ }
+
+ return (!queued || ret);
+}
+
+int xe_eudebug_handle_pagefaults(struct xe_gt *gt)
+{
+ struct xe_exec_queue *q;
+ struct xe_eudebug *d;
+ int ret, lrc_idx;
+
+ q = xe_gt_runalone_active_queue_get(gt, &lrc_idx);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
+
+ if (!xe_exec_queue_is_debuggable(q)) {
+ ret = -EPERM;
+ goto out_exec_queue_put;
+ }
+
+ d = xe_eudebug_get_nolock_with_discovery(q->vm->xef);
+ if (!d) {
+ ret = -ENOTCONN;
+ goto out_exec_queue_put;
+ } else {
+ if (!completion_done(&d->discovery)) {
+ xe_eudebug_put(d);
+ ret = -EBUSY;
+ goto out_exec_queue_put;
+ }
+ }
+
+ ret = send_queued_pagefaults(d);
+
+ xe_eudebug_put(d);
+
+out_exec_queue_put:
+ xe_exec_queue_put(q);
+
+ return ret;
+}
+
+static bool
+xe_eudebug_pagefault_queue_has_asid(struct xe_pagefault_queue *pf_queue,
+ u32 asid)
+{
+ struct xe_device *xe = container_of(pf_queue, typeof(*xe),
+ usm.pf_queue);
+ struct xe_pagefault_work *pf_work;
+ struct xe_pagefault *lpf;
+ u32 head, tail;
+ int i;
+
+ guard(spinlock_irq)(&pf_queue->lock);
+
+ /*
+ * Entry can be as pf_worker.cache but
+ * waiting for eudebug hw mutex.
+ */
+ pf_work = xe->usm.pf_workers;
+ for (i = 0; i < xe->info.num_pf_work; ++i)
+ if (pf_work[i].cache.asid == asid &&
+ pf_work[i].cache.start != XE_PAGEFAULT_CACHE_START_INVALID)
+ return true;
+
+ head = pf_queue->head;
+ tail = pf_queue->tail;
+
+ /* PF my be queued and pending processing. */
+ while (head != tail) {
+ lpf = (pf_queue->data + tail);
+ if (lpf->consumer.alloc_state == XE_PAGEFAULT_ALLOC_STATE_QUEUED)
+ if (lpf->consumer.asid == asid)
+ return true;
+
+ tail = (tail + xe_pagefault_entry_size()) % pf_queue->size;
+ }
+
+ return false;
+}
+
+void xe_eudebug_pagefault_end(void *private, int err)
+{
+ struct xe_eudebug_pagefault *epf = _get_epf(private);
+ struct xe_eudebug_pagefault *first_epf = NULL;
+ struct xe_pagefault_queue *pf_queue;
+ struct xe_device *xe;
+ struct xe_eudebug *d;
+ struct xe_vm *vm;
+ int resume_attn = 0, destroy_pf = 0;
+
+ if (!epf)
+ return;
+
+ xe = epf->q->xef->xe;
+ pf_queue = &xe->usm.pf_queue;
+
+ d = epf->d;
+ vm = xe_vm_get(epf->q->vm);
+ /* Need to have outher vm lock for eudebug lock as for pf start */
+ down_write(&vm->lock);
+ mutex_lock(&d->xe->eudebug.lock);
+ if (!--d->pf.active) {
+ /*
+ * This will also catch entries that are popped from pagefault
+ * queue and moved to worker but not yet processed.
+ * xe_eudebug_pagefault_start() will catch later it and increase
+ * the pf.active counter.
+ */
+ if (!xe_eudebug_pagefault_queue_has_asid(pf_queue, d->pf.asid)) {
+ if (!err)
+ xe_eudebug_pagefault_process(d->pf.first);
+
+ destroy_pf = eudebug_pagefault_finalize(d->pf.first, err);
+ /* If d->pf.first was queued the epf shall be removed. */
+ if (epf != d->pf.first) {
+ if (destroy_pf)
+ first_epf = d->pf.first;
+ else
+ destroy_pf = 1;
+ }
+ d->pf.first = NULL;
+ d->pf.asid = 0;
+ resume_attn = 1;
+ } else {
+ /* page faults still queued */
+ if (epf != d->pf.first)
+ destroy_pf = 1;
+ }
+ } else {
+ /* Multiple page faults for different addresses. Remove vma.*/
+ if (epf != d->pf.first)
+ destroy_pf = 1;
+ }
+ mutex_unlock(&d->xe->eudebug.lock);
+
+ if (destroy_pf) {
+ destroy_pagefault(epf);
+ if (first_epf)
+ destroy_pagefault(first_epf);
+ }
+ up_write(&vm->lock);
+ xe_vm_put(vm);
+
+ if (resume_attn)
+ xe_eudebug_attention_poll_start(xe);
+}
+
+void xe_eudebug_pagefault_fini(struct xe_eudebug *d)
+{
+ struct xe_eudebug_pagefault *epf, *epf_temp;
+
+ /* Since it's the last reference no race here */
+
+ list_for_each_entry_safe(epf, epf_temp, &d->pf.pagefaults, link) {
+ list_del(&epf->link);
+ destroy_pagefault(epf);
+ }
+
+ if (d->pf.first) {
+ struct xe_vm *vm;
+ epf = d->pf.first;
+ vm = xe_vm_get(epf->q->vm);
+ down_write(&vm->lock);
+ destroy_pagefault(epf);
+ up_write(&vm->lock);
+ xe_vm_put(vm);
+ }
+ XE_WARN_ON(d->pf.fence);
+}
+
+void xe_eudebug_pagefault_signal(struct xe_eudebug *d)
+{
+ struct dma_fence *f;
+
+ mutex_lock(&d->xe->eudebug.lock);
+ f = d->pf.fence;
+ d->pf.fence = NULL;
+ mutex_unlock(&d->xe->eudebug.lock);
+
+ if (f) {
+ dma_fence_signal(f);
+ dma_fence_put(f);
+ }
+}
+
+bool xe_eudebug_pagefault_creatable(struct xe_gt *gt, struct xe_vm *vm)
+{
+ struct xe_exec_queue *q;
+ struct xe_eudebug *d;
+ bool ret = false;
+ int lrc_idx;
+
+ if (GRAPHICS_VER(gt_to_xe(gt)) >= 35)
+ goto out;
+
+ d = xe_eudebug_get_nolock(vm->xef);
+ if (!d)
+ goto out;
+
+ q = xe_gt_runalone_active_queue_get(gt, &lrc_idx);
+ if (IS_ERR(q))
+ goto err_put_eudebug;
+
+ if (XE_WARN_ON(q->vm != vm))
+ goto err_put_exec_queue;
+
+ if (!xe_exec_queue_is_debuggable(q))
+ goto err_put_exec_queue;
+
+ ret = true;
+
+err_put_exec_queue:
+ xe_exec_queue_put(q);
+err_put_eudebug:
+ xe_eudebug_put(d);
+
+out:
+ return ret;
+}
diff --git a/drivers/gpu/drm/xe/xe_eudebug_pagefault.h b/drivers/gpu/drm/xe/xe_eudebug_pagefault.h
new file mode 100644
index 000000000000..927c9b83457c
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_pagefault.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023-2025 Intel Corporation
+ */
+
+#ifndef _XE_EUDEBUG_PAGEFAULT_H_
+#define _XE_EUDEBUG_PAGEFAULT_H_
+
+#include <linux/types.h>
+
+struct xe_eudebug;
+struct xe_gt;
+struct xe_pagefault;
+struct xe_eudebug_pagefault;
+struct xe_vm;
+struct xe_file;
+
+void xe_eudebug_pagefault_fini(struct xe_eudebug *d);
+int xe_eudebug_handle_pagefaults(struct xe_gt *gt);
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+int xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf);
+struct xe_vma *xe_eudebug_create_vma(struct xe_vm *vm, struct xe_pagefault *pf);
+void xe_eudebug_pagefault_end(void *private, int err);
+/*
+ * The (struct xe_pagefault *)->producer.private is a pointer which, for now,
+ * stores the pointer guc.
+ * EU Debug intercepts this pointer to store struct xe_eudebug_pagefault.
+ * Original pointer can be obtained via eudebug function below called with
+ * mentioned producer's private field.
+ */
+#define XE_EUDEBUG_PAGEFAULT_PRIVATE_EUDEBUG 0x1
+void xe_eudebug_pagefault_set_private(struct xe_pagefault *pf,
+ struct xe_vm *vm);
+void *xe_eudebug_pagefault_get_private(void *private);
+
+void xe_eudebug_pagefault_signal(struct xe_eudebug *d);
+
+bool xe_eudebug_pagefault_creatable(struct xe_gt *gt, struct xe_vm *vm);
+#else
+
+static inline int
+xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void xe_eudebug_pagefault_end(void *private, int err)
+{
+}
+
+static inline struct xe_vma *xe_eudebug_create_vma(struct xe_vm *vm,
+ struct xe_pagefault *pf)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void xe_eudebug_pagefault_set_private(struct xe_pagefault *pf,
+ struct xe_vm *vm)
+{
+}
+
+static inline void *xe_eudebug_pagefault_get_private(void *private)
+{
+ return private;
+}
+
+static inline void xe_eudebug_pagefault_signal(struct xe_eudebug *d)
+{
+}
+
+static inline bool xe_eudebug_pagefault_creatable(struct xe_gt *gt,
+ struct xe_vm *vm)
+{
+ return false;
+}
+#endif
+
+#endif /* _XE_EUDEBUG_PAGEFAULT_H_ */
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 5d3f190baecd..12711f507ddc 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -17,6 +17,7 @@
#include <linux/xarray.h>
#include <uapi/drm/xe_drm_eudebug.h>
+#include "xe_gt_debug_types.h"
struct xe_device;
struct xe_eudebug;
@@ -38,7 +39,7 @@ enum xe_eudebug_cap_state {
XE_EUDEBUG_CAP_ENABLED,
};
-#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
+#define XE_EUDEBUG_MAX_EVENT_TYPE DRM_XE_EUDEBUG_EVENT_PAGEFAULT
/**
* struct xe_eudebug_handle - eudebug resource handle
@@ -169,6 +170,110 @@ struct xe_eudebug {
/** @ops: operations for eu_control */
const struct xe_eudebug_eu_control_ops *ops;
+
+ /**
+ * @pf: Aggregates pagefault related fields.
+ */
+ struct {
+ /** @pf.lock: guards access to pagefaults list*/
+ struct mutex lock;
+
+ /** @pf.pagefaults: xe_eudebug_pagefault list for pagefault event queuing */
+ struct list_head pagefaults;
+
+ /**
+ * @pf.fence: fence on operations of eus (eu thread control and attention)
+ * when page faults are being handled, protected by @xe.eudebug.lock.
+ */
+ struct dma_fence *fence;
+
+ /**
+ * @pf.active: number of pagefaults that are being processed in
+ * parallel by workers and that are after xe_eudebug_pagefault_start()
+ * but before xe_eudebug_pagefault_end() (ack_fault_end() handler).
+ *
+ * Value 0 means that no other worker is currently handling eudebug
+ * related pagefault but there still may be a pagefault queued and waiting.
+ *
+ * Protected by @xe.eudebug.lock.
+ */
+ u32 active;
+
+ /**
+ * @pf.first: first pagefault. Only this pagefault will be reported
+ * with event.
+ * Subsequent pagefaults with matching VM will be ACKed without
+ * being handled by eudebug.
+ * Valid until there are no more pagefaults with matching asid.
+ *
+ * This field may be set while @pf.active is 0 if eudebug related
+ * pagefault is queued but not yet processed.
+ * Protected by @xe.eudebug.lock.
+ */
+ struct xe_eudebug_pagefault *first;
+
+ /**
+ * @pf.asid: VM id of the first pagefault (@pf.first).
+ */
+ u32 asid;
+ } pf;
+};
+
+/**
+ * struct xe_eudebug_pagefault - eudebug structure for queuing pagefault
+ */
+struct xe_eudebug_pagefault {
+ /** @link: link into the xe_eudebug.pagefaults */
+ struct list_head link;
+ /** @d: eudebug instance. */
+ struct xe_eudebug *d;
+ /** @q: exec_queue which raised pagefault */
+ struct xe_exec_queue *q;
+ /** @lrc_idx: lrc index of the workload which raised pagefault */
+ int lrc_idx;
+
+ /** @fault: pagefault raw partial data passed from guc */
+ struct {
+ /** @fault.addr: ppgtt address where the pagefault occurred */
+ u64 addr;
+ /** @fault.type_level: mixed type & level */
+ u8 type_level;
+ /** @fault.access_type: access type */
+ u8 access_type;
+ } fault;
+
+ /** @attentions: attention states in different phases of fault */
+ struct {
+ /** @attentions.before: state of attention bits before page fault WA processing*/
+ struct xe_eu_attentions before;
+ /**
+ * @attentions.after: status of attention bits during page fault WA processing.
+ * It includes eu threads where attention bits are turned on for
+ * reasons other than page fault WA (breakpoint, interrupt, etc.).
+ */
+ struct xe_eu_attentions after;
+ /**
+ * @attentions.resolved: state of the attention bits after page fault WA.
+ * It includes the eu thread that caused the page fault.
+ * To determine the eu thread that caused the page fault,
+ * do XOR attentions.after and attentions.resolved.
+ */
+ struct xe_eu_attentions resolved;
+ } attentions;
+
+ /**
+ * @private: copied the (struct xe_pagefault *)->producer.private filed.
+ * EU Debugger masks private field in the struct xe_pagefault.
+ * The xe_eudebug_pagefault_get_private() function to extracts original
+ * private field regardless if it was shadowed or not.
+ */
+ void *private;
+
+ /**
+ * @null_vma: temporary vma for handling pagefault. Shall be removed
+ * when pagefault is handled.
+ */
+ struct xe_vma *null_vma;
};
#endif /* _XE_EUDEBUG_TYPES_H_ */
diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h
index f99b4e22441c..c7ff08408e43 100644
--- a/drivers/gpu/drm/xe/xe_pagefault_types.h
+++ b/drivers/gpu/drm/xe/xe_pagefault_types.h
@@ -10,6 +10,7 @@
struct xe_gt;
struct xe_pagefault;
+struct xe_eudebug_pagefault;
/** enum xe_pagefault_access_type - Xe page fault access type */
enum xe_pagefault_access_type {
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 57ff3d90ac29..903c01703792 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -74,6 +74,7 @@ struct drm_xe_eudebug_event {
#define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_DEBUG_DATA 5
#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE 6
#define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION 7
+#define DRM_XE_EUDEBUG_EVENT_PAGEFAULT 8
/** @flags: Flags */
__u16 flags;
@@ -397,6 +398,17 @@ struct drm_xe_eudebug_event_eu_attention {
__u8 bitmask[];
};
+struct drm_xe_eudebug_event_pagefault {
+ struct drm_xe_eudebug_event base;
+
+ __u64 exec_queue_handle;
+ __u64 lrc_handle;
+ __u32 flags;
+ __u32 bitmask_size;
+ __u64 pagefault_address;
+ __u8 bitmask[];
+};
+
#if defined(__cplusplus)
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v10 27/27] drm/xe/eudebug: Enable EU pagefault handling
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (25 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 26/27] drm/xe/eudebug: Introduce EU pagefault handling interface Mika Kuoppala
@ 2026-09-03 14:59 ` Mika Kuoppala
2026-09-03 15:46 ` sashiko-bot
2026-09-03 15:35 ` ✗ CI.checkpatch: warning for Intel Xe GPU Debug Support (eudebug) v10 Patchwork
` (5 subsequent siblings)
32 siblings, 1 reply; 48+ messages in thread
From: Mika Kuoppala @ 2026-09-03 14:59 UTC (permalink / raw)
To: intel-xe
Cc: simona.vetter, matthew.brost, christian.koenig, thomas.hellstrom,
joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, rodrigo.vivi, andrzej.hajda,
matthew.auld, maciej.patelczyk, gwan-gyeong.mun, Mika Kuoppala
From: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
The XE2 (and PVC) HW has a limitation that the pagefault due to invalid
access will halt the corresponding EUs. To solve this problem, enable
EU pagefault handling functionality, which allows to unhalt pagefaulted
eu threads and to EU debugger to get inform about the eu attentions state
of EU threads during execution.
If a pagefault occurs, send the DRM_XE_EUDEBUG_EVENT_PAGEFAULT event
after handling the pagefault.
The pagefault handling is a mechanism that allows a stalled EU thread to
enter SIP mode by installing a temporal null page to the page table entry
where the pagefault happened.
A brief description of the page fault handling mechanism flow between KMD
and the eu thread is as follows
(1) eu thread accesses unallocated address
(2) pagefault happens and eu thread stalls
(3) XE kmd set an force eu thread exception to allow the running eu thread
to enter SIP mode (kmd set ForceException bit of TD_CTL register)
Not stalled (none-pagefaulted) eu threads enter SIP mode
(4) XE kmd installs temporal null page to the pagetable entry of the
address where pagefault happened.
(5) XE kmd replies pagefault successful message to GUC
(6) When a given pagefault is fully handled temporary NULL VMA is
removed.
(7) If multiple threads caused a pagefault and this is reflected in
pagefault queue or worker's cache then the first pagefault
finalization is postponed but the worker is released
(8) All subsequent pagefaults for a given VM are handled by eudebug by
inserting NULL VMA, ACK and then remove the temporary VMA
(9) stalled eu thread resumes as per pagefault condition has resolved
(10) resumed eu thread enters SIP mode due to force exception set
by (3)
(9) When there are no more pagefault to process the first pagefault
finalization is performed and event is send.
As designed this feature to only work when eudbug is enabled, it should
have no impact to regular recoverable pagefault code path.
v2: - pf->q holds the vm ref so drop it (Mika)
- streamline uapi (Mika)
- cleanup the pagefault through producer if (Mika)
v3: - pagefault rework (Maciej)
Assisted-by: GitHub Copilot CLI:claude-opus-4.7
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Gustavo Sousa <gustavo.sousa@intel.com>
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
drivers/gpu/drm/xe/xe_eudebug_pagefault.c | 25 ++++-
drivers/gpu/drm/xe/xe_eudebug_pagefault.h | 6 +-
drivers/gpu/drm/xe/xe_eudebug_types.h | 5 +
drivers/gpu/drm/xe/xe_guc_pagefault.c | 10 +-
drivers/gpu/drm/xe/xe_pagefault.c | 106 +++++++++++++++++++++-
drivers/gpu/drm/xe/xe_pagefault_types.h | 3 +-
6 files changed, 142 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_eudebug_pagefault.c b/drivers/gpu/drm/xe/xe_eudebug_pagefault.c
index 5ad37e757f69..f64e1974c86d 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_eudebug_pagefault.c
@@ -139,8 +139,18 @@ void *xe_eudebug_pagefault_get_private(void *private)
return private;
}
+static void
+eudebug_try_svm_remap(struct xe_vm *vm, struct xe_vma *vma)
+{
+ if (xe_vm_insert_vma(vm, vma)) {
+ xe_vm_destroy_vma(vma);
+ xe_vm_kill(vm, true);
+ }
+}
+
int
-xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf)
+xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_vma *vma,
+ struct xe_pagefault *pf)
{
struct pagefault_fence *pf_fence;
struct xe_eudebug_pagefault *epf;
@@ -170,6 +180,9 @@ xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf)
if (!xe_exec_queue_is_debuggable(q))
goto err_put_exec_queue;
+ if (vma && !xe_vma_is_cpu_addr_mirror(vma))
+ goto err_put_exec_queue;
+
/**
* Check if there is an active pagefault.
* If so, attach original epf to current pagefault and leave.
@@ -267,6 +280,7 @@ xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf)
epf->fault.access_type = pf->consumer.access_type;
pagefault_set_private(pf, epf);
+ epf->svm_vma = vma;
return 0;
@@ -352,6 +366,11 @@ static void destroy_pagefault(struct xe_eudebug_pagefault *epf)
eudebug_destroy_vma(epf->q->vm, epf->null_vma);
}
+ if (epf->svm_vma) {
+ lockdep_assert_held(&epf->q->vm->lock);
+ eudebug_try_svm_remap(epf->q->vm, epf->svm_vma);
+ }
+
xe_exec_queue_put(epf->q);
if (epf->d)
xe_eudebug_put(epf->d);
@@ -370,6 +389,10 @@ static void queue_pagefault(struct xe_eudebug *d,
epf->null_vma = NULL;
}
+ if (epf->svm_vma) {
+ eudebug_try_svm_remap(epf->q->vm, epf->svm_vma);
+ epf->svm_vma = NULL;
+ }
list_add_tail(&epf->link, &d->pf.pagefaults);
mutex_unlock(&d->pf.lock);
diff --git a/drivers/gpu/drm/xe/xe_eudebug_pagefault.h b/drivers/gpu/drm/xe/xe_eudebug_pagefault.h
index 927c9b83457c..976c8a88b9ba 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_pagefault.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_pagefault.h
@@ -13,13 +13,15 @@ struct xe_gt;
struct xe_pagefault;
struct xe_eudebug_pagefault;
struct xe_vm;
+struct xe_vma;
struct xe_file;
void xe_eudebug_pagefault_fini(struct xe_eudebug *d);
int xe_eudebug_handle_pagefaults(struct xe_gt *gt);
#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
-int xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf);
+int xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_vma *vma,
+ struct xe_pagefault *pf);
struct xe_vma *xe_eudebug_create_vma(struct xe_vm *vm, struct xe_pagefault *pf);
void xe_eudebug_pagefault_end(void *private, int err);
/*
@@ -40,7 +42,7 @@ bool xe_eudebug_pagefault_creatable(struct xe_gt *gt, struct xe_vm *vm);
#else
static inline int
-xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf)
+xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_vma *vma, struct xe_pagefault *pf)
{
return -EOPNOTSUPP;
}
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 12711f507ddc..2f364aa48ab7 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -274,6 +274,11 @@ struct xe_eudebug_pagefault {
* when pagefault is handled.
*/
struct xe_vma *null_vma;
+ /**
+ * @svm_vma: After handling SVM pagefault original mapping shall be restored.
+ * The svm_vma is the vma which was removed from original SVM mapping.
+ */
+ struct xe_vma *svm_vma;
};
#endif /* _XE_EUDEBUG_TYPES_H_ */
diff --git a/drivers/gpu/drm/xe/xe_guc_pagefault.c b/drivers/gpu/drm/xe/xe_guc_pagefault.c
index 8f8210a732e9..12a8fb4db134 100644
--- a/drivers/gpu/drm/xe/xe_guc_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_guc_pagefault.c
@@ -9,12 +9,13 @@
#include "xe_guc_pagefault.h"
#include "xe_pagefault.h"
#include "xe_pagefault_types.h"
+#include "xe_eudebug_pagefault.h"
#define XE_GUC_PAGEFAULT_FLUSH_PERIOD BIT(4) /* Sixteen */
static void guc_ack_fault_begin(void *private)
{
- struct xe_guc *guc = private;
+ struct xe_guc *guc = xe_eudebug_pagefault_get_private(private);
xe_guc_ct_lock(&guc->ct);
@@ -51,7 +52,7 @@ static void guc_ack_fault(struct xe_pagefault *pf, int err)
FIELD_PREP(PFR_ENG_CLASS, engine_class) |
FIELD_PREP(PFR_PDATA, pdata),
};
- struct xe_guc *guc = pf->producer.private;
+ struct xe_guc *guc = xe_eudebug_pagefault_get_private(pf->producer.private);
bool write_only = guc->pagefault_ack_counter++ &
(XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1);
@@ -59,13 +60,14 @@ static void guc_ack_fault(struct xe_pagefault *pf, int err)
write_only);
}
-static void guc_ack_fault_end(void *private)
+static void guc_ack_fault_end(void *private, int err)
{
- struct xe_guc *guc = private;
+ struct xe_guc *guc = xe_eudebug_pagefault_get_private(private);
if ((guc->pagefault_ack_counter & (XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1)) != 1)
xe_guc_ct_send_flush(&guc->ct);
xe_guc_ct_unlock(&guc->ct);
+ xe_eudebug_pagefault_end(private, err);
}
static const struct xe_pagefault_ops guc_pagefault_ops = {
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 27c3a90e4e73..348ebda5a5fc 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -10,6 +10,7 @@
#include "xe_bo.h"
#include "xe_device.h"
+#include "xe_eudebug_pagefault.h"
#include "xe_gt_printk.h"
#include "xe_gt_types.h"
#include "xe_gt_stats.h"
@@ -227,8 +228,56 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
vma = xe_vm_find_vma_by_addr(vm, pf->consumer.page_addr);
if (!vma) {
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+retry_eudebug_pf:
+#endif
err = -EINVAL;
- goto unlock_vm;
+ if (!xe_eudebug_pagefault_start(vm, vma, pf)) {
+ /*
+ * This section is reachable only when eudebug is connected.
+ * It's rather safe since page faults hitting same vma
+ * are chained. Only the first one will be fully processed.
+ *
+ * For SVM retry case we're holding vm write lock
+ */
+ if (!vma) {
+ up_read(&vm->lock);
+ down_write(&vm->lock);
+ /* The lock was dropped, re-check the vma */
+ vma = xe_vm_find_vma_by_addr(vm, pf->consumer.page_addr);
+ if (vma) {
+ err = -EINVAL;
+ downgrade_write(&vm->lock);
+ goto unlock_vm;
+ }
+ }
+ vma = xe_eudebug_create_vma(vm, pf);
+ downgrade_write(&vm->lock);
+ if (IS_ERR(vma)) {
+ err = PTR_ERR(vma);
+ vma = NULL;
+ }
+ } else if (vma) {
+ /*
+ * xe_eudebug_pagefault_start() failed on svm retry.
+ * Need to insert again vma.
+ * Write-lock is still held so no error expected.
+ */
+ xe_vm_insert_vma(vm, vma);
+ vma = NULL;
+ downgrade_write(&vm->lock);
+ }
+ if (!vma)
+ goto unlock_vm;
+ } else {
+ /*
+ * For non-SVM case:
+ * Eudebug with active pagefault always needs to be attached
+ * to pagefault since it waits for all pagefaults with matching
+ * asid to be resolved.
+ */
+ if (!xe_vma_is_cpu_addr_mirror(vma))
+ xe_eudebug_pagefault_set_private(pf, vm);
}
if (xe_vma_read_only(vma) &&
@@ -239,11 +288,52 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
atomic = xe_pagefault_access_is_atomic(pf->consumer.access_type);
- if (xe_vma_is_cpu_addr_mirror(vma))
+ if (xe_vma_is_cpu_addr_mirror(vma)) {
err = xe_svm_handle_pagefault(vm, vma, pf, gt,
pf->consumer.page_addr, atomic);
- else
+
+#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
+ /*
+ * If err is -ENOENT, it means that the cpu-address-space-mirrored
+ * xe vma exists, but there is no mm vma allocated in
+ * the CPU address space. This indicates that no memory has been
+ * allocated in the CPU address space.
+ */
+ if (err == -ENOENT &&
+ !xe_vm_is_closed_or_banned(vm) &&
+ xe_eudebug_pagefault_creatable(gt, vm)) {
+ u32 page_size = vm->flags & XE_VM_FLAG_64K ? SZ_64K : SZ_4K;
+
+ /*
+ * This section is reachable only when eudebug is connected.
+ *
+ * Up until now there was a read-lock. Now entering write-lock.
+ * Under new lock a vma split may occur. This means that before
+ * entering write-lock a origin vma could be already split.
+ * Update the vma to get current one before subtracting.
+ */
+ up_read(&vm->lock);
+ down_write(&vm->lock);
+ vma = xe_vm_find_vma_by_addr(vm, pf->consumer.page_addr);
+ if (vma && xe_vma_is_cpu_addr_mirror(vma))
+ vma = xe_vm_svm_vma_subtract(vm, vma,
+ pf->consumer.page_addr,
+ pf->consumer.page_addr + page_size);
+ else
+ vma = ERR_PTR(-EINVAL);
+
+ if (IS_ERR(vma)) {
+ downgrade_write(&vm->lock);
+ err = PTR_ERR(vma);
+ } else {
+ /* keep the write lock for vma */
+ goto retry_eudebug_pf;
+ }
+ }
+#endif
+ } else {
err = xe_pagefault_handle_vma(gt, vma, pf, atomic);
+ }
unlock_vm:
up_read(&vm->lock);
@@ -565,7 +655,7 @@ static void xe_pagefault_queue_work(struct work_struct *w)
while (xe_pagefault_queue_pop(pf_queue, &pf, pf_work->id)) {
const struct xe_pagefault_ops *ops = pf->producer.ops;
- void *private = pf->producer.private;
+ void *private;
struct xe_gt *gt = pf->gt;
u32 asid = pf->consumer.asid;
int err = 0;
@@ -598,6 +688,12 @@ static void xe_pagefault_queue_work(struct work_struct *w)
}
ack_fault:
+ /*
+ * set private after xe_pagefault_service() since eudebug could swap
+ * the pf->producer.private field. Also needed when cache was hit.
+ */
+ private = pf->producer.private;
+
xe_assert(xe, pf->consumer.alloc_state ==
XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
xe_assert(xe, pf == pf_work->cache.pf);
@@ -637,7 +733,7 @@ static void xe_pagefault_queue_work(struct work_struct *w)
spin_unlock_irq(&pf_queue->lock);
}
- ops->ack_fault_end(private);
+ ops->ack_fault_end(private, err);
if (time_after(jiffies, threshold)) {
queue_work(xe->usm.pagefault_wq, w);
diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h
index c7ff08408e43..8067724a2c66 100644
--- a/drivers/gpu/drm/xe/xe_pagefault_types.h
+++ b/drivers/gpu/drm/xe/xe_pagefault_types.h
@@ -53,10 +53,11 @@ struct xe_pagefault_ops {
/**
* @ack_fault_end: Ack fault end
* @private: producer private data
+ * @err: Error state of fault
*
* Page fault producer ends acknowledgment from the consumer.
*/
- void (*ack_fault_end)(void *private);
+ void (*ack_fault_end)(void *private, int err);
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* Re: [PATCH v10 05/27] drm/xe: Add EUDEBUG_ENABLE exec queue property
2026-09-03 14:59 ` [PATCH v10 05/27] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
@ 2026-09-03 15:14 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:14 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The restriction preventing the combination of EUDEBUG and multi-queue (MULTI_GROUP) is incomplete and trivially bypassed due to extension chaining order.
--
commit ed5a1d80f63515e05517829f344f3a806b4618aa
Author: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
drm/xe: Add EUDEBUG_ENABLE exec queue property
This commit introduces an immutable eudebug property for exec_queues.
It uses a flags value to enable eudebug-specific features like the runalone
hardware feature. This ensures that only one hardware engine in a group is
active on a tile.
> diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
> index a663c55b386de..d13f69eb025ca 100644
> --- a/drivers/gpu/drm/xe/xe_exec_queue.c
> +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
[ ... ]
> @@ -991,6 +994,51 @@ static int exec_queue_set_state_cache_perf_fix(struct xe_device *xe, struct xe_e
> return 0;
> }
>
> +static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
> + u64 value)
> +{
[ ... ]
> + if (XE_IOCTL_DBG(xe, xe_exec_queue_uses_pxp(q)))
> + return -EPERM;
> +
> + if (XE_IOCTL_DBG(xe, xe_exec_queue_is_multi_queue_secondary(q)))
> + return -EINVAL;
[Severity: High]
Can this state-based check be defeated if userspace chains the extensions
such that the EUDEBUG property is processed before the MULTI_GROUP extension
makes the queue secondary?
> +
> + q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
> + q->sched_props.preempt_timeout_us = 0;
> +
> + return 0;
> +}
[ ... ]
> @@ -1077,6 +1126,17 @@ static int exec_queue_user_ext_check(struct xe_exec_queue *q, u64 properties)
> (properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE))))
> return -EINVAL;
>
> + /*
> + * A debugger can inspect and modify the EU state and memory of a
> + * debuggable queue, so it must not be combined with protected content.
> + * Test the property mask rather than the queue state, as the extensions
> + * are applied in the order userspace chained them and either one may be
> + * processed first.
> + */
> + if (XE_IOCTL_DBG(xe, (properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG)) &&
> + (properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE))))
> + return -EINVAL;
> +
[Severity: High]
This correctly handles the extension chaining order for PXP. Should a similar
stateless bitmask check be added here for
DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP to prevent applying EUDEBUG to a
multi-queue?
Additionally, when attaching a secondary queue to a primary queue in
xe_exec_queue_group_validate():
drivers/gpu/drm/xe/xe_exec_queue.c:xe_exec_queue_group_validate() {
...
if (XE_IOCTL_DBG(xe, !xe_exec_queue_is_multi_queue_primary(primary)) ||
XE_IOCTL_DBG(xe, q->vm != primary->vm) ||
XE_IOCTL_DBG(xe, q->logical_mask != primary->logical_mask)) {
ret = -EINVAL;
goto put_primary;
}
...
}
Does this code also need to verify that the primary queue does not have
EUDEBUG/runalone enabled to prevent bypassing the restriction?
Enforcing RUNALONE on a MULTI_GROUP execution violates hardware invariants
and could cause a regression leading to GPU hangs or resets.
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=5
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 14/27] drm/xe/eudebug: Add hw enablement
2026-09-03 14:59 ` [PATCH v10 14/27] drm/xe/eudebug: Add hw enablement Mika Kuoppala
@ 2026-09-03 15:15 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:15 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The overwrite logic in `xe_reg_sr_add` fails to clear previously set bits when `e->set_bits` is non-zero, corrupting register state.
- [Low] Redundant duplicate macro definition of `STALL_DOP_GATING_DISABLE`.
--
commit 5a2461057e026a59c99e9e1133f757b575f16e78
Author: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Subject: drm/xe/eudebug: Add hw enablement
This commit implements eudebug mode enabling by programming TD_CTL and other
registers. It introduces eudebug-related workarounds and modifies the
register save/restore logic to allow dynamic manipulation with overwrites.
> diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> index 8056d007c23e2..7537fc1a9c3fa 100644
> --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
[ ... ]
> @@ -546,11 +558,13 @@
> #define MDQ_ARBITRATION_MODE REG_BIT(12)
> #define STALL_DOP_GATING_DISABLE REG_BIT(5)
> #define EARLY_EOT_DIS REG_BIT(1)
> +#define STALL_DOP_GATING_DISABLE REG_BIT(5)
[Severity: Low]
Does this code inadvertently redefine STALL_DOP_GATING_DISABLE? This isn't a
bug, but the macro is redefined with the exact same value immediately after
its original definition.
[ ... ]
> diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
> index e328f50725572..72919a5612a5a 100644
> --- a/drivers/gpu/drm/xe/xe_reg_sr.c
> +++ b/drivers/gpu/drm/xe/xe_reg_sr.c
[ ... ]
> @@ -114,15 +115,20 @@ int xe_reg_sr_add(struct xe_reg_sr *sr,
> reg = sanitize_mcr(sr, e, gt);
>
> if (pentry) {
> - if (!compatible_entries(pentry, e)) {
> + if (!overwrite && !compatible_entries(pentry, e)) {
> ret = -EINVAL;
> goto fail;
> }
>
> pentry->clr_bits |= e->clr_bits;
> - pentry->set_bits |= e->set_bits;
> pentry->read_mask |= e->read_mask;
>
> + /* An overwrite with nothing to set clears instead */
> + if (overwrite && !e->set_bits)
> + pentry->set_bits &= ~e->clr_bits;
> + else
> + pentry->set_bits |= e->set_bits;
> +
> return 0;
> }
[Severity: High]
Does this logic bypass clearing e->clr_bits when e->set_bits is non-zero
during an overwrite in xe_reg_sr_add()?
If xe_reg_sr_add() is called with overwrite = true and e->set_bits != 0, the
old bits intersecting with e->clr_bits do not appear to be cleared from
pentry->set_bits before the new bits are logically OR-ed. Could this result
in hardware registers being programmed with corrupted, logically OR-ed values
instead of the requested explicit values?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=14
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 01/27] drm/xe/eudebug: Introduce eudebug interface
2026-09-03 14:59 ` [PATCH v10 01/27] drm/xe/eudebug: Introduce eudebug interface Mika Kuoppala
@ 2026-09-03 15:16 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:16 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Pending events are inaccessible to the debugger after the target is detached, violating the UAPI contract because the event queue is not drained.
--
commit 048c5c077c45df4be0f59a215d2b70b35b5c5301
Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Subject: drm/xe/eudebug: Introduce eudebug interface
This commit introduces the eudebug interface for the Xe driver. It allows
user-space debuggers to connect, track GPU resources, and listen for resource
creation and destruction events via a file descriptor.
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> new file mode 100644
> index 0000000000000..9fe073f606801
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
[ ... ]
> +static int event_fifo_pending(struct xe_eudebug *d,
> + struct drm_xe_eudebug_event **pending)
> +{
> + struct drm_xe_eudebug_event *e = d->events.pending;
> + unsigned int len, copied;
> +
> + lockdep_assert_held(&d->events.lock);
> +
> + *pending = NULL;
> +
> + if (xe_eudebug_detached(d))
> + return -ENOTCONN;
[Severity: High]
If the target DRM client closes its file descriptor and detaches the debugger
while there are still unread events in the kfifo (such as VM destruction
events), does this check prevent the debugger from reading them?
The UAPI documentation explicitly guarantees that -ENOTCONN is returned if the
debug target is gone and the queue has been drained. Should we allow the queue
to be drained before returning -ENOTCONN?
> +
> + if (d->events.pending_occupied) {
> + *pending = e;
> + return 0;
> + }
[ ... ]
> +static long xe_eudebug_read_event(struct xe_eudebug *d,
> + const u64 arg,
> + const bool wait)
> +{
> + struct xe_device *xe = d->xe;
> + struct drm_xe_eudebug_event __user * const user_orig =
> + u64_to_user_ptr(arg);
> + struct xe_eudebug *reader __free(reader_active) = NULL;
> + struct drm_xe_eudebug_event *event_out __free(kvfree) = NULL;
> + struct drm_xe_eudebug_event user_event;
> + struct drm_xe_eudebug_event *pending;
> + long ret = 0;
> + int pending_len = 0;
> + int fifo_ret;
> +
> + if (XE_IOCTL_DBG(xe, copy_from_user(&user_event, user_orig, sizeof(user_event))))
> + return -EFAULT;
> +
> + if (XE_IOCTL_DBG(xe, user_event.type != DRM_XE_EUDEBUG_EVENT_READ))
> + return -EINVAL;
> +
> + if (XE_IOCTL_DBG(xe, user_event.len < sizeof(*user_orig)))
> + return -EINVAL;
> +
> + if (XE_IOCTL_DBG(xe, user_event.flags))
> + return -EINVAL;
> +
> + if (XE_IOCTL_DBG(xe, user_event.seqno))
> + return -EINVAL;
> +
> + if (XE_IOCTL_DBG(xe, user_event.reserved))
> + return -EINVAL;
> +
> + if (XE_IOCTL_DBG(xe, xe_eudebug_detached(d)))
> + return -ENOTCONN;
[Severity: High]
Similarly, this short-circuits the read ioctl entirely if the target is
detached. Can this be modified to check if the queue is empty first, ensuring
the debugger can pull any pending events leading up to the target's termination?
> +
> + if (test_and_set_bit_lock(XE_EUDEBUG_READER_ACTIVE, &d->flags))
> + return -EBUSY;
> +
> + reader = d;
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=1
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 11/27] drm/xe/eudebug: Add ufence events with acks
2026-09-03 14:59 ` [PATCH v10 11/27] drm/xe/eudebug: Add ufence events with acks Mika Kuoppala
@ 2026-09-03 15:20 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:20 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] A race condition in `xe_eudebug_ufence_track` during debugger detachment leaves `ufence->eudebug.bind_ref_seqno` uncleared, triggering a `XE_WARN_ON` during ufence destruction.
- [High] Unbounded non-accounted kernel memory allocation in `xe_eudebug_track_ufence` allows a malicious debugger to exhaust system memory (DoS).
--
commit a5714f9c14ecadc50ce9b02c008c2b316e1293f6
Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
drm/xe/eudebug: Add ufence events with acks
This commit introduces ufence event tracking for the Xe eudebug interface.
It allows the debugger to intercept workloads and stall the delivery of
ufence signals until the debugger explicitly acknowledges the ufence via a
new ioctl.
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index fe3b2ae06a31f..a1f07db6ad817 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
[ ... ]
> @@ -1038,11 +1155,169 @@ static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
[ ... ]
> +void xe_eudebug_ufence_fini(struct xe_user_fence *ufence)
> +{
> + struct xe_eudebug *d;
> +
> + XE_WARN_ON(READ_ONCE(ufence->eudebug.bind_ref_seqno));
> +
> + d = READ_ONCE(ufence->eudebug.debugger);
> + if (!d)
> + return;
> +
> + /* last ref */
> + ufence->eudebug.debugger = NULL;
> +
> + xe_eudebug_put(d);
> +}
> +
> +static int xe_eudebug_track_ufence(struct xe_eudebug *d,
> + struct xe_user_fence *f,
> + u64 seqno)
> +{
> + struct xe_eudebug_ack *ack;
> + struct rb_node *old;
> +
> + ack = kzalloc_obj(*ack, GFP_KERNEL);
> + if (!ack) {
> + eu_dbg(d, "ack allocation fail");
> + return -ENOMEM;
> + }
[Severity: High]
Can this unbounded allocation be exploited by a malicious debugger to exhaust
kernel memory?
The allocation here uses GFP_KERNEL without __GFP_ACCOUNT (which would charge
it to the memory cgroup). A debugger could continuously read events via
DRM_XE_EUDEBUG_IOCTL_READ_EVENT to clear the FIFO, but never acknowledge them
using DRM_XE_EUDEBUG_IOCTL_ACK_EVENT.
Because the ACKs and their associated ufences are only freed when explicitly
acknowledged by userspace, a target process looping VM_BINDs with ufences
could cause d->acks.tree to grow indefinitely until a system-wide
Out-Of-Memory (OOM) panic occurs.
> +
> + ack->seqno = seqno;
> + ack->ts_insert = ktime_get();
[ ... ]
> +bool xe_eudebug_ufence_track(struct xe_user_fence *ufence)
> +{
> + struct xe_eudebug *d;
> + bool tracked = false;
> + int ret;
> +
> + spin_lock(&ufence->eudebug.lock);
> + d = ufence->eudebug.debugger;
> + if (d && !kref_get_unless_zero(&d->ref))
> + d = NULL;
> +
> + if (!d || xe_eudebug_detached(d)) {
> + ufence->eudebug.bind_ref_seqno = 0;
> + ufence->eudebug.signalled_seqno = 0;
> + }
> + spin_unlock(&ufence->eudebug.lock);
> +
> + if (!d)
> + return false;
> +
> + if (xe_eudebug_detached(d)) {
> + xe_eudebug_put(d);
> + return false;
> + }
[Severity: High]
Is there a race condition here if the debugger detaches right after the lock
is released?
If xe_eudebug_detached(d) becomes true immediately after
spin_unlock(&ufence->eudebug.lock), this check will evaluate to true and
return false without clearing ufence->eudebug.bind_ref_seqno and
signalled_seqno.
Since false is returned, the caller user_fence_worker() will signal and
release the ufence. When the ufence is subsequently destroyed,
xe_eudebug_ufence_fini() will hit the
XE_WARN_ON(READ_ONCE(ufence->eudebug.bind_ref_seqno)) assertion because the
field was never cleared.
> +
> + ret = track_ufence(d, ufence, &tracked);
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=11
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 09/27] drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops
2026-09-03 14:59 ` [PATCH v10 09/27] drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops Mika Kuoppala
@ 2026-09-03 15:22 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:22 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing enforcement of the debug data extension for `ADD_DEBUG_DATA` and `REMOVE_DEBUG_DATA` operations, allowing them to silently execute as no-ops and pass a NULL pointer to eudebug.
--
commit 7fdd31439ab20b18aec25bd5e11c3a84839d451e
Author: Christoph Manszewski <c.manszewski@gmail.com>
drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops
This commit introduces new VM bind operations to add and remove per-VM
debug data. It adds extension parsing to the VM bind ioctl to accept
pseudopaths or file paths for mapping binary instructions to code lines.
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
[ ... ]
> @@ -3903,6 +4061,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;
[Severity: High]
Does this code correctly enforce that the extensions field must be
non-zero for DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA and
DRM_XE_VM_BIND_OP_REMOVE_DEBUG_DATA?
If extensions is 0, vm_bind_ioctl_check_user_extensions() simply returns 0
without validating that the required debug data struct is present. This
allows a malformed VM bind ioctl to proceed.
[ ... ]
> @@ -4180,11 +4342,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;
[Severity: High]
When extensions is 0, this block is skipped entirely, leaving the added and
removed pointers in op->modify_debug_data as NULL.
Later, xe_eudebug_vm_bind_execute() extracts this NULL dd pointer and
passes it to vm_bind_op_event(), where debug_data->addr is unconditionally
dereferenced. Can an unprivileged local user trigger a kernel panic by
opening the DRM device, connecting via DRM_IOCTL_XE_EUDEBUG_CONNECT, and
submitting a DRM_XE_VM_BIND_OP_ADD_DEBUG_DATA request with extensions set
to 0?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=9
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 04/27] drm/xe/eudebug: Introduce discovery for resources
2026-09-03 14:59 ` [PATCH v10 04/27] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
@ 2026-09-03 15:22 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:22 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Global ordered workqueue stall via copy_from_user block while holding ioctl_lock.
- [Medium] Event sequence numbers (seqno) can be queued out-of-order in the event stream due to a race between seqno generation and event queuing.
--
commit e2061e72d8e954a17bde35e9c970ee41bc2db0ad
Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
drm/xe/eudebug: Introduce discovery for resources
This commit introduces a resource discovery mechanism for debugger connections.
When a debugger connects, all existing resources for the target client are
relayed as events via an ordered workqueue, and DRM ioctls are blocked using
an rw_semaphore until discovery is complete.
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 032a7ec5fbc8d..f10959b898297 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
[ ... ]
> @@ -238,8 +239,12 @@ static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>
> ACQUIRE(xe_pm_runtime_ioctl, pm)(xe);
> ret = ACQUIRE_ERR(xe_pm_runtime_ioctl, &pm);
> - if (ret >= 0)
> + if (ret >= 0) {
> + bool lock = xe_eudebug_discovery_lock(file, cmd);
> ret = drm_ioctl(file, cmd, arg);
[Severity: High]
Does holding the discovery lock across drm_ioctl() create a vector for a
workqueue stall?
If an unprivileged user maps the ioctl argument pointer to a blocking FUSE
or userfaultfd region, drm_ioctl() can be stalled indefinitely during
copy_from_user() while holding xef->eudebug.ioctl_lock for read.
> + if (lock)
> + xe_eudebug_discovery_unlock(file, cmd);
> + }
>
> return ret;
> }
[ ... ]
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 835dbd7309af5..7a5b14346e059 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
[ ... ]
> @@ -659,6 +705,87 @@ void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
> xe_eudebug_put(d);
> }
>
> +static struct xe_file *xe_eudebug_target_get(struct xe_eudebug *d)
> +{
[ ... ]
> +static void discover_client(struct xe_eudebug *d)
> +{
> + struct xe_file *xef;
> + struct xe_vm *vm;
> + unsigned long i;
> + unsigned int vm_count = 0;
> + int err = 0;
> +
> + xef = xe_eudebug_target_get(d);
> + if (!xef) {
> + complete_all(&d->discovery);
> + return;
> + }
> +
> + /*
> + * An xe_eudebug ref is taken for the discovery worker, which holds a
> + * ref to the target xe_file; the xe_file in turn holds the vm and
> + * exec_queue refs.
> + *
> + * All the relevant ioctls that manipulate the xe_file resources eudebug
> + * cares about are gated behind down_read(&xef->eudebug.ioctl_lock).
> + * Thus taking the write lock excludes all those ioctls, which lets us
> + * peek into the resource lists without taking their individual locks.
> + */
> + down_write(&xef->eudebug.ioctl_lock);
[Severity: High]
If the target process is blocked in copy_from_user() inside drm_ioctl()
while holding the read lock, will this down_write() block indefinitely?
Because discovery runs on a global ordered workqueue (configured below in
xe_eudebug_init), this single blocked work item could stall all eudebug
discovery operations system-wide, causing a Denial of Service for all
debugger connections.
> +
> + if (xe_eudebug_detached(d))
> + goto out;
[ ... ]
> @@ -1126,12 +1266,20 @@ void xe_eudebug_init_early(struct xe_device *xe)
> void xe_eudebug_init(struct xe_device *xe)
> {
> struct drm_device *dev = &xe->drm;
> + struct workqueue_struct *wq;
> int err;
>
> /* early init failed */
> if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
> return;
>
> + wq = drmm_alloc_ordered_workqueue(dev, "xe-eudebug-discovery", 0);
[Severity: High]
This allocates the workqueue as ordered (max_active=1), which means a single
stalled work item blocks all other discovery work.
Can the workqueue be allocated differently, or can the ioctl_lock be managed
to avoid wrapping the copy_from_user() operations in drm_ioctl()?
> + if (IS_ERR(wq)) {
> + err = PTR_ERR(wq);
> + goto out_err;
> + }
> + xe->eudebug.discovery_wq = wq;
> +
> err = sysfs_create_file(&dev->dev->kobj,
> &dev_attr_enable_eudebug.attr);
> if (err)
[ ... ]
[Severity: Medium]
Can sequence numbers be queued out-of-order in the event stream?
Looking at send_vm_bind_event() in xe_eudebug.c:
*seqno = atomic_long_inc_return(&d->events.seqno);
spin_lock(&d->events.lock);
event = xe_eudebug_prepare_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND,
*seqno, base_flags, sz);
Since the sequence number is incremented atomically outside of the FIFO
spinlock, could two threads acquire sequence numbers N and N+1, but acquire
the FIFO lock in reverse order?
This same pattern appears in _xe_eudebug_add_handle(). Pushing N+1 before
N would break the expected monotonicity of the event stream and could cause
the debugger to drop events.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=4
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 13/27] drm/xe/eudebug: Add userptr vm pread/pwrite
2026-09-03 14:59 ` [PATCH v10 13/27] drm/xe/eudebug: Add userptr vm pread/pwrite Mika Kuoppala
@ 2026-09-03 15:24 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:24 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Time-of-Check to Time-of-Use (TOCTOU) race condition in `xe_eudebug_vma_access()` allows a debugger to bypass security checks and read/write arbitrary memory in an unrelated privileged process.
- [High] Debugger access to userptr memory spuriously fails with `-ESRCH` if the specific thread that bound the userptr exits, even though the process and address space remain fully valid.
--
commit f0c74c4990322a45ea5e521e420b8ab7f3f80507
Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
drm/xe/eudebug: Add userptr vm pread/pwrite
This commit implements debugger VM access for userptrs by taking a reference
to the current task when the bind is done. During pread/pwrite, it uses this
task parameter to access the debuggee VM via access_process_vm().
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_vm.c b/drivers/gpu/drm/xe/xe_eudebug_vm.c
> index 316fe29586b0a..42e24c1bc09c7 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug_vm.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug_vm.c
[ ... ]
> @@ -52,6 +53,50 @@ static int xe_eudebug_vma_access(struct xe_vma *vma,
[ ... ]
> + } else if (xe_vma_is_userptr(vma)) {
> + struct xe_userptr *userptr = &to_userptr_vma(vma)->userptr;
> + struct mm_struct *mm;
> + int ret;
[ ... ]
> + mm = get_task_mm(userptr->eudebug.task);
> + if (!mm)
> + return -ESRCH;
[Severity: High]
Will this cause spurious -ESRCH failures if the specific thread that bound
the userptr exits?
When the specific thread exits, its task->mm is cleared to NULL in exit_mm(),
causing get_task_mm() to return NULL here. If an application (like a
Vulkan/OpenGL driver) uses background worker threads to allocate and bind
memory, won't the debugger lose access to this valid memory once that worker
thread terminates, even though the process and mm_struct are still fully
alive?
> +
> + ret = mm == userptr->notifier.mm ? 0 : -ESRCH;
> + mmput(mm);
> + if (ret)
> + return ret;
> +
> + return access_process_vm(userptr->eudebug.task,
> + xe_vma_userptr(vma) + offset_in_vma,
> + buf, bytes,
> + write ? FOLL_WRITE : 0);
[Severity: Critical]
Does this sequence introduce a Time-of-Check to Time-of-Use (TOCTOU) race
condition that could allow local privilege escalation?
The code verifies that the mm matches the expected userptr->notifier.mm,
but then it drops the reference with mmput(mm) before proceeding.
Because access_process_vm() internally re-resolves the mm dynamically
without ptrace_may_access() checks, could a malicious unprivileged process
bind a userptr, pass the eudebug fd to a collaborating process, and call
execve() on a setuid binary?
If the execve() executes during the race window between mmput(mm) and
access_process_vm(), it appears this would fetch the new, privileged mm of
the setuid binary, granting the debugger arbitrary read/write access to it.
> diff --git a/drivers/gpu/drm/xe/xe_userptr.h b/drivers/gpu/drm/xe/xe_userptr.h
> index 2a3cd1b5efbb0..b0781618b3f46 100644
> --- a/drivers/gpu/drm/xe/xe_userptr.h
> +++ b/drivers/gpu/drm/xe/xe_userptr.h
[ ... ]
> @@ -133,4 +139,30 @@ static inline void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma)
[ ... ]
> +#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
> +static inline void xe_eudebug_track_userptr_task(struct xe_userptr *userptr)
> +{
> + /*
> + * We could use the mm which is on notifier. But
> + * the access_remote_vm() is not exported. Thus
> + * we get reference to task for access_process_vm()
> + */
> + userptr->eudebug.task = get_task_struct(current);
[Severity: High]
Should this track the process leader rather than the specific calling thread?
By saving the specific thread (current) here, the userptr becomes bound to
this thread's lifespan. Changing this to track the process leader instead
(e.g., current->group_leader) might prevent the spurious -ESRCH failures
in xe_eudebug_vma_access() when background worker threads exit.
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=13
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 10/27] drm/xe/eudebug: Introduce vm bind and vm bind debug data events
2026-09-03 14:59 ` [PATCH v10 10/27] drm/xe/eudebug: Introduce vm bind and vm bind debug data events Mika Kuoppala
@ 2026-09-03 15:26 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:26 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing `xe_vm_in_lr_mode(vm)` check in `vm_discover_binds` causes debugger discovery to fail if non-LR VMs have debug data.
--
commit c9fa46a5dd0ac097fb655eda186ce81f79cd82c1
Author: Christoph Manszewski <c.manszewski@gmail.com>
drm/xe/eudebug: Introduce vm bind and vm bind debug data events
This commit introduces events to track bind ioctls and their associated
debug data add and remove operations. It adds a bind event to signal debugger
execution and implements discovery of existing binds when attaching.
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index d70970f70a8bc..fe3b2ae06a31f 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
[ ... ]
> @@ -942,13 +1118,57 @@ static struct xe_file *xe_eudebug_target_get(struct xe_eudebug *d)
> return xef;
> }
>
> +static int vm_discover_binds(struct xe_eudebug *d, struct xe_vm *vm)
> +{
> + struct xe_debug_data *dd;
> + struct list_head *pos;
> + unsigned int ops, count;
> + u64 ref_seqno;
> + int err;
> +
> + /*
> + * Walked without vm->debug_data.lock. The caller holds the target's
> + * eudebug.ioctl_lock for write, and everything that adds to or
> + * removes from this list runs under DRM_XE_VM_BIND, which takes that
> + * same rwsem for read, so the list cannot change under us here.
> + */
> + if (list_empty(&vm->debug_data.list))
> + return 0;
[Severity: High]
Is it intentional that vm_discover_binds() lacks a check for LR mode?
If a userspace client adds debug data to a non-LR VM, this function will
still attempt to process it since it's missing a check like
if (!xe_vm_in_lr_mode(vm)).
[ ... ]
> @@ -980,6 +1200,12 @@ static void discover_client(struct xe_eudebug *d)
> if (err)
> goto out;
> vm_count++;
> +
> + err = vm_discover_binds(d, vm);
> + if (err < 0)
> + goto out;
[Severity: High]
Can this sequence cause the debugger discovery to fail completely?
In discover_client(), vm_create_event() correctly skips creating events
and handles for non-LR VMs. However, vm_discover_binds() is called
unconditionally for all VMs.
If userspace adds debug data to a non-LR VM, vm_discover_binds() will
attempt to send bind events via vm_bind_event(). Because the VM handle was
never registered, find_handle() will fail with -ENOENT.
This error will propagate to the out label, immediately disconnecting the
eudebug session. Could an unprivileged userspace client use this to
intentionally break the eudebug facility for their process?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=10
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 12/27] drm/xe/eudebug: Add vm open/pread/pwrite
2026-09-03 14:59 ` [PATCH v10 12/27] drm/xe/eudebug: Add vm open/pread/pwrite Mika Kuoppala
@ 2026-09-03 15:27 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:27 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Missing runtime PM reference acquisition before accessing device memory and MMIO registers in VM read/write and fsync operations.
- [High] Missing bounds check on `timeout_ns` causes integer truncation and allows a user-controlled unbounded timeout that leads to device-wide lock starvation.
--
commit 4d072be6d2def21f4bb83f2b06e9fdfe40aeb1c5
Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
drm/xe/eudebug: Add vm open/pread/pwrite
The debugger needs access to the client's vm to read and write, for
example to inspect ISA/ELF and set up breakpoints.
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_vm.c b/drivers/gpu/drm/xe/xe_eudebug_vm.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_eudebug_vm.c
[ ... ]
> +static ssize_t __xe_eudebug_vm_access(struct file *file,
> + char __user *r_buffer,
> + const char __user *w_buffer,
> + size_t count, loff_t *__pos)
> +{
[ ... ]
> + do {
> + const ssize_t len = min_t(ssize_t, bytes_left, alloc_len);
> +
> + ret = __vm_read_write(vm, k_buffer,
> + write ? NULL : r_buffer + copied,
> + write ? w_buffer + copied : NULL,
> + (u64)(pos + copied),
> + len,
> + write);
> + if (ret <= 0)
> + break;
> +
> + bytes_left -= ret;
> + copied += ret;
> + } while (bytes_left > 0);
[Severity: High]
Does this code need to acquire a runtime PM reference before accessing memory?
VM/VRAM access delegates down to ttm_bo_access(), which requires an active
runtime PM reference that is absent in this call chain. Because the fops
handlers execute as standard VFS file operations, they do not automatically
hold the DRM IOCTL PM runtime reference. ttm_bo_access() delegates to
xe_ttm_access_memory(), directly hitting the xe_device_assert_mem_access(xe)
assertion. If the device has entered runtime suspend, accessing memory will
crash the kernel.
[ ... ]
> +static int engine_rcu_flush(struct xe_eudebug *d,
> + struct xe_hw_engine *hwe,
> + unsigned int timeout_us)
> +{
[ ... ]
> + /* Prevent concurrent flushes */
> + mutex_lock(&d->xe->eudebug.lock);
> + psmi_ctrl = xe_mmio_read32(>->mmio, psmi_addr);
> + if (!(psmi_ctrl & IDLE_MSG_DISABLE))
> + xe_mmio_write32(>->mmio, psmi_addr,
> + REG_MASKED_FIELD_ENABLE(IDLE_MSG_DISABLE));
> +
> + /* XXX: Timeout is per operation but in here we flush previous */
> + ret = xe_mmio_wait32(>->mmio, RCU_ASYNC_FLUSH,
> + RCU_ASYNC_FLUSH_IN_PROGRESS, 0,
> + timeout_us, NULL, false);
[Severity: High]
Does this code block indefinitely and cause lock starvation?
There is no bounds check on timeout_ns when passed from user space, allowing
an unbounded timeout. engine_rcu_flush() implicitly truncates the 64-bit
value to a 32-bit unsigned int timeout_us. xe_mmio_wait32() will block for
this duration while holding the device-wide d->xe->eudebug.lock mutex.
Furthermore, because the PM runtime reference is missing during fsync (as
noted below), the MMIO register read will likely return 0xFFFFFFFF, meaning
the polling loop will never succeed and will guarantee the full sleep
duration. This completely locks up the eudebug subsystem and EU page fault
processing across the entire device.
[ ... ]
> +static int xe_eudebug_vm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
> +{
[ ... ]
> + for_each_gt(gt, d->xe, gt_id) {
> + struct xe_hw_engine *hwe;
> + enum xe_hw_engine_id id;
> +
> + /* XXX: vm open per engine? */
> + xe_eudebug_for_each_hw_engine(hwe, gt, id) {
> + ret = engine_rcu_flush(d, hwe, vmf->timeout_us);
> + if (ret)
> + goto out;
> + }
> + }
> +out:
> + return ret;
> +}
[Severity: High]
Does this code need to acquire a runtime PM reference before accessing MMIO
registers?
Hardware engines are iterated and MMIO registers flushed without asserting
that the device is awake via a runtime PM reference. Because
xe_eudebug_vm_fsync() executes as a standard VFS file operation, it does not
automatically hold the DRM IOCTL PM runtime reference. engine_rcu_flush()
directly accesses MMIO registers (RING_PSMI_CTL and RCU_ASYNC_FLUSH). If the
device has entered runtime suspend, accessing MMIO registers will cause PCIe
aborts or system hangs.
[ ... ]
> +long xe_eudebug_vm_open_ioctl(struct xe_eudebug *d, unsigned long arg)
> +{
[ ... ]
> + kref_get(&d->ref);
> + vmf->debugger = d;
> + vmf->vm = vm;
> + vmf->flags = param.flags;
> + vmf->vm_handle = param.vm_handle;
> + vmf->timeout_us = div64_u64(param.timeout_ns, 1000ull);
[Severity: High]
Can a malicious userspace client provide a huge value for timeout_ns and
cause lock starvation?
This is where the user-controlled timeout is saved without any upper bound
validation, setting up the lock starvation issue in engine_rcu_flush()
mentioned above.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=12
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 21/27] drm/xe/eudebug: Add read/count/compare helper for eu attention
2026-09-03 14:59 ` [PATCH v10 21/27] drm/xe/eudebug: Add read/count/compare helper for eu attention Mika Kuoppala
@ 2026-09-03 15:31 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:31 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Unaligned memory access and endianness bugs due to incorrect type punning in `xe_eu_attentions_count`.
- [High] Unbounded CPU stall / soft lockup due to 1.5-second `udelay()` busy-waiting in `xe_gt_eu_attentions_read`.
- [Medium] Silent failure when reading hardware attentions causes the debugger to process zeroed memory as valid EU threads.
- [Medium] Meaningful code and commit message mismatch: The patch claims to add an EU thread compare function, but the implementation is completely missing.
--
commit a0b2cd07131e7090249ddf2ff617e3c4283b5549
Author: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
drm/xe/eudebug: Add read/count/compare helper for eu attention
This commit adds the xe_eu_attentions structure to capture and store EU
attention bits. It also introduces functions to read and count the number of
EU threads that have triggered attentions.
> drm/xe/eudebug: Add read/count/compare helper for eu attention
>
> Add xe_eu_attentions structure to capture and store eu attention bits.
> Add a function to count the number of eu threads that have turned on from
> eu attentions, and add a function to count the number of eu threads that
> have changed on a state between eu attentions.
[Severity: Medium]
This isn't a bug, but the commit message states it adds a compare helper "to
count the number of eu threads that have changed on a state between eu
attentions." Does the patch actually include this function? It appears to be
missing from the implementation.
> diff --git a/drivers/gpu/drm/xe/xe_gt_debug.c b/drivers/gpu/drm/xe/xe_gt_debug.c
> index b20e42e66c5bc..bff78c0b232a8 100644
> --- a/drivers/gpu/drm/xe/xe_gt_debug.c
> +++ b/drivers/gpu/drm/xe/xe_gt_debug.c
[ ... ]
> @@ -199,3 +202,50 @@ int xe_gt_eu_threads_needing_attention(struct xe_gt *gt)
>
> return err < 0 ? 0 : err;
> }
> +
> +static inline unsigned int
> +xe_eu_attentions_count(const struct xe_eu_attentions *a)
> +{
> + return bitmap_weight((void *)a->att, a->size * BITS_PER_BYTE);
> +}
[Severity: High]
Does casting this u8 array to an unsigned long pointer cause unaligned memory
accesses?
In drivers/gpu/drm/xe/xe_gt_debug_types.h, the xe_eu_attentions struct
declares att as a u8 array, meaning the struct has at most a 4-byte
alignment (dictated by unsigned int size).
When xe_eu_attentions_count() in drivers/gpu/drm/xe/xe_gt_debug.c casts this
array to void * and passes it to bitmap_weight(), which expects an unsigned
long *, it can cause undefined behavior. Dereferencing a 4-byte aligned
address as an 8-byte unsigned long can cause faults on architectures with
strict alignment requirements, or incorrect bit counting on big-endian systems.
> +
> +void xe_gt_eu_attentions_read(struct xe_gt *gt,
> + struct xe_eu_attentions *a,
> + const unsigned int settle_time_ms)
> +{
> + unsigned int attn, prev = 0;
> + ktime_t end, now;
> +
> + now = ktime_get_raw();
> + /* Initially wait longer for attentions to appear */
> + end = ktime_add_ms(now, settle_time_ms * 10);
> +
> + a->size = min_t(int,
> + xe_gt_eu_attention_bitmap_size(gt),
> + sizeof(a->att));
> +
> + do {
> + if (xe_gt_eu_attention_bitmap(gt, a->att, a->size) < 0)
> + return;
[Severity: Medium]
Will this early return swallow the error code and corrupt the debugger's
data flow?
If xe_gt_eu_attention_bitmap() fails in xe_gt_eu_attentions_read(), it
returns early but leaves a->size set to a positive value. Since the function
signature is void, the caller has no way of knowing a failure occurred.
Could the caller then process the structure's att array (which contains
zeroes) and falsely report that no threads triggered an attention?
> +
> + if (!settle_time_ms)
> + break;
> +
> + attn = xe_eu_attentions_count(a);
> +
> + now = ktime_get_raw();
> +
> + if (attn > prev) {
> + prev = attn;
> + end = ktime_add_ms(now, settle_time_ms);
> + }
> +
> + udelay(15);
> +
> + /*
> + * XXX We are gathering data for production SIP to find
> + * the upper limit of settle time. For now, we wait full
> + * timeout value regardless.
> + */
> + } while ((attn < a->size * 8) && ktime_before(now, end));
> +}
[Severity: High]
Can this loop cause an unbounded CPU stall or soft lockup?
The loop in xe_gt_eu_attentions_read() waits for a timeout of
settle_time_ms * 10. When called from a pagefault handler with
XE_GT_ATTENTION_TIMEOUT_MS (150ms), the timeout is 1.5 seconds. Inside the
loop, it busy-waits using udelay(15) instead of a sleeping delay.
Additionally, if any DSS in the middle of the topology is fused off, attn
will never reach a->size * 8 because a->size overestimates the valid bits.
Does this guarantee the loop will always busy-wait for the full 1.5 seconds
per call?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=21
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 18/27] drm/xe: Implement SR-IOV and eudebug exclusivity
2026-09-03 14:59 ` [PATCH v10 18/27] drm/xe: Implement SR-IOV and eudebug exclusivity Mika Kuoppala
@ 2026-09-03 15:32 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:32 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Race condition in eudebug disable path allows SR-IOV VFs to be enabled while eudebug hardware polling is still running, causing hardware interference.
- [Medium] Unconditional drm_info() log spam during SR-IOV VF initialization.
--
commit 639131d56a88cb02a02b54b4b9a2563ae44da661
Author: Christoph Manszewski <c.manszewski@gmail.com>
drm/xe: Implement SR-IOV and eudebug exclusivity
EU debug functionality relies on access to specific mmio registers.
Since VFs don't have access to those registers and in order to avoid
interference with VFs, make SR-IOV and eudebug functionality exclusive.
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 470246af9810a..2c8d8fc82898e 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -2276,10 +2286,14 @@ int xe_eudebug_enable(struct xe_device *xe, bool enable)
> WRITE_ONCE(xe->eudebug.cap_state, enable ?
> XE_EUDEBUG_CAP_ENABLED : XE_EUDEBUG_CAP_DISABLED);
>
> - if (enable)
> + if (enable) {
> xe_eudebug_attention_poll_start(xe);
> - else
> + } else {
> + if (IS_SRIOV_PF(xe))
> + xe_sriov_pf_end_lockdown(xe);
> +
> xe_eudebug_attention_poll_stop(xe);
> + }
[Severity: High]
Does releasing the SR-IOV lockdown before stopping the eudebug worker allow
VFs to be enabled while the worker is still actively reading GT MMIO
registers?
Since xe_eudebug_attention_poll_stop() uses cancel_delayed_work() (which is
asynchronous), the polling worker may still be executing and accessing MMIO
registers after xe_sriov_pf_end_lockdown() releases the exclusivity guard.
Reversing the order of these two calls might still be susceptible to a race
since the cancel is async.
>
> return 0;
> }
> [ ... ]
> @@ -2359,6 +2373,11 @@ void xe_eudebug_init(struct xe_device *xe)
> if (xe->eudebug.cap_state == XE_EUDEBUG_CAP_NOT_SUPPORTED)
> return;
>
> + if (IS_SRIOV_VF(xe)) {
> + drm_info(&xe->drm, "eudebug not available in SR-IOV VF mode\n");
> + goto out_not_supported;
> + }
> +
[Severity: Medium]
Will this unconditionally spam the kernel log with drm_info messages during
SR-IOV VF initialization?
When SR-IOV is enabled, many Virtual Functions are initialized simultaneously.
Calling drm_info unconditionally during the initialization of every VF will
flood the dmesg buffer with identical "eudebug not available in SR-IOV VF
mode" messages.
Would drm_info_once() or drm_dbg() be more appropriate here?
> wq = drmm_alloc_ordered_workqueue(dev, "xe-eudebug-discovery", 0);
> if (IS_ERR(wq)) {
> err = PTR_ERR(wq);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=18
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 15/27] drm/xe/eudebug: Introduce EU control interface
2026-09-03 14:59 ` [PATCH v10 15/27] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
@ 2026-09-03 15:34 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:34 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect hardware engine (hwe) used to read RING_CURRENT_LRCA for virtual exec queues, causing valid EU interruption to fail with -EBUSY.
- [High] Calling `xe_eudebug_exec_queue_get` triggers a use-after-free because the debugger handle map stores raw pointers to queues that can be freed when the target process exits.
--
commit ae12753c8db49bf5356301911889cee3d0b8fe63
Author: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
drm/xe/eudebug: Introduce EU control interface
This commit introduces the EU control interface, allowing the EU debugger
to interrupt, resume, and query the state of EU threads. It provides an
abstraction layer for the GuC to hook into in the future.
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 188a4c60513c5..ecd6d4c5d63ca 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
[ ... ]
> @@ -738,6 +741,33 @@ struct xe_vm *xe_eudebug_vm_get(struct xe_eudebug *d, u32 id)
> return vm;
> }
>
> +struct xe_exec_queue *xe_eudebug_exec_queue_get(struct xe_eudebug *d, u32 id)
> +{
> + struct xe_eudebug_resource *r =
> + resource_from_type(d, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE);
> + struct xe_exec_queue *eq;
> +
> + mutex_lock(&r->lock);
> + eq = find_resource__unlocked(r, id);
> + if (eq)
> + xe_exec_queue_get(eq);
> + mutex_unlock(&r->lock);
> +
> + return eq;
> +}
[Severity: High]
Does this code introduce a use-after-free risk during target process exit?
The debugger handle map (d->target.res) stores raw pointers to target
resources like exec queues. When the target process closes its DRM fd,
xe_file_close() sets d->target.xef = NULL via xe_eudebug_file_close(), and
proceeds to drop references to all target exec queues, freeing them.
However, the raw pointers remain in the debugger's resource map until the
debugger itself is closed. If a debugger races with the target process
exit and invokes the DRM_XE_EUDEBUG_IOCTL_EU_CONTROL ioctl, it can pass
the xe_eudebug_detached() check before the target clears d->target.xef.
Then do_eu_control() calls xe_eudebug_exec_queue_get(), which retrieves the
freed pointer and calls xe_exec_queue_get(eq), performing a kref_get() on
freed memory.
[ ... ]
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_hw.c b/drivers/gpu/drm/xe/xe_eudebug_hw.c
> index aa31b4c917133..d14e4e4775f2f 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug_hw.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug_hw.c
[ ... ]
> +struct xe_exec_queue *
> +xe_gt_runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
> +{
> + struct xe_hw_engine *active;
> +
> + active = get_runalone_active_hw_engine(gt);
> + if (IS_ERR(active))
> + return ERR_CAST(active);
> +
> + return active_hwe_to_exec_queue(active, lrc_idx);
> +}
[Severity: High]
Does returning only the exec queue here discard the specific active
physical engine context?
This discovers the correct active hardware engine but discards it by
returning only the queue, removing context necessary for subsequent hw
access. For virtual queues, the physical engine where the queue is actively
running might not be the primary assigned engine. When
active_hwe_to_exec_queue() returns the queue, the knowledge of which
physical engine it was found on is lost.
[ ... ]
> +static int xe_eu_control_interrupt_all(struct xe_eudebug *d,
> + struct xe_exec_queue *active,
> + struct xe_lrc *lrc)
> +{
> + unsigned int fw_ref = 0;
> + u32 lrc_hw, lrc_hw_post;
> + u32 td_ctl;
> + int err = -EINVAL;
> +
> + fw_ref = xe_force_wake_get(gt_to_fw(active->gt), active->hwe->domain);
> + if (!fw_ref) {
> + err = -ETIMEDOUT;
> + goto out;
> + }
> +
> + /* Additional check just before issuing MMIO writes */
> + err = read_hw_lrca_fw(active->hwe, &lrc_hw);
> + if (err)
> + goto out;
> +
> + if (!lrca_equals(lower_32_bits(xe_lrc_descriptor(lrc)), lrc_hw)) {
> + err = -EBUSY;
> + goto out;
> + }
[Severity: High]
Is active->hwe always the correct physical engine to read
RING_CURRENT_LRCA from?
When do_eu_control() passes a virtual exec queue into this function,
active->hwe represents the primary assigned engine rather than the actual
physical engine where the runalone workload is currently executing. This
can cause read_hw_lrca_fw(active->hwe, ...) to target the wrong physical
engine, making the LRCA check fail and erroneously return -EBUSY, preventing
the EU interruption from succeeding on virtual queues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=15
^ permalink raw reply [flat|nested] 48+ messages in thread
* ✗ CI.checkpatch: warning for Intel Xe GPU Debug Support (eudebug) v10
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (26 preceding siblings ...)
2026-09-03 14:59 ` [PATCH v10 27/27] drm/xe/eudebug: Enable EU pagefault handling Mika Kuoppala
@ 2026-09-03 15:35 ` Patchwork
2026-09-03 15:37 ` ✓ CI.KUnit: success " Patchwork
` (4 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Patchwork @ 2026-09-03 15:35 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
== Series Details ==
Series: Intel Xe GPU Debug Support (eudebug) v10
URL : https://patchwork.freedesktop.org/series/173321/
State : warning
== Summary ==
+ KERNEL=/kernel
+ git clone https://gitlab.freedesktop.org/drm/maintainer-tools mt
Cloning into 'mt'...
warning: redirecting to https://gitlab.freedesktop.org/drm/maintainer-tools.git/
+ git -C mt rev-list -n1 origin/master
d875049d2b299159a272bd5151994970cdcd1e31
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ git log -n1
commit d03ce24af3561c5b07e9ec0e6df79468661c27ff
Author: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Date: Thu Sep 3 17:59:51 2026 +0300
drm/xe/eudebug: Enable EU pagefault handling
The XE2 (and PVC) HW has a limitation that the pagefault due to invalid
access will halt the corresponding EUs. To solve this problem, enable
EU pagefault handling functionality, which allows to unhalt pagefaulted
eu threads and to EU debugger to get inform about the eu attentions state
of EU threads during execution.
If a pagefault occurs, send the DRM_XE_EUDEBUG_EVENT_PAGEFAULT event
after handling the pagefault.
The pagefault handling is a mechanism that allows a stalled EU thread to
enter SIP mode by installing a temporal null page to the page table entry
where the pagefault happened.
A brief description of the page fault handling mechanism flow between KMD
and the eu thread is as follows
(1) eu thread accesses unallocated address
(2) pagefault happens and eu thread stalls
(3) XE kmd set an force eu thread exception to allow the running eu thread
to enter SIP mode (kmd set ForceException bit of TD_CTL register)
Not stalled (none-pagefaulted) eu threads enter SIP mode
(4) XE kmd installs temporal null page to the pagetable entry of the
address where pagefault happened.
(5) XE kmd replies pagefault successful message to GUC
(6) When a given pagefault is fully handled temporary NULL VMA is
removed.
(7) If multiple threads caused a pagefault and this is reflected in
pagefault queue or worker's cache then the first pagefault
finalization is postponed but the worker is released
(8) All subsequent pagefaults for a given VM are handled by eudebug by
inserting NULL VMA, ACK and then remove the temporary VMA
(9) stalled eu thread resumes as per pagefault condition has resolved
(10) resumed eu thread enters SIP mode due to force exception set
by (3)
(9) When there are no more pagefault to process the first pagefault
finalization is performed and event is send.
As designed this feature to only work when eudbug is enabled, it should
have no impact to regular recoverable pagefault code path.
v2: - pf->q holds the vm ref so drop it (Mika)
- streamline uapi (Mika)
- cleanup the pagefault through producer if (Mika)
v3: - pagefault rework (Maciej)
Assisted-by: GitHub Copilot CLI:claude-opus-4.7
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Gustavo Sousa <gustavo.sousa@intel.com>
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
+ /mt/dim checkpatch 78e2bb86709699d886be71a6f9c9dc41e4bf9aab drm-intel
322a1f188b42 drm/xe/eudebug: Introduce eudebug interface
-:106: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#106:
new file mode 100644
-:1666: WARNING:LONG_LINE: line length of 129 exceeds 100 columns
#1666: FILE: include/uapi/drm/xe_drm.h:133:
+#define DRM_IOCTL_XE_EUDEBUG_CONNECT DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)
total: 0 errors, 2 warnings, 0 checks, 1618 lines checked
fa8a713d1d4d drm/xe/eudebug: Add documentation
-:21: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#21:
new file mode 100644
total: 0 errors, 1 warnings, 0 checks, 74 lines checked
deb802674560 drm/xe/eudebug: Add connection establishment documentation
c0a975307c69 drm/xe/eudebug: Introduce discovery for resources
e40b9cb77532 drm/xe: Add EUDEBUG_ENABLE exec queue property
88c9ba66c927 drm/xe/eudebug: Introduce exec_queue events
63a035d43d2c drm/xe/eudebug: Mark guc contexts as debuggable
6bf14ce4a7e6 drm/xe: Remove ifdef in DRM_GPUVA_OP_DRIVER svm subop checking
0fdc2fa23802 drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops
-:51: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#51:
new file mode 100644
total: 0 errors, 1 warnings, 0 checks, 901 lines checked
928cfe738f7d drm/xe/eudebug: Introduce vm bind and vm bind debug data events
-:420: WARNING:LONG_LINE_COMMENT: line length of 102 exceeds 100 columns
#420: FILE: include/uapi/drm/xe_drm_eudebug.h:133:
+ * │ EVENT_VM_BIND ├──────────────────┬─┬┄┐
-:421: WARNING:LONG_LINE_COMMENT: line length of 108 exceeds 100 columns
#421: FILE: include/uapi/drm/xe_drm_eudebug.h:134:
+ * └───────────────────────┘ │ │ ┊
-:422: WARNING:LONG_LINE_COMMENT: line length of 130 exceeds 100 columns
#422: FILE: include/uapi/drm/xe_drm_eudebug.h:135:
+ * ┌──────────────────────────────────┐ │ │ ┊
-:424: WARNING:LONG_LINE_COMMENT: line length of 128 exceeds 100 columns
#424: FILE: include/uapi/drm/xe_drm_eudebug.h:137:
+ * └──────────────────────────────────┘ │ ┊
-:426: WARNING:LONG_LINE_COMMENT: line length of 128 exceeds 100 columns
#426: FILE: include/uapi/drm/xe_drm_eudebug.h:139:
+ * ┌──────────────────────────────────┐ │ ┊
-:428: WARNING:LONG_LINE_COMMENT: line length of 126 exceeds 100 columns
#428: FILE: include/uapi/drm/xe_drm_eudebug.h:141:
+ * └──────────────────────────────────┘ ┊
-:430: WARNING:LONG_LINE_COMMENT: line length of 126 exceeds 100 columns
#430: FILE: include/uapi/drm/xe_drm_eudebug.h:143:
+ * ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐ ┊
-:432: WARNING:LONG_LINE_COMMENT: line length of 116 exceeds 100 columns
#432: FILE: include/uapi/drm/xe_drm_eudebug.h:145:
+ * └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
total: 0 errors, 8 warnings, 0 checks, 432 lines checked
2703cac288c2 drm/xe/eudebug: Add ufence events with acks
5abf0595edf3 drm/xe/eudebug: Add vm open/pread/pwrite
-:191: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#191: FILE: drivers/gpu/drm/xe/xe_eudebug.h:46:
+#define xe_eudebug_for_each_hw_engine(__hwe, __gt, __id) \
+ for_each_hw_engine(__hwe, __gt, __id) \
+ for_each_if(xe_hw_engine_has_eudebug(__hwe))
BUT SEE:
do {} while (0) advice is over-stated in a few situations:
The more obvious case is macros, like MODULE_PARM_DESC, invoked at
file-scope, where C disallows code (it must be in functions). See
$exceptions if you have one to add by name.
More troublesome is declarative macros used at top of new scope,
like DECLARE_PER_CPU. These might just compile with a do-while-0
wrapper, but would be incorrect. Most of these are handled by
detecting struct,union,etc declaration primitives in $exceptions.
Theres also macros called inside an if (block), which "return" an
expression. These cannot do-while, and need a ({}) wrapper.
Enjoy this qualification while we work to improve our heuristics.
-:191: CHECK:MACRO_ARG_REUSE: Macro argument reuse '__hwe' - possible side-effects?
#191: FILE: drivers/gpu/drm/xe/xe_eudebug.h:46:
+#define xe_eudebug_for_each_hw_engine(__hwe, __gt, __id) \
+ for_each_hw_engine(__hwe, __gt, __id) \
+ for_each_if(xe_hw_engine_has_eudebug(__hwe))
-:217: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#217:
new file mode 100644
total: 1 errors, 1 warnings, 1 checks, 642 lines checked
a1425e0f0c96 drm/xe/eudebug: Add userptr vm pread/pwrite
e22df9db693a drm/xe/eudebug: Add hw enablement
-:101: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#101:
new file mode 100644
total: 0 errors, 1 warnings, 0 checks, 456 lines checked
44eb27038319 drm/xe/eudebug: Introduce EU control interface
1c242ee4bbfa drm/xe/eudebug: Introduce per device attention scan worker
762caa7954a6 drm/xe/eudebug_test: Introduce eudebug live tests
-:22: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#22:
new file mode 100644
total: 0 errors, 1 warnings, 0 checks, 242 lines checked
5451f466ea71 drm/xe: Implement SR-IOV and eudebug exclusivity
6e7fc2819d05 drm/xe: Add xe_client_debugfs and introduce debug_data file
-:39: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#39:
new file mode 100644
total: 0 errors, 1 warnings, 0 checks, 149 lines checked
d580805aec6f drm/xe/pagefault: export pagefault queue properties
30c56dbd14db drm/xe/eudebug: Add read/count/compare helper for eu attention
-:82: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see function description of usleep_range() and udelay().
#82: FILE: drivers/gpu/drm/xe/xe_gt_debug.c:243:
+ udelay(15);
-:116: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#116:
new file mode 100644
-:138: CHECK:SPACING: spaces preferred around that '/' (ctx:VxV)
#138: FILE: drivers/gpu/drm/xe/xe_gt_debug_types.h:18:
+ XE_GT_EU_ATT_MAX_THREADS/8];
^
total: 0 errors, 1 warnings, 2 checks, 105 lines checked
71a69c0a851c drm/xe/vm: Support for adding null page VMA to VM on request
-:15: WARNING:COMMIT_LOG_LONG_LINE: Prefer a maximum 75 chars per line (possible unwrapped commit description?)
#15:
[1] https://lore.kernel.org/intel-xe/20230829231648.4438-1-yu.bruce.chang@intel.com/
total: 0 errors, 1 warnings, 0 checks, 66 lines checked
8b06486bccb1 drm/xe/vm: Add xe_vm_svm_vma_subtract() to carve out a sub-range from an SVM VMA
f27d7b656acb drm/xe: Support for xe_vma_unbind()
-:33: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#33: FILE: drivers/gpu/drm/xe/xe_vm.c:1081:
+static int xe_vm_ops_add_unbind(struct xe_vma_ops *vops,
+ struct xe_vma *vma,
total: 0 errors, 0 warnings, 1 checks, 99 lines checked
0ebfc10ecda1 drm/xe: export prep_vma_destroy as xe_vm_prep_vma_destroy
-:59: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#59: FILE: drivers/gpu/drm/xe/xe_vm.c:2904:
+ xe_vm_prep_vma_destroy(vm, gpuva_to_vma(op->base.remap.unmap->va),
true);
total: 0 errors, 0 warnings, 1 checks, 80 lines checked
6b9c82eb5cb7 drm/xe/eudebug: Introduce EU pagefault handling interface
-:257: CHECK:LINE_SPACING: Please don't use multiple blank lines
#257: FILE: drivers/gpu/drm/xe/xe_eudebug.c:2085:
+
+
-:407: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#407:
new file mode 100644
-:484: CHECK:UNCOMMENTED_DEFINITION: spinlock_t definition without comment
#484: FILE: drivers/gpu/drm/xe/xe_eudebug_pagefault.c:73:
+ spinlock_t lock;
-:492: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "!fence"
#492: FILE: drivers/gpu/drm/xe/xe_eudebug_pagefault.c:81:
+ if (fence == NULL)
-:710: CHECK:BRACES: Blank lines aren't necessary before a close brace '}'
#710: FILE: drivers/gpu/drm/xe/xe_eudebug_pagefault.c:299:
+
+}
-:711: CHECK:LINE_SPACING: Please use a blank line after function/struct/union/enum declarations
#711: FILE: drivers/gpu/drm/xe/xe_eudebug_pagefault.c:300:
+}
+static struct xe_eudebug_pagefault *xe_eudebug_get_epf(struct xe_pagefault *pf)
-:1052: WARNING:LINE_SPACING: Missing a blank line after declarations
#1052: FILE: drivers/gpu/drm/xe/xe_eudebug_pagefault.c:641:
+ struct xe_vm *vm;
+ epf = d->pf.first;
total: 0 errors, 2 warnings, 5 checks, 1234 lines checked
d03ce24af356 drm/xe/eudebug: Enable EU pagefault handling
^ permalink raw reply [flat|nested] 48+ messages in thread
* ✓ CI.KUnit: success for Intel Xe GPU Debug Support (eudebug) v10
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (27 preceding siblings ...)
2026-09-03 15:35 ` ✗ CI.checkpatch: warning for Intel Xe GPU Debug Support (eudebug) v10 Patchwork
@ 2026-09-03 15:37 ` Patchwork
2026-09-03 15:53 ` ✗ CI.checksparse: warning " Patchwork
` (3 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Patchwork @ 2026-09-03 15:37 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
== Series Details ==
Series: Intel Xe GPU Debug Support (eudebug) v10
URL : https://patchwork.freedesktop.org/series/173321/
State : success
== Summary ==
+ trap cleanup EXIT
+ kunitconfigs=('/kernel/drivers/gpu/tests/.kunitconfig' '/kernel/drivers/gpu/drm/xe/.kunitconfig' '/kernel/drivers/gpu/drm/tests/.kunitconfig' '/kernel/drivers/gpu/drm/ttm/tests/.kunitconfig' '/kernel/drivers/dma-buf/.kunitconfig')
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/tests/.kunitconfig
[15:35:01] Configuring KUnit Kernel ...
Generating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[15:35:05] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[15:35:25] Starting KUnit Kernel (1/1)...
[15:35:25] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[15:35:25] ============= refcount_interrupt (4 subtests) ==============
[15:35:25] [PASSED] test_single_irq_change
[15:35:25] [PASSED] test_nested_irq_change
[15:35:25] [PASSED] test_multiple_irq_change
[15:35:25] [PASSED] test_irq_save
[15:35:25] =============== [PASSED] refcount_interrupt ================
[15:35:25] ================= gpu_buddy (14 subtests) ==================
[15:35:25] [PASSED] gpu_test_buddy_alloc_limit
[15:35:25] [PASSED] gpu_test_buddy_alloc_optimistic
[15:35:25] [PASSED] gpu_test_buddy_alloc_pessimistic
[15:35:25] [PASSED] gpu_test_buddy_alloc_pathological
[15:35:25] [PASSED] gpu_test_buddy_alloc_contiguous
[15:35:25] [PASSED] gpu_test_buddy_alloc_clear
[15:35:25] [PASSED] gpu_test_buddy_alloc_range
[15:35:26] [PASSED] gpu_test_buddy_alloc_range_bias
[15:35:27] [PASSED] gpu_test_buddy_fragmentation_performance
[15:35:27] [PASSED] gpu_test_buddy_dirty_tracker_performance
[15:35:27] [PASSED] gpu_test_buddy_alloc_exceeds_max_order
[15:35:27] [PASSED] gpu_test_buddy_offset_aligned_allocation
[15:35:27] [PASSED] gpu_test_buddy_subtree_offset_alignment_stress
[15:35:27] [PASSED] gpu_test_buddy_addr_to_block
[15:35:27] ==================== [PASSED] gpu_buddy ====================
[15:35:27] ============================================================
[15:35:27] Testing complete. Ran 18 tests: passed: 18
[15:35:27] Elapsed time: 26.701s total, 4.469s configuring, 20.315s building, 1.857s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/xe/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/xe/.kunitconfig
[15:35:27] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[15:35:29] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[15:36:04] Starting KUnit Kernel (1/1)...
[15:36:04] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[15:36:04] ============= refcount_interrupt (4 subtests) ==============
[15:36:04] [PASSED] test_single_irq_change
[15:36:04] [PASSED] test_nested_irq_change
[15:36:04] [PASSED] test_multiple_irq_change
[15:36:04] [PASSED] test_irq_save
[15:36:04] =============== [PASSED] refcount_interrupt ================
[15:36:04] ================== guc_buf (11 subtests) ===================
[15:36:04] [PASSED] test_smallest
[15:36:04] [PASSED] test_largest
[15:36:04] [PASSED] test_granular
[15:36:04] [PASSED] test_unique
[15:36:04] [PASSED] test_overlap
[15:36:04] [PASSED] test_reusable
[15:36:04] [PASSED] test_too_big
[15:36:04] [PASSED] test_flush
[15:36:04] [PASSED] test_lookup
[15:36:04] [PASSED] test_data
[15:36:04] [PASSED] test_class
[15:36:04] ===================== [PASSED] guc_buf =====================
[15:36:04] =================== guc_dbm (7 subtests) ===================
[15:36:04] [PASSED] test_empty
[15:36:04] [PASSED] test_default
[15:36:04] ======================== test_size ========================
[15:36:04] [PASSED] 4
[15:36:04] [PASSED] 8
[15:36:04] [PASSED] 32
[15:36:04] [PASSED] 256
[15:36:04] ==================== [PASSED] test_size ====================
[15:36:04] ======================= test_reuse ========================
[15:36:04] [PASSED] 4
[15:36:04] [PASSED] 8
[15:36:04] [PASSED] 32
[15:36:04] [PASSED] 256
[15:36:04] =================== [PASSED] test_reuse ====================
[15:36:04] =================== test_range_overlap ====================
[15:36:04] [PASSED] 4
[15:36:04] [PASSED] 8
[15:36:04] [PASSED] 32
[15:36:04] [PASSED] 256
[15:36:04] =============== [PASSED] test_range_overlap ================
[15:36:04] =================== test_range_compact ====================
[15:36:04] [PASSED] 4
[15:36:04] [PASSED] 8
[15:36:04] [PASSED] 32
[15:36:04] [PASSED] 256
[15:36:04] =============== [PASSED] test_range_compact ================
[15:36:04] ==================== test_range_spare =====================
[15:36:04] [PASSED] 4
[15:36:04] [PASSED] 8
[15:36:04] [PASSED] 32
[15:36:04] [PASSED] 256
[15:36:04] ================ [PASSED] test_range_spare =================
[15:36:04] ===================== [PASSED] guc_dbm =====================
[15:36:04] =================== guc_idm (6 subtests) ===================
[15:36:04] [PASSED] bad_init
[15:36:04] [PASSED] no_init
[15:36:04] [PASSED] init_fini
[15:36:04] [PASSED] check_used
[15:36:04] [PASSED] check_quota
[15:36:04] [PASSED] check_all
[15:36:04] ===================== [PASSED] guc_idm =====================
[15:36:04] =============== guc_klv_helpers (9 subtests) ===============
[15:36:04] [PASSED] test_count
[15:36:04] [PASSED] test_encode_u32
[15:36:04] [PASSED] test_encode_u64
[15:36:04] [PASSED] test_encode_string
[15:36:04] [PASSED] test_encode_object_raw
[15:36:04] [PASSED] test_encode_object_klv
[15:36:04] [PASSED] test_encode_object_nested
[15:36:04] [PASSED] test_encode_object_basic
[15:36:04] [PASSED] test_print
[15:36:04] ================= [PASSED] guc_klv_helpers =================
[15:36:04] =================== xe_log (4 subtests) ====================
[15:36:04] [PASSED] demo_cper
[15:36:04] [PASSED] demo_dmesg
[15:36:04] ======================= test_dmesg ========================
[15:36:04] [PASSED] test_fatal
[15:36:04] [PASSED] test_fatal_tile
[15:36:04] [PASSED] test_fatal_gt
[15:36:04] [PASSED] test_fatal_comp
[15:36:04] [PASSED] test_fatal_comp_tile
[15:36:04] [PASSED] test_fatal_comp_gt
[15:36:04] [PASSED] test_fatal_all
[15:36:04] [PASSED] test_recoverable
[15:36:04] [PASSED] test_recoverable_tile
[15:36:04] [PASSED] test_recoverable_gt
[15:36:04] [PASSED] test_recoverable_comp
[15:36:04] [PASSED] test_recoverable_comp_tile
[15:36:04] [PASSED] test_recoverable_comp_gt
[15:36:04] [PASSED] test_recoverable_all
[15:36:04] [PASSED] test_info
[15:36:04] [PASSED] test_info_tile
[15:36:04] [PASSED] test_info_gt
[15:36:04] [PASSED] test_info_err
[15:36:04] [PASSED] test_info_comp
[15:36:04] [PASSED] test_info_comp_tile
[15:36:04] [PASSED] test_info_comp_gt
[15:36:04] [PASSED] test_info_all
[15:36:04] [PASSED] test_hw_fatal
[15:36:04] [PASSED] test_hw_recoverable
[15:36:04] [PASSED] test_hw_corrected
[15:36:04] [PASSED] test_hw_informational
[15:36:04] =================== [PASSED] test_dmesg ====================
[15:36:04] ====================== test_invalid =======================
[15:36:04] [SKIPPED] no-component no-location no-warn (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] reserved location (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] unknown location (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] nonzero-device-id location (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] invalid-tile-id location (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] invalid-gt-id location (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] unknown component class (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] unknown system component (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] unknown hardware component (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] [SKIPPED] unknown component and location (requires CONFIG_DRM_XE_DEBUG)
[15:36:04] ================== [SKIPPED] test_invalid ==================
[15:36:04] ===================== [PASSED] xe_log ======================
[15:36:04] ================== no_relay (3 subtests) ===================
[15:36:04] [PASSED] xe_drops_guc2pf_if_not_ready
[15:36:04] [PASSED] xe_drops_guc2vf_if_not_ready
[15:36:04] [PASSED] xe_rejects_send_if_not_ready
[15:36:04] ==================== [PASSED] no_relay =====================
[15:36:04] ================== pf_relay (14 subtests) ==================
[15:36:04] [PASSED] pf_rejects_guc2pf_too_short
[15:36:04] [PASSED] pf_rejects_guc2pf_too_long
[15:36:04] [PASSED] pf_rejects_guc2pf_no_payload
[15:36:04] [PASSED] pf_fails_no_payload
[15:36:04] [PASSED] pf_fails_bad_origin
[15:36:04] [PASSED] pf_fails_bad_type
[15:36:04] [PASSED] pf_txn_reports_error
[15:36:04] [PASSED] pf_txn_sends_pf2guc
[15:36:04] [PASSED] pf_sends_pf2guc
[15:36:04] [SKIPPED] pf_loopback_nop (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[15:36:04] [SKIPPED] pf_loopback_echo (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[15:36:04] [SKIPPED] pf_loopback_fail (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[15:36:04] [SKIPPED] pf_loopback_busy (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[15:36:04] [SKIPPED] pf_loopback_retry (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[15:36:04] ==================== [PASSED] pf_relay =====================
[15:36:04] ================== vf_relay (3 subtests) ===================
[15:36:04] [PASSED] vf_rejects_guc2vf_too_short
[15:36:04] [PASSED] vf_rejects_guc2vf_too_long
[15:36:04] [PASSED] vf_rejects_guc2vf_no_payload
[15:36:04] ==================== [PASSED] vf_relay =====================
[15:36:04] ================ pf_gt_config (9 subtests) =================
[15:36:04] [PASSED] fair_contexts_1vf
[15:36:04] [PASSED] fair_doorbells_1vf
[15:36:04] [PASSED] fair_ggtt_1vf
[15:36:04] ====================== fair_vram_1vf ======================
[15:36:04] [PASSED] 3.50 GiB
[15:36:04] [PASSED] 11.5 GiB
[15:36:04] [PASSED] 15.5 GiB
[15:36:04] [PASSED] 31.5 GiB
[15:36:04] [PASSED] 63.5 GiB
[15:36:04] [PASSED] 1.91 GiB
[15:36:04] ================== [PASSED] fair_vram_1vf ==================
[15:36:04] ================ fair_vram_1vf_admin_only =================
[15:36:04] [PASSED] 3.50 GiB
[15:36:04] [PASSED] 11.5 GiB
[15:36:04] [PASSED] 15.5 GiB
[15:36:04] [PASSED] 31.5 GiB
[15:36:04] [PASSED] 63.5 GiB
[15:36:04] [PASSED] 1.91 GiB
[15:36:04] ============ [PASSED] fair_vram_1vf_admin_only =============
[15:36:04] ====================== fair_contexts ======================
[15:36:04] [PASSED] 1 VF
[15:36:04] [PASSED] 2 VFs
[15:36:04] [PASSED] 3 VFs
[15:36:04] [PASSED] 4 VFs
[15:36:04] [PASSED] 5 VFs
[15:36:04] [PASSED] 6 VFs
[15:36:04] [PASSED] 7 VFs
[15:36:04] [PASSED] 8 VFs
[15:36:04] [PASSED] 9 VFs
[15:36:04] [PASSED] 10 VFs
[15:36:04] [PASSED] 11 VFs
[15:36:04] [PASSED] 12 VFs
[15:36:04] [PASSED] 13 VFs
[15:36:04] [PASSED] 14 VFs
[15:36:04] [PASSED] 15 VFs
[15:36:04] [PASSED] 16 VFs
[15:36:04] [PASSED] 17 VFs
[15:36:04] [PASSED] 18 VFs
[15:36:04] [PASSED] 19 VFs
[15:36:04] [PASSED] 20 VFs
[15:36:04] [PASSED] 21 VFs
[15:36:04] [PASSED] 22 VFs
[15:36:04] [PASSED] 23 VFs
[15:36:04] [PASSED] 24 VFs
[15:36:04] [PASSED] 25 VFs
[15:36:04] [PASSED] 26 VFs
[15:36:04] [PASSED] 27 VFs
[15:36:04] [PASSED] 28 VFs
[15:36:04] [PASSED] 29 VFs
[15:36:04] [PASSED] 30 VFs
[15:36:04] [PASSED] 31 VFs
[15:36:04] [PASSED] 32 VFs
[15:36:04] [PASSED] 33 VFs
[15:36:04] [PASSED] 34 VFs
[15:36:04] [PASSED] 35 VFs
[15:36:04] [PASSED] 36 VFs
[15:36:04] [PASSED] 37 VFs
[15:36:04] [PASSED] 38 VFs
[15:36:04] [PASSED] 39 VFs
[15:36:04] [PASSED] 40 VFs
[15:36:04] [PASSED] 41 VFs
[15:36:04] [PASSED] 42 VFs
[15:36:04] [PASSED] 43 VFs
[15:36:04] [PASSED] 44 VFs
[15:36:04] [PASSED] 45 VFs
[15:36:04] [PASSED] 46 VFs
[15:36:04] [PASSED] 47 VFs
[15:36:04] [PASSED] 48 VFs
[15:36:04] [PASSED] 49 VFs
[15:36:04] [PASSED] 50 VFs
[15:36:04] [PASSED] 51 VFs
[15:36:04] [PASSED] 52 VFs
[15:36:04] [PASSED] 53 VFs
[15:36:04] [PASSED] 54 VFs
[15:36:04] [PASSED] 55 VFs
[15:36:04] [PASSED] 56 VFs
[15:36:04] [PASSED] 57 VFs
[15:36:04] [PASSED] 58 VFs
[15:36:04] [PASSED] 59 VFs
[15:36:04] [PASSED] 60 VFs
[15:36:04] [PASSED] 61 VFs
[15:36:04] [PASSED] 62 VFs
[15:36:04] [PASSED] 63 VFs
[15:36:04] ================== [PASSED] fair_contexts ==================
[15:36:04] ===================== fair_doorbells ======================
[15:36:04] [PASSED] 1 VF
[15:36:04] [PASSED] 2 VFs
[15:36:04] [PASSED] 3 VFs
[15:36:04] [PASSED] 4 VFs
[15:36:04] [PASSED] 5 VFs
[15:36:04] [PASSED] 6 VFs
[15:36:04] [PASSED] 7 VFs
[15:36:04] [PASSED] 8 VFs
[15:36:04] [PASSED] 9 VFs
[15:36:04] [PASSED] 10 VFs
[15:36:04] [PASSED] 11 VFs
[15:36:04] [PASSED] 12 VFs
[15:36:04] [PASSED] 13 VFs
[15:36:04] [PASSED] 14 VFs
[15:36:04] [PASSED] 15 VFs
[15:36:04] [PASSED] 16 VFs
[15:36:04] [PASSED] 17 VFs
[15:36:04] [PASSED] 18 VFs
[15:36:04] [PASSED] 19 VFs
[15:36:04] [PASSED] 20 VFs
[15:36:04] [PASSED] 21 VFs
[15:36:04] [PASSED] 22 VFs
[15:36:04] [PASSED] 23 VFs
[15:36:04] [PASSED] 24 VFs
[15:36:04] [PASSED] 25 VFs
[15:36:04] [PASSED] 26 VFs
[15:36:04] [PASSED] 27 VFs
[15:36:04] [PASSED] 28 VFs
[15:36:04] [PASSED] 29 VFs
[15:36:04] [PASSED] 30 VFs
[15:36:04] [PASSED] 31 VFs
[15:36:04] [PASSED] 32 VFs
[15:36:04] [PASSED] 33 VFs
[15:36:04] [PASSED] 34 VFs
[15:36:04] [PASSED] 35 VFs
[15:36:04] [PASSED] 36 VFs
[15:36:04] [PASSED] 37 VFs
[15:36:04] [PASSED] 38 VFs
[15:36:04] [PASSED] 39 VFs
[15:36:04] [PASSED] 40 VFs
[15:36:04] [PASSED] 41 VFs
[15:36:04] [PASSED] 42 VFs
[15:36:04] [PASSED] 43 VFs
[15:36:04] [PASSED] 44 VFs
[15:36:04] [PASSED] 45 VFs
[15:36:04] [PASSED] 46 VFs
[15:36:04] [PASSED] 47 VFs
[15:36:04] [PASSED] 48 VFs
[15:36:04] [PASSED] 49 VFs
[15:36:04] [PASSED] 50 VFs
[15:36:04] [PASSED] 51 VFs
[15:36:04] [PASSED] 52 VFs
[15:36:04] [PASSED] 53 VFs
[15:36:04] [PASSED] 54 VFs
[15:36:04] [PASSED] 55 VFs
[15:36:04] [PASSED] 56 VFs
[15:36:04] [PASSED] 57 VFs
[15:36:04] [PASSED] 58 VFs
[15:36:04] [PASSED] 59 VFs
[15:36:04] [PASSED] 60 VFs
[15:36:04] [PASSED] 61 VFs
[15:36:04] [PASSED] 62 VFs
[15:36:04] [PASSED] 63 VFs
[15:36:04] ================= [PASSED] fair_doorbells ==================
[15:36:04] ======================== fair_ggtt ========================
[15:36:04] [PASSED] 1 VF
[15:36:04] [PASSED] 2 VFs
[15:36:04] [PASSED] 3 VFs
[15:36:04] [PASSED] 4 VFs
[15:36:04] [PASSED] 5 VFs
[15:36:04] [PASSED] 6 VFs
[15:36:04] [PASSED] 7 VFs
[15:36:04] [PASSED] 8 VFs
[15:36:04] [PASSED] 9 VFs
[15:36:04] [PASSED] 10 VFs
[15:36:04] [PASSED] 11 VFs
[15:36:04] [PASSED] 12 VFs
[15:36:04] [PASSED] 13 VFs
[15:36:04] [PASSED] 14 VFs
[15:36:04] [PASSED] 15 VFs
[15:36:04] [PASSED] 16 VFs
[15:36:04] [PASSED] 17 VFs
[15:36:04] [PASSED] 18 VFs
[15:36:04] [PASSED] 19 VFs
[15:36:04] [PASSED] 20 VFs
[15:36:04] [PASSED] 21 VFs
[15:36:04] [PASSED] 22 VFs
[15:36:04] [PASSED] 23 VFs
[15:36:04] [PASSED] 24 VFs
[15:36:04] [PASSED] 25 VFs
[15:36:04] [PASSED] 26 VFs
[15:36:04] [PASSED] 27 VFs
[15:36:04] [PASSED] 28 VFs
[15:36:04] [PASSED] 29 VFs
[15:36:04] [PASSED] 30 VFs
[15:36:04] [PASSED] 31 VFs
[15:36:04] [PASSED] 32 VFs
[15:36:04] [PASSED] 33 VFs
[15:36:04] [PASSED] 34 VFs
[15:36:04] [PASSED] 35 VFs
[15:36:04] [PASSED] 36 VFs
[15:36:04] [PASSED] 37 VFs
[15:36:04] [PASSED] 38 VFs
[15:36:04] [PASSED] 39 VFs
[15:36:04] [PASSED] 40 VFs
[15:36:04] [PASSED] 41 VFs
[15:36:04] [PASSED] 42 VFs
[15:36:04] [PASSED] 43 VFs
[15:36:04] [PASSED] 44 VFs
[15:36:04] [PASSED] 45 VFs
[15:36:04] [PASSED] 46 VFs
[15:36:04] [PASSED] 47 VFs
[15:36:04] [PASSED] 48 VFs
[15:36:04] [PASSED] 49 VFs
[15:36:04] [PASSED] 50 VFs
[15:36:04] [PASSED] 51 VFs
[15:36:04] [PASSED] 52 VFs
[15:36:04] [PASSED] 53 VFs
[15:36:04] [PASSED] 54 VFs
[15:36:04] [PASSED] 55 VFs
[15:36:04] [PASSED] 56 VFs
[15:36:04] [PASSED] 57 VFs
[15:36:04] [PASSED] 58 VFs
[15:36:04] [PASSED] 59 VFs
[15:36:04] [PASSED] 60 VFs
[15:36:04] [PASSED] 61 VFs
[15:36:04] [PASSED] 62 VFs
[15:36:04] [PASSED] 63 VFs
[15:36:04] ==================== [PASSED] fair_ggtt ====================
[15:36:04] ======================== fair_vram ========================
[15:36:04] [PASSED] 1 VF
[15:36:04] [PASSED] 2 VFs
[15:36:04] [PASSED] 3 VFs
[15:36:04] [PASSED] 4 VFs
[15:36:04] [PASSED] 5 VFs
[15:36:04] [PASSED] 6 VFs
[15:36:04] [PASSED] 7 VFs
[15:36:04] [PASSED] 8 VFs
[15:36:04] [PASSED] 9 VFs
[15:36:04] [PASSED] 10 VFs
[15:36:04] [PASSED] 11 VFs
[15:36:04] [PASSED] 12 VFs
[15:36:04] [PASSED] 13 VFs
[15:36:04] [PASSED] 14 VFs
[15:36:04] [PASSED] 15 VFs
[15:36:04] [PASSED] 16 VFs
[15:36:04] [PASSED] 17 VFs
[15:36:04] [PASSED] 18 VFs
[15:36:05] [PASSED] 19 VFs
[15:36:05] [PASSED] 20 VFs
[15:36:05] [PASSED] 21 VFs
[15:36:05] [PASSED] 22 VFs
[15:36:05] [PASSED] 23 VFs
[15:36:05] [PASSED] 24 VFs
[15:36:05] [PASSED] 25 VFs
[15:36:05] [PASSED] 26 VFs
[15:36:05] [PASSED] 27 VFs
[15:36:05] [PASSED] 28 VFs
[15:36:05] [PASSED] 29 VFs
[15:36:05] [PASSED] 30 VFs
[15:36:05] [PASSED] 31 VFs
[15:36:05] [PASSED] 32 VFs
[15:36:05] [PASSED] 33 VFs
[15:36:05] [PASSED] 34 VFs
[15:36:05] [PASSED] 35 VFs
[15:36:05] [PASSED] 36 VFs
[15:36:05] [PASSED] 37 VFs
[15:36:05] [PASSED] 38 VFs
[15:36:05] [PASSED] 39 VFs
[15:36:05] [PASSED] 40 VFs
[15:36:05] [PASSED] 41 VFs
[15:36:05] [PASSED] 42 VFs
[15:36:05] [PASSED] 43 VFs
[15:36:05] [PASSED] 44 VFs
[15:36:05] [PASSED] 45 VFs
[15:36:05] [PASSED] 46 VFs
[15:36:05] [PASSED] 47 VFs
[15:36:05] [PASSED] 48 VFs
[15:36:05] [PASSED] 49 VFs
[15:36:05] [PASSED] 50 VFs
[15:36:05] [PASSED] 51 VFs
[15:36:05] [PASSED] 52 VFs
[15:36:05] [PASSED] 53 VFs
[15:36:05] [PASSED] 54 VFs
[15:36:05] [PASSED] 55 VFs
[15:36:05] [PASSED] 56 VFs
[15:36:05] [PASSED] 57 VFs
[15:36:05] [PASSED] 58 VFs
[15:36:05] [PASSED] 59 VFs
[15:36:05] [PASSED] 60 VFs
[15:36:05] [PASSED] 61 VFs
[15:36:05] [PASSED] 62 VFs
[15:36:05] [PASSED] 63 VFs
[15:36:05] ==================== [PASSED] fair_vram ====================
[15:36:05] ================== [PASSED] pf_gt_config ===================
[15:36:05] ===================== lmtt (1 subtest) =====================
[15:36:05] ======================== test_ops =========================
[15:36:05] [PASSED] 2-level
[15:36:05] [PASSED] multi-level
[15:36:05] ==================== [PASSED] test_ops =====================
[15:36:05] ====================== [PASSED] lmtt =======================
[15:36:05] ================= sriov_packet (1 subtest) =================
[15:36:05] [PASSED] test_descriptor_init
[15:36:05] ================== [PASSED] sriov_packet ===================
[15:36:05] ================= pf_service (11 subtests) =================
[15:36:05] [PASSED] pf_negotiate_any
[15:36:05] [PASSED] pf_negotiate_base_match
[15:36:05] [PASSED] pf_negotiate_base_newer
[15:36:05] [PASSED] pf_negotiate_base_next
[15:36:05] [SKIPPED] pf_negotiate_base_older (no older minor)
[15:36:05] [PASSED] pf_negotiate_base_prev
[15:36:05] [PASSED] pf_negotiate_latest_match
[15:36:05] [PASSED] pf_negotiate_latest_newer
[15:36:05] [PASSED] pf_negotiate_latest_next
[15:36:05] [SKIPPED] pf_negotiate_latest_older (no older minor)
[15:36:05] [SKIPPED] pf_negotiate_latest_prev (no prev major)
[15:36:05] =================== [PASSED] pf_service ====================
[15:36:05] ================== xe_eudebug (1 subtest) ==================
[15:36:05] ======================= toggle_reg ========================
[15:36:05] =================== [SKIPPED] toggle_reg ===================
[15:36:05] =================== [SKIPPED] xe_eudebug ===================
[15:36:05] ================= xe_guc_g2g (2 subtests) ==================
[15:36:05] ============== xe_live_guc_g2g_kunit_default ==============
[15:36:05] ========= [SKIPPED] xe_live_guc_g2g_kunit_default ==========
[15:36:05] ============== xe_live_guc_g2g_kunit_allmem ===============
[15:36:05] ========== [SKIPPED] xe_live_guc_g2g_kunit_allmem ==========
[15:36:05] =================== [SKIPPED] xe_guc_g2g ===================
[15:36:05] =================== xe_mocs (2 subtests) ===================
[15:36:05] ================ xe_live_mocs_kernel_kunit ================
[15:36:05] =========== [SKIPPED] xe_live_mocs_kernel_kunit ============
[15:36:05] ================ xe_live_mocs_reset_kunit =================
[15:36:05] ============ [SKIPPED] xe_live_mocs_reset_kunit ============
[15:36:05] ==================== [SKIPPED] xe_mocs =====================
[15:36:05] ================= xe_migrate (2 subtests) ==================
[15:36:05] ================= xe_migrate_sanity_kunit =================
[15:36:05] ============ [SKIPPED] xe_migrate_sanity_kunit =============
[15:36:05] ================== xe_validate_ccs_kunit ==================
[15:36:05] ============= [SKIPPED] xe_validate_ccs_kunit ==============
[15:36:05] =================== [SKIPPED] xe_migrate ===================
[15:36:05] ================== xe_dma_buf (1 subtest) ==================
[15:36:05] ==================== xe_dma_buf_kunit =====================
[15:36:05] ================ [SKIPPED] xe_dma_buf_kunit ================
[15:36:05] =================== [SKIPPED] xe_dma_buf ===================
[15:36:05] ================= xe_bo_shrink (1 subtest) =================
[15:36:05] =================== xe_bo_shrink_kunit ====================
[15:36:05] =============== [SKIPPED] xe_bo_shrink_kunit ===============
[15:36:05] ================== [SKIPPED] xe_bo_shrink ==================
[15:36:05] ==================== xe_bo (2 subtests) ====================
[15:36:05] ================== xe_ccs_migrate_kunit ===================
[15:36:05] ============== [SKIPPED] xe_ccs_migrate_kunit ==============
[15:36:05] ==================== xe_bo_evict_kunit ====================
[15:36:05] =============== [SKIPPED] xe_bo_evict_kunit ================
[15:36:05] ===================== [SKIPPED] xe_bo ======================
[15:36:05] =================== xe_any (9 subtests) ====================
[15:36:05] [PASSED] test_to_xe
[15:36:05] [PASSED] test_to_dev
[15:36:05] [PASSED] test_to_pdev
[15:36:05] [PASSED] test_to_drm
[15:36:05] [PASSED] test_if_pdev
[15:36:05] [PASSED] test_if_xe
[15:36:05] [PASSED] test_if_tile
[15:36:05] [PASSED] test_if_gt
[15:36:05] [PASSED] test_to_id
[15:36:05] ===================== [PASSED] xe_any ======================
[15:36:05] ==================== args (13 subtests) ====================
[15:36:05] [PASSED] count_args_test
[15:36:05] [PASSED] call_args_example
[15:36:05] [PASSED] call_args_test
[15:36:05] [PASSED] drop_first_arg_example
[15:36:05] [PASSED] drop_first_arg_test
[15:36:05] [PASSED] first_arg_example
[15:36:05] [PASSED] first_arg_test
[15:36:05] [PASSED] last_arg_example
[15:36:05] [PASSED] last_arg_test
[15:36:05] [PASSED] pick_arg_example
[15:36:05] [PASSED] if_args_example
[15:36:05] [PASSED] if_args_test
[15:36:05] [PASSED] sep_comma_example
[15:36:05] ====================== [PASSED] args =======================
[15:36:05] =================== xe_pci (3 subtests) ====================
[15:36:05] ==================== check_graphics_ip ====================
[15:36:05] [PASSED] 12.00 Xe_LP
[15:36:05] [PASSED] 12.10 Xe_LP+
[15:36:05] [PASSED] 12.55 Xe_HPG
[15:36:05] [PASSED] 12.60 Xe_HPC
[15:36:05] [PASSED] 12.70 Xe_LPG
[15:36:05] [PASSED] 12.71 Xe_LPG
[15:36:05] [PASSED] 12.74 Xe_LPG+
[15:36:05] [PASSED] 20.01 Xe2_HPG
[15:36:05] [PASSED] 20.02 Xe2_HPG
[15:36:05] [PASSED] 20.04 Xe2_LPG
[15:36:05] [PASSED] 30.00 Xe3_LPG
[15:36:05] [PASSED] 30.01 Xe3_LPG
[15:36:05] [PASSED] 30.03 Xe3_LPG
[15:36:05] [PASSED] 30.04 Xe3_LPG
[15:36:05] [PASSED] 30.05 Xe3_LPG
[15:36:05] [PASSED] 35.10 Xe3p_LPG
[15:36:05] [PASSED] 35.11 Xe3p_XPC
[15:36:05] ================ [PASSED] check_graphics_ip ================
[15:36:05] ===================== check_media_ip ======================
[15:36:05] [PASSED] 12.00 Xe_M
[15:36:05] [PASSED] 12.55 Xe_HPM
[15:36:05] [PASSED] 13.00 Xe_LPM+
[15:36:05] [PASSED] 13.01 Xe2_HPM
[15:36:05] [PASSED] 20.00 Xe2_LPM
[15:36:05] [PASSED] 30.00 Xe3_LPM
[15:36:05] [PASSED] 30.02 Xe3_LPM
[15:36:05] [PASSED] 35.00 Xe3p_LPM
[15:36:05] [PASSED] 35.03 Xe3p_HPM
[15:36:05] ================= [PASSED] check_media_ip ==================
[15:36:05] =================== check_platform_desc ===================
[15:36:05] [PASSED] 0x9A60 (TIGERLAKE)
[15:36:05] [PASSED] 0x9A68 (TIGERLAKE)
[15:36:05] [PASSED] 0x9A70 (TIGERLAKE)
[15:36:05] [PASSED] 0x9A40 (TIGERLAKE)
[15:36:05] [PASSED] 0x9A49 (TIGERLAKE)
[15:36:05] [PASSED] 0x9A59 (TIGERLAKE)
[15:36:05] [PASSED] 0x9A78 (TIGERLAKE)
[15:36:05] [PASSED] 0x9AC0 (TIGERLAKE)
[15:36:05] [PASSED] 0x9AC9 (TIGERLAKE)
[15:36:05] [PASSED] 0x9AD9 (TIGERLAKE)
[15:36:05] [PASSED] 0x9AF8 (TIGERLAKE)
[15:36:05] [PASSED] 0x4C80 (ROCKETLAKE)
[15:36:05] [PASSED] 0x4C8A (ROCKETLAKE)
[15:36:05] [PASSED] 0x4C8B (ROCKETLAKE)
[15:36:05] [PASSED] 0x4C8C (ROCKETLAKE)
[15:36:05] [PASSED] 0x4C90 (ROCKETLAKE)
[15:36:05] [PASSED] 0x4C9A (ROCKETLAKE)
[15:36:05] [PASSED] 0x4680 (ALDERLAKE_S)
[15:36:05] [PASSED] 0x4682 (ALDERLAKE_S)
[15:36:05] [PASSED] 0x4688 (ALDERLAKE_S)
[15:36:05] [PASSED] 0x468A (ALDERLAKE_S)
[15:36:05] [PASSED] 0x468B (ALDERLAKE_S)
[15:36:05] [PASSED] 0x4690 (ALDERLAKE_S)
[15:36:05] [PASSED] 0x4692 (ALDERLAKE_S)
[15:36:05] [PASSED] 0x4693 (ALDERLAKE_S)
[15:36:05] [PASSED] 0x46A0 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46A1 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46A2 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46A3 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46A6 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46A8 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46AA (ALDERLAKE_P)
[15:36:05] [PASSED] 0x462A (ALDERLAKE_P)
[15:36:05] [PASSED] 0x4626 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x4628 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46B0 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46B1 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46B2 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46B3 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46C0 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46C1 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46C2 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46C3 (ALDERLAKE_P)
[15:36:05] [PASSED] 0x46D0 (ALDERLAKE_N)
[15:36:05] [PASSED] 0x46D1 (ALDERLAKE_N)
[15:36:05] [PASSED] 0x46D2 (ALDERLAKE_N)
[15:36:05] [PASSED] 0x46D3 (ALDERLAKE_N)
[15:36:05] [PASSED] 0x46D4 (ALDERLAKE_N)
[15:36:05] [PASSED] 0xA721 (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7A1 (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7A9 (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7AC (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7AD (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA720 (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7A0 (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7A8 (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7AA (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA7AB (ALDERLAKE_P)
[15:36:05] [PASSED] 0xA780 (ALDERLAKE_S)
[15:36:05] [PASSED] 0xA781 (ALDERLAKE_S)
[15:36:05] [PASSED] 0xA782 (ALDERLAKE_S)
[15:36:05] [PASSED] 0xA783 (ALDERLAKE_S)
[15:36:05] [PASSED] 0xA788 (ALDERLAKE_S)
[15:36:05] [PASSED] 0xA789 (ALDERLAKE_S)
[15:36:05] [PASSED] 0xA78A (ALDERLAKE_S)
[15:36:05] [PASSED] 0xA78B (ALDERLAKE_S)
[15:36:05] [PASSED] 0x4905 (DG1)
[15:36:05] [PASSED] 0x4906 (DG1)
[15:36:05] [PASSED] 0x4907 (DG1)
[15:36:05] [PASSED] 0x4908 (DG1)
[15:36:05] [PASSED] 0x4909 (DG1)
[15:36:05] [PASSED] 0x56C0 (DG2)
[15:36:05] [PASSED] 0x56C2 (DG2)
[15:36:05] [PASSED] 0x56C1 (DG2)
[15:36:05] [PASSED] 0x7D51 (METEORLAKE)
[15:36:05] [PASSED] 0x7DD1 (METEORLAKE)
[15:36:05] [PASSED] 0x7D41 (METEORLAKE)
[15:36:05] [PASSED] 0x7D67 (METEORLAKE)
[15:36:05] [PASSED] 0xB640 (METEORLAKE)
[15:36:05] [PASSED] 0x56A0 (DG2)
[15:36:05] [PASSED] 0x56A1 (DG2)
[15:36:05] [PASSED] 0x56A2 (DG2)
[15:36:05] [PASSED] 0x56BE (DG2)
[15:36:05] [PASSED] 0x56BF (DG2)
[15:36:05] [PASSED] 0x5690 (DG2)
[15:36:05] [PASSED] 0x5691 (DG2)
[15:36:05] [PASSED] 0x5692 (DG2)
[15:36:05] [PASSED] 0x56A5 (DG2)
[15:36:05] [PASSED] 0x56A6 (DG2)
[15:36:05] [PASSED] 0x56B0 (DG2)
[15:36:05] [PASSED] 0x56B1 (DG2)
[15:36:05] [PASSED] 0x56BA (DG2)
[15:36:05] [PASSED] 0x56BB (DG2)
[15:36:05] [PASSED] 0x56BC (DG2)
[15:36:05] [PASSED] 0x56BD (DG2)
[15:36:05] [PASSED] 0x5693 (DG2)
[15:36:05] [PASSED] 0x5694 (DG2)
[15:36:05] [PASSED] 0x5695 (DG2)
[15:36:05] [PASSED] 0x56A3 (DG2)
[15:36:05] [PASSED] 0x56A4 (DG2)
[15:36:05] [PASSED] 0x56B2 (DG2)
[15:36:05] [PASSED] 0x56B3 (DG2)
[15:36:05] [PASSED] 0x5696 (DG2)
[15:36:05] [PASSED] 0x5697 (DG2)
[15:36:05] [PASSED] 0xB69 (PVC)
[15:36:05] [PASSED] 0xB6E (PVC)
[15:36:05] [PASSED] 0xBD4 (PVC)
[15:36:05] [PASSED] 0xBD5 (PVC)
[15:36:05] [PASSED] 0xBD6 (PVC)
[15:36:05] [PASSED] 0xBD7 (PVC)
[15:36:05] [PASSED] 0xBD8 (PVC)
[15:36:05] [PASSED] 0xBD9 (PVC)
[15:36:05] [PASSED] 0xBDA (PVC)
[15:36:05] [PASSED] 0xBDB (PVC)
[15:36:05] [PASSED] 0xBE0 (PVC)
[15:36:05] [PASSED] 0xBE1 (PVC)
[15:36:05] [PASSED] 0xBE5 (PVC)
[15:36:05] [PASSED] 0x7D40 (METEORLAKE)
[15:36:05] [PASSED] 0x7D45 (METEORLAKE)
[15:36:05] [PASSED] 0x7D55 (METEORLAKE)
[15:36:05] [PASSED] 0x7D60 (METEORLAKE)
[15:36:05] [PASSED] 0x7DD5 (METEORLAKE)
[15:36:05] [PASSED] 0x6420 (LUNARLAKE)
[15:36:05] [PASSED] 0x64A0 (LUNARLAKE)
[15:36:05] [PASSED] 0x64B0 (LUNARLAKE)
[15:36:05] [PASSED] 0xE202 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE209 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE20B (BATTLEMAGE)
[15:36:05] [PASSED] 0xE20C (BATTLEMAGE)
[15:36:05] [PASSED] 0xE20D (BATTLEMAGE)
[15:36:05] [PASSED] 0xE210 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE211 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE212 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE216 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE220 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE221 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE222 (BATTLEMAGE)
[15:36:05] [PASSED] 0xE223 (BATTLEMAGE)
[15:36:05] [PASSED] 0xB080 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB081 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB082 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB083 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB084 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB085 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB086 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB087 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB08F (PANTHERLAKE)
[15:36:05] [PASSED] 0xB090 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB0A0 (PANTHERLAKE)
[15:36:05] [PASSED] 0xB0B0 (PANTHERLAKE)
[15:36:05] [PASSED] 0xFD80 (PANTHERLAKE)
[15:36:05] [PASSED] 0xFD81 (PANTHERLAKE)
[15:36:05] [PASSED] 0xD740 (NOVALAKE_S)
[15:36:05] [PASSED] 0xD741 (NOVALAKE_S)
[15:36:05] [PASSED] 0xD742 (NOVALAKE_S)
[15:36:05] [PASSED] 0xD743 (NOVALAKE_S)
[15:36:05] [PASSED] 0xD745 (NOVALAKE_S)
[15:36:05] [PASSED] 0xD74A (NOVALAKE_S)
[15:36:05] [PASSED] 0xD74B (NOVALAKE_S)
[15:36:05] [PASSED] 0x674C (CRESCENTISLAND)
[15:36:05] [PASSED] 0x674D (CRESCENTISLAND)
[15:36:05] [PASSED] 0x674E (CRESCENTISLAND)
[15:36:05] [PASSED] 0x674F (CRESCENTISLAND)
[15:36:05] [PASSED] 0x6750 (CRESCENTISLAND)
[15:36:05] [PASSED] 0xD750 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD751 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD752 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD753 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD754 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD755 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD756 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD757 (NOVALAKE_P)
[15:36:05] [PASSED] 0xD75F (NOVALAKE_P)
[15:36:05] =============== [PASSED] check_platform_desc ===============
[15:36:05] ===================== [PASSED] xe_pci ======================
[15:36:05] ============= xe_rtp_tables_test (5 subtests) ==============
[15:36:05] ================== xe_rtp_table_gt_test ===================
[15:36:05] [PASSED] gt_was/14011060649
[15:36:05] [PASSED] gt_was/14011059788
[15:36:05] [PASSED] gt_was/14015795083
[15:36:05] [PASSED] gt_was/16021867713
[15:36:05] [PASSED] gt_was/14019449301
[15:36:05] [PASSED] gt_was/16028005424
[15:36:05] [PASSED] gt_was/14026578760
[15:36:05] [PASSED] gt_was/1409420604
[15:36:05] [PASSED] gt_was/1408615072
[15:36:05] [PASSED] gt_was/22010523718
[15:36:05] [PASSED] gt_was/14011006942
[15:36:05] [PASSED] gt_was/14014830051
[15:36:05] [PASSED] gt_was/18018781329
[15:36:05] [PASSED] gt_was/1509235366
[15:36:05] [PASSED] gt_was/18018781329
[15:36:05] [PASSED] gt_was/16016694945
[15:36:05] [PASSED] gt_was/14018575942
[15:36:05] [PASSED] gt_was/22016670082
[15:36:05] [PASSED] gt_was/22016670082
[15:36:05] [PASSED] gt_was/14017421178
[15:36:05] [PASSED] gt_was/16025250150
[15:36:05] [PASSED] gt_was/14021871409
[15:36:05] [PASSED] gt_was/16021865536
[15:36:05] [PASSED] gt_was/14021486841
[15:36:05] [PASSED] gt_was/14025160223
[15:36:05] [PASSED] gt_was/14026144927, 16029437861, 14026127056
[15:36:05] [PASSED] gt_was/14025635424
[15:36:05] [PASSED] gt_was/16028005424
[15:36:05] ============== [PASSED] xe_rtp_table_gt_test ===============
[15:36:05] ================== xe_rtp_table_gt_test ===================
[15:36:05] [PASSED] gt_tunings/Tuning: Blend Fill Caching Optimization Disable
[15:36:05] [PASSED] gt_tunings/Tuning: 32B Access Enable
[15:36:05] [PASSED] gt_tunings/Tuning: L3 cache
[15:36:05] [PASSED] gt_tunings/Tuning: L3 cache - media
[15:36:05] [PASSED] gt_tunings/Tuning: Compression Overfetch
[15:36:05] [PASSED] gt_tunings/Tuning: Compression Overfetch - media
[15:36:05] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3
[15:36:05] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3 - media
[15:36:05] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only
[15:36:05] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only - media
[15:36:05] [PASSED] gt_tunings/Tuning: Stateless compression control
[15:36:05] [PASSED] gt_tunings/Tuning: Stateless compression control - media
[15:36:05] [PASSED] gt_tunings/Tuning: L3 RW flush all Cache
[15:36:05] [PASSED] gt_tunings/Tuning: L3 RW flush all cache - media
[15:36:05] [PASSED] gt_tunings/Tuning: Set STLB Bank Hash Mode to 4KB
[15:36:05] ============== [PASSED] xe_rtp_table_gt_test ===============
[15:36:05] ================== xe_rtp_table_oob_test ==================
[15:36:05] [PASSED] oob_was/1607983814
[15:36:05] [PASSED] oob_was/16010904313
[15:36:05] [PASSED] oob_was/18022495364
[15:36:05] [PASSED] oob_was/22012773006
[15:36:05] [PASSED] oob_was/14014475959
[15:36:05] [PASSED] oob_was/22011391025
[15:36:05] [PASSED] oob_was/22012727170
[15:36:05] [PASSED] oob_was/22012727685
[15:36:05] [PASSED] oob_was/22016596838
[15:36:05] [PASSED] oob_was/18020744125
[15:36:05] [PASSED] oob_was/1409600907
[15:36:05] [PASSED] oob_was/22014953428
[15:36:05] [PASSED] oob_was/16017236439
[15:36:05] [PASSED] oob_was/14019821291
[15:36:05] [PASSED] oob_was/14015076503
[15:36:05] [PASSED] oob_was/14018913170
[15:36:05] [PASSED] oob_was/14018094691
[15:36:05] [PASSED] oob_was/18024947630
[15:36:05] [PASSED] oob_was/16022287689
[15:36:05] [PASSED] oob_was/13011645652
[15:36:05] [PASSED] oob_was/14022293748
[15:36:05] [PASSED] oob_was/22019794406
[15:36:05] [PASSED] oob_was/22019338487
[15:36:05] [PASSED] oob_was/16023588340
[15:36:05] [PASSED] oob_was/14019789679
[15:36:05] [PASSED] oob_was/14022866841
[15:36:05] [PASSED] oob_was/16021333562
[15:36:05] [PASSED] oob_was/14016712196
[15:36:05] [PASSED] oob_was/14015568240
[15:36:05] [PASSED] oob_was/18013179988
[15:36:05] [PASSED] oob_was/1508761755
[15:36:05] [PASSED] oob_was/16023105232
[15:36:05] [PASSED] oob_was/16026508708
[15:36:05] [PASSED] oob_was/14020001231
[15:36:05] [PASSED] oob_was/16023683509
[15:36:05] [PASSED] oob_was/14025515070
[15:36:05] [PASSED] oob_was/15015404425_disable
[15:36:05] [PASSED] oob_was/16026007364
[15:36:05] [PASSED] oob_was/14020316580
[15:36:05] [PASSED] oob_was/14025883347
[15:36:05] [PASSED] oob_was/16029380221
[15:36:05] [PASSED] oob_was/22022079272
[15:36:05] [PASSED] oob_was/16029897822
[15:36:05] [PASSED] oob_was/14027054324
[15:36:05] [PASSED] oob_was/14022766366
[15:36:05] [PASSED] oob_was/18022722726
[15:36:05] [PASSED] oob_was/14015474168
[15:36:05] ============== [PASSED] xe_rtp_table_oob_test ==============
[15:36:05] ================ xe_rtp_table_dev_oob_test ================
[15:36:05] [PASSED] device_oob_was/22010954014
[15:36:05] [PASSED] device_oob_was/15015404425
[15:36:05] [PASSED] device_oob_was/22019338487_display
[15:36:05] [PASSED] device_oob_was/14022085890
[15:36:05] [PASSED] device_oob_was/14026539277
[15:36:05] [PASSED] device_oob_was/14026633728
[15:36:05] [PASSED] device_oob_was/14026746987
[15:36:05] [PASSED] device_oob_was/14026779378
[15:36:05] ============ [PASSED] xe_rtp_table_dev_oob_test ============
[15:36:05] ========== xe_rtp_table_missing_upper_bound_test ==========
[15:36:05] [PASSED] register_whitelist/WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865
[15:36:05] [PASSED] register_whitelist/1508744258, 14012131227, 1808121037
[15:36:05] [PASSED] register_whitelist/1806527549
[15:36:05] [PASSED] register_whitelist/allow_read_ctx_timestamp
[15:36:05] [PASSED] register_whitelist/allow_read_queue_timestamp
[15:36:05] [PASSED] register_whitelist/16014440446
[15:36:05] [PASSED] register_whitelist/16017236439
[15:36:05] [PASSED] register_whitelist/16020183090
[15:36:05] [PASSED] register_whitelist/14024997852
[15:36:05] [PASSED] register_whitelist/14024997852
[15:36:05] ====== [PASSED] xe_rtp_table_missing_upper_bound_test ======
[15:36:05] =============== [PASSED] xe_rtp_tables_test ================
[15:36:05] =================== xe_rtp (3 subtests) ====================
[15:36:05] =================== xe_rtp_rules_tests ====================
[15:36:05] [PASSED] no
[15:36:05] [PASSED] yes
[15:36:05] [PASSED] no-and-no
[15:36:05] [PASSED] no-and-yes
[15:36:05] [PASSED] yes-and-no
[15:36:05] [PASSED] yes-and-yes
[15:36:05] [PASSED] no-or-no
[15:36:05] [PASSED] no-or-yes
[15:36:05] [PASSED] yes-or-no
[15:36:05] [PASSED] yes-or-yes
[15:36:05] [PASSED] no-yes-or-yes-no
[15:36:05] [PASSED] no-yes-or-yes-yes
[15:36:05] [PASSED] yes-yes-or-no-yes
[15:36:05] [PASSED] yes-yes-or-yes-yes
[15:36:05] [PASSED] no-no-or-yes-or-no
[15:36:05] [PASSED] or
[15:36:05] [PASSED] or-yes
[15:36:05] [PASSED] or-no
[15:36:05] [PASSED] yes-or
[15:36:05] [PASSED] no-or
[15:36:05] [PASSED] no-or-or-yes
[15:36:05] [PASSED] yes-or-or-no
[15:36:05] [PASSED] no-or-or-no
[15:36:05] [PASSED] missing-context-engine-class
[15:36:05] [PASSED] missing-context-engine-class-or-yes
[15:36:05] [PASSED] missing-context-engine-class-or-or-yes
[15:36:05] =============== [PASSED] xe_rtp_rules_tests ================
[15:36:05] =============== xe_rtp_process_to_sr_tests ================
[15:36:05] [PASSED] coalesce-same-reg
[15:36:05] [PASSED] coalesce-same-reg-literal-and-func
[15:36:05] [PASSED] no-match-no-add
[15:36:05] [PASSED] two-regs-two-entries
[15:36:05] [PASSED] clr-one-set-other
[15:36:05] [PASSED] set-field
[15:36:05] [PASSED] conflict-duplicate
[15:36:05] [PASSED] conflict-not-disjoint
[15:36:05] [PASSED] conflict-not-disjoint-literal-and-func
[15:36:05] [PASSED] conflict-reg-type
[15:36:05] [PASSED] bad-mcr-reg-forced-to-regular
[15:36:05] [PASSED] bad-regular-reg-forced-to-mcr
[15:36:05] =========== [PASSED] xe_rtp_process_to_sr_tests ============
[15:36:05] ================== xe_rtp_process_tests ===================
[15:36:05] [PASSED] active1
[15:36:05] [PASSED] active2
[15:36:05] [PASSED] active-inactive
[15:36:05] [PASSED] inactive-active
[15:36:05] [PASSED] inactive-active-inactive
[15:36:05] [PASSED] inactive-inactive-inactive
[15:36:05] ============== [PASSED] xe_rtp_process_tests ===============
[15:36:05] ===================== [PASSED] xe_rtp ======================
[15:36:05] ==================== xe_wa (1 subtest) =====================
[15:36:05] ======================== xe_wa_gt =========================
[15:36:05] [PASSED] TIGERLAKE B0
[15:36:05] [PASSED] DG1 A0
[15:36:05] [PASSED] DG1 B0
[15:36:05] [PASSED] ALDERLAKE_S A0
[15:36:05] [PASSED] ALDERLAKE_S B0
[15:36:05] [PASSED] ALDERLAKE_S C0
[15:36:05] [PASSED] ALDERLAKE_S D0
[15:36:05] [PASSED] ALDERLAKE_P A0
[15:36:05] [PASSED] ALDERLAKE_P B0
[15:36:05] [PASSED] ALDERLAKE_P C0
[15:36:05] [PASSED] ALDERLAKE_S RPLS D0
[15:36:05] [PASSED] ALDERLAKE_P RPLU E0
[15:36:05] [PASSED] DG2 G10 C0
[15:36:05] [PASSED] DG2 G11 B1
[15:36:05] [PASSED] DG2 G12 A1
[15:36:05] [PASSED] METEORLAKE 12.70(Xe_LPG) A0 13.00(Xe_LPM+) A0
[15:36:05] [PASSED] METEORLAKE 12.71(Xe_LPG) A0 13.00(Xe_LPM+) A0
[15:36:05] [PASSED] METEORLAKE 12.74(Xe_LPG+) A0 13.00(Xe_LPM+) A0
[15:36:05] [PASSED] LUNARLAKE 20.04(Xe2_LPG) A0 20.00(Xe2_LPM) A0
[15:36:05] [PASSED] LUNARLAKE 20.04(Xe2_LPG) B0 20.00(Xe2_LPM) A0
[15:36:05] [PASSED] BATTLEMAGE 20.01(Xe2_HPG) A0 13.01(Xe2_HPM) A1
[15:36:05] [PASSED] PANTHERLAKE 30.00(Xe3_LPG) A0 30.00(Xe3_LPM) A0
[15:36:05] ==================== [PASSED] xe_wa_gt =====================
[15:36:05] ====================== [PASSED] xe_wa ======================
[15:36:05] ============================================================
[15:36:05] Testing complete. Ran 797 tests: passed: 768, skipped: 29
[15:36:05] Elapsed time: 37.215s total, 1.834s configuring, 34.664s building, 0.710s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/tests/.kunitconfig
[15:36:05] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[15:36:07] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[15:36:32] Starting KUnit Kernel (1/1)...
[15:36:32] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[15:36:32] ============= refcount_interrupt (4 subtests) ==============
[15:36:32] [PASSED] test_single_irq_change
[15:36:32] [PASSED] test_nested_irq_change
[15:36:32] [PASSED] test_multiple_irq_change
[15:36:32] [PASSED] test_irq_save
[15:36:32] =============== [PASSED] refcount_interrupt ================
[15:36:32] ============ drm_test_pick_cmdline (2 subtests) ============
[15:36:32] [PASSED] drm_test_pick_cmdline_res_1920_1080_60
[15:36:32] =============== drm_test_pick_cmdline_named ===============
[15:36:32] [PASSED] NTSC
[15:36:32] [PASSED] NTSC-J
[15:36:32] [PASSED] PAL
[15:36:32] [PASSED] PAL-M
[15:36:32] =========== [PASSED] drm_test_pick_cmdline_named ===========
[15:36:32] ============== [PASSED] drm_test_pick_cmdline ==============
[15:36:32] == drm_test_atomic_get_connector_for_encoder (1 subtest) ===
[15:36:32] [PASSED] drm_test_drm_atomic_get_connector_for_encoder
[15:36:32] ==== [PASSED] drm_test_atomic_get_connector_for_encoder ====
[15:36:32] =========== drm_validate_clone_mode (2 subtests) ===========
[15:36:32] ============== drm_test_check_in_clone_mode ===============
[15:36:32] [PASSED] in_clone_mode
[15:36:32] [PASSED] not_in_clone_mode
[15:36:32] ========== [PASSED] drm_test_check_in_clone_mode ===========
[15:36:32] =============== drm_test_check_valid_clones ===============
[15:36:32] [PASSED] not_in_clone_mode
[15:36:32] [PASSED] valid_clone
[15:36:32] [PASSED] invalid_clone
[15:36:32] =========== [PASSED] drm_test_check_valid_clones ===========
[15:36:32] ============= [PASSED] drm_validate_clone_mode =============
[15:36:32] ============= drm_validate_modeset (1 subtest) =============
[15:36:32] [PASSED] drm_test_check_connector_changed_modeset
[15:36:32] ============== [PASSED] drm_validate_modeset ===============
[15:36:32] ====== drm_test_bridge_get_current_state (1 subtest) =======
[15:36:32] [PASSED] drm_test_drm_bridge_get_current_state_atomic
[15:36:32] ======== [PASSED] drm_test_bridge_get_current_state ========
[15:36:32] ====== drm_test_bridge_helper_reset_crtc (3 subtests) ======
[15:36:32] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic
[15:36:32] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic_disabled
[15:36:32] [PASSED] drm_test_drm_bridge_helper_hdmi_output_bus_fmts
[15:36:32] ======== [PASSED] drm_test_bridge_helper_reset_crtc ========
[15:36:32] ============== drm_bridge_alloc (2 subtests) ===============
[15:36:32] [PASSED] drm_test_drm_bridge_alloc_basic
[15:36:32] [PASSED] drm_test_drm_bridge_alloc_get_put
[15:36:32] ================ [PASSED] drm_bridge_alloc =================
[15:36:32] ============= drm_bridge_bus_fmt (5 subtests) ==============
[15:36:32] [PASSED] drm_test_bridge_rgb_yuv_rgb
[15:36:32] [PASSED] drm_test_bridge_must_convert_to_yuv444
[15:36:32] [PASSED] drm_test_bridge_hdmi_auto_rgb
[15:36:32] [PASSED] drm_test_bridge_auto_first
[15:36:32] [PASSED] drm_test_bridge_rgb_yuv_no_path
[15:36:32] =============== [PASSED] drm_bridge_bus_fmt ================
[15:36:32] ============= drm_cmdline_parser (40 subtests) =============
[15:36:32] [PASSED] drm_test_cmdline_force_d_only
[15:36:32] [PASSED] drm_test_cmdline_force_D_only_dvi
[15:36:32] [PASSED] drm_test_cmdline_force_D_only_hdmi
[15:36:32] [PASSED] drm_test_cmdline_force_D_only_not_digital
[15:36:32] [PASSED] drm_test_cmdline_force_e_only
[15:36:32] [PASSED] drm_test_cmdline_res
[15:36:32] [PASSED] drm_test_cmdline_res_vesa
[15:36:32] [PASSED] drm_test_cmdline_res_vesa_rblank
[15:36:32] [PASSED] drm_test_cmdline_res_rblank
[15:36:32] [PASSED] drm_test_cmdline_res_bpp
[15:36:32] [PASSED] drm_test_cmdline_res_refresh
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh_margins
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh_force_off
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_analog
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_digital
[15:36:32] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on
[15:36:32] [PASSED] drm_test_cmdline_res_margins_force_on
[15:36:32] [PASSED] drm_test_cmdline_res_vesa_margins
[15:36:32] [PASSED] drm_test_cmdline_name
[15:36:32] [PASSED] drm_test_cmdline_name_bpp
[15:36:32] [PASSED] drm_test_cmdline_name_option
[15:36:32] [PASSED] drm_test_cmdline_name_bpp_option
[15:36:32] [PASSED] drm_test_cmdline_rotate_0
[15:36:32] [PASSED] drm_test_cmdline_rotate_90
[15:36:32] [PASSED] drm_test_cmdline_rotate_180
[15:36:32] [PASSED] drm_test_cmdline_rotate_270
[15:36:32] [PASSED] drm_test_cmdline_hmirror
[15:36:32] [PASSED] drm_test_cmdline_vmirror
[15:36:32] [PASSED] drm_test_cmdline_margin_options
[15:36:32] [PASSED] drm_test_cmdline_multiple_options
[15:36:32] [PASSED] drm_test_cmdline_bpp_extra_and_option
[15:36:32] [PASSED] drm_test_cmdline_extra_and_option
[15:36:32] [PASSED] drm_test_cmdline_freestanding_options
[15:36:32] [PASSED] drm_test_cmdline_freestanding_force_e_and_options
[15:36:32] [PASSED] drm_test_cmdline_panel_orientation
[15:36:32] ================ drm_test_cmdline_invalid =================
[15:36:32] [PASSED] margin_only
[15:36:32] [PASSED] interlace_only
[15:36:32] [PASSED] res_missing_x
[15:36:32] [PASSED] res_missing_y
[15:36:32] [PASSED] res_bad_y
[15:36:32] [PASSED] res_missing_y_bpp
[15:36:32] [PASSED] res_bad_bpp
[15:36:32] [PASSED] res_bad_refresh
[15:36:32] [PASSED] res_bpp_refresh_force_on_off
[15:36:32] [PASSED] res_invalid_mode
[15:36:32] [PASSED] res_bpp_wrong_place_mode
[15:36:32] [PASSED] name_bpp_refresh
[15:36:32] [PASSED] name_refresh
[15:36:32] [PASSED] name_refresh_wrong_mode
[15:36:32] [PASSED] name_refresh_invalid_mode
[15:36:32] [PASSED] rotate_multiple
[15:36:32] [PASSED] rotate_invalid_val
[15:36:32] [PASSED] rotate_truncated
[15:36:32] [PASSED] invalid_option
[15:36:32] [PASSED] invalid_tv_option
[15:36:32] [PASSED] truncated_tv_option
[15:36:32] ============ [PASSED] drm_test_cmdline_invalid =============
[15:36:32] =============== drm_test_cmdline_tv_options ===============
[15:36:32] [PASSED] NTSC
[15:36:32] [PASSED] NTSC_443
[15:36:32] [PASSED] NTSC_J
[15:36:32] [PASSED] PAL
[15:36:32] [PASSED] PAL_M
[15:36:32] [PASSED] PAL_N
[15:36:32] [PASSED] SECAM
[15:36:32] [PASSED] MONO_525
[15:36:32] [PASSED] MONO_625
[15:36:32] =========== [PASSED] drm_test_cmdline_tv_options ===========
[15:36:32] =============== [PASSED] drm_cmdline_parser ================
[15:36:32] ========== drmm_connector_hdmi_init (20 subtests) ==========
[15:36:32] [PASSED] drm_test_connector_hdmi_init_valid
[15:36:32] [PASSED] drm_test_connector_hdmi_init_bpc_8
[15:36:32] [PASSED] drm_test_connector_hdmi_init_bpc_10
[15:36:32] [PASSED] drm_test_connector_hdmi_init_bpc_12
[15:36:32] [PASSED] drm_test_connector_hdmi_init_bpc_invalid
[15:36:32] [PASSED] drm_test_connector_hdmi_init_bpc_null
[15:36:32] [PASSED] drm_test_connector_hdmi_init_formats_empty
[15:36:32] [PASSED] drm_test_connector_hdmi_init_formats_no_rgb
[15:36:32] === drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[15:36:32] [PASSED] supported_formats=0x9 yuv420_allowed=1
[15:36:32] [PASSED] supported_formats=0x9 yuv420_allowed=0
[15:36:32] [PASSED] supported_formats=0x5 yuv420_allowed=1
[15:36:32] [PASSED] supported_formats=0x5 yuv420_allowed=0
[15:36:32] === [PASSED] drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[15:36:32] [PASSED] drm_test_connector_hdmi_init_null_ddc
[15:36:32] [PASSED] drm_test_connector_hdmi_init_null_product
[15:36:32] [PASSED] drm_test_connector_hdmi_init_null_vendor
[15:36:32] [PASSED] drm_test_connector_hdmi_init_product_length_exact
[15:36:32] [PASSED] drm_test_connector_hdmi_init_product_length_too_long
[15:36:32] [PASSED] drm_test_connector_hdmi_init_product_valid
[15:36:32] [PASSED] drm_test_connector_hdmi_init_vendor_length_exact
[15:36:32] [PASSED] drm_test_connector_hdmi_init_vendor_length_too_long
[15:36:32] [PASSED] drm_test_connector_hdmi_init_vendor_valid
[15:36:32] ========= drm_test_connector_hdmi_init_type_valid =========
[15:36:32] [PASSED] HDMI-A
[15:36:32] [PASSED] HDMI-B
[15:36:32] ===== [PASSED] drm_test_connector_hdmi_init_type_valid =====
[15:36:32] ======== drm_test_connector_hdmi_init_type_invalid ========
[15:36:32] [PASSED] Unknown
[15:36:32] [PASSED] VGA
[15:36:32] [PASSED] DVI-I
[15:36:32] [PASSED] DVI-D
[15:36:32] [PASSED] DVI-A
[15:36:32] [PASSED] Composite
[15:36:32] [PASSED] SVIDEO
[15:36:32] [PASSED] LVDS
[15:36:32] [PASSED] Component
[15:36:32] [PASSED] DIN
[15:36:32] [PASSED] DP
[15:36:32] [PASSED] TV
[15:36:32] [PASSED] eDP
[15:36:32] [PASSED] Virtual
[15:36:32] [PASSED] DSI
[15:36:32] [PASSED] DPI
[15:36:32] [PASSED] Writeback
[15:36:32] [PASSED] SPI
[15:36:32] [PASSED] USB
[15:36:32] ==== [PASSED] drm_test_connector_hdmi_init_type_invalid ====
[15:36:32] ============ [PASSED] drmm_connector_hdmi_init =============
[15:36:32] ============= drmm_connector_init (3 subtests) =============
[15:36:32] [PASSED] drm_test_drmm_connector_init
[15:36:32] [PASSED] drm_test_drmm_connector_init_null_ddc
[15:36:32] ========= drm_test_drmm_connector_init_type_valid =========
[15:36:32] [PASSED] Unknown
[15:36:32] [PASSED] VGA
[15:36:32] [PASSED] DVI-I
[15:36:32] [PASSED] DVI-D
[15:36:32] [PASSED] DVI-A
[15:36:32] [PASSED] Composite
[15:36:32] [PASSED] SVIDEO
[15:36:32] [PASSED] LVDS
[15:36:32] [PASSED] Component
[15:36:32] [PASSED] DIN
[15:36:32] [PASSED] DP
[15:36:32] [PASSED] HDMI-A
[15:36:32] [PASSED] HDMI-B
[15:36:32] [PASSED] TV
[15:36:32] [PASSED] eDP
[15:36:32] [PASSED] Virtual
[15:36:32] [PASSED] DSI
[15:36:32] [PASSED] DPI
[15:36:32] [PASSED] Writeback
[15:36:32] [PASSED] SPI
[15:36:32] [PASSED] USB
[15:36:32] ===== [PASSED] drm_test_drmm_connector_init_type_valid =====
[15:36:32] =============== [PASSED] drmm_connector_init ===============
[15:36:32] ========= drm_connector_dynamic_init (6 subtests) ==========
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_init
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_init_null_ddc
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_init_not_added
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_init_properties
[15:36:32] ===== drm_test_drm_connector_dynamic_init_type_valid ======
[15:36:32] [PASSED] Unknown
[15:36:32] [PASSED] VGA
[15:36:32] [PASSED] DVI-I
[15:36:32] [PASSED] DVI-D
[15:36:32] [PASSED] DVI-A
[15:36:32] [PASSED] Composite
[15:36:32] [PASSED] SVIDEO
[15:36:32] [PASSED] LVDS
[15:36:32] [PASSED] Component
[15:36:32] [PASSED] DIN
[15:36:32] [PASSED] DP
[15:36:32] [PASSED] HDMI-A
[15:36:32] [PASSED] HDMI-B
[15:36:32] [PASSED] TV
[15:36:32] [PASSED] eDP
[15:36:32] [PASSED] Virtual
[15:36:32] [PASSED] DSI
[15:36:32] [PASSED] DPI
[15:36:32] [PASSED] Writeback
[15:36:32] [PASSED] SPI
[15:36:32] [PASSED] USB
[15:36:32] = [PASSED] drm_test_drm_connector_dynamic_init_type_valid ==
[15:36:32] ======== drm_test_drm_connector_dynamic_init_name =========
[15:36:32] [PASSED] Unknown
[15:36:32] [PASSED] VGA
[15:36:32] [PASSED] DVI-I
[15:36:32] [PASSED] DVI-D
[15:36:32] [PASSED] DVI-A
[15:36:32] [PASSED] Composite
[15:36:32] [PASSED] SVIDEO
[15:36:32] [PASSED] LVDS
[15:36:32] [PASSED] Component
[15:36:32] [PASSED] DIN
[15:36:32] [PASSED] DP
[15:36:32] [PASSED] HDMI-A
[15:36:32] [PASSED] HDMI-B
[15:36:32] [PASSED] TV
[15:36:32] [PASSED] eDP
[15:36:32] [PASSED] Virtual
[15:36:32] [PASSED] DSI
[15:36:32] [PASSED] DPI
[15:36:32] [PASSED] Writeback
[15:36:32] [PASSED] SPI
[15:36:32] [PASSED] USB
[15:36:32] ==== [PASSED] drm_test_drm_connector_dynamic_init_name =====
[15:36:32] =========== [PASSED] drm_connector_dynamic_init ============
[15:36:32] ==== drm_connector_dynamic_register_early (4 subtests) =====
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_early_on_list
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_early_defer
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_early_no_init
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_early_no_mode_object
[15:36:32] ====== [PASSED] drm_connector_dynamic_register_early =======
[15:36:32] ======= drm_connector_dynamic_register (7 subtests) ========
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_on_list
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_no_defer
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_no_init
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_mode_object
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_sysfs
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_sysfs_name
[15:36:32] [PASSED] drm_test_drm_connector_dynamic_register_debugfs
[15:36:32] ========= [PASSED] drm_connector_dynamic_register ==========
[15:36:32] = drm_connector_attach_broadcast_rgb_property (2 subtests) =
[15:36:32] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property
[15:36:32] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector
[15:36:32] === [PASSED] drm_connector_attach_broadcast_rgb_property ===
[15:36:32] ========== drm_get_tv_mode_from_name (2 subtests) ==========
[15:36:32] ========== drm_test_get_tv_mode_from_name_valid ===========
[15:36:32] [PASSED] NTSC
[15:36:32] [PASSED] NTSC-443
[15:36:32] [PASSED] NTSC-J
[15:36:32] [PASSED] PAL
[15:36:32] [PASSED] PAL-M
[15:36:32] [PASSED] PAL-N
[15:36:32] [PASSED] SECAM
[15:36:32] [PASSED] Mono
[15:36:32] ====== [PASSED] drm_test_get_tv_mode_from_name_valid =======
[15:36:32] [PASSED] drm_test_get_tv_mode_from_name_truncated
[15:36:32] ============ [PASSED] drm_get_tv_mode_from_name ============
[15:36:32] = drm_test_connector_hdmi_compute_mode_clock (12 subtests) =
[15:36:32] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb
[15:36:32] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc
[15:36:32] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1
[15:36:32] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc
[15:36:32] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1
[15:36:32] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_double
[15:36:32] = drm_test_connector_hdmi_compute_mode_clock_yuv420_valid =
[15:36:32] [PASSED] VIC 96
[15:36:32] [PASSED] VIC 97
[15:36:32] [PASSED] VIC 101
[15:36:32] [PASSED] VIC 102
[15:36:32] [PASSED] VIC 106
[15:36:32] [PASSED] VIC 107
[15:36:32] === [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_valid ===
[15:36:32] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc
[15:36:32] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc
[15:36:32] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc
[15:36:32] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc
[15:36:32] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc
[15:36:32] === [PASSED] drm_test_connector_hdmi_compute_mode_clock ====
[15:36:32] == drm_hdmi_connector_get_broadcast_rgb_name (2 subtests) ==
[15:36:32] === drm_test_drm_hdmi_connector_get_broadcast_rgb_name ====
[15:36:32] [PASSED] Automatic
[15:36:32] [PASSED] Full
[15:36:32] [PASSED] Limited 16:235
[15:36:32] === [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name ===
[15:36:32] [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid
[15:36:32] ==== [PASSED] drm_hdmi_connector_get_broadcast_rgb_name ====
[15:36:32] == drm_hdmi_connector_get_output_format_name (2 subtests) ==
[15:36:32] === drm_test_drm_hdmi_connector_get_output_format_name ====
[15:36:32] [PASSED] RGB
[15:36:32] [PASSED] YUV 4:2:0
[15:36:32] [PASSED] YUV 4:2:2
[15:36:32] [PASSED] YUV 4:4:4
[15:36:32] === [PASSED] drm_test_drm_hdmi_connector_get_output_format_name ===
[15:36:32] [PASSED] drm_test_drm_hdmi_connector_get_output_format_name_invalid
[15:36:32] ==== [PASSED] drm_hdmi_connector_get_output_format_name ====
[15:36:32] ============= drm_damage_helper (21 subtests) ==============
[15:36:32] [PASSED] drm_test_damage_iter_no_damage
[15:36:32] [PASSED] drm_test_damage_iter_no_damage_fractional_src
[15:36:32] [PASSED] drm_test_damage_iter_no_damage_src_moved
[15:36:32] [PASSED] drm_test_damage_iter_no_damage_fractional_src_moved
[15:36:32] [PASSED] drm_test_damage_iter_no_damage_not_visible
[15:36:32] [PASSED] drm_test_damage_iter_no_damage_no_crtc
[15:36:32] [PASSED] drm_test_damage_iter_no_damage_no_fb
[15:36:32] [PASSED] drm_test_damage_iter_simple_damage
[15:36:32] [PASSED] drm_test_damage_iter_single_damage
[15:36:32] [PASSED] drm_test_damage_iter_single_damage_intersect_src
[15:36:32] [PASSED] drm_test_damage_iter_single_damage_outside_src
[15:36:32] [PASSED] drm_test_damage_iter_single_damage_fractional_src
[15:36:32] [PASSED] drm_test_damage_iter_single_damage_intersect_fractional_src
[15:36:32] [PASSED] drm_test_damage_iter_single_damage_outside_fractional_src
[15:36:32] [PASSED] drm_test_damage_iter_single_damage_src_moved
[15:36:32] [PASSED] drm_test_damage_iter_single_damage_fractional_src_moved
[15:36:32] [PASSED] drm_test_damage_iter_damage
[15:36:32] [PASSED] drm_test_damage_iter_damage_one_intersect
[15:36:32] [PASSED] drm_test_damage_iter_damage_one_outside
[15:36:32] [PASSED] drm_test_damage_iter_damage_src_moved
[15:36:32] [PASSED] drm_test_damage_iter_damage_not_visible
[15:36:32] ================ [PASSED] drm_damage_helper ================
[15:36:32] ============== drm_dp_mst_helper (3 subtests) ==============
[15:36:32] ============== drm_test_dp_mst_calc_pbn_mode ==============
[15:36:32] [PASSED] Clock 154000 BPP 30 DSC disabled
[15:36:32] [PASSED] Clock 234000 BPP 30 DSC disabled
[15:36:32] [PASSED] Clock 297000 BPP 24 DSC disabled
[15:36:32] [PASSED] Clock 332880 BPP 24 DSC enabled
[15:36:32] [PASSED] Clock 324540 BPP 24 DSC enabled
[15:36:32] ========== [PASSED] drm_test_dp_mst_calc_pbn_mode ==========
[15:36:32] ============== drm_test_dp_mst_calc_pbn_div ===============
[15:36:32] [PASSED] Link rate 2000000 lane count 4
[15:36:32] [PASSED] Link rate 2000000 lane count 2
[15:36:32] [PASSED] Link rate 2000000 lane count 1
[15:36:32] [PASSED] Link rate 1350000 lane count 4
[15:36:32] [PASSED] Link rate 1350000 lane count 2
[15:36:32] [PASSED] Link rate 1350000 lane count 1
[15:36:32] [PASSED] Link rate 1000000 lane count 4
[15:36:32] [PASSED] Link rate 1000000 lane count 2
[15:36:32] [PASSED] Link rate 1000000 lane count 1
[15:36:32] [PASSED] Link rate 810000 lane count 4
[15:36:32] [PASSED] Link rate 810000 lane count 2
[15:36:32] [PASSED] Link rate 810000 lane count 1
[15:36:32] [PASSED] Link rate 540000 lane count 4
[15:36:32] [PASSED] Link rate 540000 lane count 2
[15:36:32] [PASSED] Link rate 540000 lane count 1
[15:36:32] [PASSED] Link rate 270000 lane count 4
[15:36:32] [PASSED] Link rate 270000 lane count 2
[15:36:32] [PASSED] Link rate 270000 lane count 1
[15:36:32] [PASSED] Link rate 162000 lane count 4
[15:36:32] [PASSED] Link rate 162000 lane count 2
[15:36:32] [PASSED] Link rate 162000 lane count 1
[15:36:32] ========== [PASSED] drm_test_dp_mst_calc_pbn_div ===========
[15:36:32] ========= drm_test_dp_mst_sideband_msg_req_decode =========
[15:36:32] [PASSED] DP_ENUM_PATH_RESOURCES with port number
[15:36:32] [PASSED] DP_POWER_UP_PHY with port number
[15:36:32] [PASSED] DP_POWER_DOWN_PHY with port number
[15:36:32] [PASSED] DP_ALLOCATE_PAYLOAD with SDP stream sinks
[15:36:32] [PASSED] DP_ALLOCATE_PAYLOAD with port number
[15:36:32] [PASSED] DP_ALLOCATE_PAYLOAD with VCPI
[15:36:32] [PASSED] DP_ALLOCATE_PAYLOAD with PBN
[15:36:32] [PASSED] DP_QUERY_PAYLOAD with port number
[15:36:32] [PASSED] DP_QUERY_PAYLOAD with VCPI
[15:36:32] [PASSED] DP_REMOTE_DPCD_READ with port number
[15:36:32] [PASSED] DP_REMOTE_DPCD_READ with DPCD address
[15:36:32] [PASSED] DP_REMOTE_DPCD_READ with max number of bytes
[15:36:32] [PASSED] DP_REMOTE_DPCD_WRITE with port number
[15:36:32] [PASSED] DP_REMOTE_DPCD_WRITE with DPCD address
[15:36:32] [PASSED] DP_REMOTE_DPCD_WRITE with data array
[15:36:32] [PASSED] DP_REMOTE_I2C_READ with port number
[15:36:32] [PASSED] DP_REMOTE_I2C_READ with I2C device ID
[15:36:32] [PASSED] DP_REMOTE_I2C_READ with transactions array
[15:36:32] [PASSED] DP_REMOTE_I2C_WRITE with port number
[15:36:32] [PASSED] DP_REMOTE_I2C_WRITE with I2C device ID
[15:36:32] [PASSED] DP_REMOTE_I2C_WRITE with data array
[15:36:32] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream ID
[15:36:32] [PASSED] DP_QUERY_STREAM_ENC_STATUS with client ID
[15:36:32] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream event
[15:36:32] [PASSED] DP_QUERY_STREAM_ENC_STATUS with valid stream event
[15:36:32] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream behavior
[15:36:32] [PASSED] DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior
[15:36:32] ===== [PASSED] drm_test_dp_mst_sideband_msg_req_decode =====
[15:36:32] ================ [PASSED] drm_dp_mst_helper ================
[15:36:32] ================== drm_exec (7 subtests) ===================
[15:36:32] [PASSED] sanitycheck
[15:36:32] [PASSED] test_lock
[15:36:32] [PASSED] test_lock_unlock
[15:36:32] [PASSED] test_duplicates
[15:36:32] [PASSED] test_prepare
[15:36:32] [PASSED] test_prepare_array
[15:36:32] [PASSED] test_multiple_loops
[15:36:32] ==================== [PASSED] drm_exec =====================
[15:36:32] =========== drm_format_helper_test (17 subtests) ===========
[15:36:32] ============== drm_test_fb_xrgb8888_to_gray8 ==============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ========== [PASSED] drm_test_fb_xrgb8888_to_gray8 ==========
[15:36:32] ============= drm_test_fb_xrgb8888_to_rgb332 ==============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb332 ==========
[15:36:32] ============= drm_test_fb_xrgb8888_to_rgb565 ==============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb565 ==========
[15:36:32] ============ drm_test_fb_xrgb8888_to_xrgb1555 =============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======== [PASSED] drm_test_fb_xrgb8888_to_xrgb1555 =========
[15:36:32] ============ drm_test_fb_xrgb8888_to_argb1555 =============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======== [PASSED] drm_test_fb_xrgb8888_to_argb1555 =========
[15:36:32] ============ drm_test_fb_xrgb8888_to_rgba5551 =============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======== [PASSED] drm_test_fb_xrgb8888_to_rgba5551 =========
[15:36:32] ============= drm_test_fb_xrgb8888_to_rgb888 ==============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb888 ==========
[15:36:32] ============= drm_test_fb_xrgb8888_to_bgr888 ==============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ========= [PASSED] drm_test_fb_xrgb8888_to_bgr888 ==========
[15:36:32] ============ drm_test_fb_xrgb8888_to_argb8888 =============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======== [PASSED] drm_test_fb_xrgb8888_to_argb8888 =========
[15:36:32] =========== drm_test_fb_xrgb8888_to_xrgb2101010 ===========
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======= [PASSED] drm_test_fb_xrgb8888_to_xrgb2101010 =======
[15:36:32] =========== drm_test_fb_xrgb8888_to_argb2101010 ===========
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======= [PASSED] drm_test_fb_xrgb8888_to_argb2101010 =======
[15:36:32] ============== drm_test_fb_xrgb8888_to_mono ===============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ========== [PASSED] drm_test_fb_xrgb8888_to_mono ===========
[15:36:32] ==================== drm_test_fb_swab =====================
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ================ [PASSED] drm_test_fb_swab =================
[15:36:32] ============ drm_test_fb_xrgb8888_to_xbgr8888 =============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======== [PASSED] drm_test_fb_xrgb8888_to_xbgr8888 =========
[15:36:32] ============ drm_test_fb_xrgb8888_to_abgr8888 =============
[15:36:32] [PASSED] single_pixel_source_buffer
[15:36:32] [PASSED] single_pixel_clip_rectangle
[15:36:32] [PASSED] well_known_colors
[15:36:32] [PASSED] destination_pitch
[15:36:32] ======== [PASSED] drm_test_fb_xrgb8888_to_abgr8888 =========
[15:36:32] ================= drm_test_fb_clip_offset =================
[15:36:32] [PASSED] pass through
[15:36:32] [PASSED] horizontal offset
[15:36:32] [PASSED] vertical offset
[15:36:32] [PASSED] horizontal and vertical offset
[15:36:32] [PASSED] horizontal offset (custom pitch)
[15:36:32] [PASSED] vertical offset (custom pitch)
[15:36:32] [PASSED] horizontal and vertical offset (custom pitch)
[15:36:32] ============= [PASSED] drm_test_fb_clip_offset =============
[15:36:32] =================== drm_test_fb_memcpy ====================
[15:36:32] [PASSED] single_pixel_source_buffer: XR24 little-endian (0x34325258)
[15:36:32] [PASSED] single_pixel_source_buffer: XRA8 little-endian (0x38415258)
[15:36:32] [PASSED] single_pixel_source_buffer: YU24 little-endian (0x34325559)
[15:36:32] [PASSED] single_pixel_clip_rectangle: XB24 little-endian (0x34324258)
[15:36:32] [PASSED] single_pixel_clip_rectangle: XRA8 little-endian (0x38415258)
[15:36:32] [PASSED] single_pixel_clip_rectangle: YU24 little-endian (0x34325559)
[15:36:32] [PASSED] well_known_colors: XB24 little-endian (0x34324258)
[15:36:32] [PASSED] well_known_colors: XRA8 little-endian (0x38415258)
[15:36:32] [PASSED] well_known_colors: YU24 little-endian (0x34325559)
[15:36:32] [PASSED] destination_pitch: XB24 little-endian (0x34324258)
[15:36:32] [PASSED] destination_pitch: XRA8 little-endian (0x38415258)
[15:36:32] [PASSED] destination_pitch: YU24 little-endian (0x34325559)
[15:36:32] =============== [PASSED] drm_test_fb_memcpy ================
[15:36:32] ============= [PASSED] drm_format_helper_test ==============
[15:36:32] ================= drm_format (18 subtests) =================
[15:36:32] [PASSED] drm_test_format_block_width_invalid
[15:36:32] [PASSED] drm_test_format_block_width_one_plane
[15:36:32] [PASSED] drm_test_format_block_width_two_plane
[15:36:32] [PASSED] drm_test_format_block_width_three_plane
[15:36:32] [PASSED] drm_test_format_block_width_tiled
[15:36:32] [PASSED] drm_test_format_block_height_invalid
[15:36:32] [PASSED] drm_test_format_block_height_one_plane
[15:36:32] [PASSED] drm_test_format_block_height_two_plane
[15:36:32] [PASSED] drm_test_format_block_height_three_plane
[15:36:32] [PASSED] drm_test_format_block_height_tiled
[15:36:32] [PASSED] drm_test_format_min_pitch_invalid
[15:36:32] [PASSED] drm_test_format_min_pitch_one_plane_8bpp
[15:36:32] [PASSED] drm_test_format_min_pitch_one_plane_16bpp
[15:36:32] [PASSED] drm_test_format_min_pitch_one_plane_24bpp
[15:36:32] [PASSED] drm_test_format_min_pitch_one_plane_32bpp
[15:36:32] [PASSED] drm_test_format_min_pitch_two_plane
[15:36:32] [PASSED] drm_test_format_min_pitch_three_plane_8bpp
[15:36:32] [PASSED] drm_test_format_min_pitch_tiled
[15:36:32] =================== [PASSED] drm_format ====================
[15:36:32] ============== drm_framebuffer (10 subtests) ===============
[15:36:32] ========== drm_test_framebuffer_check_src_coords ==========
[15:36:32] [PASSED] Success: source fits into fb
[15:36:32] [PASSED] Fail: overflowing fb with x-axis coordinate
[15:36:32] [PASSED] Fail: overflowing fb with y-axis coordinate
[15:36:32] [PASSED] Fail: overflowing fb with source width
[15:36:32] [PASSED] Fail: overflowing fb with source height
[15:36:32] ====== [PASSED] drm_test_framebuffer_check_src_coords ======
[15:36:32] [PASSED] drm_test_framebuffer_cleanup
[15:36:32] =============== drm_test_framebuffer_create ===============
[15:36:32] [PASSED] ABGR8888 normal sizes
[15:36:32] [PASSED] ABGR8888 max sizes
[15:36:32] [PASSED] ABGR8888 pitch greater than min required
[15:36:32] [PASSED] ABGR8888 pitch less than min required
[15:36:32] [PASSED] ABGR8888 Invalid width
[15:36:32] [PASSED] ABGR8888 Invalid buffer handle
[15:36:32] [PASSED] No pixel format
[15:36:32] [PASSED] ABGR8888 Width 0
[15:36:32] [PASSED] ABGR8888 Height 0
[15:36:32] [PASSED] ABGR8888 Out of bound height * pitch combination
[15:36:32] [PASSED] ABGR8888 Large buffer offset
[15:36:32] [PASSED] ABGR8888 Buffer offset for inexistent plane
[15:36:32] [PASSED] ABGR8888 Invalid flag
[15:36:32] [PASSED] ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers
[15:36:32] [PASSED] ABGR8888 Valid buffer modifier
[15:36:32] [PASSED] ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
[15:36:32] [PASSED] ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS
[15:36:32] [PASSED] ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS
[15:36:32] [PASSED] NV12 Normal sizes
[15:36:32] [PASSED] NV12 Max sizes
[15:36:32] [PASSED] NV12 Invalid pitch
[15:36:32] [PASSED] NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag
[15:36:32] [PASSED] NV12 different modifier per-plane
[15:36:32] [PASSED] NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
[15:36:32] [PASSED] NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS
[15:36:32] [PASSED] NV12 Modifier for inexistent plane
[15:36:32] [PASSED] NV12 Handle for inexistent plane
[15:36:32] [PASSED] NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS
[15:36:32] [PASSED] YVU420 DRM_MODE_FB_MODIFIERS set without modifier
[15:36:32] [PASSED] YVU420 Normal sizes
[15:36:32] [PASSED] YVU420 Max sizes
[15:36:32] [PASSED] YVU420 Invalid pitch
[15:36:32] [PASSED] YVU420 Different pitches
[15:36:32] [PASSED] YVU420 Different buffer offsets/pitches
[15:36:32] [PASSED] YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS
[15:36:32] [PASSED] YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS
[15:36:32] [PASSED] YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS
[15:36:32] [PASSED] YVU420 Valid modifier
[15:36:32] [PASSED] YVU420 Different modifiers per plane
[15:36:32] [PASSED] YVU420 Modifier for inexistent plane
[15:36:32] [PASSED] YUV420_10BIT Invalid modifier(DRM_FORMAT_MOD_LINEAR)
[15:36:32] [PASSED] X0L2 Normal sizes
[15:36:32] [PASSED] X0L2 Max sizes
[15:36:32] [PASSED] X0L2 Invalid pitch
[15:36:32] [PASSED] X0L2 Pitch greater than minimum required
[15:36:32] [PASSED] X0L2 Handle for inexistent plane
[15:36:32] [PASSED] X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set
[15:36:32] [PASSED] X0L2 Modifier without DRM_MODE_FB_MODIFIERS set
[15:36:32] [PASSED] X0L2 Valid modifier
[15:36:32] [PASSED] X0L2 Modifier for inexistent plane
[15:36:32] =========== [PASSED] drm_test_framebuffer_create ===========
[15:36:32] [PASSED] drm_test_framebuffer_free
[15:36:32] [PASSED] drm_test_framebuffer_init
[15:36:32] [PASSED] drm_test_framebuffer_init_bad_format
[15:36:32] [PASSED] drm_test_framebuffer_init_dev_mismatch
[15:36:32] [PASSED] drm_test_framebuffer_lookup
[15:36:32] [PASSED] drm_test_framebuffer_lookup_inexistent
[15:36:32] [PASSED] drm_test_framebuffer_modifiers_not_supported
[15:36:32] ================= [PASSED] drm_framebuffer =================
[15:36:32] ================ drm_gem_shmem (8 subtests) ================
[15:36:32] [PASSED] drm_gem_shmem_test_obj_create
[15:36:32] [PASSED] drm_gem_shmem_test_obj_create_private
[15:36:32] [PASSED] drm_gem_shmem_test_pin_pages
[15:36:32] [PASSED] drm_gem_shmem_test_vmap
[15:36:32] [PASSED] drm_gem_shmem_test_get_sg_table
[15:36:32] [PASSED] drm_gem_shmem_test_get_pages_sgt
[15:36:32] [PASSED] drm_gem_shmem_test_madvise
[15:36:32] [PASSED] drm_gem_shmem_test_purge
[15:36:32] ================== [PASSED] drm_gem_shmem ==================
[15:36:32] === drm_atomic_helper_connector_hdmi_check (29 subtests) ===
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode_vic_1
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode_vic_1
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode_vic_1
[15:36:32] ====== drm_test_check_broadcast_rgb_cea_mode_yuv420 =======
[15:36:32] [PASSED] Automatic
[15:36:32] [PASSED] Full
[15:36:32] [PASSED] Limited 16:235
[15:36:32] == [PASSED] drm_test_check_broadcast_rgb_cea_mode_yuv420 ===
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_changed
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_not_changed
[15:36:32] [PASSED] drm_test_check_disable_connector
[15:36:32] [PASSED] drm_test_check_hdmi_funcs_reject_rate
[15:36:32] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_rgb
[15:36:32] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_yuv420
[15:36:32] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422
[15:36:32] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420
[15:36:32] [PASSED] drm_test_check_driver_unsupported_fallback_yuv420
[15:36:32] [PASSED] drm_test_check_output_bpc_crtc_mode_changed
[15:36:32] [PASSED] drm_test_check_output_bpc_crtc_mode_not_changed
[15:36:32] [PASSED] drm_test_check_output_bpc_dvi
[15:36:32] [PASSED] drm_test_check_output_bpc_format_vic_1
[15:36:32] [PASSED] drm_test_check_output_bpc_format_display_8bpc_only
[15:36:32] [PASSED] drm_test_check_output_bpc_format_display_rgb_only
[15:36:32] [PASSED] drm_test_check_output_bpc_format_driver_8bpc_only
[15:36:32] [PASSED] drm_test_check_output_bpc_format_driver_rgb_only
[15:36:32] [PASSED] drm_test_check_tmds_char_rate_rgb_8bpc
[15:36:32] [PASSED] drm_test_check_tmds_char_rate_rgb_10bpc
[15:36:32] [PASSED] drm_test_check_tmds_char_rate_rgb_12bpc
[15:36:32] ============ drm_test_check_hdmi_color_format =============
[15:36:32] [PASSED] AUTO -> RGB
[15:36:32] [PASSED] YCBCR422 -> YUV422
[15:36:32] [PASSED] YCBCR420 -> YUV420
[15:36:32] [PASSED] YCBCR444 -> YUV444
[15:36:32] [PASSED] RGB -> RGB
[15:36:32] ======== [PASSED] drm_test_check_hdmi_color_format =========
[15:36:32] ======== drm_test_check_hdmi_color_format_420_only ========
[15:36:32] [PASSED] RGB should fail
[15:36:32] [PASSED] YUV444 should fail
[15:36:32] [PASSED] YUV422 should fail
[15:36:32] [PASSED] YUV420 should work
[15:36:32] ==== [PASSED] drm_test_check_hdmi_color_format_420_only ====
[15:36:32] ===== [PASSED] drm_atomic_helper_connector_hdmi_check ======
[15:36:32] === drm_atomic_helper_connector_hdmi_reset (6 subtests) ====
[15:36:32] [PASSED] drm_test_check_broadcast_rgb_value
[15:36:32] [PASSED] drm_test_check_bpc_8_value
[15:36:32] [PASSED] drm_test_check_bpc_10_value
[15:36:32] [PASSED] drm_test_check_bpc_12_value
[15:36:32] [PASSED] drm_test_check_format_value
[15:36:32] [PASSED] drm_test_check_tmds_char_value
[15:36:32] ===== [PASSED] drm_atomic_helper_connector_hdmi_reset ======
[15:36:32] = drm_atomic_helper_connector_hdmi_mode_valid (7 subtests) =
[15:36:32] [PASSED] drm_test_check_mode_valid
[15:36:32] [PASSED] drm_test_check_mode_valid_reject
[15:36:32] [PASSED] drm_test_check_mode_valid_reject_rate
[15:36:32] [PASSED] drm_test_check_mode_valid_reject_max_clock
[15:36:32] [PASSED] drm_test_check_mode_valid_yuv420_only_max_clock
[15:36:32] [PASSED] drm_test_check_mode_valid_reject_yuv420_only_connector
[15:36:32] [PASSED] drm_test_check_mode_valid_accept_yuv420_also_connector_rgb
[15:36:32] === [PASSED] drm_atomic_helper_connector_hdmi_mode_valid ===
[15:36:32] = drm_atomic_helper_connector_hdmi_infoframes (5 subtests) =
[15:36:32] [PASSED] drm_test_check_infoframes
[15:36:32] [PASSED] drm_test_check_reject_avi_infoframe
[15:36:32] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_8
[15:36:32] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_10
[15:36:32] [PASSED] drm_test_check_reject_audio_infoframe
[15:36:32] === [PASSED] drm_atomic_helper_connector_hdmi_infoframes ===
[15:36:32] ================= drm_managed (2 subtests) =================
[15:36:32] [PASSED] drm_test_managed_release_action
[15:36:32] [PASSED] drm_test_managed_run_action
[15:36:32] =================== [PASSED] drm_managed ===================
[15:36:32] =================== drm_mm (6 subtests) ====================
[15:36:32] [PASSED] drm_test_mm_init
[15:36:32] [PASSED] drm_test_mm_debug
[15:36:32] [PASSED] drm_test_mm_align32
[15:36:32] [PASSED] drm_test_mm_align64
[15:36:32] [PASSED] drm_test_mm_lowest
[15:36:32] [PASSED] drm_test_mm_highest
[15:36:32] ===================== [PASSED] drm_mm ======================
[15:36:32] ============= drm_modes_analog_tv (5 subtests) =============
[15:36:32] [PASSED] drm_test_modes_analog_tv_mono_576i
[15:36:32] [PASSED] drm_test_modes_analog_tv_ntsc_480i
[15:36:32] [PASSED] drm_test_modes_analog_tv_ntsc_480i_inlined
[15:36:32] [PASSED] drm_test_modes_analog_tv_pal_576i
[15:36:32] [PASSED] drm_test_modes_analog_tv_pal_576i_inlined
[15:36:32] =============== [PASSED] drm_modes_analog_tv ===============
[15:36:32] ============== drm_plane_helper (2 subtests) ===============
[15:36:32] =============== drm_test_check_plane_state ================
[15:36:32] [PASSED] clipping_simple
[15:36:32] [PASSED] clipping_rotate_reflect
[15:36:32] [PASSED] positioning_simple
[15:36:32] [PASSED] upscaling
[15:36:32] [PASSED] downscaling
[15:36:32] [PASSED] rounding1
[15:36:32] [PASSED] rounding2
[15:36:32] [PASSED] rounding3
[15:36:32] [PASSED] rounding4
[15:36:32] =========== [PASSED] drm_test_check_plane_state ============
[15:36:32] =========== drm_test_check_invalid_plane_state ============
[15:36:32] [PASSED] positioning_invalid
[15:36:32] [PASSED] upscaling_invalid
[15:36:32] [PASSED] downscaling_invalid
[15:36:32] ======= [PASSED] drm_test_check_invalid_plane_state ========
[15:36:32] ================ [PASSED] drm_plane_helper =================
[15:36:32] ====== drm_connector_helper_tv_get_modes (1 subtest) =======
[15:36:32] ====== drm_test_connector_helper_tv_get_modes_check =======
[15:36:32] [PASSED] None
[15:36:32] [PASSED] PAL
[15:36:32] [PASSED] NTSC
[15:36:32] [PASSED] Both, NTSC Default
[15:36:32] [PASSED] Both, PAL Default
[15:36:32] [PASSED] Both, NTSC Default, with PAL on command-line
[15:36:32] [PASSED] Both, PAL Default, with NTSC on command-line
[15:36:32] == [PASSED] drm_test_connector_helper_tv_get_modes_check ===
[15:36:32] ======== [PASSED] drm_connector_helper_tv_get_modes ========
[15:36:32] ================== drm_rect (9 subtests) ===================
[15:36:32] [PASSED] drm_test_rect_clip_scaled_div_by_zero
[15:36:32] [PASSED] drm_test_rect_clip_scaled_not_clipped
[15:36:32] [PASSED] drm_test_rect_clip_scaled_clipped
[15:36:32] [PASSED] drm_test_rect_clip_scaled_signed_vs_unsigned
[15:36:32] ================= drm_test_rect_intersect =================
[15:36:32] [PASSED] top-left x bottom-right: 2x2+1+1 x 2x2+0+0
[15:36:32] [PASSED] top-right x bottom-left: 2x2+0+0 x 2x2+1-1
[15:36:32] [PASSED] bottom-left x top-right: 2x2+1-1 x 2x2+0+0
[15:36:32] [PASSED] bottom-right x top-left: 2x2+0+0 x 2x2+1+1
[15:36:32] [PASSED] right x left: 2x1+0+0 x 3x1+1+0
[15:36:32] [PASSED] left x right: 3x1+1+0 x 2x1+0+0
[15:36:32] [PASSED] up x bottom: 1x2+0+0 x 1x3+0-1
[15:36:32] [PASSED] bottom x up: 1x3+0-1 x 1x2+0+0
[15:36:32] [PASSED] touching corner: 1x1+0+0 x 2x2+1+1
[15:36:32] [PASSED] touching side: 1x1+0+0 x 1x1+1+0
[15:36:32] [PASSED] equal rects: 2x2+0+0 x 2x2+0+0
[15:36:32] [PASSED] inside another: 2x2+0+0 x 1x1+1+1
[15:36:32] [PASSED] far away: 1x1+0+0 x 1x1+3+6
[15:36:32] [PASSED] points intersecting: 0x0+5+10 x 0x0+5+10
[15:36:32] [PASSED] points not intersecting: 0x0+0+0 x 0x0+5+10
[15:36:32] ============= [PASSED] drm_test_rect_intersect =============
[15:36:32] ================ drm_test_rect_calc_hscale ================
[15:36:32] [PASSED] normal use
[15:36:32] [PASSED] out of max range
[15:36:32] [PASSED] out of min range
[15:36:32] [PASSED] zero dst
[15:36:32] [PASSED] negative src
[15:36:32] [PASSED] negative dst
[15:36:32] ============ [PASSED] drm_test_rect_calc_hscale ============
[15:36:32] ================ drm_test_rect_calc_vscale ================
[15:36:32] [PASSED] normal use
[15:36:32] [PASSED] out of max range
[15:36:32] [PASSED] out of min range
[15:36:32] [PASSED] zero dst
[15:36:32] [PASSED] negative src
[15:36:32] [PASSED] negative dst
[15:36:32] ============ [PASSED] drm_test_rect_calc_vscale ============
[15:36:32] ================== drm_test_rect_rotate ===================
[15:36:32] [PASSED] reflect-x
[15:36:32] [PASSED] reflect-y
[15:36:32] [PASSED] rotate-0
[15:36:32] [PASSED] rotate-90
[15:36:32] [PASSED] rotate-180
[15:36:32] [PASSED] rotate-270
[15:36:32] ============== [PASSED] drm_test_rect_rotate ===============
[15:36:32] ================ drm_test_rect_rotate_inv =================
[15:36:32] [PASSED] reflect-x
[15:36:32] [PASSED] reflect-y
[15:36:32] [PASSED] rotate-0
[15:36:32] [PASSED] rotate-90
[15:36:32] [PASSED] rotate-180
[15:36:32] [PASSED] rotate-270
[15:36:32] ============ [PASSED] drm_test_rect_rotate_inv =============
[15:36:32] ==================== [PASSED] drm_rect =====================
[15:36:32] ============ drm_sysfb_modeset_test (1 subtest) ============
[15:36:32] ============ drm_test_sysfb_build_fourcc_list =============
[15:36:32] [PASSED] no native formats
[15:36:32] [PASSED] XRGB8888 as native format
[15:36:32] [PASSED] remove duplicates
[15:36:32] [PASSED] convert alpha formats
[15:36:32] [PASSED] random formats
[15:36:32] ======== [PASSED] drm_test_sysfb_build_fourcc_list =========
[15:36:32] ============= [PASSED] drm_sysfb_modeset_test ==============
[15:36:32] ================== drm_fixp (2 subtests) ===================
[15:36:32] [PASSED] drm_test_int2fixp
[15:36:32] [PASSED] drm_test_sm2fixp
[15:36:32] ==================== [PASSED] drm_fixp =====================
[15:36:32] ============================================================
[15:36:32] Testing complete. Ran 641 tests: passed: 641
[15:36:32] Elapsed time: 27.314s total, 1.840s configuring, 25.309s building, 0.144s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig
[15:36:32] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[15:36:34] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[15:36:44] Starting KUnit Kernel (1/1)...
[15:36:44] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[15:36:44] ============= refcount_interrupt (4 subtests) ==============
[15:36:44] [PASSED] test_single_irq_change
[15:36:44] [PASSED] test_nested_irq_change
[15:36:44] [PASSED] test_multiple_irq_change
[15:36:44] [PASSED] test_irq_save
[15:36:44] =============== [PASSED] refcount_interrupt ================
[15:36:44] ================= ttm_device (5 subtests) ==================
[15:36:44] [PASSED] ttm_device_init_basic
[15:36:44] [PASSED] ttm_device_init_multiple
[15:36:44] [PASSED] ttm_device_fini_basic
[15:36:44] [PASSED] ttm_device_init_no_vma_man
[15:36:44] ================== ttm_device_init_pools ==================
[15:36:44] [PASSED] No DMA allocations, no DMA32 required
[15:36:44] [PASSED] DMA allocations, DMA32 required
[15:36:44] [PASSED] No DMA allocations, DMA32 required
[15:36:44] [PASSED] DMA allocations, no DMA32 required
[15:36:44] ============== [PASSED] ttm_device_init_pools ==============
[15:36:44] =================== [PASSED] ttm_device ====================
[15:36:44] ================== ttm_pool (8 subtests) ===================
[15:36:44] ================== ttm_pool_alloc_basic ===================
[15:36:44] [PASSED] One page
[15:36:44] [PASSED] More than one page
[15:36:44] [PASSED] Above the allocation limit
[15:36:44] [PASSED] One page, with coherent DMA mappings enabled
[15:36:44] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[15:36:44] ============== [PASSED] ttm_pool_alloc_basic ===============
[15:36:44] ============== ttm_pool_alloc_basic_dma_addr ==============
[15:36:44] [PASSED] One page
[15:36:44] [PASSED] More than one page
[15:36:44] [PASSED] Above the allocation limit
[15:36:44] [PASSED] One page, with coherent DMA mappings enabled
[15:36:44] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[15:36:44] ========== [PASSED] ttm_pool_alloc_basic_dma_addr ==========
[15:36:44] [PASSED] ttm_pool_alloc_order_caching_match
[15:36:44] [PASSED] ttm_pool_alloc_caching_mismatch
[15:36:44] [PASSED] ttm_pool_alloc_order_mismatch
[15:36:44] [PASSED] ttm_pool_free_dma_alloc
[15:36:44] [PASSED] ttm_pool_free_no_dma_alloc
[15:36:44] [PASSED] ttm_pool_fini_basic
[15:36:44] ==================== [PASSED] ttm_pool =====================
[15:36:44] ================ ttm_resource (8 subtests) =================
[15:36:44] ================= ttm_resource_init_basic =================
[15:36:44] [PASSED] Init resource in TTM_PL_SYSTEM
[15:36:44] [PASSED] Init resource in TTM_PL_VRAM
[15:36:44] [PASSED] Init resource in a private placement
[15:36:44] [PASSED] Init resource in TTM_PL_SYSTEM, set placement flags
[15:36:44] ============= [PASSED] ttm_resource_init_basic =============
[15:36:44] [PASSED] ttm_resource_init_pinned
[15:36:44] [PASSED] ttm_resource_fini_basic
[15:36:44] [PASSED] ttm_resource_manager_init_basic
[15:36:44] [PASSED] ttm_resource_manager_usage_basic
[15:36:44] [PASSED] ttm_resource_manager_set_used_basic
[15:36:44] [PASSED] ttm_sys_man_alloc_basic
[15:36:44] [PASSED] ttm_sys_man_free_basic
[15:36:44] ================== [PASSED] ttm_resource ===================
[15:36:44] =================== ttm_tt (15 subtests) ===================
[15:36:44] ==================== ttm_tt_init_basic ====================
[15:36:44] [PASSED] Page-aligned size
[15:36:44] [PASSED] Extra pages requested
[15:36:44] ================ [PASSED] ttm_tt_init_basic ================
[15:36:44] [PASSED] ttm_tt_init_misaligned
[15:36:44] [PASSED] ttm_tt_fini_basic
[15:36:44] [PASSED] ttm_tt_fini_sg
[15:36:44] [PASSED] ttm_tt_fini_shmem
[15:36:44] [PASSED] ttm_tt_create_basic
[15:36:44] [PASSED] ttm_tt_create_invalid_bo_type
[15:36:44] [PASSED] ttm_tt_create_ttm_exists
[15:36:44] [PASSED] ttm_tt_create_failed
[15:36:44] [PASSED] ttm_tt_destroy_basic
[15:36:44] [PASSED] ttm_tt_populate_null_ttm
[15:36:44] [PASSED] ttm_tt_populate_populated_ttm
[15:36:44] [PASSED] ttm_tt_unpopulate_basic
[15:36:44] [PASSED] ttm_tt_unpopulate_empty_ttm
[15:36:44] [PASSED] ttm_tt_swapin_basic
[15:36:44] ===================== [PASSED] ttm_tt ======================
[15:36:44] =================== ttm_bo (14 subtests) ===================
[15:36:44] =========== ttm_bo_reserve_optimistic_no_ticket ===========
[15:36:44] [PASSED] Cannot be interrupted and sleeps
[15:36:44] [PASSED] Cannot be interrupted, locks straight away
[15:36:44] [PASSED] Can be interrupted, sleeps
[15:36:44] ======= [PASSED] ttm_bo_reserve_optimistic_no_ticket =======
[15:36:44] [PASSED] ttm_bo_reserve_locked_no_sleep
[15:36:44] [PASSED] ttm_bo_reserve_no_wait_ticket
[15:36:44] [PASSED] ttm_bo_reserve_double_resv
[15:36:44] [PASSED] ttm_bo_reserve_interrupted
[15:36:44] [PASSED] ttm_bo_reserve_deadlock
[15:36:44] [PASSED] ttm_bo_unreserve_basic
[15:36:44] [PASSED] ttm_bo_unreserve_pinned
[15:36:44] [PASSED] ttm_bo_unreserve_bulk
[15:36:44] [PASSED] ttm_bo_fini_basic
[15:36:44] [PASSED] ttm_bo_fini_shared_resv
[15:36:44] [PASSED] ttm_bo_pin_basic
[15:36:44] [PASSED] ttm_bo_pin_unpin_resource
[15:36:44] [PASSED] ttm_bo_multiple_pin_one_unpin
[15:36:44] ===================== [PASSED] ttm_bo ======================
[15:36:44] ============== ttm_bo_validate (22 subtests) ===============
[15:36:44] ============== ttm_bo_init_reserved_sys_man ===============
[15:36:44] [PASSED] Buffer object for userspace
[15:36:44] [PASSED] Kernel buffer object
[15:36:44] [PASSED] Shared buffer object
[15:36:44] ========== [PASSED] ttm_bo_init_reserved_sys_man ===========
[15:36:44] ============== ttm_bo_init_reserved_mock_man ==============
[15:36:44] [PASSED] Buffer object for userspace
[15:36:44] [PASSED] Kernel buffer object
[15:36:44] [PASSED] Shared buffer object
[15:36:44] ========== [PASSED] ttm_bo_init_reserved_mock_man ==========
[15:36:44] [PASSED] ttm_bo_init_reserved_resv
[15:36:44] ================== ttm_bo_validate_basic ==================
[15:36:44] [PASSED] Buffer object for userspace
[15:36:44] [PASSED] Kernel buffer object
[15:36:44] [PASSED] Shared buffer object
[15:36:44] ============== [PASSED] ttm_bo_validate_basic ==============
[15:36:44] [PASSED] ttm_bo_validate_invalid_placement
[15:36:44] ============= ttm_bo_validate_same_placement ==============
[15:36:44] [PASSED] System manager
[15:36:44] [PASSED] VRAM manager
[15:36:44] ========= [PASSED] ttm_bo_validate_same_placement ==========
[15:36:44] [PASSED] ttm_bo_validate_failed_alloc
[15:36:44] [PASSED] ttm_bo_validate_pinned
[15:36:44] [PASSED] ttm_bo_validate_busy_placement
[15:36:44] ================ ttm_bo_validate_multihop =================
[15:36:44] [PASSED] Buffer object for userspace
[15:36:44] [PASSED] Kernel buffer object
[15:36:44] [PASSED] Shared buffer object
[15:36:44] ============ [PASSED] ttm_bo_validate_multihop =============
[15:36:44] ========== ttm_bo_validate_no_placement_signaled ==========
[15:36:44] [PASSED] Buffer object in system domain, no page vector
[15:36:44] [PASSED] Buffer object in system domain with an existing page vector
[15:36:44] ====== [PASSED] ttm_bo_validate_no_placement_signaled ======
[15:36:44] ======== ttm_bo_validate_no_placement_not_signaled ========
[15:36:44] [PASSED] Buffer object for userspace
[15:36:44] [PASSED] Kernel buffer object
[15:36:44] [PASSED] Shared buffer object
[15:36:44] ==== [PASSED] ttm_bo_validate_no_placement_not_signaled ====
[15:36:44] [PASSED] ttm_bo_validate_move_fence_signaled
[15:36:45] ========= ttm_bo_validate_move_fence_not_signaled =========
[15:36:45] [PASSED] Waits for GPU
[15:36:45] [PASSED] Tries to lock straight away
[15:36:45] ===== [PASSED] ttm_bo_validate_move_fence_not_signaled =====
[15:36:45] [PASSED] ttm_bo_validate_swapout
[15:36:45] [PASSED] ttm_bo_validate_happy_evict
[15:36:45] [PASSED] ttm_bo_validate_all_pinned_evict
[15:36:45] [PASSED] ttm_bo_validate_allowed_only_evict
[15:36:45] [PASSED] ttm_bo_validate_deleted_evict
[15:36:45] [PASSED] ttm_bo_validate_busy_domain_evict
[15:36:45] [PASSED] ttm_bo_validate_evict_gutting
[15:36:45] [PASSED] ttm_bo_validate_recrusive_evict
[15:36:45] ================= [PASSED] ttm_bo_validate =================
[15:36:45] ============================================================
[15:36:45] Testing complete. Ran 106 tests: passed: 106
[15:36:45] Elapsed time: 12.297s total, 1.824s configuring, 10.258s building, 0.183s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/dma-buf/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/dma-buf/.kunitconfig
[15:36:45] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[15:36:47] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[15:36:55] Starting KUnit Kernel (1/1)...
[15:36:55] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[15:36:55] ============= refcount_interrupt (4 subtests) ==============
[15:36:55] [PASSED] test_single_irq_change
[15:36:55] [PASSED] test_nested_irq_change
[15:36:55] [PASSED] test_multiple_irq_change
[15:36:55] [PASSED] test_irq_save
[15:36:55] =============== [PASSED] refcount_interrupt ================
[15:36:55] =============== dma-buf-fence (12 subtests) ================
[15:36:55] [PASSED] test_sanitycheck
[15:36:55] [PASSED] test_signaling
[15:36:55] [PASSED] test_add_callback
[15:36:55] [PASSED] test_late_add_callback
[15:36:55] [PASSED] test_rm_callback
[15:36:55] [PASSED] test_late_rm_callback
[15:36:55] [PASSED] test_status
[15:36:55] [PASSED] test_error
[15:36:55] [PASSED] test_wait
[15:36:55] [PASSED] test_wait_timeout
[15:36:55] [PASSED] test_stub
[15:36:55] [SKIPPED] test_race_signal_callback (requires at least 2 CPUs)
[15:36:55] ================== [PASSED] dma-buf-fence ==================
[15:36:55] ============ dma-buf-fence-chain (11 subtests) =============
[15:36:55] [PASSED] test_sanitycheck
[15:36:55] [PASSED] test_find_seqno
[15:36:55] [PASSED] test_find_signaled
[15:36:55] [PASSED] test_find_out_of_order
[15:37:00] [PASSED] test_find_gap
[15:37:00] [PASSED] test_find_race
[15:37:00] [PASSED] test_signal_forward
[15:37:00] [PASSED] test_signal_backward
[15:37:01] [PASSED] test_wait_forward
[15:37:01] [PASSED] test_wait_backward
[15:37:01] [PASSED] test_wait_random
[15:37:01] =============== [PASSED] dma-buf-fence-chain ===============
[15:37:01] ============ dma-buf-fence-unwrap (10 subtests) ============
[15:37:01] [PASSED] test_sanitycheck
[15:37:01] [PASSED] test_unwrap_array
[15:37:01] [PASSED] test_unwrap_chain
[15:37:01] [PASSED] test_unwrap_chain_array
[15:37:01] [PASSED] test_unwrap_merge
[15:37:01] [PASSED] test_unwrap_merge_duplicate
[15:37:01] [PASSED] test_unwrap_merge_seqno
[15:37:01] [PASSED] test_unwrap_merge_order
[15:37:01] [PASSED] test_unwrap_merge_complex
[15:37:01] [PASSED] test_unwrap_merge_complex_seqno
[15:37:01] ============== [PASSED] dma-buf-fence-unwrap ===============
[15:37:01] ================ dma-buf-resv (5 subtests) =================
[15:37:01] [PASSED] test_sanitycheck
[15:37:01] ===================== test_signaling ======================
[15:37:01] [PASSED] kernel
[15:37:01] [PASSED] write
[15:37:01] [PASSED] read
[15:37:01] [PASSED] bookkeep
[15:37:01] ================= [PASSED] test_signaling ==================
[15:37:01] ====================== test_for_each ======================
[15:37:01] [PASSED] kernel
[15:37:01] [PASSED] write
[15:37:01] [PASSED] read
[15:37:01] [PASSED] bookkeep
[15:37:01] ================== [PASSED] test_for_each ==================
[15:37:01] ================= test_for_each_unlocked ==================
[15:37:01] [PASSED] kernel
[15:37:01] [PASSED] write
[15:37:01] [PASSED] read
[15:37:01] [PASSED] bookkeep
[15:37:01] ============= [PASSED] test_for_each_unlocked ==============
[15:37:01] ===================== test_get_fences =====================
[15:37:01] [PASSED] kernel
[15:37:01] [PASSED] write
[15:37:01] [PASSED] read
[15:37:01] [PASSED] bookkeep
[15:37:01] ================= [PASSED] test_get_fences =================
[15:37:01] ================== [PASSED] dma-buf-resv ===================
[15:37:01] ============================================================
[15:37:01] Testing complete. Ran 54 tests: passed: 53, skipped: 1
[15:37:01] Elapsed time: 15.854s total, 1.867s configuring, 8.716s building, 5.265s running
+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 26/27] drm/xe/eudebug: Introduce EU pagefault handling interface
2026-09-03 14:59 ` [PATCH v10 26/27] drm/xe/eudebug: Introduce EU pagefault handling interface Mika Kuoppala
@ 2026-09-03 15:43 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:43 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] Race condition in `queue_pagefault` when accessing `epf->d` after unlocking causes Use-After-Free and double-put.
- [High] Unverified ASID in `xe_eudebug_pagefault_start` groups unrelated pagefaults, causing VMA destruction under the wrong VM lock and triggering lockdep failures.
- [High] Missing NULL check for `vm->xef` in `xe_eudebug_pagefault_start` and `xe_eudebug_pagefault_creatable` causes a kernel panic for kernel/migrate VMs.
- [High] Non-recoverable error in `send_queued_pagefaults` triggers a full GPU reset, enabling a Denial of Service via queue destruction.
- [High] Deferring finalization in `xe_eudebug_pagefault_end` hangs the state machine if subsequent pagefaults fail to initialize.
- [Medium] Failure to clear `TD_CTL_FORCE_EXCEPTION` in `eudebug_pagefault_finalize` ignores a hardware timeout without triggering a recovery reset.
--
commit b7afc29c50bd1c63ce9ec88327c0929d8ad87515
Author: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Subject: drm/xe/eudebug: Introduce EU pagefault handling interface
The XE2 (and PVC) HW has a limitation that the pagefault due to invalid
access will halt the corresponding EUs. To solve this problem, introduce
EU pagefault handling functionality, which allows to unhalt pagefaulted
eu threads and to EU debugger to get inform about the eu attentions state
of EU threads during execution.
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_pagefault.c b/drivers/gpu/drm/xe/xe_eudebug_pagefault.c
> new file mode 100644
> index 0000000000000..5ad37e757f692
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_eudebug_pagefault.c
[ ... ]
> +int
> +xe_eudebug_pagefault_start(struct xe_vm *vm, struct xe_pagefault *pf)
> +{
> + struct pagefault_fence *pf_fence;
> + struct xe_eudebug_pagefault *epf;
> + struct xe_gt *gt = pf->gt;
> + struct xe_exec_queue *q;
> + struct dma_fence *fence;
> + struct xe_eudebug *d;
> + unsigned long tdctl_timeout;
> + unsigned int fw_ref;
> + int lrc_idx;
> + u32 td_ctl;
> +
> + if (!xe_eudebug_is_enabled(vm->xe))
> + return -EOPNOTSUPP;
> +
> + d = xe_eudebug_get_nolock_with_discovery(vm->xef);
> + if (!d)
> + return -ENOENT;
[Severity: High]
Does this code handle kernel VMs safely? Kernel VMs like the migration VM
created via xe_vm_create_bare() will have a NULL xef. If a page fault occurs
in a kernel VM and is passed to xe_eudebug_pagefault_start(), could this
trigger a NULL pointer dereference when xe_eudebug_get_nolock_with_discovery()
dereferences xef->xe?
> +
> + q = xe_gt_runalone_active_queue_get(gt, &lrc_idx);
> + if (IS_ERR(q))
> + goto err_put_eudebug;
> +
> + if (XE_WARN_ON(q->vm != vm))
> + goto err_put_exec_queue;
> +
> + if (!xe_exec_queue_is_debuggable(q))
> + goto err_put_exec_queue;
> +
> + /**
> + * Check if there is an active pagefault.
> + * If so, attach original epf to current pagefault and leave.
> + */
> + mutex_lock(&d->xe->eudebug.lock);
> + if (d->pf.active || d->pf.first) {
> + epf = kzalloc_obj(*epf, GFP_KERNEL);
> + if (!epf) {
> + mutex_unlock(&d->xe->eudebug.lock);
> + goto err_put_exec_queue;
> + }
> + d->pf.active++;
> + goto out_set_epf;
> + }
[Severity: High]
Is it safe to group page faults without verifying they belong to the same ASID?
If multiple VMs belonging to the same xe_file trigger page faults concurrently,
the page fault workqueue will process them in parallel.
Could this logic erroneously group them just by incrementing pf.active without
checking if pf->consumer.asid matches d->pf.asid?
If an unrelated page fault drops pf.active to 0 and calls destroy_pagefault()
on the first page fault, could this attempt to destroy the first VM's VMA while
holding the second VM's write lock, resulting in data corruption and a lockdep
failure?
[ ... ]
> +static void queue_pagefault(struct xe_eudebug *d,
> + struct xe_eudebug_pagefault *epf)
> +{
> + lockdep_assert_held(&epf->q->vm->lock);
> +
> + mutex_lock(&d->pf.lock);
> +
> + if (epf->null_vma) {
> + eudebug_destroy_vma(epf->q->vm, epf->null_vma);
> + epf->null_vma = NULL;
> + }
> +
> + list_add_tail(&epf->link, &d->pf.pagefaults);
> + mutex_unlock(&d->pf.lock);
> +
> + /* Queued is equivalent of sent. Drop references */
> + xe_eudebug_put(epf->d);
> + epf->d = NULL;
> +}
[Severity: Critical]
Is there a use-after-free race condition here?
Once epf is added to the pagefaults list and the lock is dropped, a concurrent
thread like attention_poll_work() could acquire the lock, process the entry,
and free epf via destroy_pagefault().
If the concurrent thread frees epf before xe_eudebug_put() is called, could
this result in putting a reference on freed memory and writing NULL to a freed
pointer?
[ ... ]
> +static int send_queued_pagefaults(struct xe_eudebug *d)
> +{
> + struct xe_eudebug_pagefault *epf, *epf_temp;
> + int ret = 0;
> +
> + mutex_lock(&d->pf.lock);
> + list_for_each_entry_safe(epf, epf_temp, &d->pf.pagefaults, link) {
> + ret = xe_eudebug_send_pagefault_event(d, epf);
> +
> + if (ret == -ENOSPC) {
> + ret = 0;
> + break;
> + }
> +
> + list_del(&epf->link);
> +
> + destroy_pagefault(epf);
> +
> + if (ret)
> + break;
> + }
> + mutex_unlock(&d->pf.lock);
> + return ret;
> +}
[Severity: High]
Does returning early on failure here introduce a denial of service vector?
If an execution queue is destroyed while its page fault is queued,
xe_eudebug_send_pagefault_event() will return -ENOENT. Breaking the loop here
will propagate that error back up to attention_poll_work().
Because attention_poll_work() treats any non-zero return (other than -EBUSY)
as a fatal error and triggers a full GPU reset via handle_attention_fail(),
could a malicious application intentionally fault and immediately destroy the
queue to force a reset of the entire GPU?
[ ... ]
> +static int
> +eudebug_pagefault_finalize(struct xe_eudebug_pagefault *epf, int err)
> +{
> + struct xe_gt *gt = epf_to_gt(epf);
> + struct xe_eudebug *d;
> + unsigned long tdctl_timeout;
> + unsigned int fw_ref;
> + bool queued = false;
> + u32 td_ctl, ret = 0;
> +
> + fw_ref = xe_force_wake_get(gt_to_fw(gt), epf->q->hwe->domain);
> + if (!fw_ref) {
> + struct xe_device *xe = gt_to_xe(gt);
> +
> + drm_warn(&xe->drm, "Forcewake fail: Can not recover TD_CTL");
> + } else {
> + td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
> + tdctl_timeout = jiffies + msecs_to_jiffies(XE_GT_ATTENTION_TIMEOUT_MS);
> + do {
> + xe_gt_mcr_multicast_write(gt, TD_CTL, td_ctl &
> + ~(TD_CTL_FORCE_EXCEPTION));
> + usleep_range(200, 220);
> + td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
> +
> + if ((td_ctl & TD_CTL_FORCE_EXCEPTION) &&
> + time_after(jiffies, tdctl_timeout)) {
> + eu_err(epf->d, "Failed to clear Force Exception!!!");
> + break;
> + }
> + } while (td_ctl & TD_CTL_FORCE_EXCEPTION);
[Severity: Medium]
Should a failure to clear the TD_CTL_FORCE_EXCEPTION bit trigger a recovery
reset?
If the hardware fails to clear the exception bit within the timeout window,
this loop breaks and logs an error, but it does not propagate a hard failure
or initiate a reset.
Could this silent swallow of the hardware timeout leave the Execution Units
permanently halted and the workload stuck in an unrecoverable state?
[ ... ]
> +void xe_eudebug_pagefault_end(void *private, int err)
> +{
> + struct xe_eudebug_pagefault *epf = _get_epf(private);
> + struct xe_eudebug_pagefault *first_epf = NULL;
> + struct xe_pagefault_queue *pf_queue;
> + struct xe_device *xe;
> + struct xe_eudebug *d;
> + struct xe_vm *vm;
> + int resume_attn = 0, destroy_pf = 0;
> +
> + if (!epf)
> + return;
> +
> + xe = epf->q->xef->xe;
> + pf_queue = &xe->usm.pf_queue;
> +
> + d = epf->d;
> + vm = xe_vm_get(epf->q->vm);
> + /* Need to have outher vm lock for eudebug lock as for pf start */
> + down_write(&vm->lock);
> + mutex_lock(&d->xe->eudebug.lock);
> + if (!--d->pf.active) {
> + /*
> + * This will also catch entries that are popped from pagefault
> + * queue and moved to worker but not yet processed.
> + * xe_eudebug_pagefault_start() will catch later it and increase
> + * the pf.active counter.
> + */
> + if (!xe_eudebug_pagefault_queue_has_asid(pf_queue, d->pf.asid)) {
> + if (!err)
> + xe_eudebug_pagefault_process(d->pf.first);
> +
> + destroy_pf = eudebug_pagefault_finalize(d->pf.first, err);
> + /* If d->pf.first was queued the epf shall be removed. */
> + if (epf != d->pf.first) {
> + if (destroy_pf)
> + first_epf = d->pf.first;
> + else
> + destroy_pf = 1;
> + }
> + d->pf.first = NULL;
> + d->pf.asid = 0;
> + resume_attn = 1;
> + } else {
> + /* page faults still queued */
> + if (epf != d->pf.first)
> + destroy_pf = 1;
> + }
[Severity: High]
Does deferring finalization when page faults are still queued risk deadlocking
the state machine?
If xe_eudebug_pagefault_queue_has_asid() is true, eudebug_pagefault_finalize()
is deferred on the assumption that the next queued page fault will successfully
attach to the eudebug state machine.
If the next page fault fails in xe_eudebug_pagefault_start() (for example, if
the exec queue is no longer debuggable), eudebug setup is skipped. When that
fault completes, xe_eudebug_pagefault_end() will receive a NULL private pointer
and return early.
Could this leave pf.active at 0 while eudebug_pagefault_finalize() is never
called, permanently hanging the GPU with TD_CTL_FORCE_EXCEPTION still active
and deadlocking EU_CONTROL ioctls waiting on the unsignaled pf.fence?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=26
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 27/27] drm/xe/eudebug: Enable EU pagefault handling
2026-09-03 14:59 ` [PATCH v10 27/27] drm/xe/eudebug: Enable EU pagefault handling Mika Kuoppala
@ 2026-09-03 15:46 ` sashiko-bot
0 siblings, 0 replies; 48+ messages in thread
From: sashiko-bot @ 2026-09-03 15:46 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Temporary NULL VMAs for subsequent eudebug pagefaults are destroyed immediately after ACKing the fault, creating a race condition that leads to livelock.
- [High] Successful SVM pagefaults bypass private tagging, which permanently stalls the finalization of the active eudebug session.
- [High] Pagefault cache hits bypass eudebug tagging, permanently hanging the debugger session.
- [High] `xe_vm_svm_vma_subtract()` is called with unaligned address boundaries, corrupting the VM layout.
--
commit bd171058301961cced31067feb0527d9f0b38c87
Author: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
drm/xe/eudebug: Enable EU pagefault handling
This commit enables EU pagefault handling for XE2/PVC hardware, allowing
the driver to unhalt pagefaulted EU threads via SIP mode and a temporary
null page.
> diff --git a/drivers/gpu/drm/xe/xe_guc_pagefault.c b/drivers/gpu/drm/xe/xe_guc_pagefault.c
> --- a/drivers/gpu/drm/xe/xe_guc_pagefault.c
> +++ b/drivers/gpu/drm/xe/xe_guc_pagefault.c
> @@ -59,13 +60,14 @@ static void guc_ack_fault(struct xe_pagefault *pf, int err)
> write_only);
> }
>
> -static void guc_ack_fault_end(void *private)
> +static void guc_ack_fault_end(void *private, int err)
> {
> - struct xe_guc *guc = private;
> + struct xe_guc *guc = xe_eudebug_pagefault_get_private(private);
>
> if ((guc->pagefault_ack_counter & (XE_GUC_PAGEFAULT_FLUSH_PERIOD - 1)) != 1)
> xe_guc_ct_send_flush(&guc->ct);
> xe_guc_ct_unlock(&guc->ct);
> + xe_eudebug_pagefault_end(private, err);
[Severity: High]
Does this create a race condition that leads to a livelock?
When this calls xe_eudebug_pagefault_end(), temporary null VMAs for
subsequent pagefaults are destroyed immediately (destroy_pf = 1) after
ACKing the fault and signaling the hardware to resume.
Since there is no synchronization to guarantee the EU thread has re-executed
the faulting instruction before the KMD unbinds the VMA, if the VMA is
unbound before the EU thread accesses the address, won't the thread
pagefault again on the same instruction and loop infinitely?
> }
>
> diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
> --- a/drivers/gpu/drm/xe/xe_pagefault.c
> +++ b/drivers/gpu/drm/xe/xe_pagefault.c
[ ... ]
> @@ -227,8 +228,56 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
>
> vma = xe_vm_find_vma_by_addr(vm, pf->consumer.page_addr);
> if (!vma) {
[ ... ]
> + } else {
> + /*
> + * For non-SVM case:
> + * Eudebug with active pagefault always needs to be attached
> + * to pagefault since it waits for all pagefaults with matching
> + * asid to be resolved.
> + */
> + if (!xe_vma_is_cpu_addr_mirror(vma))
> + xe_eudebug_pagefault_set_private(pf, vm);
[Severity: High]
Does skipping the private tagging for SVM (cpu_addr_mirror) VMAs cause the
eudebug session to hang permanently?
If an active eudebug session exists for the same ASID and its finalization
was postponed because this SVM fault was still in the queue,
xe_eudebug_pagefault_end() will see no eudebug tag and return immediately
without triggering eudebug_pagefault_finalize(). This seems like it would
leave the EU threads permanently stuck in SIP mode.
> + }
>
> if (xe_vma_read_only(vma) &&
> @@ -239,11 +288,52 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
>
> atomic = xe_pagefault_access_is_atomic(pf->consumer.access_type);
>
> - if (xe_vma_is_cpu_addr_mirror(vma))
> + if (xe_vma_is_cpu_addr_mirror(vma)) {
> err = xe_svm_handle_pagefault(vm, vma, pf, gt,
> pf->consumer.page_addr, atomic);
> - else
> +
> +#if IS_ENABLED(CONFIG_DRM_XE_EUDEBUG)
> + /*
> + * If err is -ENOENT, it means that the cpu-address-space-mirrored
> + * xe vma exists, but there is no mm vma allocated in
> + * the CPU address space. This indicates that no memory has been
> + * allocated in the CPU address space.
> + */
> + if (err == -ENOENT &&
> + !xe_vm_is_closed_or_banned(vm) &&
> + xe_eudebug_pagefault_creatable(gt, vm)) {
> + u32 page_size = vm->flags & XE_VM_FLAG_64K ? SZ_64K : SZ_4K;
[ ... ]
> + vma = xe_vm_find_vma_by_addr(vm, pf->consumer.page_addr);
> + if (vma && xe_vma_is_cpu_addr_mirror(vma))
> + vma = xe_vm_svm_vma_subtract(vm, vma,
> + pf->consumer.page_addr,
> + pf->consumer.page_addr + page_size);
[Severity: High]
Is it safe to pass pf->consumer.page_addr directly as the subtraction
boundaries?
The hardware fault address is not guaranteed to be aligned to page_size.
Passing unaligned boundaries to xe_vm_svm_vma_subtract() will create
unaligned head/tail VMAs via xe_vma_create().
Inserting unaligned VMAs into the interval tree and page tables violates
core memory management invariants and could lead to page table corruption or
kernel panics.
> + else
> + vma = ERR_PTR(-EINVAL);
[ ... ]
> @@ -598,6 +688,12 @@ static void xe_pagefault_queue_work(struct work_struct *w)
> }
>
> ack_fault:
> + /*
> + * set private after xe_pagefault_service() since eudebug could swap
> + * the pf->producer.private field. Also needed when cache was hit.
> + */
> + private = pf->producer.private;
[Severity: High]
Does a pagefault cache hit permanently hang the eudebug session?
When a pagefault matches the cache, the code jumps directly to ack_fault,
skipping xe_pagefault_service(). Since the service routine is bypassed,
xe_eudebug_pagefault_set_private() is never called, leaving the fault
untagged.
Similar to the SVM bypass above, if the session postponed finalization for
this queued fault, it will never trigger eudebug_pagefault_finalize() upon
completion.
> +
> xe_assert(xe, pf->consumer.alloc_state ==
> XE_PAGEFAULT_ALLOC_STATE_ACTIVE);
> xe_assert(xe, pf == pf_work->cache.pf);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260903145952.848051-1-mika.kuoppala@linux.intel.com?part=27
^ permalink raw reply [flat|nested] 48+ messages in thread
* ✗ CI.checksparse: warning for Intel Xe GPU Debug Support (eudebug) v10
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (28 preceding siblings ...)
2026-09-03 15:37 ` ✓ CI.KUnit: success " Patchwork
@ 2026-09-03 15:53 ` Patchwork
2026-09-03 16:17 ` ✓ Xe.CI.BAT: success " Patchwork
` (2 subsequent siblings)
32 siblings, 0 replies; 48+ messages in thread
From: Patchwork @ 2026-09-03 15:53 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
== Series Details ==
Series: Intel Xe GPU Debug Support (eudebug) v10
URL : https://patchwork.freedesktop.org/series/173321/
State : warning
== Summary ==
+ trap cleanup EXIT
+ KERNEL=/kernel
+ MT=/root/linux/maintainer-tools
+ git clone https://gitlab.freedesktop.org/drm/maintainer-tools /root/linux/maintainer-tools
Cloning into '/root/linux/maintainer-tools'...
warning: redirecting to https://gitlab.freedesktop.org/drm/maintainer-tools.git/
+ make -C /root/linux/maintainer-tools
make: Entering directory '/root/linux/maintainer-tools'
cc -O2 -g -Wextra -o remap-log remap-log.c
make: Leaving directory '/root/linux/maintainer-tools'
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ /root/linux/maintainer-tools/dim sparse --fast 78e2bb86709699d886be71a6f9c9dc41e4bf9aab
Sparse version: 0.6.4 (Ubuntu: 0.6.4-4ubuntu3)
Fast mode used, each commit won't be checked separately.
+/kernel/Makefile:1300: C=1 specified, but sparse is not available or not up to date
+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel
^ permalink raw reply [flat|nested] 48+ messages in thread
* ✓ Xe.CI.BAT: success for Intel Xe GPU Debug Support (eudebug) v10
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (29 preceding siblings ...)
2026-09-03 15:53 ` ✗ CI.checksparse: warning " Patchwork
@ 2026-09-03 16:17 ` Patchwork
2026-09-03 16:30 ` [PATCH v10 00/27] " Rodrigo Vivi
2026-09-04 3:21 ` ✗ Xe.CI.FULL: failure for " Patchwork
32 siblings, 0 replies; 48+ messages in thread
From: Patchwork @ 2026-09-03 16:17 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
[-- Attachment #1: Type: text/plain, Size: 954 bytes --]
== Series Details ==
Series: Intel Xe GPU Debug Support (eudebug) v10
URL : https://patchwork.freedesktop.org/series/173321/
State : success
== Summary ==
CI Bug Log - changes from xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34_BAT -> xe-pw-173321v1_BAT
====================================================
Summary
-------
**SUCCESS**
No regressions found.
Participating hosts (15 -> 15)
------------------------------
No changes in participating hosts
Changes
-------
No changes found
Build changes
-------------
* Linux: xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34 -> xe-pw-173321v1
IGT_9082: 2d61f578d998115259b87f9fa27f597ce11a0c89 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34: 76a34199970d93cfb3ed5dbbd745c23b6f0cff34
xe-pw-173321v1: 173321v1
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/index.html
[-- Attachment #2: Type: text/html, Size: 1502 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (30 preceding siblings ...)
2026-09-03 16:17 ` ✓ Xe.CI.BAT: success " Patchwork
@ 2026-09-03 16:30 ` Rodrigo Vivi
2026-09-04 3:21 ` ✗ Xe.CI.FULL: failure for " Patchwork
32 siblings, 0 replies; 48+ messages in thread
From: Rodrigo Vivi @ 2026-09-03 16:30 UTC (permalink / raw)
To: Mika Kuoppala
Cc: intel-xe, simona.vetter, matthew.brost, christian.koenig,
thomas.hellstrom, joonas.lahtinen, gustavo.sousa, jan.maslak,
dominik.karol.piatkowski, andrzej.hajda, matthew.auld,
maciej.patelczyk, gwan-gyeong.mun
On Thu, Sep 03, 2026 at 05:59:24PM +0300, Mika Kuoppala wrote:
> Hi,
>
> This is the v10 patch series for Intel Xe GPU debug support (eudebug).
>
> This series continues from the following previous submissions:
> - v1: https://lists.freedesktop.org/archives/intel-xe/2024-July/043605.html
> - v2: https://lists.freedesktop.org/archives/intel-xe/2024-October/052260.html
> - v3: https://lists.freedesktop.org/archives/intel-xe/2024-December/061476.html
> - v4: https://lists.freedesktop.org/archives/intel-xe/2025-August/091645.html
> - v5: https://lists.freedesktop.org/archives/intel-xe/2025-October/097859.html
> - v6: https://lists.freedesktop.org/archives/intel-xe/2025-December/106405.html
> - v7: https://lists.freedesktop.org/archives/intel-xe/2026-February/115750.html
> - v8: https://lists.freedesktop.org/archives/intel-xe/2026-April/124147.html
> - v9: https://lists.freedesktop.org/archives/intel-xe/2026-June/128834.html
>
> # Series layout: core and page faults
>
> v9 shipped eudebug core only, with EU page fault handling split out to be
> sent separately. In v10 the page fault work is included again, but it is
> deliberately kept as a distinct block on top of the core:
>
> - Patches 1-19 are eudebug core. This is a self-contained, functional
> debugger interface and can be reviewed and merged on its own.
> - Patches 20-27 add EU page fault handling on top. They touch xe page
> fault and SVM paths, and nothing in patches 1-19 depends on them.
>
> They are posted together for completeness, so that reviewers can see
> where the core interface is heading and judge the core design with the
> page fault use case in view. Treat the second block as a follow-up series
> that happens to be in the same posting.
>
> # Major Changes from v9
>
> Page fault support is back in the series (see above).
>
> Continued to work through Sashiko feedback, plus review comments on v9.
>
> Core eudebug:
>
> - Reworked the eudebug workqueues. Deferred ufence signalling no longer
> shares the ordered discovery workqueue, and the per device attention
> poller moved off the shared system workqueue onto a device workqueue of
> its own. Both were sources of head of line blocking: a client's ufence
> signal, which is what releases the debuggee from wait_user_fence, could
> queue behind an unrelated client's discovery, and the attention poller
> blocks on eudebug.lock across a gt reset.
> - Connection lifetime and teardown fixes: wake up after detach taking the
> occupied event into account, O_CLOEXEC on the connection fd, hold the
> drm_device for the lifetime of the connection, do not silently truncate
> the target fd, and reject zero as a target fd.
> - Event fifo allocated with GFP_KERNEL_ACCOUNT, resource handles preallocated.
> - ufence acks: avoid double signal when the fence is not tracked, clear
> the bind ref seqno when there is no debugger or when tracking fails,
> and stop referencing the ack after dropping the lock.
> - EU control: take runtime pm around hw access, gate SR-IOV, proper
> teardown when runtime is not active, and no warn on wrong context.
> - Documentation and kernel-doc fixes throughout, including the ioctl_lock
> in struct xe_file, which is held across a whole ioctl and therefore
> nests outside every lock those ioctls take. The security model DOC now
> states which fd acquisition methods the ptrace_may_access() parity
> claim actually covers.
>
> Page faults:
>
> Reworked on top of 'Fine grained fault locking, threaded prefetch,
> storm cache' series (merged). Added svm support and improved multiple
> fault handling.
>
> TODO:
> access_process_vm(task, ...) still has the possible race with
> execve due to mm changing for task, pointed by Sashiko.
> See the relevant code and XXX FIXME in xe_eudebug_vm.c, in
> xe_eudebug_vma_access(), and in xe_eudebug_track_userptr_task()
> in xe_userptr.h. The most straightforward way to fix this
> would be to export access_remote_vm(mm, ...) and then use the
> notifier mm for it.
>
> # Supported Hardware
> - Lunarlake (LNL)
> - Battlemage (BMG)
> - Pantherlake (PTL)
Are we adding CI?
>
> The code for this submission can be found at:
> https://gitlab.freedesktop.org/miku/kernel/-/tree/eudebug-v10
>
> Tests:
> https://gitlab.freedesktop.org/DominikPiatkowski-Intel/igt-gpu-tools/-/tree/eudebug-dev-next
What about the upper level PRs and reviews?
Could you please update us on how that side of the review is going?
Thanks,
Rodrigo.
>
>
> Christoph Manszewski (5):
> drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops
> drm/xe/eudebug: Introduce vm bind and vm bind debug data events
> drm/xe/eudebug_test: Introduce eudebug live tests
> drm/xe: Implement SR-IOV and eudebug exclusivity
> drm/xe: Add xe_client_debugfs and introduce debug_data file
>
> Dominik Grzegorzek (5):
> drm/xe: Add EUDEBUG_ENABLE exec queue property
> drm/xe/eudebug: Introduce exec_queue events
> drm/xe/eudebug: Add hw enablement
> drm/xe/eudebug: Introduce EU control interface
> drm/xe/eudebug: Introduce per device attention scan worker
>
> Gwan-gyeong Mun (5):
> drm/xe/eudebug: Add read/count/compare helper for eu attention
> drm/xe/vm: Support for adding null page VMA to VM on request
> drm/xe/vm: Add xe_vm_svm_vma_subtract() to carve out a sub-range from
> an SVM VMA
> drm/xe/eudebug: Introduce EU pagefault handling interface
> drm/xe/eudebug: Enable EU pagefault handling
>
> Maciej Patelczyk (3):
> drm/xe/pagefault: export pagefault queue properties
> drm/xe: Support for xe_vma_unbind()
> drm/xe: export prep_vma_destroy as xe_vm_prep_vma_destroy
>
> Mika Kuoppala (9):
> drm/xe/eudebug: Introduce eudebug interface
> drm/xe/eudebug: Add documentation
> drm/xe/eudebug: Add connection establishment documentation
> drm/xe/eudebug: Introduce discovery for resources
> drm/xe/eudebug: Mark guc contexts as debuggable
> drm/xe: Remove ifdef in DRM_GPUVA_OP_DRIVER svm subop checking
> drm/xe/eudebug: Add ufence events with acks
> drm/xe/eudebug: Add vm open/pread/pwrite
> drm/xe/eudebug: Add userptr vm pread/pwrite
>
> .../ABI/testing/sysfs-driver-intel-xe-eudebug | 21 +
> Documentation/gpu/driver-uapi.rst | 2 +
> Documentation/gpu/xe/index.rst | 1 +
> Documentation/gpu/xe/xe_eudebug.rst | 83 +
> MAINTAINERS | 2 +
> drivers/gpu/drm/xe/Kconfig | 10 +
> drivers/gpu/drm/xe/Makefile | 7 +-
> drivers/gpu/drm/xe/abi/guc_actions_abi.h | 5 +
> drivers/gpu/drm/xe/abi/guc_klvs_abi.h | 1 +
> drivers/gpu/drm/xe/regs/xe_engine_regs.h | 1 +
> drivers/gpu/drm/xe/regs/xe_gt_regs.h | 43 +
> drivers/gpu/drm/xe/tests/xe_eudebug_test.c | 227 ++
> drivers/gpu/drm/xe/tests/xe_live_test_mod.c | 5 +
> drivers/gpu/drm/xe/xe_client_debugfs.c | 108 +
> drivers/gpu/drm/xe/xe_client_debugfs.h | 17 +
> drivers/gpu/drm/xe/xe_debug_data.c | 383 +++
> drivers/gpu/drm/xe/xe_debug_data.h | 22 +
> drivers/gpu/drm/xe/xe_debug_data_types.h | 25 +
> drivers/gpu/drm/xe/xe_device.c | 28 +-
> drivers/gpu/drm/xe/xe_device.h | 42 +
> drivers/gpu/drm/xe/xe_device_types.h | 57 +
> drivers/gpu/drm/xe/xe_eudebug.c | 2514 +++++++++++++++++
> drivers/gpu/drm/xe/xe_eudebug.h | 119 +
> drivers/gpu/drm/xe/xe_eudebug_hw.c | 730 +++++
> drivers/gpu/drm/xe/xe_eudebug_hw.h | 30 +
> drivers/gpu/drm/xe/xe_eudebug_pagefault.c | 722 +++++
> drivers/gpu/drm/xe/xe_eudebug_pagefault.h | 81 +
> drivers/gpu/drm/xe/xe_eudebug_types.h | 284 ++
> drivers/gpu/drm/xe/xe_eudebug_vm.c | 501 ++++
> drivers/gpu/drm/xe/xe_eudebug_vm.h | 8 +
> drivers/gpu/drm/xe/xe_exec_queue.c | 77 +-
> drivers/gpu/drm/xe/xe_exec_queue.h | 2 +
> drivers/gpu/drm/xe/xe_exec_queue_types.h | 7 +
> drivers/gpu/drm/xe/xe_gt_debug.c | 251 ++
> drivers/gpu/drm/xe/xe_gt_debug.h | 36 +
> drivers/gpu/drm/xe/xe_gt_debug_types.h | 22 +
> drivers/gpu/drm/xe/xe_guc.c | 8 +
> drivers/gpu/drm/xe/xe_guc.h | 6 +
> drivers/gpu/drm/xe/xe_guc_ads.c | 12 +
> drivers/gpu/drm/xe/xe_guc_pagefault.c | 10 +-
> drivers/gpu/drm/xe/xe_guc_submit.c | 34 +
> drivers/gpu/drm/xe/xe_guc_submit.h | 1 +
> drivers/gpu/drm/xe/xe_hw_engine.h | 14 +
> drivers/gpu/drm/xe/xe_pagefault.c | 150 +-
> drivers/gpu/drm/xe/xe_pagefault.h | 10 +
> drivers/gpu/drm/xe/xe_pagefault_types.h | 38 +-
> drivers/gpu/drm/xe/xe_pt.c | 2 -
> drivers/gpu/drm/xe/xe_reg_sr.c | 12 +-
> drivers/gpu/drm/xe/xe_reg_sr.h | 4 +-
> drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +-
> drivers/gpu/drm/xe/xe_rtp.c | 2 +-
> drivers/gpu/drm/xe/xe_sync.c | 45 +-
> drivers/gpu/drm/xe/xe_sync.h | 7 +-
> drivers/gpu/drm/xe/xe_sync_types.h | 29 +-
> drivers/gpu/drm/xe/xe_userptr.c | 4 +
> drivers/gpu/drm/xe/xe_userptr.h | 32 +
> drivers/gpu/drm/xe/xe_vm.c | 491 +++-
> drivers/gpu/drm/xe/xe_vm.h | 13 +
> drivers/gpu/drm/xe/xe_vm_types.h | 28 +
> drivers/gpu/drm/xe/xe_wa_oob.rules | 4 +
> include/uapi/drm/xe_drm.h | 89 +
> include/uapi/drm/xe_drm_eudebug.h | 416 +++
> 62 files changed, 7826 insertions(+), 111 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-xe-eudebug
> create mode 100644 Documentation/gpu/xe/xe_eudebug.rst
> create mode 100644 drivers/gpu/drm/xe/tests/xe_eudebug_test.c
> create mode 100644 drivers/gpu/drm/xe/xe_client_debugfs.c
> create mode 100644 drivers/gpu/drm/xe/xe_client_debugfs.h
> 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
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug.c
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug.h
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug_hw.c
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug_hw.h
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug_pagefault.c
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug_pagefault.h
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug_types.h
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug_vm.c
> create mode 100644 drivers/gpu/drm/xe/xe_eudebug_vm.h
> create mode 100644 drivers/gpu/drm/xe/xe_gt_debug.c
> create mode 100644 drivers/gpu/drm/xe/xe_gt_debug.h
> create mode 100644 drivers/gpu/drm/xe/xe_gt_debug_types.h
> create mode 100644 include/uapi/drm/xe_drm_eudebug.h
>
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 48+ messages in thread
* ✗ Xe.CI.FULL: failure for Intel Xe GPU Debug Support (eudebug) v10
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
` (31 preceding siblings ...)
2026-09-03 16:30 ` [PATCH v10 00/27] " Rodrigo Vivi
@ 2026-09-04 3:21 ` Patchwork
32 siblings, 0 replies; 48+ messages in thread
From: Patchwork @ 2026-09-04 3:21 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-xe
[-- Attachment #1: Type: text/plain, Size: 73313 bytes --]
== Series Details ==
Series: Intel Xe GPU Debug Support (eudebug) v10
URL : https://patchwork.freedesktop.org/series/173321/
State : failure
== Summary ==
CI Bug Log - changes from xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34_FULL -> xe-pw-173321v1_FULL
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with xe-pw-173321v1_FULL absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in xe-pw-173321v1_FULL, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
to document this new failure mode, which will reduce false positives in CI.
Participating hosts (2 -> 2)
------------------------------
No changes in participating hosts
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in xe-pw-173321v1_FULL:
### IGT changes ###
#### Possible regressions ####
* igt@kms_vblank@ts-continuation-suspend@pipe-a-hdmi-a-3:
- shard-bmg: [PASS][1] -> [DMESG-FAIL][2]
[1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-4/igt@kms_vblank@ts-continuation-suspend@pipe-a-hdmi-a-3.html
[2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-7/igt@kms_vblank@ts-continuation-suspend@pipe-a-hdmi-a-3.html
New tests
---------
New tests have been introduced between xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34_FULL and xe-pw-173321v1_FULL:
### New IGT tests (1) ###
* igt@xe_live_ktest@xe_eudebug@toggle_reg:
- Statuses : 2 pass(s)
- Exec time: [0.21, 0.23] s
Known issues
------------
Here are the changes found in xe-pw-173321v1_FULL that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@core_hotunplug@hotreplug-with-load:
- shard-lnl: [PASS][3] -> [ABORT][4] ([Intel XE#8007]) +19 other tests abort
[3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@core_hotunplug@hotreplug-with-load.html
[4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@core_hotunplug@hotreplug-with-load.html
* igt@fbdev@pan:
- shard-lnl: [PASS][5] -> [SKIP][6] ([Intel XE#2134])
[5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@fbdev@pan.html
[6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@fbdev@pan.html
* igt@kms_atomic_transition@plane-all-modeset-transition-fencing:
- shard-lnl: NOTRUN -> [SKIP][7] ([Intel XE#3279])
[7]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_atomic_transition@plane-all-modeset-transition-fencing.html
* igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-0-hflip:
- shard-lnl: NOTRUN -> [SKIP][8] ([Intel XE#7059] / [Intel XE#7085])
[8]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-0-hflip.html
* igt@kms_big_fb@y-tiled-64bpp-rotate-90:
- shard-bmg: NOTRUN -> [SKIP][9] ([Intel XE#1124]) +1 other test skip
[9]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_big_fb@y-tiled-64bpp-rotate-90.html
* igt@kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip:
- shard-lnl: NOTRUN -> [SKIP][10] ([Intel XE#1124])
[10]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip.html
* igt@kms_bw@connected-linear-tiling-2-displays-target-3840x2160p:
- shard-lnl: NOTRUN -> [SKIP][11] ([Intel XE#7679])
[11]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_bw@connected-linear-tiling-2-displays-target-3840x2160p.html
* igt@kms_ccs@bad-rotation-90-4-tiled-bmg-ccs@pipe-a-edp-1:
- shard-lnl: NOTRUN -> [SKIP][12] ([Intel XE#2669] / [Intel XE#7389]) +3 other tests skip
[12]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_ccs@bad-rotation-90-4-tiled-bmg-ccs@pipe-a-edp-1.html
* igt@kms_ccs@bad-rotation-90-4-tiled-dg2-mc-ccs:
- shard-bmg: NOTRUN -> [SKIP][13] ([Intel XE#2887]) +4 other tests skip
[13]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@kms_ccs@bad-rotation-90-4-tiled-dg2-mc-ccs.html
* igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-d-hdmi-a-3:
- shard-bmg: NOTRUN -> [INCOMPLETE][14] ([Intel XE#7084] / [Intel XE#8150])
[14]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-10/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-d-hdmi-a-3.html
* igt@kms_ccs@crc-primary-suspend-y-tiled-ccs:
- shard-lnl: NOTRUN -> [SKIP][15] ([Intel XE#3432])
[15]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_ccs@crc-primary-suspend-y-tiled-ccs.html
* igt@kms_ccs@random-ccs-data-y-tiled-gen12-mc-ccs:
- shard-lnl: NOTRUN -> [SKIP][16] ([Intel XE#2887]) +2 other tests skip
[16]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_ccs@random-ccs-data-y-tiled-gen12-mc-ccs.html
* igt@kms_chamelium_color@ctm-0-25:
- shard-lnl: NOTRUN -> [SKIP][17] ([Intel XE#306] / [Intel XE#7358])
[17]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_chamelium_color@ctm-0-25.html
* igt@kms_chamelium_edid@dp-edid-read:
- shard-bmg: NOTRUN -> [SKIP][18] ([Intel XE#2252])
[18]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_chamelium_edid@dp-edid-read.html
* igt@kms_chamelium_frames@dp-crc-fast:
- shard-lnl: NOTRUN -> [SKIP][19] ([Intel XE#373])
[19]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_chamelium_frames@dp-crc-fast.html
* igt@kms_color@ctm-blue-to-red:
- shard-lnl: [PASS][20] -> [SKIP][21] ([Intel XE#3297])
[20]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_color@ctm-blue-to-red.html
[21]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_color@ctm-blue-to-red.html
* igt@kms_color@deep-color:
- shard-lnl: [PASS][22] -> [SKIP][23] ([Intel XE#1511] / [Intel XE#3297])
[22]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_color@deep-color.html
[23]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_color@deep-color.html
* igt@kms_color_pipeline@plane-ctm3x4-lut1d:
- shard-lnl: [PASS][24] -> [SKIP][25] ([Intel XE#7006]) +1 other test skip
[24]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_color_pipeline@plane-ctm3x4-lut1d.html
[25]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_color_pipeline@plane-ctm3x4-lut1d.html
* igt@kms_content_protection@srm@pipe-a-dp-2:
- shard-bmg: NOTRUN -> [FAIL][26] ([Intel XE#1178] / [Intel XE#3304] / [Intel XE#7374]) +1 other test fail
[26]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@kms_content_protection@srm@pipe-a-dp-2.html
* igt@kms_cursor_crc@cursor-offscreen-32x10:
- shard-bmg: NOTRUN -> [SKIP][27] ([Intel XE#2320]) +1 other test skip
[27]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_cursor_crc@cursor-offscreen-32x10.html
* igt@kms_cursor_crc@cursor-sliding-32x32:
- shard-lnl: NOTRUN -> [SKIP][28] ([Intel XE#1424]) +1 other test skip
[28]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_cursor_crc@cursor-sliding-32x32.html
* igt@kms_cursor_legacy@flip-vs-cursor-legacy:
- shard-lnl: [PASS][29] -> [SKIP][30] ([Intel XE#9125]) +28 other tests skip
[29]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html
[30]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html
- shard-bmg: [PASS][31] -> [FAIL][32] ([Intel XE#7809])
[31]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-4/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html
[32]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-7/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html
* igt@kms_dp_aux_dev@basic:
- shard-lnl: [PASS][33] -> [SKIP][34] ([Intel XE#3009])
[33]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_dp_aux_dev@basic.html
[34]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_dp_aux_dev@basic.html
* igt@kms_dsc@dsc-with-bpc-formats-bigjoiner:
- shard-lnl: NOTRUN -> [SKIP][35] ([Intel XE#8265])
[35]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_dsc@dsc-with-bpc-formats-bigjoiner.html
* igt@kms_fbcon_fbt@fbc:
- shard-bmg: NOTRUN -> [SKIP][36] ([Intel XE#4156] / [Intel XE#7425])
[36]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_fbcon_fbt@fbc.html
* igt@kms_fbcon_fbt@psr:
- shard-lnl: [PASS][37] -> [SKIP][38] ([Intel XE#8680])
[37]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_fbcon_fbt@psr.html
[38]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_fbcon_fbt@psr.html
* igt@kms_feature_discovery@display-2x:
- shard-lnl: NOTRUN -> [SKIP][39] ([Intel XE#702] / [Intel XE#7344])
[39]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_feature_discovery@display-2x.html
* igt@kms_feature_discovery@vrr:
- shard-bmg: NOTRUN -> [SKIP][40] ([Intel XE#8586])
[40]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_feature_discovery@vrr.html
* igt@kms_flip@flip-vs-expired-vblank@a-edp1:
- shard-lnl: [PASS][41] -> [FAIL][42] ([Intel XE#301])
[41]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html
[42]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html
* igt@kms_flip@flip-vs-expired-vblank@c-edp1:
- shard-lnl: [PASS][43] -> [FAIL][44] ([Intel XE#301] / [Intel XE#3149]) +1 other test fail
[43]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_flip@flip-vs-expired-vblank@c-edp1.html
[44]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_flip@flip-vs-expired-vblank@c-edp1.html
* igt@kms_flip@flip-vs-rmfb:
- shard-lnl: [PASS][45] -> [SKIP][46] ([Intel XE#2482]) +7 other tests skip
[45]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_flip@flip-vs-rmfb.html
[46]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_flip@flip-vs-rmfb.html
* igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-downscaling:
- shard-lnl: NOTRUN -> [SKIP][47] ([Intel XE#7178] / [Intel XE#7351])
[47]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-downscaling.html
* igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tile-upscaling:
- shard-lnl: [PASS][48] -> [SKIP][49] ([Intel XE#1745])
[48]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tile-upscaling.html
[49]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tile-upscaling.html
* igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling:
- shard-bmg: NOTRUN -> [SKIP][50] ([Intel XE#7178] / [Intel XE#7351])
[50]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling.html
* igt@kms_frontbuffer_tracking@drrs-indfb-scaledprimary:
- shard-lnl: NOTRUN -> [SKIP][51] ([Intel XE#6312] / [Intel XE#651]) +1 other test skip
[51]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_frontbuffer_tracking@drrs-indfb-scaledprimary.html
* igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-wc:
- shard-bmg: NOTRUN -> [SKIP][52] ([Intel XE#4141]) +1 other test skip
[52]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-fullscreen:
- shard-lnl: [PASS][53] -> [SKIP][54] ([Intel XE#2548] / [Intel XE#7779]) +9 other tests skip
[53]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-fullscreen.html
[54]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-fullscreen.html
* igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-offscreen-pri-indfb-draw-render:
- shard-lnl: NOTRUN -> [SKIP][55] ([Intel XE#6312]) +3 other tests skip
[55]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-offscreen-pri-indfb-draw-render.html
* igt@kms_frontbuffer_tracking@fbcdrrshdr-2p-scndscrn-cur-indfb-draw-mmap-wc:
- shard-lnl: NOTRUN -> [SKIP][56] ([Intel XE#7905]) +6 other tests skip
[56]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_frontbuffer_tracking@fbcdrrshdr-2p-scndscrn-cur-indfb-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@fbcdrrshdr-2p-scndscrn-spr-indfb-draw-mmap-wc:
- shard-bmg: NOTRUN -> [SKIP][57] ([Intel XE#2311]) +11 other tests skip
[57]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_frontbuffer_tracking@fbcdrrshdr-2p-scndscrn-spr-indfb-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@fbcpsrhdr-abgr161616f-draw-blt:
- shard-bmg: NOTRUN -> [SKIP][58] ([Intel XE#7061])
[58]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_frontbuffer_tracking@fbcpsrhdr-abgr161616f-draw-blt.html
* igt@kms_frontbuffer_tracking@fbcpsrhdr-slowdraw:
- shard-lnl: NOTRUN -> [SKIP][59] ([Intel XE#7865])
[59]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_frontbuffer_tracking@fbcpsrhdr-slowdraw.html
* igt@kms_frontbuffer_tracking@hdr-1p-pri-indfb-multidraw:
- shard-bmg: [PASS][60] -> [DMESG-WARN][61] ([Intel XE#7774])
[60]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-7/igt@kms_frontbuffer_tracking@hdr-1p-pri-indfb-multidraw.html
[61]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@kms_frontbuffer_tracking@hdr-1p-pri-indfb-multidraw.html
* igt@kms_frontbuffer_tracking@psr-1p-offscreen-pri-shrfb-draw-render:
- shard-lnl: [PASS][62] -> [SKIP][63] ([Intel XE#7779])
[62]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_frontbuffer_tracking@psr-1p-offscreen-pri-shrfb-draw-render.html
[63]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@psr-1p-offscreen-pri-shrfb-draw-render.html
* igt@kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-move:
- shard-lnl: NOTRUN -> [SKIP][64] ([Intel XE#656] / [Intel XE#7905]) +3 other tests skip
[64]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-move.html
* igt@kms_frontbuffer_tracking@psrhdr-rgb565-draw-render:
- shard-bmg: NOTRUN -> [SKIP][65] ([Intel XE#2313]) +8 other tests skip
[65]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_frontbuffer_tracking@psrhdr-rgb565-draw-render.html
* igt@kms_joiner@basic-force-ultra-joiner:
- shard-lnl: NOTRUN -> [SKIP][66] ([Intel XE#6900] / [Intel XE#7362])
[66]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_joiner@basic-force-ultra-joiner.html
* igt@kms_pipe_stress@stress-xrgb8888-ytiled:
- shard-lnl: NOTRUN -> [SKIP][67] ([Intel XE#4329] / [Intel XE#6912] / [Intel XE#7375])
[67]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_pipe_stress@stress-xrgb8888-ytiled.html
* igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-modifier:
- shard-lnl: NOTRUN -> [SKIP][68] ([Intel XE#7283]) +1 other test skip
[68]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-modifier.html
* igt@kms_plane@pixel-format-4-tiled-mtl-rc-ccs-modifier:
- shard-bmg: NOTRUN -> [SKIP][69] ([Intel XE#7283])
[69]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@kms_plane@pixel-format-4-tiled-mtl-rc-ccs-modifier.html
* igt@kms_plane_multiple@2x-tiling-none:
- shard-bmg: [PASS][70] -> [INCOMPLETE][71] ([Intel XE#6819]) +1 other test incomplete
[70]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-4/igt@kms_plane_multiple@2x-tiling-none.html
[71]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-3/igt@kms_plane_multiple@2x-tiling-none.html
* igt@kms_plane_scaling@plane-downscale-factor-0-75-with-modifiers@pipe-a:
- shard-lnl: [PASS][72] -> [SKIP][73] ([Intel XE#2763] / [Intel XE#6886]) +3 other tests skip
[72]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_plane_scaling@plane-downscale-factor-0-75-with-modifiers@pipe-a.html
[73]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_plane_scaling@plane-downscale-factor-0-75-with-modifiers@pipe-a.html
* igt@kms_plane_scaling@planes-upscale-factor-0-25:
- shard-lnl: [PASS][74] -> [SKIP][75] ([Intel XE#2763] / [Intel XE#6886] / [Intel XE#7687] / [Intel XE#9125]) +3 other tests skip
[74]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_plane_scaling@planes-upscale-factor-0-25.html
[75]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_plane_scaling@planes-upscale-factor-0-25.html
* igt@kms_pm_backlight@basic-brightness:
- shard-lnl: [PASS][76] -> [SKIP][77] ([Intel XE#870])
[76]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_pm_backlight@basic-brightness.html
[77]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_pm_backlight@basic-brightness.html
* igt@kms_pm_dc@dc5-psr:
- shard-bmg: NOTRUN -> [SKIP][78] ([Intel XE#7794])
[78]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_pm_dc@dc5-psr.html
* igt@kms_pm_rpm@drm-resources-equal:
- shard-lnl: [PASS][79] -> [SKIP][80] ([Intel XE#7106])
[79]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_pm_rpm@drm-resources-equal.html
[80]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_pm_rpm@drm-resources-equal.html
* igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-continuous-sf@pipe-a-edp-1:
- shard-lnl: NOTRUN -> [SKIP][81] ([Intel XE#4608])
[81]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-continuous-sf@pipe-a-edp-1.html
* igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-continuous-sf@pipe-b-edp-1:
- shard-lnl: NOTRUN -> [SKIP][82] ([Intel XE#4608] / [Intel XE#7304])
[82]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-continuous-sf@pipe-b-edp-1.html
* igt@kms_psr2_sf@fbc-psr2-plane-move-sf-dmg-area:
- shard-bmg: NOTRUN -> [SKIP][83] ([Intel XE#1489]) +2 other tests skip
[83]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@kms_psr2_sf@fbc-psr2-plane-move-sf-dmg-area.html
* igt@kms_psr2_sf@pr-plane-move-sf-dmg-area:
- shard-lnl: NOTRUN -> [SKIP][84] ([Intel XE#2893] / [Intel XE#7304])
[84]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_psr2_sf@pr-plane-move-sf-dmg-area.html
* igt@kms_psr2_sf@psr2-primary-plane-update-sf-dmg-area:
- shard-lnl: [PASS][85] -> [SKIP][86] ([Intel XE#1489])
[85]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_psr2_sf@psr2-primary-plane-update-sf-dmg-area.html
[86]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_psr2_sf@psr2-primary-plane-update-sf-dmg-area.html
* igt@kms_psr@fbc-psr2-primary-page-flip:
- shard-lnl: NOTRUN -> [SKIP][87] ([Intel XE#1406] / [Intel XE#7345])
[87]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_psr@fbc-psr2-primary-page-flip.html
* igt@kms_psr@fbc-psr2-primary-page-flip@edp-1:
- shard-lnl: NOTRUN -> [SKIP][88] ([Intel XE#1406] / [Intel XE#4609] / [Intel XE#7345])
[88]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_psr@fbc-psr2-primary-page-flip@edp-1.html
* igt@kms_psr@pr-dpms:
- shard-lnl: NOTRUN -> [SKIP][89] ([Intel XE#1406])
[89]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@kms_psr@pr-dpms.html
* igt@kms_psr@psr2-primary-page-flip:
- shard-bmg: NOTRUN -> [SKIP][90] ([Intel XE#2234] / [Intel XE#2850]) +2 other tests skip
[90]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@kms_psr@psr2-primary-page-flip.html
* igt@kms_psr@psr2-sprite-plane-onoff:
- shard-lnl: [PASS][91] -> [SKIP][92] ([Intel XE#2850] / [Intel XE#929]) +3 other tests skip
[91]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_psr@psr2-sprite-plane-onoff.html
[92]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_psr@psr2-sprite-plane-onoff.html
* igt@kms_rotation_crc@primary-y-tiled-reflect-x-180:
- shard-bmg: NOTRUN -> [SKIP][93] ([Intel XE#2330] / [Intel XE#5813])
[93]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_rotation_crc@primary-y-tiled-reflect-x-180.html
* igt@kms_sharpness_filter@invalid-filter-with-nearest-neighbor:
- shard-bmg: NOTRUN -> [SKIP][94] ([Intel XE#6503])
[94]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_sharpness_filter@invalid-filter-with-nearest-neighbor.html
* igt@kms_vrr@flip-dpms:
- shard-bmg: NOTRUN -> [SKIP][95] ([Intel XE#1499]) +1 other test skip
[95]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@kms_vrr@flip-dpms.html
* igt@runner@aborted:
- shard-lnl: NOTRUN -> [FAIL][96] ([Intel XE#8990])
[96]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-5/igt@runner@aborted.html
* igt@sriov_basic@pf-unbind-with-vfs-enabled-numvfs-all:
- shard-bmg: NOTRUN -> [ABORT][97] ([Intel XE#8868])
[97]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@sriov_basic@pf-unbind-with-vfs-enabled-numvfs-all.html
* igt@xe_evict@evict-beng-mixed-many-threads-small:
- shard-bmg: [PASS][98] -> [INCOMPLETE][99] ([Intel XE#6321] / [Intel XE#8355])
[98]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-5/igt@xe_evict@evict-beng-mixed-many-threads-small.html
[99]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@xe_evict@evict-beng-mixed-many-threads-small.html
* igt@xe_evict@evict-beng-threads-large-multi-vm:
- shard-lnl: NOTRUN -> [SKIP][100] ([Intel XE#6540] / [Intel XE#688]) +2 other tests skip
[100]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_evict@evict-beng-threads-large-multi-vm.html
* igt@xe_exec_balancer@no-exec-cm-parallel-userptr-invalidate-race:
- shard-lnl: NOTRUN -> [SKIP][101] ([Intel XE#7482]) +3 other tests skip
[101]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_exec_balancer@no-exec-cm-parallel-userptr-invalidate-race.html
* igt@xe_exec_basic@multigpu-many-execqueues-many-vm-basic-defer-mmap:
- shard-bmg: NOTRUN -> [SKIP][102] ([Intel XE#2322] / [Intel XE#7372]) +1 other test skip
[102]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_exec_basic@multigpu-many-execqueues-many-vm-basic-defer-mmap.html
* igt@xe_exec_fault_mode@many-multi-queue-invalid-fault:
- shard-bmg: NOTRUN -> [SKIP][103] ([Intel XE#8374]) +3 other tests skip
[103]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_exec_fault_mode@many-multi-queue-invalid-fault.html
* igt@xe_exec_fault_mode@twice-multi-queue-invalid-fault:
- shard-lnl: NOTRUN -> [SKIP][104] ([Intel XE#8374])
[104]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_exec_fault_mode@twice-multi-queue-invalid-fault.html
* igt@xe_exec_multi_queue@few-execs-preempt-mode-close-fd:
- shard-lnl: NOTRUN -> [SKIP][105] ([Intel XE#8364]) +4 other tests skip
[105]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_exec_multi_queue@few-execs-preempt-mode-close-fd.html
* igt@xe_exec_multi_queue@max-queues-preempt-mode-priority-smem:
- shard-bmg: NOTRUN -> [SKIP][106] ([Intel XE#8364]) +5 other tests skip
[106]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_exec_multi_queue@max-queues-preempt-mode-priority-smem.html
* igt@xe_exec_system_allocator@pat-index-madvise-pat-idx-uc-comp-single-vma:
- shard-lnl: NOTRUN -> [SKIP][107] ([Intel XE#6196])
[107]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_exec_system_allocator@pat-index-madvise-pat-idx-uc-comp-single-vma.html
* igt@xe_exec_threads@threads-multi-queue-cm-userptr-invalidate:
- shard-bmg: NOTRUN -> [SKIP][108] ([Intel XE#8378])
[108]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_exec_threads@threads-multi-queue-cm-userptr-invalidate.html
* igt@xe_exec_threads@threads-multi-queue-mixed-userptr:
- shard-lnl: NOTRUN -> [SKIP][109] ([Intel XE#8378]) +1 other test skip
[109]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_exec_threads@threads-multi-queue-mixed-userptr.html
* igt@xe_fault_injection@inject-fault-probe-function-xe_ggtt_init_early:
- shard-bmg: [PASS][110] -> [ABORT][111] ([Intel XE#8007]) +21 other tests abort
[110]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-1/igt@xe_fault_injection@inject-fault-probe-function-xe_ggtt_init_early.html
[111]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-6/igt@xe_fault_injection@inject-fault-probe-function-xe_ggtt_init_early.html
* igt@xe_mmap@pci-membarrier-bad-object:
- shard-lnl: NOTRUN -> [SKIP][112] ([Intel XE#5100] / [Intel XE#7322] / [Intel XE#7408])
[112]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_mmap@pci-membarrier-bad-object.html
* igt@xe_multigpu_svm@mgpu-xgpu-access-prefetch:
- shard-bmg: NOTRUN -> [SKIP][113] ([Intel XE#6964])
[113]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@xe_multigpu_svm@mgpu-xgpu-access-prefetch.html
* igt@xe_pm@d3cold-basic-exec:
- shard-bmg: NOTRUN -> [SKIP][114] ([Intel XE#2284] / [Intel XE#7370])
[114]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@xe_pm@d3cold-basic-exec.html
* igt@xe_pm@s2idle-basic-exec:
- shard-lnl: NOTRUN -> [ABORT][115] ([Intel XE#8007])
[115]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_pm@s2idle-basic-exec.html
* igt@xe_pm@s2idle-exec-after:
- shard-bmg: NOTRUN -> [ABORT][116] ([Intel XE#8007]) +2 other tests abort
[116]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@xe_pm@s2idle-exec-after.html
* igt@xe_query@multigpu-query-hwconfig:
- shard-bmg: NOTRUN -> [SKIP][117] ([Intel XE#944])
[117]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_query@multigpu-query-hwconfig.html
* igt@xe_query@multigpu-query-topology:
- shard-lnl: NOTRUN -> [SKIP][118] ([Intel XE#944])
[118]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_query@multigpu-query-topology.html
* igt@xe_sriov_admin@bulk-sched-priority-vfs-disabled:
- shard-lnl: NOTRUN -> [SKIP][119] ([Intel XE#7174])
[119]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_sriov_admin@bulk-sched-priority-vfs-disabled.html
#### Possible fixes ####
* igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-d-dp-2:
- shard-bmg: [INCOMPLETE][120] ([Intel XE#7084] / [Intel XE#8150]) -> [PASS][121]
[120]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-3/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-d-dp-2.html
[121]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-10/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-d-dp-2.html
* igt@kms_frontbuffer_tracking@psr-shrfb-scaledprimary:
- shard-lnl: [SKIP][122] ([Intel XE#2548] / [Intel XE#7779]) -> [PASS][123] +1 other test pass
[122]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_frontbuffer_tracking@psr-shrfb-scaledprimary.html
[123]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_frontbuffer_tracking@psr-shrfb-scaledprimary.html
* igt@kms_plane_scaling@invalid-num-scalers:
- shard-lnl: [SKIP][124] ([Intel XE#3307] / [Intel XE#7687] / [Intel XE#9125]) -> [PASS][125]
[124]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_plane_scaling@invalid-num-scalers.html
[125]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@kms_plane_scaling@invalid-num-scalers.html
* igt@kms_sharpness_filter@filter-suspend:
- shard-lnl: [SKIP][126] ([Intel XE#9125]) -> [PASS][127] +6 other tests pass
[126]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_sharpness_filter@filter-suspend.html
[127]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_sharpness_filter@filter-suspend.html
* igt@xe_fault_injection@vm-create-fail-xe_vm_create_scratch:
- shard-bmg: [ABORT][128] ([Intel XE#8007]) -> [PASS][129] +2 other tests pass
[128]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-5/igt@xe_fault_injection@vm-create-fail-xe_vm_create_scratch.html
[129]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@xe_fault_injection@vm-create-fail-xe_vm_create_scratch.html
* igt@xe_live_ktest@xe_eudebug:
- shard-lnl: [SKIP][130] ([Intel XE#2833]) -> [PASS][131]
[130]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@xe_live_ktest@xe_eudebug.html
[131]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@xe_live_ktest@xe_eudebug.html
- shard-bmg: [SKIP][132] ([Intel XE#2833]) -> [PASS][133]
[132]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-1/igt@xe_live_ktest@xe_eudebug.html
[133]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-6/igt@xe_live_ktest@xe_eudebug.html
* igt@xe_module_load@load:
- shard-bmg: ([PASS][134], [PASS][135], [PASS][136], [PASS][137], [PASS][138], [PASS][139], [SKIP][140], [PASS][141], [PASS][142], [PASS][143], [PASS][144], [PASS][145], [PASS][146], [PASS][147], [PASS][148], [PASS][149], [PASS][150], [PASS][151], [PASS][152], [PASS][153], [PASS][154], [PASS][155], [PASS][156], [PASS][157], [PASS][158], [PASS][159]) ([Intel XE#2457] / [Intel XE#7405]) -> ([PASS][160], [PASS][161], [PASS][162], [PASS][163], [PASS][164], [PASS][165], [PASS][166], [PASS][167], [PASS][168], [PASS][169], [PASS][170], [PASS][171], [PASS][172], [PASS][173], [PASS][174], [PASS][175], [PASS][176], [PASS][177], [PASS][178], [PASS][179], [PASS][180], [PASS][181], [PASS][182], [PASS][183], [PASS][184])
[134]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-10/igt@xe_module_load@load.html
[135]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-5/igt@xe_module_load@load.html
[136]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-5/igt@xe_module_load@load.html
[137]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-10/igt@xe_module_load@load.html
[138]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-3/igt@xe_module_load@load.html
[139]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-5/igt@xe_module_load@load.html
[140]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-4/igt@xe_module_load@load.html
[141]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-3/igt@xe_module_load@load.html
[142]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-7/igt@xe_module_load@load.html
[143]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-7/igt@xe_module_load@load.html
[144]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-4/igt@xe_module_load@load.html
[145]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-4/igt@xe_module_load@load.html
[146]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-4/igt@xe_module_load@load.html
[147]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-8/igt@xe_module_load@load.html
[148]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-8/igt@xe_module_load@load.html
[149]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-6/igt@xe_module_load@load.html
[150]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-6/igt@xe_module_load@load.html
[151]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-2/igt@xe_module_load@load.html
[152]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-2/igt@xe_module_load@load.html
[153]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-2/igt@xe_module_load@load.html
[154]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-1/igt@xe_module_load@load.html
[155]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-1/igt@xe_module_load@load.html
[156]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-9/igt@xe_module_load@load.html
[157]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-9/igt@xe_module_load@load.html
[158]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-9/igt@xe_module_load@load.html
[159]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-1/igt@xe_module_load@load.html
[160]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-3/igt@xe_module_load@load.html
[161]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-7/igt@xe_module_load@load.html
[162]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-6/igt@xe_module_load@load.html
[163]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@xe_module_load@load.html
[164]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@xe_module_load@load.html
[165]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-1/igt@xe_module_load@load.html
[166]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-3/igt@xe_module_load@load.html
[167]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-10/igt@xe_module_load@load.html
[168]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-3/igt@xe_module_load@load.html
[169]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-10/igt@xe_module_load@load.html
[170]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_module_load@load.html
[171]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-2/igt@xe_module_load@load.html
[172]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-2/igt@xe_module_load@load.html
[173]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-9/igt@xe_module_load@load.html
[174]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@xe_module_load@load.html
[175]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@xe_module_load@load.html
[176]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-8/igt@xe_module_load@load.html
[177]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-10/igt@xe_module_load@load.html
[178]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-8/igt@xe_module_load@load.html
[179]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-7/igt@xe_module_load@load.html
[180]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-7/igt@xe_module_load@load.html
[181]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-8/igt@xe_module_load@load.html
[182]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_module_load@load.html
[183]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-4/igt@xe_module_load@load.html
[184]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-6/igt@xe_module_load@load.html
#### Warnings ####
* igt@kms_big_fb@4-tiled-8bpp-rotate-90:
- shard-lnl: [SKIP][185] ([Intel XE#1407]) -> [SKIP][186] ([Intel XE#9125]) +1 other test skip
[185]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_big_fb@4-tiled-8bpp-rotate-90.html
[186]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_big_fb@4-tiled-8bpp-rotate-90.html
* igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-180-hflip:
- shard-lnl: [SKIP][187] ([Intel XE#7059] / [Intel XE#7085]) -> [SKIP][188] ([Intel XE#9125])
[187]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-180-hflip.html
[188]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-180-hflip.html
* igt@kms_big_fb@x-tiled-32bpp-rotate-90:
- shard-lnl: [SKIP][189] ([Intel XE#9125]) -> [SKIP][190] ([Intel XE#1407])
[189]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_big_fb@x-tiled-32bpp-rotate-90.html
[190]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@kms_big_fb@x-tiled-32bpp-rotate-90.html
* igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip:
- shard-lnl: [SKIP][191] ([Intel XE#1124]) -> [SKIP][192] ([Intel XE#9125]) +5 other tests skip
[191]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html
[192]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html
* igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip:
- shard-lnl: [SKIP][193] ([Intel XE#9125]) -> [SKIP][194] ([Intel XE#1124])
[193]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip.html
[194]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip.html
* igt@kms_bw@connected-linear-tiling-2-displays-target-2560x1440p:
- shard-lnl: [SKIP][195] ([Intel XE#7679]) -> [SKIP][196] ([Intel XE#9125]) +1 other test skip
[195]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_bw@connected-linear-tiling-2-displays-target-2560x1440p.html
[196]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_bw@connected-linear-tiling-2-displays-target-2560x1440p.html
* igt@kms_ccs@crc-primary-basic-4-tiled-bmg-ccs:
- shard-lnl: [SKIP][197] ([Intel XE#2669] / [Intel XE#7389]) -> [SKIP][198] ([Intel XE#9125])
[197]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_ccs@crc-primary-basic-4-tiled-bmg-ccs.html
[198]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_ccs@crc-primary-basic-4-tiled-bmg-ccs.html
* igt@kms_ccs@crc-primary-rotation-180-4-tiled-dg2-mc-ccs:
- shard-lnl: [SKIP][199] ([Intel XE#9125]) -> [SKIP][200] ([Intel XE#2887])
[199]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_ccs@crc-primary-rotation-180-4-tiled-dg2-mc-ccs.html
[200]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_ccs@crc-primary-rotation-180-4-tiled-dg2-mc-ccs.html
* igt@kms_ccs@missing-ccs-buffer-y-tiled-gen12-rc-ccs-cc:
- shard-lnl: [SKIP][201] ([Intel XE#2887]) -> [SKIP][202] ([Intel XE#9125]) +10 other tests skip
[201]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_ccs@missing-ccs-buffer-y-tiled-gen12-rc-ccs-cc.html
[202]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_ccs@missing-ccs-buffer-y-tiled-gen12-rc-ccs-cc.html
* igt@kms_content_protection@dp-mst-type-1:
- shard-lnl: [SKIP][203] ([Intel XE#307] / [Intel XE#6974]) -> [SKIP][204] ([Intel XE#9125])
[203]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_content_protection@dp-mst-type-1.html
[204]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_content_protection@dp-mst-type-1.html
* igt@kms_content_protection@srm:
- shard-lnl: [SKIP][205] ([Intel XE#7642]) -> [SKIP][206] ([Intel XE#9125])
[205]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_content_protection@srm.html
[206]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_content_protection@srm.html
* igt@kms_content_protection@type1:
- shard-lnl: [SKIP][207] ([Intel XE#9125]) -> [SKIP][208] ([Intel XE#7642])
[207]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_content_protection@type1.html
[208]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_content_protection@type1.html
* igt@kms_cursor_crc@cursor-onscreen-512x512:
- shard-lnl: [SKIP][209] ([Intel XE#2321] / [Intel XE#7355]) -> [SKIP][210] ([Intel XE#9125]) +1 other test skip
[209]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_cursor_crc@cursor-onscreen-512x512.html
[210]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_cursor_crc@cursor-onscreen-512x512.html
* igt@kms_cursor_crc@cursor-rapid-movement-256x85:
- shard-lnl: [SKIP][211] ([Intel XE#1424]) -> [SKIP][212] ([Intel XE#9125]) +3 other tests skip
[211]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_cursor_crc@cursor-rapid-movement-256x85.html
[212]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_cursor_crc@cursor-rapid-movement-256x85.html
* igt@kms_cursor_legacy@2x-flip-vs-cursor-atomic:
- shard-lnl: [SKIP][213] ([Intel XE#309] / [Intel XE#7343]) -> [SKIP][214] ([Intel XE#9125]) +1 other test skip
[213]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_cursor_legacy@2x-flip-vs-cursor-atomic.html
[214]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_cursor_legacy@2x-flip-vs-cursor-atomic.html
* igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions:
- shard-lnl: [SKIP][215] ([Intel XE#323] / [Intel XE#6035]) -> [SKIP][216] ([Intel XE#9125])
[215]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions.html
[216]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions.html
* igt@kms_dsc@dsc-fractional-bpp-with-bpc:
- shard-lnl: [SKIP][217] ([Intel XE#8265]) -> [SKIP][218] ([Intel XE#9125]) +1 other test skip
[217]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_dsc@dsc-fractional-bpp-with-bpc.html
[218]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_dsc@dsc-fractional-bpp-with-bpc.html
* igt@kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling:
- shard-lnl: [SKIP][219] ([Intel XE#1397] / [Intel XE#1745] / [Intel XE#7385]) -> [SKIP][220] ([Intel XE#1745])
[219]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling.html
[220]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_flip_scaled_crc@flip-64bpp-linear-to-32bpp-linear-downscaling.html
* igt@kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-render:
- shard-lnl: [SKIP][221] ([Intel XE#2548] / [Intel XE#7779]) -> [SKIP][222] ([Intel XE#6312] / [Intel XE#651]) +2 other tests skip
[221]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-render.html
[222]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@kms_frontbuffer_tracking@drrs-1p-primscrn-spr-indfb-draw-render.html
* igt@kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-render:
- shard-lnl: [SKIP][223] ([Intel XE#656] / [Intel XE#7905]) -> [SKIP][224] ([Intel XE#2548] / [Intel XE#7779]) +22 other tests skip
[223]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-render.html
[224]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@drrs-2p-scndscrn-spr-indfb-draw-render.html
* igt@kms_frontbuffer_tracking@fbc-argb161616f-draw-mmap-wc:
- shard-lnl: [SKIP][225] ([Intel XE#7779]) -> [SKIP][226] ([Intel XE#7061] / [Intel XE#7356]) +1 other test skip
[225]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_frontbuffer_tracking@fbc-argb161616f-draw-mmap-wc.html
[226]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@kms_frontbuffer_tracking@fbc-argb161616f-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-indfb-msflip-blt:
- shard-lnl: [SKIP][227] ([Intel XE#6312] / [Intel XE#651]) -> [SKIP][228] ([Intel XE#2548] / [Intel XE#7779]) +7 other tests skip
[227]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-indfb-msflip-blt.html
[228]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-indfb-msflip-blt.html
* igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-primscrn-spr-indfb-onoff:
- shard-lnl: [SKIP][229] ([Intel XE#6312]) -> [SKIP][230] ([Intel XE#7779]) +6 other tests skip
[229]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-primscrn-spr-indfb-onoff.html
[230]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-primscrn-spr-indfb-onoff.html
* igt@kms_frontbuffer_tracking@fbchdr-rgb101010-draw-mmap-wc:
- shard-lnl: [SKIP][231] ([Intel XE#7779]) -> [SKIP][232] ([Intel XE#7865]) +2 other tests skip
[231]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_frontbuffer_tracking@fbchdr-rgb101010-draw-mmap-wc.html
[232]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_frontbuffer_tracking@fbchdr-rgb101010-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-render:
- shard-lnl: [SKIP][233] ([Intel XE#2548] / [Intel XE#7779]) -> [SKIP][234] ([Intel XE#656] / [Intel XE#7905]) +2 other tests skip
[233]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-render.html
[234]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-render.html
* igt@kms_frontbuffer_tracking@fbcpsrhdr-2p-primscrn-spr-indfb-move:
- shard-lnl: [SKIP][235] ([Intel XE#7779]) -> [SKIP][236] ([Intel XE#7905]) +2 other tests skip
[235]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_frontbuffer_tracking@fbcpsrhdr-2p-primscrn-spr-indfb-move.html
[236]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-3/igt@kms_frontbuffer_tracking@fbcpsrhdr-2p-primscrn-spr-indfb-move.html
* igt@kms_frontbuffer_tracking@fbcpsrhdr-2p-scndscrn-indfb-msflip-blt:
- shard-lnl: [SKIP][237] ([Intel XE#7905]) -> [SKIP][238] ([Intel XE#7779]) +26 other tests skip
[237]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_frontbuffer_tracking@fbcpsrhdr-2p-scndscrn-indfb-msflip-blt.html
[238]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@fbcpsrhdr-2p-scndscrn-indfb-msflip-blt.html
* igt@kms_frontbuffer_tracking@fbcpsrhdr-suspend:
- shard-lnl: [SKIP][239] ([Intel XE#7865]) -> [SKIP][240] ([Intel XE#7779]) +13 other tests skip
[239]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_frontbuffer_tracking@fbcpsrhdr-suspend.html
[240]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@fbcpsrhdr-suspend.html
* igt@kms_frontbuffer_tracking@hdr-argb161616f-draw-render:
- shard-lnl: [SKIP][241] ([Intel XE#7061]) -> [SKIP][242] ([Intel XE#7779]) +3 other tests skip
[241]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_frontbuffer_tracking@hdr-argb161616f-draw-render.html
[242]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@hdr-argb161616f-draw-render.html
* igt@kms_frontbuffer_tracking@psr-argb161616f-draw-mmap-wc:
- shard-lnl: [SKIP][243] ([Intel XE#7061] / [Intel XE#7356]) -> [SKIP][244] ([Intel XE#7779])
[243]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_frontbuffer_tracking@psr-argb161616f-draw-mmap-wc.html
[244]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_frontbuffer_tracking@psr-argb161616f-draw-mmap-wc.html
* igt@kms_hdr@invalid-metadata-sizes:
- shard-lnl: [SKIP][245] ([Intel XE#1503]) -> [SKIP][246] ([Intel XE#9125])
[245]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_hdr@invalid-metadata-sizes.html
[246]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_hdr@invalid-metadata-sizes.html
* igt@kms_pipe_stress@stress-xrgb8888-yftiled:
- shard-lnl: [SKIP][247] ([Intel XE#6912] / [Intel XE#7375]) -> [SKIP][248] ([Intel XE#9125])
[247]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_pipe_stress@stress-xrgb8888-yftiled.html
[248]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_pipe_stress@stress-xrgb8888-yftiled.html
* igt@kms_plane_multiple@2x-tiling-y:
- shard-lnl: [SKIP][249] ([Intel XE#4596] / [Intel XE#5854]) -> [SKIP][250] ([Intel XE#9125])
[249]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_plane_multiple@2x-tiling-y.html
[250]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_plane_multiple@2x-tiling-y.html
* igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-c:
- shard-lnl: [SKIP][251] ([Intel XE#2763] / [Intel XE#6886]) -> [SKIP][252] ([Intel XE#2763] / [Intel XE#6886] / [Intel XE#7687] / [Intel XE#9125]) +1 other test skip
[251]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-c.html
[252]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-c.html
* igt@kms_psr2_sf@fbc-pr-overlay-plane-move-continuous-exceed-fully-sf:
- shard-lnl: [SKIP][253] ([Intel XE#2893] / [Intel XE#7304]) -> [SKIP][254] ([Intel XE#1489]) +2 other tests skip
[253]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-2/igt@kms_psr2_sf@fbc-pr-overlay-plane-move-continuous-exceed-fully-sf.html
[254]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_psr2_sf@fbc-pr-overlay-plane-move-continuous-exceed-fully-sf.html
* igt@kms_psr2_sf@fbc-psr2-overlay-plane-move-continuous-sf:
- shard-lnl: [SKIP][255] ([Intel XE#2893] / [Intel XE#4608] / [Intel XE#7304]) -> [SKIP][256] ([Intel XE#1489])
[255]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_psr2_sf@fbc-psr2-overlay-plane-move-continuous-sf.html
[256]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_psr2_sf@fbc-psr2-overlay-plane-move-continuous-sf.html
* igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-continuous-sf:
- shard-lnl: [SKIP][257] ([Intel XE#1489]) -> [SKIP][258] ([Intel XE#2893] / [Intel XE#4608] / [Intel XE#7304])
[257]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-continuous-sf.html
[258]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-continuous-sf.html
* igt@kms_psr2_su@page_flip-nv12:
- shard-lnl: [SKIP][259] ([Intel XE#1128] / [Intel XE#7413]) -> [SKIP][260] ([Intel XE#1122] / [Intel XE#7429])
[259]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_psr2_su@page_flip-nv12.html
[260]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_psr2_su@page_flip-nv12.html
* igt@kms_psr@fbc-psr2-no-drrs:
- shard-lnl: [SKIP][261] ([Intel XE#1406] / [Intel XE#7345]) -> [SKIP][262] ([Intel XE#2850] / [Intel XE#929]) +1 other test skip
[261]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_psr@fbc-psr2-no-drrs.html
[262]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_psr@fbc-psr2-no-drrs.html
* igt@kms_psr@pr-sprite-render:
- shard-lnl: [SKIP][263] ([Intel XE#1406]) -> [SKIP][264] ([Intel XE#2850] / [Intel XE#929]) +1 other test skip
[263]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@kms_psr@pr-sprite-render.html
[264]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_psr@pr-sprite-render.html
* igt@kms_rotation_crc@primary-yf-tiled-reflect-x-90:
- shard-lnl: [SKIP][265] ([Intel XE#3414] / [Intel XE#3904] / [Intel XE#7342]) -> [SKIP][266] ([Intel XE#9125])
[265]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-4/igt@kms_rotation_crc@primary-yf-tiled-reflect-x-90.html
[266]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-6/igt@kms_rotation_crc@primary-yf-tiled-reflect-x-90.html
* igt@kms_tiled_display@basic-test-pattern-with-chamelium:
- shard-lnl: [SKIP][267] ([Intel XE#9125]) -> [SKIP][268] ([Intel XE#362] / [Intel XE#5848])
[267]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-6/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html
[268]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html
- shard-bmg: [SKIP][269] ([Intel XE#2426] / [Intel XE#5848]) -> [SKIP][270] ([Intel XE#2509] / [Intel XE#7437])
[269]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-bmg-7/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html
[270]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-bmg-5/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html
* igt@xe_configfs@survivability-mode:
- shard-lnl: [SKIP][271] ([Intel XE#8428]) -> [ABORT][272] ([Intel XE#8007])
[271]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-3/igt@xe_configfs@survivability-mode.html
[272]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-8/igt@xe_configfs@survivability-mode.html
* igt@xe_exec_reset@gt-reset-fault-injection:
- shard-lnl: [DMESG-WARN][273] ([Intel XE#9130]) -> [ABORT][274] ([Intel XE#8007] / [Intel XE#9140])
[273]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-1/igt@xe_exec_reset@gt-reset-fault-injection.html
[274]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-2/igt@xe_exec_reset@gt-reset-fault-injection.html
* igt@xe_wedged@basic-wedged:
- shard-lnl: [ABORT][275] ([Intel XE#8963]) -> [DMESG-WARN][276] ([Intel XE#8963])
[275]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34/shard-lnl-8/igt@xe_wedged@basic-wedged.html
[276]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/shard-lnl-7/igt@xe_wedged@basic-wedged.html
[Intel XE#1122]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1122
[Intel XE#1124]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1124
[Intel XE#1128]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1128
[Intel XE#1178]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1178
[Intel XE#1397]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1397
[Intel XE#1406]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1406
[Intel XE#1407]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1407
[Intel XE#1424]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1424
[Intel XE#1489]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1489
[Intel XE#1499]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1499
[Intel XE#1503]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1503
[Intel XE#1511]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1511
[Intel XE#1745]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1745
[Intel XE#2134]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2134
[Intel XE#2234]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2234
[Intel XE#2252]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2252
[Intel XE#2284]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2284
[Intel XE#2311]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2311
[Intel XE#2313]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2313
[Intel XE#2320]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2320
[Intel XE#2321]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2321
[Intel XE#2322]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2322
[Intel XE#2330]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2330
[Intel XE#2426]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2426
[Intel XE#2457]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2457
[Intel XE#2482]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2482
[Intel XE#2509]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2509
[Intel XE#2548]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2548
[Intel XE#2669]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2669
[Intel XE#2763]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2763
[Intel XE#2833]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2833
[Intel XE#2850]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2850
[Intel XE#2887]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2887
[Intel XE#2893]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2893
[Intel XE#3009]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3009
[Intel XE#301]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/301
[Intel XE#306]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/306
[Intel XE#307]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/307
[Intel XE#309]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/309
[Intel XE#3149]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3149
[Intel XE#323]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/323
[Intel XE#3279]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3279
[Intel XE#3297]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3297
[Intel XE#3304]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3304
[Intel XE#3307]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3307
[Intel XE#3414]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3414
[Intel XE#3432]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3432
[Intel XE#362]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/362
[Intel XE#373]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/373
[Intel XE#3904]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3904
[Intel XE#4141]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4141
[Intel XE#4156]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4156
[Intel XE#4329]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4329
[Intel XE#4596]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4596
[Intel XE#4608]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4608
[Intel XE#4609]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4609
[Intel XE#5100]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5100
[Intel XE#5813]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5813
[Intel XE#5848]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5848
[Intel XE#5854]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5854
[Intel XE#6035]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6035
[Intel XE#6196]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6196
[Intel XE#6312]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6312
[Intel XE#6321]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6321
[Intel XE#6503]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6503
[Intel XE#651]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/651
[Intel XE#6540]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6540
[Intel XE#656]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/656
[Intel XE#6819]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6819
[Intel XE#688]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/688
[Intel XE#6886]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6886
[Intel XE#6900]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6900
[Intel XE#6912]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6912
[Intel XE#6964]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6964
[Intel XE#6974]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6974
[Intel XE#7006]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7006
[Intel XE#702]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/702
[Intel XE#7059]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7059
[Intel XE#7061]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7061
[Intel XE#7084]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7084
[Intel XE#7085]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7085
[Intel XE#7106]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7106
[Intel XE#7174]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7174
[Intel XE#7178]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7178
[Intel XE#7283]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7283
[Intel XE#7304]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7304
[Intel XE#7322]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7322
[Intel XE#7342]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7342
[Intel XE#7343]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7343
[Intel XE#7344]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7344
[Intel XE#7345]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7345
[Intel XE#7351]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7351
[Intel XE#7355]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7355
[Intel XE#7356]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7356
[Intel XE#7358]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7358
[Intel XE#7362]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7362
[Intel XE#7370]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7370
[Intel XE#7372]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7372
[Intel XE#7374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7374
[Intel XE#7375]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7375
[Intel XE#7385]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7385
[Intel XE#7389]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7389
[Intel XE#7405]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7405
[Intel XE#7408]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7408
[Intel XE#7413]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7413
[Intel XE#7425]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7425
[Intel XE#7429]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7429
[Intel XE#7437]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7437
[Intel XE#7482]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7482
[Intel XE#7642]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7642
[Intel XE#7679]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7679
[Intel XE#7687]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7687
[Intel XE#7774]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7774
[Intel XE#7779]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7779
[Intel XE#7794]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7794
[Intel XE#7809]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7809
[Intel XE#7865]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7865
[Intel XE#7905]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7905
[Intel XE#8007]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8007
[Intel XE#8150]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8150
[Intel XE#8265]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8265
[Intel XE#8355]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8355
[Intel XE#8364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8364
[Intel XE#8374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8374
[Intel XE#8378]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8378
[Intel XE#8428]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8428
[Intel XE#8586]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8586
[Intel XE#8680]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8680
[Intel XE#870]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/870
[Intel XE#8868]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8868
[Intel XE#8963]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8963
[Intel XE#8990]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8990
[Intel XE#9125]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9125
[Intel XE#9130]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9130
[Intel XE#9140]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9140
[Intel XE#929]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/929
[Intel XE#944]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/944
Build changes
-------------
* Linux: xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34 -> xe-pw-173321v1
IGT_9082: 2d61f578d998115259b87f9fa27f597ce11a0c89 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
xe-5686-76a34199970d93cfb3ed5dbbd745c23b6f0cff34: 76a34199970d93cfb3ed5dbbd745c23b6f0cff34
xe-pw-173321v1: 173321v1
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-173321v1/index.html
[-- Attachment #2: Type: text/html, Size: 87007 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread
end of thread, other threads:[~2026-09-04 3:21 UTC | newest]
Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 14:59 [PATCH v10 00/27] Intel Xe GPU Debug Support (eudebug) v10 Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 01/27] drm/xe/eudebug: Introduce eudebug interface Mika Kuoppala
2026-09-03 15:16 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 02/27] drm/xe/eudebug: Add documentation Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 03/27] drm/xe/eudebug: Add connection establishment documentation Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 04/27] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
2026-09-03 15:22 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 05/27] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
2026-09-03 15:14 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 06/27] drm/xe/eudebug: Introduce exec_queue events Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 07/27] drm/xe/eudebug: Mark guc contexts as debuggable Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 08/27] drm/xe: Remove ifdef in DRM_GPUVA_OP_DRIVER svm subop checking Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 09/27] drm/xe: Introduce ADD_DEBUG_DATA and REMOVE_DEBUG_DATA vm bind ops Mika Kuoppala
2026-09-03 15:22 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 10/27] drm/xe/eudebug: Introduce vm bind and vm bind debug data events Mika Kuoppala
2026-09-03 15:26 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 11/27] drm/xe/eudebug: Add ufence events with acks Mika Kuoppala
2026-09-03 15:20 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 12/27] drm/xe/eudebug: Add vm open/pread/pwrite Mika Kuoppala
2026-09-03 15:27 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 13/27] drm/xe/eudebug: Add userptr vm pread/pwrite Mika Kuoppala
2026-09-03 15:24 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 14/27] drm/xe/eudebug: Add hw enablement Mika Kuoppala
2026-09-03 15:15 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 15/27] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
2026-09-03 15:34 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 16/27] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 17/27] drm/xe/eudebug_test: Introduce eudebug live tests Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 18/27] drm/xe: Implement SR-IOV and eudebug exclusivity Mika Kuoppala
2026-09-03 15:32 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 19/27] drm/xe: Add xe_client_debugfs and introduce debug_data file Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 20/27] drm/xe/pagefault: export pagefault queue properties Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 21/27] drm/xe/eudebug: Add read/count/compare helper for eu attention Mika Kuoppala
2026-09-03 15:31 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 22/27] drm/xe/vm: Support for adding null page VMA to VM on request Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 23/27] drm/xe/vm: Add xe_vm_svm_vma_subtract() to carve out a sub-range from an SVM VMA Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 24/27] drm/xe: Support for xe_vma_unbind() Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 25/27] drm/xe: export prep_vma_destroy as xe_vm_prep_vma_destroy Mika Kuoppala
2026-09-03 14:59 ` [PATCH v10 26/27] drm/xe/eudebug: Introduce EU pagefault handling interface Mika Kuoppala
2026-09-03 15:43 ` sashiko-bot
2026-09-03 14:59 ` [PATCH v10 27/27] drm/xe/eudebug: Enable EU pagefault handling Mika Kuoppala
2026-09-03 15:46 ` sashiko-bot
2026-09-03 15:35 ` ✗ CI.checkpatch: warning for Intel Xe GPU Debug Support (eudebug) v10 Patchwork
2026-09-03 15:37 ` ✓ CI.KUnit: success " Patchwork
2026-09-03 15:53 ` ✗ CI.checksparse: warning " Patchwork
2026-09-03 16:17 ` ✓ Xe.CI.BAT: success " Patchwork
2026-09-03 16:30 ` [PATCH v10 00/27] " Rodrigo Vivi
2026-09-04 3:21 ` ✗ Xe.CI.FULL: failure for " Patchwork
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).