intel-xe.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/21] GPU debug support (eudebug)
@ 2024-07-26 14:07 Mika Kuoppala
  2024-07-26 14:07 ` [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors Mika Kuoppala
                   ` (29 more replies)
  0 siblings, 30 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:07 UTC (permalink / raw)
  To: intel-xe; +Cc: Mika Kuoppala

Hi,

We (Intel eudebug kernel team) would like to submit this
patchset to enable debug support for Intel GPU devices.

The aim is to allow Level-Zero + GDB (or some other tool)
to attach to xe driver in order to receive information
about relevant driver resources, hardware events and to allow debug
related hardware control. End goal is full debug capability
of supported Intel hardware, see [4].

Debugger first opens a connection to a device through
drm ioctl with debug target process as a pid. This will
return a dedicated file descriptor used for debugging
for further events and control.

Xe internal resources that are considered essential
to debugger functionality are relayed as events to the
debugger. On debugger connection, all existing resources
are relayed to debugger (discovery) and from that
point onwards, as they are created/destroyed.

uapi is extended to allow an application/lib to provide
debug metadata information. These are relayed as events
to the debugger so it can decode the program state.

Along with the resource and metadata events, an event for
hardware exceptions, called EU attention, is provided.
The debugger, with the assistance of an exception handling
program called System Routine (short: SIP) provided
with the pipeline setup, can determine which specific
EU/thread and instruction encountered the breakpoint
or other exceptions.

EU controlling ioctl interface is also introduced where
debugger can manipulate individual threads of the currently
active workload. This interface enables the debugger to
interrupt all threads on demand, check their current state
and resume them individually.

The intent is to provide a similar but not API compatible
functionality as in out-of-tree i915 debugger support:
https://dgpu-docs.intel.com/driver/gpu-debugging.html

For xe the aim is to have all support merged in upstream,
starting with this series. With Lunarlake being first targetted
hardware.

I have split the events into xe_drm_eudebug.h instead
pushing everything into xe_drm.h, in order to help
distinguish what is controlled by which descriptor.
If it's through the original xe fd, it is in xe_drm.h and
if it's through the opened debugger connection fd, it
is in xe_drm_eudebug.h.

Latest code can be found in:
[1] https://gitlab.freedesktop.org/miku/kernel/-/tree/eudebug-dev

With the associated IGT tests:
[2] https://gitlab.freedesktop.org/cmanszew/igt-gpu-tools/-/tree/eudebug-dev

The user for this uapi:
[3] https://github.com/intel/compute-runtime
Event loop and thread control interaction can be found at:
https://github.com/intel/compute-runtime/tree/master/level_zero/tools/source/debug/linux/xe
And the wrappers in:
https://github.com/intel/compute-runtime/tree/master/shared/source/os_interface/linux/xe
https://github.com/intel/compute-runtime/blob/master/shared/source/os_interface/linux/xe/ioctl_helper_xe_debugger.cpp
Note that the XE support is disabled by default and you will need
NEO_ENABLE_XE_EU_DEBUG_SUPPORT enabled in order to test.

GDB support:
[4]: https://sourceware.org/pipermail/gdb-patches/2024-July/210264.html

Thank you in advance for any comments and insight.


Andrzej Hajda (1):
  drm/xe/eudebug: implement userptr_vma access

Christoph Manszewski (3):
  drm/xe/eudebug: Add vm bind and vm bind ops
  drm/xe/eudebug: Dynamically toggle debugger functionality
  drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test

Dominik Grzegorzek (10):
  drm/xe: Export xe_hw_engine's mmio accessors
  drm/xe: Move and export xe_hw_engine lookup.
  drm/xe/eudebug: Introduce exec_queue events
  drm/xe/eudebug: hw enablement for eudebug
  drm/xe: Add EUDEBUG_ENABLE exec queue property
  drm/xe/eudebug: Introduce per device attention scan worker
  drm/xe/eudebug: Introduce EU control interface
  drm/xe: Debug metadata create/destroy ioctls
  drm/xe: Attach debug metadata to vma
  drm/xe/eudebug: Add debug metadata support for xe_eudebug

Jonathan Cavitt (1):
  drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach

Mika Kuoppala (6):
  drm/xe/eudebug: Introduce eudebug support
  kernel: export ptrace_may_access
  drm/xe/eudebug: Introduce discovery for resources
  drm/xe/eudebug: Add UFENCE events with acks
  drm/xe/eudebug: vm open/pread/pwrite
  drm/xe/eudebug: Implement vm_bind_op discovery

 drivers/gpu/drm/xe/Makefile                  |    5 +-
 drivers/gpu/drm/xe/regs/xe_engine_regs.h     |    8 +
 drivers/gpu/drm/xe/regs/xe_gt_regs.h         |   43 +
 drivers/gpu/drm/xe/tests/xe_eudebug.c        |  170 +
 drivers/gpu/drm/xe/tests/xe_live_test_mod.c  |    2 +
 drivers/gpu/drm/xe/xe_debug_metadata.c       |  125 +
 drivers/gpu/drm/xe/xe_debug_metadata.h       |   25 +
 drivers/gpu/drm/xe/xe_debug_metadata_types.h |   28 +
 drivers/gpu/drm/xe/xe_device.c               |   47 +-
 drivers/gpu/drm/xe/xe_device_types.h         |   45 +
 drivers/gpu/drm/xe/xe_eudebug.c              | 3841 ++++++++++++++++++
 drivers/gpu/drm/xe/xe_eudebug.h              |   51 +
 drivers/gpu/drm/xe/xe_eudebug_types.h        |  326 ++
 drivers/gpu/drm/xe/xe_exec.c                 |    2 +-
 drivers/gpu/drm/xe/xe_exec_queue.c           |   80 +-
 drivers/gpu/drm/xe/xe_exec_queue_types.h     |    7 +
 drivers/gpu/drm/xe/xe_gt_debug.c             |  152 +
 drivers/gpu/drm/xe/xe_gt_debug.h             |   27 +
 drivers/gpu/drm/xe/xe_hw_engine.c            |   39 +-
 drivers/gpu/drm/xe/xe_hw_engine.h            |   11 +
 drivers/gpu/drm/xe/xe_lrc.c                  |   16 +-
 drivers/gpu/drm/xe/xe_lrc.h                  |    4 +-
 drivers/gpu/drm/xe/xe_reg_sr.c               |   21 +-
 drivers/gpu/drm/xe/xe_reg_sr.h               |    4 +-
 drivers/gpu/drm/xe/xe_rtp.c                  |    2 +-
 drivers/gpu/drm/xe/xe_rtp_types.h            |    1 +
 drivers/gpu/drm/xe/xe_sync.c                 |   49 +-
 drivers/gpu/drm/xe/xe_sync.h                 |    8 +-
 drivers/gpu/drm/xe/xe_sync_types.h           |   26 +-
 drivers/gpu/drm/xe/xe_vm.c                   |  227 +-
 drivers/gpu/drm/xe/xe_vm_types.h             |   26 +
 include/uapi/drm/xe_drm.h                    |   96 +-
 include/uapi/drm/xe_drm_eudebug.h            |  226 ++
 kernel/ptrace.c                              |    1 +
 34 files changed, 5655 insertions(+), 86 deletions(-)
 create mode 100644 drivers/gpu/drm/xe/tests/xe_eudebug.c
 create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.c
 create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.h
 create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata_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_types.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 include/uapi/drm/xe_drm_eudebug.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
@ 2024-07-26 14:07 ` Mika Kuoppala
  2024-07-27  5:45   ` Matthew Brost
  2024-08-08 11:04   ` Andi Shyti
  2024-07-26 14:07 ` [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup Mika Kuoppala
                   ` (28 subsequent siblings)
  29 siblings, 2 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:07 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Declare hw engine's mmio accessors in header file.
This is in preparation to use these from eudebug code.

Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/xe/xe_hw_engine.c | 5 ++---
 drivers/gpu/drm/xe/xe_hw_engine.h | 5 +++++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index 07ed9fd28f19..b8c0cfbf8b49 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -274,8 +274,7 @@ static void hw_engine_fini(struct drm_device *drm, void *arg)
 	hwe->gt = NULL;
 }
 
-static void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg,
-				   u32 val)
+void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg, u32 val)
 {
 	xe_gt_assert(hwe->gt, !(reg.addr & hwe->mmio_base));
 	xe_force_wake_assert_held(gt_to_fw(hwe->gt), hwe->domain);
@@ -285,7 +284,7 @@ static void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg,
 	xe_mmio_write32(hwe->gt, reg, val);
 }
 
-static u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg)
+u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg)
 {
 	xe_gt_assert(hwe->gt, !(reg.addr & hwe->mmio_base));
 	xe_force_wake_assert_held(gt_to_fw(hwe->gt), hwe->domain);
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.h b/drivers/gpu/drm/xe/xe_hw_engine.h
index 900c8c991430..08c3a9df7154 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.h
+++ b/drivers/gpu/drm/xe/xe_hw_engine.h
@@ -62,6 +62,11 @@ void xe_hw_engine_print(struct xe_hw_engine *hwe, struct drm_printer *p);
 void xe_hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe);
 
 bool xe_hw_engine_is_reserved(struct xe_hw_engine *hwe);
+
+void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg, u32 val);
+
+u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg);
+
 static inline bool xe_hw_engine_is_valid(struct xe_hw_engine *hwe)
 {
 	return hwe->name;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup.
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
  2024-07-26 14:07 ` [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors Mika Kuoppala
@ 2024-07-26 14:07 ` Mika Kuoppala
  2024-07-27  5:49   ` Matthew Brost
  2024-08-08 11:08   ` Andi Shyti
  2024-07-26 14:08 ` [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support Mika Kuoppala
                   ` (27 subsequent siblings)
  29 siblings, 2 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:07 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Move and export xe_hw_engine lookup. This is in preparation
to use this in eudebug code where we want to find active
engine.

v2: s/tile/gt due to uapi changes (Mika)

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 | 37 ++++--------------------------
 drivers/gpu/drm/xe/xe_hw_engine.c  | 31 +++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_hw_engine.h  |  6 +++++
 3 files changed, 41 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index 69867a7b7c77..956dc15b432a 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -413,34 +413,6 @@ static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue
 	return 0;
 }
 
-static const enum xe_engine_class user_to_xe_engine_class[] = {
-	[DRM_XE_ENGINE_CLASS_RENDER] = XE_ENGINE_CLASS_RENDER,
-	[DRM_XE_ENGINE_CLASS_COPY] = XE_ENGINE_CLASS_COPY,
-	[DRM_XE_ENGINE_CLASS_VIDEO_DECODE] = XE_ENGINE_CLASS_VIDEO_DECODE,
-	[DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE] = XE_ENGINE_CLASS_VIDEO_ENHANCE,
-	[DRM_XE_ENGINE_CLASS_COMPUTE] = XE_ENGINE_CLASS_COMPUTE,
-};
-
-static struct xe_hw_engine *
-find_hw_engine(struct xe_device *xe,
-	       struct drm_xe_engine_class_instance eci)
-{
-	u32 idx;
-
-	if (eci.engine_class >= ARRAY_SIZE(user_to_xe_engine_class))
-		return NULL;
-
-	if (eci.gt_id >= xe->info.gt_count)
-		return NULL;
-
-	idx = array_index_nospec(eci.engine_class,
-				 ARRAY_SIZE(user_to_xe_engine_class));
-
-	return xe_gt_hw_engine(xe_device_get_gt(xe, eci.gt_id),
-			       user_to_xe_engine_class[idx],
-			       eci.engine_instance, true);
-}
-
 static u32 bind_exec_queue_logical_mask(struct xe_device *xe, struct xe_gt *gt,
 					struct drm_xe_engine_class_instance *eci,
 					u16 width, u16 num_placements)
@@ -462,8 +434,7 @@ static u32 bind_exec_queue_logical_mask(struct xe_device *xe, struct xe_gt *gt,
 		if (xe_hw_engine_is_reserved(hwe))
 			continue;
 
-		if (hwe->class ==
-		    user_to_xe_engine_class[DRM_XE_ENGINE_CLASS_COPY])
+		if (hwe->class == XE_ENGINE_CLASS_COPY)
 			logical_mask |= BIT(hwe->logical_instance);
 	}
 
@@ -492,7 +463,7 @@ static u32 calc_validate_logical_mask(struct xe_device *xe, struct xe_gt *gt,
 
 			n = j * width + i;
 
-			hwe = find_hw_engine(xe, eci[n]);
+			hwe = xe_hw_engine_lookup(xe, eci[n]);
 			if (XE_IOCTL_DBG(xe, !hwe))
 				return 0;
 
@@ -571,7 +542,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
 			if (XE_IOCTL_DBG(xe, !logical_mask))
 				return -EINVAL;
 
-			hwe = find_hw_engine(xe, eci[0]);
+			hwe = xe_hw_engine_lookup(xe, eci[0]);
 			if (XE_IOCTL_DBG(xe, !hwe))
 				return -EINVAL;
 
@@ -608,7 +579,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
 		if (XE_IOCTL_DBG(xe, !logical_mask))
 			return -EINVAL;
 
-		hwe = find_hw_engine(xe, eci[0]);
+		hwe = xe_hw_engine_lookup(xe, eci[0]);
 		if (XE_IOCTL_DBG(xe, !hwe))
 			return -EINVAL;
 
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index b8c0cfbf8b49..20c4fdf40790 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -5,7 +5,10 @@
 
 #include "xe_hw_engine.h"
 
+#include <linux/nospec.h>
+
 #include <drm/drm_managed.h>
+#include <drm/xe_drm.h>
 
 #include "regs/xe_engine_regs.h"
 #include "regs/xe_gt_regs.h"
@@ -1134,3 +1137,31 @@ enum xe_force_wake_domains xe_hw_engine_to_fw_domain(struct xe_hw_engine *hwe)
 {
 	return engine_infos[hwe->engine_id].domain;
 }
+
+static const enum xe_engine_class user_to_xe_engine_class[] = {
+	[DRM_XE_ENGINE_CLASS_RENDER] = XE_ENGINE_CLASS_RENDER,
+	[DRM_XE_ENGINE_CLASS_COPY] = XE_ENGINE_CLASS_COPY,
+	[DRM_XE_ENGINE_CLASS_VIDEO_DECODE] = XE_ENGINE_CLASS_VIDEO_DECODE,
+	[DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE] = XE_ENGINE_CLASS_VIDEO_ENHANCE,
+	[DRM_XE_ENGINE_CLASS_COMPUTE] = XE_ENGINE_CLASS_COMPUTE,
+};
+
+struct xe_hw_engine *
+xe_hw_engine_lookup(struct xe_device *xe,
+		    struct drm_xe_engine_class_instance eci)
+{
+	unsigned int idx;
+
+	if (eci.engine_class > ARRAY_SIZE(user_to_xe_engine_class))
+		return NULL;
+
+	if (eci.gt_id >= xe->info.gt_count)
+		return NULL;
+
+	idx = array_index_nospec(eci.engine_class,
+				 ARRAY_SIZE(user_to_xe_engine_class));
+
+	return xe_gt_hw_engine(xe_device_get_gt(xe, eci.gt_id),
+			       user_to_xe_engine_class[idx],
+			       eci.engine_instance, true);
+}
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.h b/drivers/gpu/drm/xe/xe_hw_engine.h
index 08c3a9df7154..0383aa7d8e89 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.h
+++ b/drivers/gpu/drm/xe/xe_hw_engine.h
@@ -9,6 +9,8 @@
 #include "xe_hw_engine_types.h"
 
 struct drm_printer;
+struct drm_xe_engine_class_instance;
+struct xe_device;
 
 #ifdef CONFIG_DRM_XE_JOB_TIMEOUT_MIN
 #define XE_HW_ENGINE_JOB_TIMEOUT_MIN CONFIG_DRM_XE_JOB_TIMEOUT_MIN
@@ -67,6 +69,10 @@ void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg, u32 val
 
 u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg);
 
+struct xe_hw_engine *
+xe_hw_engine_lookup(struct xe_device *xe,
+		    struct drm_xe_engine_class_instance eci);
+
 static inline bool xe_hw_engine_is_valid(struct xe_hw_engine *hwe)
 {
 	return hwe->name;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
  2024-07-26 14:07 ` [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors Mika Kuoppala
  2024-07-26 14:07 ` [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 19:20   ` Matthew Brost
                     ` (2 more replies)
  2024-07-26 14:08 ` [PATCH 04/21] kernel: export ptrace_may_access Mika Kuoppala
                   ` (26 subsequent siblings)
  29 siblings, 3 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe
  Cc: Mika Kuoppala, Maarten Lankhorst, Lucas De Marchi,
	Dominik Grzegorzek, Andi Shyti, Matt Roper, Maciej Patelczyk

With eudebug event interface, user space debugger process (like gdb)
is able to keep track of resources created by another process
(debuggee using drm/xe) and act upon these resources.

For example, debugger can find a client vm which contains isa/elf
for a particular shader/eu-kernel and then inspect and modify it
(for example installing a breakpoint).

Debugger first opens a connection to xe with a drm ioctl specifying
target pid to connect. This returns an anon fd handle that can then be
used to listen for events with dedicated ioctl.

This patch introduces eudebug connection and event queuing, adding
client create/destroy and vm create/destroy events as a baseline.
More events for full debugger operation are needed and
those will be introduced in follow up patches.

The resource tracking parts are inspired by the work of
Maciej Patelczyk on resource handling for i915. Chris Wilson
suggested improvement of two ways mapping which makes it easy to
use resource map as a definitive bookkeep of what resources
are played to debugger in the discovery phase (on follow up patch).

v2: - event printer removed (Maarten)
    - trim down kfifo accessors (Maarten)
    - xa_alloc spurious locking removed (Maarten)
v3: - use list for clients (Matt)
v4: - avoid reporting clients too early (Maciej, VLK-56889)
v5: - return from wait if disconnect (Mika)
v6: - read waitqueue (Mika)
v7: - ENOTCONN early in read_event (Mika)
v8: - consolidate resource error handling (Mika, Maciej)
v9: - ptrace access check (Jonathan)
v10: - detach error handling (Dominik)

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>

Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
 drivers/gpu/drm/xe/Makefile           |    3 +-
 drivers/gpu/drm/xe/xe_device.c        |   24 +
 drivers/gpu/drm/xe/xe_device_types.h  |   26 +
 drivers/gpu/drm/xe/xe_eudebug.c       | 1093 +++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_eudebug.h       |   27 +
 drivers/gpu/drm/xe/xe_eudebug_types.h |  169 ++++
 drivers/gpu/drm/xe/xe_vm.c            |    7 +-
 include/uapi/drm/xe_drm.h             |   21 +
 include/uapi/drm/xe_drm_eudebug.h     |   57 ++
 9 files changed, 1425 insertions(+), 2 deletions(-)
 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/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 1ff9602a52f6..06badc5f99af 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -114,7 +114,8 @@ xe-y += xe_bb.o \
 	xe_vram_freq.o \
 	xe_wait_user_fence.o \
 	xe_wa.o \
-	xe_wopcm.o
+	xe_wopcm.o \
+	xe_eudebug.o
 
 xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o
 
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 1aba6f9eaa19..6c5eceaca4ab 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -54,6 +54,7 @@
 #include "xe_vm.h"
 #include "xe_vram.h"
 #include "xe_wait_user_fence.h"
+#include "xe_eudebug.h"
 #include "xe_wa.h"
 
 #include <generated/xe_wa_oob.h>
@@ -100,6 +101,14 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
 		put_task_struct(task);
 	}
 
+	INIT_LIST_HEAD(&xef->link);
+
+	mutex_lock(&xe->files.lock);
+	list_add_tail(&xef->link, &xe->files.list);
+	mutex_unlock(&xe->files.lock);
+
+	xe_eudebug_file_open(xef);
+
 	return 0;
 }
 
@@ -158,6 +167,12 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
 
 	xe_pm_runtime_get(xe);
 
+	xe_eudebug_file_close(xef);
+
+	mutex_lock(&xef->xe->files.lock);
+	list_del_init(&xef->link);
+	mutex_unlock(&xef->xe->files.lock);
+
 	/*
 	 * 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
@@ -196,6 +211,7 @@ static const struct drm_ioctl_desc xe_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(XE_WAIT_USER_FENCE, xe_wait_user_fence_ioctl,
 			  DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(XE_OBSERVATION, xe_observation_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)
@@ -285,6 +301,8 @@ static void xe_device_destroy(struct drm_device *dev, void *dummy)
 {
 	struct xe_device *xe = to_xe_device(dev);
 
+	xe_eudebug_fini(xe);
+
 	if (xe->preempt_fence_wq)
 		destroy_workqueue(xe->preempt_fence_wq);
 
@@ -330,6 +348,9 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
 	spin_lock_init(&xe->irq.lock);
 	spin_lock_init(&xe->clients.lock);
 
+	drmm_mutex_init(&xe->drm, &xe->files.lock);
+	INIT_LIST_HEAD(&xe->files.list);
+
 	init_waitqueue_head(&xe->ufence_wq);
 
 	err = drmm_mutex_init(&xe->drm, &xe->usm.lock);
@@ -356,7 +377,10 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
 	INIT_LIST_HEAD(&xe->pinned.external_vram);
 	INIT_LIST_HEAD(&xe->pinned.evicted);
 
+	xe_eudebug_init(xe);
+
 	xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq", 0);
+
 	xe->ordered_wq = alloc_ordered_workqueue("xe-ordered-wq", 0);
 	xe->unordered_wq = alloc_workqueue("xe-unordered-wq", 0, 0);
 	if (!xe->ordered_wq || !xe->unordered_wq ||
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 5b7292a9a66d..bef7c11bd668 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -355,6 +355,15 @@ struct xe_device {
 		u64 count;
 	} clients;
 
+	/** @files: xe_file list (opens) */
+	struct {
+		/** @lock: Protects xe_file list */
+		struct mutex lock;
+
+		/** @list: xe file list */
+		struct list_head list;
+	} files;
+
 	/** @usm: unified memory state */
 	struct {
 		/** @usm.asid: convert a ASID to VM */
@@ -492,6 +501,20 @@ struct xe_device {
 	u8 vm_inject_error_position;
 #endif
 
+	/** @debugger connection list and globals for device */
+	struct {
+		/** @lock: protects the list of connections */
+		spinlock_t lock;
+		/** @list: list of connections, aka debuggers */
+		struct list_head list;
+
+		/** @session_count: session counter to track connections */
+		u64 session_count;
+
+		/** @available: is the debugging functionality available */
+		bool available;
+	} eudebug;
+
 	/* private: */
 
 #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
@@ -596,6 +619,9 @@ struct xe_file {
 
 	/** @refcount: ref count of this xe file */
 	struct kref refcount;
+
+	/** @link: link into xe_device.client.list */
+	struct list_head link;
 };
 
 #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..8aab02824f8a
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -0,0 +1,1093 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include <linux/uaccess.h>
+
+#include <linux/anon_inodes.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+
+#include <drm/drm_managed.h>
+
+#include "xe_device.h"
+#include "xe_assert.h"
+#include "xe_macros.h"
+
+#include "xe_eudebug_types.h"
+#include "xe_eudebug.h"
+
+/*
+ * If there is no detected event read by userspace, during this period, assume
+ * userspace problem and disconnect debugger to allow forward progress.
+ */
+#define XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS (25 * 1000)
+
+#define for_each_debugger_rcu(debugger, head) \
+	list_for_each_entry_rcu((debugger), (head), connection_link)
+#define for_each_debugger(debugger, head) \
+	list_for_each_entry((debugger), (head), connection_link)
+
+#define cast_event(T, event) container_of((event), typeof(*(T)), base)
+
+#define XE_EUDEBUG_DBG_STR "eudbg: %lld:%lu:%s (%d/%d) -> (%d/%d): "
+#define XE_EUDEBUG_DBG_ARGS(d) (d)->session, \
+		atomic_long_read(&(d)->events.seqno), \
+		READ_ONCE(d->connection.status) <= 0 ? "disconnected" : "", \
+		current->pid, \
+		task_tgid_nr(current), \
+		(d)->target_task->pid, \
+		task_tgid_nr((d)->target_task)
+
+#define eu_err(d, fmt, ...) drm_err(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
+				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
+#define eu_warn(d, fmt, ...) drm_warn(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
+				      XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
+#define eu_dbg(d, fmt, ...) drm_dbg(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
+				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
+
+#define xe_eudebug_assert(d, ...) xe_assert((d)->xe, ##__VA_ARGS__)
+
+#define struct_member(T, member) (((T *)0)->member)
+
+/* Keep 1:1 parity with uapi events */
+#define write_member(T_out, ptr, member, value) { \
+	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
+	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
+		     offsetof(typeof(T_out), member)); \
+	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
+	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
+	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
+	(ptr)->member = (value); \
+	}
+
+static struct xe_eudebug_event *
+event_fifo_pending(struct xe_eudebug *d)
+{
+	struct xe_eudebug_event *event;
+
+	if (kfifo_peek(&d->events.fifo, &event))
+		return event;
+
+	return NULL;
+}
+
+/*
+ * 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_num_events_peek(const struct xe_eudebug * const d)
+{
+	return kfifo_len(&d->events.fifo);
+}
+
+static bool
+xe_eudebug_detached(struct xe_eudebug *d)
+{
+	int status;
+
+	spin_lock(&d->connection.lock);
+	status = d->connection.status;
+	spin_unlock(&d->connection.lock);
+
+	return status <= 0;
+}
+
+static int
+xe_eudebug_error(const struct xe_eudebug * const d)
+{
+	const int status = READ_ONCE(d->connection.status);
+
+	return status <= 0 ? status : 0;
+}
+
+static unsigned int
+event_fifo_has_events(struct xe_eudebug *d)
+{
+	if (xe_eudebug_detached(d))
+		return 1;
+
+	return event_fifo_num_events_peek(d);
+}
+
+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_resources * const res, const int t)
+{
+	return &res->rt[t];
+}
+
+static struct xe_eudebug_resources *
+xe_eudebug_resources_alloc(void)
+{
+	struct xe_eudebug_resources *res;
+	int err;
+	int i;
+
+	res = kzalloc(sizeof(*res), GFP_ATOMIC);
+	if (!res)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&res->lock);
+
+	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
+		xa_init_flags(&res->rt[i].xa, XA_FLAGS_ALLOC1);
+		err = rhashtable_init(&res->rt[i].rh, &rhash_res);
+
+		if (err)
+			break;
+	}
+
+	if (err) {
+		while (i--) {
+			xa_destroy(&res->rt[i].xa);
+			rhashtable_destroy(&res->rt[i].rh);
+		}
+
+		kfree(res);
+		return ERR_PTR(err);
+	}
+
+	return res;
+}
+
+static void res_free_fn(void *ptr, void *arg)
+{
+	XE_WARN_ON(ptr);
+	kfree(ptr);
+}
+
+static void
+xe_eudebug_destroy_resources(struct xe_eudebug *d)
+{
+	struct xe_eudebug_resources *res = d->res;
+	struct xe_eudebug_handle *h;
+	unsigned long j;
+	int i;
+	int err;
+
+	mutex_lock(&res->lock);
+	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
+		struct xe_eudebug_resource *r = &res->rt[i];
+
+		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);
+			xe_eudebug_assert(d, t == h);
+			kfree(t);
+		}
+	}
+	mutex_unlock(&res->lock);
+
+	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
+		struct xe_eudebug_resource *r = &res->rt[i];
+
+		rhashtable_free_and_destroy(&r->rh, res_free_fn, NULL);
+		xe_eudebug_assert(d, xa_empty(&r->xa));
+		xa_destroy(&r->xa);
+	}
+
+	mutex_destroy(&res->lock);
+
+	kfree(res);
+}
+
+static void xe_eudebug_free(struct kref *ref)
+{
+	struct xe_eudebug *d = container_of(ref, typeof(*d), ref);
+	struct xe_eudebug_event *event;
+
+	while (kfifo_get(&d->events.fifo, &event))
+		kfree(event);
+
+	xe_eudebug_destroy_resources(d);
+	put_task_struct(d->target_task);
+
+	xe_eudebug_assert(d, !kfifo_len(&d->events.fifo));
+
+	kfree_rcu(d, rcu);
+}
+
+static void xe_eudebug_put(struct xe_eudebug *d)
+{
+	kref_put(&d->ref, xe_eudebug_free);
+}
+
+static struct task_struct *find_get_target(const pid_t nr)
+{
+	struct task_struct *task;
+
+	rcu_read_lock();
+	task = pid_task(find_pid_ns(nr, task_active_pid_ns(current)), PIDTYPE_PID);
+	if (task)
+		get_task_struct(task);
+	rcu_read_unlock();
+
+	return task;
+}
+
+static int
+xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
+		  const pid_t pid_nr)
+{
+	struct task_struct *target;
+	struct xe_eudebug *iter;
+	kuid_t uid = current_uid();
+	int ret = 0;
+
+	target = find_get_target(pid_nr);
+	if (!target)
+		return -ENOENT;
+
+	if (!uid_eq(uid, task_uid(target)) && !capable(CAP_SYS_ADMIN)) {
+		put_task_struct(target);
+		return -EACCES;
+	}
+
+	XE_WARN_ON(d->connection.status != 0);
+
+	spin_lock(&xe->eudebug.lock);
+	for_each_debugger(iter, &xe->eudebug.list) {
+		if (!same_thread_group(iter->target_task, target))
+			continue;
+
+		ret = -EBUSY;
+	}
+
+	if (!ret && xe->eudebug.session_count + 1 == 0)
+		ret = -ENOSPC;
+
+	if (!ret) {
+		d->connection.status = XE_EUDEBUG_STATUS_CONNECTED;
+		d->xe = xe;
+		d->target_task = target;
+		d->session = ++xe->eudebug.session_count;
+		kref_get(&d->ref);
+		list_add_tail_rcu(&d->connection_link, &xe->eudebug.list);
+	}
+	spin_unlock(&xe->eudebug.lock);
+
+	if (ret)
+		put_task_struct(target);
+
+	return ret;
+}
+
+static bool xe_eudebug_detach(struct xe_device *xe,
+			      struct xe_eudebug *d,
+			      const int err)
+{
+	bool detached = false;
+
+	XE_WARN_ON(err > 0);
+
+	spin_lock(&d->connection.lock);
+	if (d->connection.status == XE_EUDEBUG_STATUS_CONNECTED) {
+		d->connection.status = err;
+		detached = true;
+	}
+	spin_unlock(&d->connection.lock);
+
+	if (!detached)
+		return false;
+
+	spin_lock(&xe->eudebug.lock);
+	list_del_rcu(&d->connection_link);
+	spin_unlock(&xe->eudebug.lock);
+
+	eu_dbg(d, "session %lld detached with %d", d->session, err);
+
+	/* Our ref with the connection_link */
+	xe_eudebug_put(d);
+
+	return true;
+}
+
+static int _xe_eudebug_disconnect(struct xe_eudebug *d,
+				  const int err)
+{
+	wake_up_all(&d->events.write_done);
+	wake_up_all(&d->events.read_done);
+
+	return xe_eudebug_detach(d->xe, d, err);
+}
+
+#define xe_eudebug_disconnect(_d, _err) ({ \
+	if (_xe_eudebug_disconnect((_d), (_err))) { \
+		if ((_err) == 0 || (_err) == -ETIMEDOUT) \
+			eu_dbg(d, "Session closed (%d)", (_err)); \
+		else \
+			eu_err(d, "Session disconnected, err = %d (%s:%d)", \
+			       (_err), __func__, __LINE__); \
+	} \
+})
+
+static int xe_eudebug_release(struct inode *inode, struct file *file)
+{
+	struct xe_eudebug *d = file->private_data;
+
+	xe_eudebug_disconnect(d, 0);
+	xe_eudebug_put(d);
+
+	return 0;
+}
+
+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 (xe_eudebug_error(d))
+			ret |= EPOLLERR;
+	}
+
+	if (event_fifo_num_events_peek(d))
+		ret |= EPOLLIN;
+
+	return ret;
+}
+
+static ssize_t xe_eudebug_read(struct file *file,
+			       char __user *buf,
+			       size_t count,
+			       loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static struct xe_eudebug *
+xe_eudebug_for_task_get(struct xe_device *xe,
+			struct task_struct *task)
+{
+	struct xe_eudebug *d, *iter;
+
+	d = NULL;
+
+	rcu_read_lock();
+	for_each_debugger_rcu(iter, &xe->eudebug.list) {
+		if (!same_thread_group(iter->target_task, task))
+			continue;
+
+		if (kref_get_unless_zero(&iter->ref))
+			d = iter;
+
+		break;
+	}
+	rcu_read_unlock();
+
+	return d;
+}
+
+static struct task_struct *find_task_get(struct xe_file *xef)
+{
+	struct task_struct *task;
+	struct pid *pid;
+
+	rcu_read_lock();
+	pid = rcu_dereference(xef->drm->pid);
+	task = pid_task(pid, PIDTYPE_PID);
+	if (task)
+		get_task_struct(task);
+	rcu_read_unlock();
+
+	return task;
+}
+
+static struct xe_eudebug *
+xe_eudebug_get(struct xe_file *xef)
+{
+	struct task_struct *task;
+	struct xe_eudebug *d;
+
+	d = NULL;
+	task = find_task_get(xef);
+	if (task) {
+		d = xe_eudebug_for_task_get(to_xe_device(xef->drm->minor->dev),
+					    task);
+		put_task_struct(task);
+	}
+
+	if (!d)
+		return NULL;
+
+	if (xe_eudebug_detached(d)) {
+		xe_eudebug_put(d);
+		return NULL;
+	}
+
+	return d;
+}
+
+static int xe_eudebug_queue_event(struct xe_eudebug *d,
+				  struct xe_eudebug_event *event)
+{
+	const u64 wait_jiffies = msecs_to_jiffies(1000);
+	u64 last_read_detected_ts, last_head_seqno, start_ts;
+
+	xe_eudebug_assert(d, event->len > sizeof(struct xe_eudebug_event));
+	xe_eudebug_assert(d, event->type);
+	xe_eudebug_assert(d, event->type != DRM_XE_EUDEBUG_EVENT_READ);
+
+	start_ts = ktime_get();
+	last_read_detected_ts = start_ts;
+	last_head_seqno = 0;
+
+	do  {
+		struct xe_eudebug_event *head;
+		u64 head_seqno;
+		bool was_queued;
+
+		if (xe_eudebug_detached(d))
+			break;
+
+		spin_lock(&d->events.lock);
+		head = event_fifo_pending(d);
+		if (head)
+			head_seqno = event->seqno;
+		else
+			head_seqno = 0;
+
+		was_queued = kfifo_in(&d->events.fifo, &event, 1);
+		spin_unlock(&d->events.lock);
+
+		wake_up_all(&d->events.write_done);
+
+		if (was_queued) {
+			event = NULL;
+			break;
+		}
+
+		XE_WARN_ON(!head_seqno);
+
+		/* If we detect progress, restart timeout */
+		if (last_head_seqno != head_seqno)
+			last_read_detected_ts = ktime_get();
+
+		last_head_seqno = head_seqno;
+
+		wait_event_interruptible_timeout(d->events.read_done,
+						 !kfifo_is_full(&d->events.fifo),
+						 wait_jiffies);
+
+	} while (ktime_ms_delta(ktime_get(), last_read_detected_ts) <
+		 XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS);
+
+	if (event) {
+		eu_dbg(d,
+		       "event %llu queue failed (blocked %lld ms, avail %d)",
+		       event ? event->seqno : 0,
+		       ktime_ms_delta(ktime_get(), start_ts),
+		       kfifo_avail(&d->events.fifo));
+
+		kfree(event);
+
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static struct xe_eudebug_handle *
+alloc_handle(const int type, const u64 key)
+{
+	struct xe_eudebug_handle *h;
+
+	h = kzalloc(sizeof(*h), GFP_ATOMIC);
+	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 find_handle(struct xe_eudebug_resources *res,
+		       const int type,
+		       const void *p)
+{
+	const u64 key = (u64)p;
+	struct xe_eudebug_resource *r;
+	struct xe_eudebug_handle *h;
+	int id;
+
+	if (XE_WARN_ON(!key))
+		return -EINVAL;
+
+	r = resource_from_type(res, type);
+
+	mutex_lock(&res->lock);
+	h = __find_handle(r, key);
+	id = h ? h->id : -ENOENT;
+	mutex_unlock(&res->lock);
+
+	return id;
+}
+
+static int _xe_eudebug_add_handle(struct xe_eudebug *d,
+				  int type,
+				  void *p,
+				  u64 *seqno,
+				  int *handle)
+{
+	const u64 key = (u64)p;
+	struct xe_eudebug_resource *r;
+	struct xe_eudebug_handle *h, *o;
+	int err;
+
+	if (XE_WARN_ON(p == NULL))
+		return -EINVAL;
+
+	if (xe_eudebug_detached(d))
+		return -ENOTCONN;
+
+	h = alloc_handle(type, key);
+	if (!h)
+		return -ENOMEM;
+
+	r = resource_from_type(d->res, type);
+
+	mutex_lock(&d->res->lock);
+	o = __find_handle(r, key);
+	if (!o) {
+		err = xa_alloc(&r->xa, &h->id, h, xa_limit_31b, GFP_KERNEL);
+
+		if (h->id >= INT_MAX) {
+			xa_erase(&r->xa, h->id);
+			err = -ENOSPC;
+		}
+
+		if (!err)
+			err = rhashtable_insert_fast(&r->rh,
+						     &h->rh_head,
+						     rhash_res);
+
+		if (err) {
+			xa_erase(&r->xa, h->id);
+		} else {
+			if (seqno)
+				*seqno = atomic_long_inc_return(&d->events.seqno);
+		}
+	} else {
+		xe_eudebug_assert(d, o->id);
+		err = -EEXIST;
+	}
+	mutex_unlock(&d->res->lock);
+
+	if (handle)
+		*handle = o ? o->id : h->id;
+
+	if (err) {
+		kfree(h);
+		XE_WARN_ON(err > 0);
+		return err;
+	}
+
+	xe_eudebug_assert(d, h->id);
+
+	return h->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, NULL);
+	if (ret == -EEXIST || ret == -ENOTCONN) {
+		eu_dbg(d, "%d on adding %d", ret, type);
+		return 0;
+	}
+
+	if (ret < 0)
+		xe_eudebug_disconnect(d, ret);
+
+	return ret;
+}
+
+static int _xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
+				     u64 *seqno)
+{
+	const u64 key = (u64)p;
+	struct xe_eudebug_resource *r;
+	struct xe_eudebug_handle *h, *xa_h;
+	int ret;
+
+	if (XE_WARN_ON(!key))
+		return -EINVAL;
+
+	if (xe_eudebug_detached(d))
+		return -ENOTCONN;
+
+	r = resource_from_type(d->res, type);
+
+	mutex_lock(&d->res->lock);
+	h = __find_handle(r, key);
+	if (h) {
+		ret = rhashtable_remove_fast(&r->rh,
+					     &h->rh_head,
+					     rhash_res);
+		xe_eudebug_assert(d, !ret);
+		xa_h = xa_erase(&r->xa, h->id);
+		xe_eudebug_assert(d, xa_h == h);
+		if (!ret) {
+			ret = h->id;
+			if (seqno)
+				*seqno = atomic_long_inc_return(&d->events.seqno);
+		}
+	} else {
+		ret = -ENOENT;
+	}
+	mutex_unlock(&d->res->lock);
+
+	kfree(h);
+
+	xe_eudebug_assert(d, ret);
+
+	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);
+	if (ret == -ENOENT || ret == -ENOTCONN) {
+		eu_dbg(d, "%d on removing %d", ret, type);
+		return 0;
+	}
+
+	if (ret < 0)
+		xe_eudebug_disconnect(d, ret);
+
+	return ret;
+}
+
+static struct xe_eudebug_event *
+__xe_eudebug_create_event(struct xe_eudebug *d,
+			  u64 seqno, u16 type, u16 flags, u32 len, gfp_t gfp)
+{
+	struct xe_eudebug_event *event;
+
+	xe_eudebug_assert(d, len > sizeof(*event));
+
+	event = kzalloc(len, gfp);
+	if (!event)
+		return NULL;
+
+	event->type = type;
+	event->flags = flags;
+	event->len = len;
+	event->seqno = seqno;
+
+	return event;
+}
+
+static struct xe_eudebug_event *
+xe_eudebug_create_event(struct xe_eudebug *d, u16 type, u64 seqno, u16 flags,
+			u32 len, gfp_t gfp)
+{
+	return __xe_eudebug_create_event(d, seqno, type, flags, len, gfp);
+}
+
+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 drm_xe_eudebug_event user_event;
+	struct xe_eudebug_event *event;
+	long ret = 0;
+
+	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))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, user_event.type > DRM_XE_EUDEBUG_EVENT_MAX_EVENT))
+		return -EINVAL;
+
+	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.reserved))
+		return -EINVAL;
+
+	/* 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;
+	}
+
+	ret = 0;
+	spin_lock(&d->events.lock);
+	event = event_fifo_pending(d);
+	if (event) {
+		if (user_event.len < event->len) {
+			ret = -EMSGSIZE;
+		} else if (!kfifo_out(&d->events.fifo, &event, 1)) {
+			eu_warn(d, "internal fifo corruption");
+			ret = -ENOTCONN;
+		}
+	}
+	spin_unlock(&d->events.lock);
+
+	wake_up_all(&d->events.read_done);
+
+	if (XE_IOCTL_DBG(xe, ret))
+		return ret;
+
+	if (!event) {
+		if (xe_eudebug_detached(d))
+			return -ENOTCONN;
+		if (!wait)
+			return -EAGAIN;
+
+		return -ENOENT;
+	}
+
+	if (copy_to_user(user_orig, event, event->len))
+		ret = -EFAULT;
+	else
+		eu_dbg(d, "event read: type=%u, flags=0x%x, seqno=%llu", event->type,
+		       event->flags, event->seqno);
+
+	kfree(event);
+
+	return ret;
+}
+
+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,
+	.llseek		= no_llseek,
+	.release	= xe_eudebug_release,
+	.poll		= xe_eudebug_poll,
+	.read		= xe_eudebug_read,
+	.unlocked_ioctl	= xe_eudebug_ioctl,
+};
+
+static int
+xe_eudebug_connect(struct xe_device *xe,
+		   struct drm_xe_eudebug_connect *param)
+{
+	const u64 known_open_flags = 0;
+	unsigned long f_flags = 0;
+	struct xe_eudebug *d;
+	int fd, err;
+
+	if (param->extensions)
+		return -EINVAL;
+
+	if (!param->pid)
+		return -EINVAL;
+
+	if (param->flags & ~known_open_flags)
+		return -EINVAL;
+
+	if (param->version && param->version != DRM_XE_EUDEBUG_VERSION)
+		return -EINVAL;
+
+	param->version = DRM_XE_EUDEBUG_VERSION;
+
+	if (!xe->eudebug.available)
+		return -EOPNOTSUPP;
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d)
+		return -ENOMEM;
+
+	kref_init(&d->ref);
+	spin_lock_init(&d->connection.lock);
+	init_waitqueue_head(&d->events.write_done);
+	init_waitqueue_head(&d->events.read_done);
+
+	spin_lock_init(&d->events.lock);
+	INIT_KFIFO(d->events.fifo);
+
+	d->res = xe_eudebug_resources_alloc();
+	if (IS_ERR(d->res)) {
+		err = PTR_ERR(d->res);
+		goto err_free;
+	}
+
+	err = xe_eudebug_attach(xe, d, param->pid);
+	if (err)
+		goto err_free_res;
+
+	fd = anon_inode_getfd("[xe_eudebug]", &fops, d, f_flags);
+	if (fd < 0) {
+		err = fd;
+		goto err_detach;
+	}
+
+	eu_dbg(d, "connected session %lld", d->session);
+
+	return fd;
+
+err_detach:
+	xe_eudebug_detach(xe, d, err);
+err_free_res:
+	xe_eudebug_destroy_resources(d);
+err_free:
+	kfree(d);
+
+	return err;
+}
+
+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;
+	int ret = 0;
+
+	ret = xe_eudebug_connect(xe, param);
+
+	return ret;
+}
+
+void xe_eudebug_init(struct xe_device *xe)
+{
+	spin_lock_init(&xe->eudebug.lock);
+	INIT_LIST_HEAD(&xe->eudebug.list);
+
+	xe->eudebug.available = true;
+}
+
+void xe_eudebug_fini(struct xe_device *xe)
+{
+	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
+}
+
+static int send_open_event(struct xe_eudebug *d, u32 flags, const u64 handle,
+			   const u64 seqno)
+{
+	struct xe_eudebug_event *event;
+	struct xe_eudebug_event_open *eo;
+
+	if (!handle)
+		return -EINVAL;
+
+	if (XE_WARN_ON((long)handle >= INT_MAX))
+		return -EINVAL;
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_OPEN, seqno,
+					flags, sizeof(*eo), GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	eo = cast_event(eo, event);
+
+	write_member(struct drm_xe_eudebug_event_client, eo,
+		     client_handle, handle);
+
+	return xe_eudebug_queue_event(d, event);
+}
+
+static int client_create_event(struct xe_eudebug *d, struct xe_file *xef)
+{
+	u64 seqno;
+	int ret;
+
+	ret = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT, xef, &seqno);
+	if (ret > 0)
+		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
+					     ret, seqno);
+
+	return ret;
+}
+
+static int client_destroy_event(struct xe_eudebug *d, struct xe_file *xef)
+{
+	u64 seqno;
+	int ret;
+
+	ret = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT,
+				       xef, &seqno);
+	if (ret > 0)
+		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY,
+				      ret, seqno);
+
+	return ret;
+}
+
+#define xe_eudebug_event_put(_d, _err) ({ \
+	if ((_err)) \
+		xe_eudebug_disconnect((_d), (_err)); \
+	xe_eudebug_put((_d)); \
+	})
+
+void xe_eudebug_file_open(struct xe_file *xef)
+{
+	struct xe_eudebug *d;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, client_create_event(d, xef));
+}
+
+void xe_eudebug_file_close(struct xe_file *xef)
+{
+	struct xe_eudebug *d;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, client_destroy_event(d, xef));
+}
+
+static int send_vm_event(struct xe_eudebug *d, u32 flags,
+			 const u64 client_handle,
+			 const u64 vm_handle,
+			 const u64 seqno)
+{
+	struct xe_eudebug_event *event;
+	struct xe_eudebug_event_vm *e;
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM,
+					seqno, flags, sizeof(*e), GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	e = cast_event(e, event);
+
+	write_member(struct drm_xe_eudebug_event_vm, e, client_handle, client_handle);
+	write_member(struct drm_xe_eudebug_event_vm, e, vm_handle, vm_handle);
+
+	return xe_eudebug_queue_event(d, event);
+}
+
+static int vm_create_event(struct xe_eudebug *d,
+			   struct xe_file *xef, struct xe_vm *vm)
+{
+	int h_c, h_vm;
+	u64 seqno;
+	int ret;
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
+	if (h_c < 0)
+		return h_c;
+
+	xe_eudebug_assert(d, h_c);
+
+	h_vm = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
+	if (h_vm <= 0)
+		return h_vm;
+
+	ret = send_vm_event(d, DRM_XE_EUDEBUG_EVENT_CREATE, h_c, h_vm, seqno);
+
+	return ret;
+}
+
+static int vm_destroy_event(struct xe_eudebug *d,
+			    struct xe_file *xef, struct xe_vm *vm)
+{
+	int h_c, h_vm;
+	u64 seqno;
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
+	if (h_c < 0) {
+		XE_WARN_ON("no client found for vm");
+		eu_warn(d, "no client found for vm");
+		return h_c;
+	}
+
+	xe_eudebug_assert(d, h_c);
+
+	h_vm = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
+	if (h_vm <= 0)
+		return h_vm;
+
+	return send_vm_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY, h_c, h_vm, seqno);
+}
+
+void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm)
+{
+	struct xe_eudebug *d;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, vm_create_event(d, xef, vm));
+}
+
+void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
+{
+	struct xe_eudebug *d;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, vm_destroy_event(d, xef, vm));
+}
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
new file mode 100644
index 000000000000..df577b581364
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef _XE_EUDEBUG_H_
+
+struct drm_device;
+struct drm_file;
+struct xe_device;
+struct xe_file;
+struct xe_vm;
+
+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_fini(struct xe_device *xe);
+
+void xe_eudebug_file_open(struct xe_file *xef);
+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);
+
+#endif
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..093221a707df
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __XE_EUDEBUG_TYPES_H_
+
+#include <linux/mutex.h>
+#include <linux/kref.h>
+#include <linux/kfifo.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/xarray.h>
+#include <linux/rbtree.h>
+#include <linux/rhashtable.h>
+
+#include <uapi/drm/xe_drm.h>
+
+struct xe_device;
+struct task_struct;
+struct xe_eudebug_event;
+
+#define CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE 64
+
+/**
+ * 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 {
+	/** @xa: xarrays for <id->key> */
+	struct xarray xa;
+
+	/** @rh rhashtable for <key->id> */
+	struct rhashtable rh;
+};
+
+#define XE_EUDEBUG_RES_TYPE_CLIENT	0
+#define XE_EUDEBUG_RES_TYPE_VM		1
+#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_VM + 1)
+
+/**
+ * struct xe_eudebug_resources - eudebug resources for all types
+ */
+struct xe_eudebug_resources {
+	/** @lock: guards access into rt */
+	struct mutex lock;
+
+	/** @rt: resource maps for all types */
+	struct xe_eudebug_resource rt[XE_EUDEBUG_RES_TYPE_COUNT];
+};
+
+/**
+ * struct xe_eudebug - Top level struct for eudebug: the connection
+ */
+struct xe_eudebug {
+	/** @ref: kref counter for this struct */
+	struct kref ref;
+
+	/** @rcu: rcu_head for rcu destruction */
+	struct rcu_head rcu;
+
+	/** @connection_link: our link into the xe_device:eudebug.list */
+	struct list_head connection_link;
+
+	struct {
+		/** @status: connected = 1, disconnected = error */
+#define XE_EUDEBUG_STATUS_CONNECTED 1
+		int status;
+
+		/** @lock: guards access to status */
+		spinlock_t lock;
+	} connection;
+
+	/** @xe: the parent device we are serving */
+	struct xe_device *xe;
+
+	/** @target_task: the task that we are debugging */
+	struct task_struct *target_task;
+
+	/** @res: the resource maps we track for target_task */
+	struct xe_eudebug_resources *res;
+
+	/** @session: session number for this connection (for logs) */
+	u64 session;
+
+	/** @events: kfifo queue of to-be-delivered events */
+	struct {
+		/** @lock: guards access to fifo */
+		spinlock_t lock;
+
+		/** @fifo: queue of events pending */
+		DECLARE_KFIFO(fifo,
+			      struct xe_eudebug_event *,
+			      CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE);
+
+		/** @write_done: waitqueue for signalling write to fifo */
+		wait_queue_head_t write_done;
+
+		/** @read_done: waitqueue for signalling read from fifo */
+		wait_queue_head_t read_done;
+
+		/** @event_seqno: seqno counter to stamp events for fifo */
+		atomic_long_t seqno;
+	} events;
+
+};
+
+/**
+ * struct xe_eudebug_event - Internal base event struct for eudebug
+ */
+struct xe_eudebug_event {
+	/** @len: length of this event, including payload */
+	u32 len;
+
+	/** @type: message type */
+	u16 type;
+
+	/** @flags: message flags */
+	u16 flags;
+
+	/** @seqno: sequence number for ordering */
+	u64 seqno;
+
+	/** @reserved: reserved field MBZ */
+	u64 reserved;
+
+	/** @data: payload bytes */
+	u8 data[];
+};
+
+/**
+ * struct xe_eudebug_event_open - Internal event for client open/close
+ */
+struct xe_eudebug_event_open {
+	/** @base: base event */
+	struct xe_eudebug_event base;
+
+	/** @client_handle: opaque handle for client */
+	u64 client_handle;
+};
+
+/**
+ * struct xe_eudebug_event_vm - Internal event for vm open/close
+ */
+struct xe_eudebug_event_vm {
+	/** @base: base event */
+	struct xe_eudebug_event base;
+
+	/** @client_handle: client containing the vm open/close */
+	u64 client_handle;
+
+	/** @vm_handle: vm handle it's open/close */
+	u64 vm_handle;
+};
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index f225107bdd65..9e101c992d9c 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -39,6 +39,7 @@
 #include "xe_trace_bo.h"
 #include "xe_wa.h"
 #include "xe_hmm.h"
+#include "xe_eudebug.h"
 
 static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
 {
@@ -1818,6 +1819,8 @@ 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
 
+	xe_eudebug_vm_create(xef, vm);
+
 	return 0;
 
 err_free_id:
@@ -1853,8 +1856,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 29425d7fdc77..a68734ff12f4 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -102,6 +102,7 @@ extern "C" {
 #define DRM_XE_EXEC			0x09
 #define DRM_XE_WAIT_USER_FENCE		0x0a
 #define DRM_XE_OBSERVATION		0x0b
+#define DRM_XE_EUDEBUG_CONNECT		0x0c
 
 /* Must be kept compact -- no holes */
 
@@ -117,6 +118,7 @@ extern "C" {
 #define DRM_IOCTL_XE_EXEC			DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC, struct drm_xe_exec)
 #define DRM_IOCTL_XE_WAIT_USER_FENCE		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence)
 #define DRM_IOCTL_XE_OBSERVATION		DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param)
+#define DRM_IOCTL_XE_EUDEBUG_CONNECT		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)
 
 /**
  * DOC: Xe IOCTL Extensions
@@ -1694,6 +1696,25 @@ struct drm_xe_oa_stream_info {
 	__u64 reserved[3];
 };
 
+/*
+ * Debugger ABI (ioctl and events) Version History:
+ * 0 - No debugger available
+ * 1 - Initial version
+ */
+#define DRM_XE_EUDEBUG_VERSION 1
+
+struct drm_xe_eudebug_connect {
+	/** @extensions: Pointer to the first extension struct, if any */
+	__u64 extensions;
+
+	__u64 pid; /* input: Target process ID */
+	__u32 flags; /* MBZ */
+
+	__u32 version; /* output: current ABI (ioctl / events) version */
+};
+
+#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..a1cad9c005fc
--- /dev/null
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef _UAPI_XE_DRM_EUDEBUG_H_
+#define _UAPI_XE_DRM_EUDEBUG_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Do a eudebug event read for a debugger connection.
+ *
+ * This ioctl is available in debug version 1.
+ */
+#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
+
+/* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
+struct drm_xe_eudebug_event {
+	__u32 len;
+
+	__u16 type;
+#define DRM_XE_EUDEBUG_EVENT_NONE		0
+#define DRM_XE_EUDEBUG_EVENT_READ		1
+#define DRM_XE_EUDEBUG_EVENT_OPEN		2
+#define DRM_XE_EUDEBUG_EVENT_VM			3
+#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM
+
+	__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)
+	__u64 seqno;
+	__u64 reserved;
+};
+
+struct drm_xe_eudebug_event_client {
+	struct drm_xe_eudebug_event base;
+
+	__u64 client_handle; /* This is unique per debug connection */
+};
+
+struct drm_xe_eudebug_event_vm {
+	struct drm_xe_eudebug_event base;
+
+	__u64 client_handle;
+	__u64 vm_handle;
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 04/21] kernel: export ptrace_may_access
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (2 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-29 18:56   ` Lucas De Marchi
  2024-08-08 11:18   ` Andi Shyti
  2024-07-26 14:08 ` [PATCH 05/21] drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach Mika Kuoppala
                   ` (25 subsequent siblings)
  29 siblings, 2 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe
  Cc: Mika Kuoppala, Lucas De Marchi, Andi Shyti, Maciej Patelczyk,
	Jonathan Cavitt

We need to export ptrace_may_access to be able to
allow debugger connection to check for debuggee access and
at the same time allow xe.ko module build.

CC: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
CC: Andi Shyti <andi.shyti@intel.com>
CC: Maciej Patelczyk <maciej.patelczyk@linux.intel.com>
Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
---
 kernel/ptrace.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d5f89f9ef29f..86be1805ebd8 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -354,6 +354,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
 	task_unlock(task);
 	return !err;
 }
+EXPORT_SYMBOL_GPL(ptrace_may_access);
 
 static int check_ptrace_options(unsigned long data)
 {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 05/21] drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (3 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 04/21] kernel: export ptrace_may_access Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-29 19:00   ` Lucas De Marchi
  2024-07-26 14:08 ` [PATCH 06/21] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
                   ` (24 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Jonathan Cavitt, Mika Kuoppala

From: Jonathan Cavitt <jonathan.cavitt@intel.com>

xe_eudebug_attach wants to use ptrace_may_access for determining when
the user has the right to attach a debugger to a given process.  With
ptrace_may_access now exported, this has become possible.

Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/xe/xe_eudebug.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 8aab02824f8a..c4bc66660218 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -246,14 +246,13 @@ xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
 {
 	struct task_struct *target;
 	struct xe_eudebug *iter;
-	kuid_t uid = current_uid();
 	int ret = 0;
 
 	target = find_get_target(pid_nr);
 	if (!target)
 		return -ENOENT;
 
-	if (!uid_eq(uid, task_uid(target)) && !capable(CAP_SYS_ADMIN)) {
+	if (!ptrace_may_access(target, PTRACE_MODE_READ_REALCREDS)) {
 		put_task_struct(target);
 		return -EACCES;
 	}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 06/21] drm/xe/eudebug: Introduce discovery for resources
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (4 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 05/21] drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 14:08 ` [PATCH 07/21] drm/xe/eudebug: Introduce exec_queue events Mika Kuoppala
                   ` (23 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Mika Kuoppala, Maciej Patelczyk

Debugger connection can happen way after the client has
created and destroyed arbitrary number of resources.

We need to playback all currently existing resources for the
debugger. The client is held until this so called discovery
process, executed by workqueue, is complete.

This patch is based on discovery work by Maciej Patelczyk
for i915 driver.

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>
---
 drivers/gpu/drm/xe/xe_device.c        |  6 +-
 drivers/gpu/drm/xe/xe_device_types.h  |  3 +
 drivers/gpu/drm/xe/xe_eudebug.c       | 91 +++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_eudebug_types.h |  7 +++
 4 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 6c5eceaca4ab..90bb0a8b1881 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -312,6 +312,9 @@ static void xe_device_destroy(struct drm_device *dev, void *dummy)
 	if (xe->unordered_wq)
 		destroy_workqueue(xe->unordered_wq);
 
+	if (xe->eudebug.ordered_wq)
+		destroy_workqueue(xe->eudebug.ordered_wq);
+
 	ttm_device_fini(&xe->ttm);
 }
 
@@ -382,8 +385,9 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
 	xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq", 0);
 
 	xe->ordered_wq = alloc_ordered_workqueue("xe-ordered-wq", 0);
+	xe->eudebug.ordered_wq = alloc_ordered_workqueue("xe-eudebug-ordered-wq", 0);
 	xe->unordered_wq = alloc_workqueue("xe-unordered-wq", 0, 0);
-	if (!xe->ordered_wq || !xe->unordered_wq ||
+	if (!xe->ordered_wq || !xe->unordered_wq || !xe->eudebug.ordered_wq ||
 	    !xe->preempt_fence_wq) {
 		/*
 		 * Cleanup done in xe_device_destroy via
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index bef7c11bd668..4dcfd39cb909 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -513,6 +513,9 @@ struct xe_device {
 
 		/** @available: is the debugging functionality available */
 		bool available;
+
+		/** @ordered_wq: used to discovery */
+		struct workqueue_struct *ordered_wq;
 	} eudebug;
 
 	/* private: */
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index c4bc66660218..d3051bbe9ec8 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -427,6 +427,12 @@ xe_eudebug_get(struct xe_file *xef)
 	if (!d)
 		return NULL;
 
+	if (!xe_eudebug_detached(d) &&
+	    !completion_done(&d->discovery) &&
+	    wait_for_completion_killable_timeout(&d->discovery,
+						 HZ * 40) <= 0)
+		xe_eudebug_disconnect(d, -ETIMEDOUT);
+
 	if (xe_eudebug_detached(d)) {
 		xe_eudebug_put(d);
 		return NULL;
@@ -830,6 +836,8 @@ static const struct file_operations fops = {
 	.unlocked_ioctl	= xe_eudebug_ioctl,
 };
 
+static void discovery_work_fn(struct work_struct *work);
+
 static int
 xe_eudebug_connect(struct xe_device *xe,
 		   struct drm_xe_eudebug_connect *param)
@@ -864,9 +872,11 @@ xe_eudebug_connect(struct xe_device *xe,
 	spin_lock_init(&d->connection.lock);
 	init_waitqueue_head(&d->events.write_done);
 	init_waitqueue_head(&d->events.read_done);
+	init_completion(&d->discovery);
 
 	spin_lock_init(&d->events.lock);
 	INIT_KFIFO(d->events.fifo);
+	INIT_WORK(&d->discovery_work, discovery_work_fn);
 
 	d->res = xe_eudebug_resources_alloc();
 	if (IS_ERR(d->res)) {
@@ -884,6 +894,9 @@ xe_eudebug_connect(struct xe_device *xe,
 		goto err_detach;
 	}
 
+	kref_get(&d->ref);
+	queue_work(xe->eudebug.ordered_wq, &d->discovery_work);
+
 	eu_dbg(d, "connected session %lld", d->session);
 
 	return fd;
@@ -1090,3 +1103,81 @@ void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
 
 	xe_eudebug_event_put(d, vm_destroy_event(d, xef, vm));
 }
+
+static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
+{
+	struct xe_vm *vm;
+	unsigned long i;
+	int err;
+
+	err = client_create_event(d, xef);
+	if (err)
+		return err;
+
+	mutex_lock(&xef->vm.lock);
+	xa_for_each(&xef->vm.xa, i, vm) {
+		err = vm_create_event(d, xef, vm);
+		if (err)
+			break;
+	}
+	mutex_unlock(&xef->vm.lock);
+
+	return err;
+}
+
+static bool xe_eudebug_task_match(struct xe_eudebug *d, struct xe_file *xef)
+{
+	struct task_struct *task;
+	bool match;
+
+	task = find_task_get(xef);
+	if (!task)
+		return false;
+
+	match = same_thread_group(d->target_task, task);
+
+	put_task_struct(task);
+
+	return match;
+}
+
+static void discover_clients(struct xe_device *xe, struct xe_eudebug *d)
+{
+	struct xe_file *xef, *tmp;
+	int err;
+
+	mutex_lock(&xe->files.lock);
+	list_for_each_entry_safe(xef, tmp, &xe->files.list, link) {
+		if (xe_eudebug_detached(d))
+			break;
+
+		if (xe_eudebug_task_match(d, xef))
+			err = discover_client(d, xef);
+		else
+			err = 0;
+
+		if (err) {
+			eu_dbg(d, "discover client %p: %d\n", xef, err);
+			xe_eudebug_disconnect(d, err);
+			break;
+		}
+	}
+	mutex_unlock(&xe->files.lock);
+}
+
+static void discovery_work_fn(struct work_struct *work)
+{
+	struct xe_eudebug *d = container_of(work, typeof(*d),
+					    discovery_work);
+	struct xe_device *xe = d->xe;
+
+	eu_dbg(d, "Discovery start for %lld\n", d->session);
+
+	discover_clients(xe, d);
+
+	eu_dbg(d, "Discovery end for %lld\n", d->session);
+
+	complete_all(&d->discovery);
+
+	xe_eudebug_put(d);
+}
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 093221a707df..202ddf41a325 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -19,6 +19,7 @@
 struct xe_device;
 struct task_struct;
 struct xe_eudebug_event;
+struct workqueue_struct;
 
 #define CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE 64
 
@@ -96,6 +97,12 @@ struct xe_eudebug {
 	/** @session: session number for this connection (for logs) */
 	u64 session;
 
+	/** @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 {
 		/** @lock: guards access to fifo */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 07/21] drm/xe/eudebug: Introduce exec_queue events
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (5 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 06/21] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 14:08 ` [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug Mika Kuoppala
                   ` (22 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Maciej Patelczyk, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Inform debugger about creation and destruction of exec_queues.

1) Use user engine class types instead of internal xe_engine_class enum
   in exec_queue event.

2) During discovery do not advertise every execqueue created, only ones
   with class render or compute.

v2: struct alignment (Mika)
v3: checkpatch (Maciej)

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       | 184 +++++++++++++++++++++++++-
 drivers/gpu/drm/xe/xe_eudebug.h       |   4 +
 drivers/gpu/drm/xe/xe_eudebug_types.h |  31 ++++-
 drivers/gpu/drm/xe/xe_exec_queue.c    |   5 +
 include/uapi/drm/xe_drm_eudebug.h     |  14 +-
 5 files changed, 235 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index d3051bbe9ec8..db55e449049a 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -14,9 +14,10 @@
 #include "xe_device.h"
 #include "xe_assert.h"
 #include "xe_macros.h"
-
 #include "xe_eudebug_types.h"
 #include "xe_eudebug.h"
+#include "xe_exec_queue_types.h"
+#include "xe_vm.h"
 
 /*
  * If there is no detected event read by userspace, during this period, assume
@@ -1104,8 +1105,178 @@ void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
 	xe_eudebug_event_put(d, vm_destroy_event(d, xef, vm));
 }
 
+static bool exec_queue_class_is_tracked(enum xe_engine_class class)
+{
+	return class == XE_ENGINE_CLASS_COMPUTE ||
+		class == XE_ENGINE_CLASS_RENDER;
+}
+
+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 client_handle, u64 vm_handle,
+				 u64 exec_queue_handle, enum xe_engine_class class,
+				 u32 width, u64 *lrc_handles, u64 seqno)
+{
+	struct xe_eudebug_event *event;
+	struct xe_eudebug_event_exec_queue *e;
+	const u32 sz = struct_size(e, lrc_handle, width);
+	const u32 xe_engine_class = xe_to_user_engine_class[class];
+
+	if (!exec_queue_class_is_tracked(class))
+		return -EINVAL;
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE,
+					seqno, flags, sz, GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	e = cast_event(e, event);
+
+	write_member(struct drm_xe_eudebug_event_exec_queue, e, client_handle, client_handle);
+	write_member(struct drm_xe_eudebug_event_exec_queue, e, vm_handle, vm_handle);
+	write_member(struct drm_xe_eudebug_event_exec_queue, e, exec_queue_handle,
+		     exec_queue_handle);
+	write_member(struct drm_xe_eudebug_event_exec_queue, e, engine_class, xe_engine_class);
+	write_member(struct drm_xe_eudebug_event_exec_queue, e, width, width);
+
+	memcpy(e->lrc_handle, lrc_handles, width);
+
+	return xe_eudebug_queue_event(d, event);
+}
+
+static int exec_queue_create_event(struct xe_eudebug *d,
+				   struct xe_file *xef, struct xe_exec_queue *q)
+{
+	int h_c, h_vm, h_queue;
+	u64 h_lrc[XE_HW_ENGINE_MAX_INSTANCE], seqno;
+	int i;
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
+	if (h_c < 0)
+		return h_c;
+
+	h_vm = find_handle(d->res, 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++) {
+		int h, ret;
+
+		ret = _xe_eudebug_add_handle(d,
+					     XE_EUDEBUG_RES_TYPE_LRC,
+					     q->lrc[i],
+					     NULL,
+					     &h);
+
+		if (ret < 0 && ret != -EEXIST)
+			return ret;
+
+		XE_WARN_ON(!h);
+
+		h_lrc[i] = h;
+	}
+
+	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
+	 */
+
+	return send_exec_queue_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
+				     h_c, h_vm, h_queue, q->class,
+				     q->width, h_lrc, seqno);
+}
+
+static int exec_queue_destroy_event(struct xe_eudebug *d,
+				    struct xe_file *xef,
+				    struct xe_exec_queue *q)
+{
+	int h_c, h_vm, h_queue;
+	u64 h_lrc[XE_HW_ENGINE_MAX_INSTANCE], seqno;
+	int i;
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
+	if (h_c < 0)
+		return h_c;
+
+	h_vm = find_handle(d->res, 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;
+
+	h_queue = xe_eudebug_remove_handle(d,
+					   XE_EUDEBUG_RES_TYPE_EXEC_QUEUE,
+					   q,
+					   &seqno);
+	if (h_queue <= 0)
+		return h_queue;
+
+	for (i = 0; i < q->width; i++) {
+		int ret;
+
+		ret = _xe_eudebug_remove_handle(d,
+						XE_EUDEBUG_RES_TYPE_LRC,
+						q->lrc[i],
+						NULL);
+		if (ret < 0 && ret != -ENOENT)
+			return ret;
+
+		XE_WARN_ON(!ret);
+
+		h_lrc[i] = ret;
+	}
+
+	return send_exec_queue_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY,
+				     h_c, h_vm, h_queue, q->class,
+				     q->width, h_lrc, seqno);
+}
+
+void xe_eudebug_exec_queue_create(struct xe_file *xef, struct xe_exec_queue *q)
+{
+	struct xe_eudebug *d;
+
+	if (!exec_queue_class_is_tracked(q->class))
+		return;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, exec_queue_create_event(d, xef, q));
+}
+
+void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q)
+{
+	struct xe_eudebug *d;
+
+	if (!exec_queue_class_is_tracked(q->class))
+		return;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, exec_queue_destroy_event(d, xef, q));
+}
+
 static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 {
+	struct xe_exec_queue *q;
 	struct xe_vm *vm;
 	unsigned long i;
 	int err;
@@ -1122,6 +1293,17 @@ static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 	}
 	mutex_unlock(&xef->vm.lock);
 
+	mutex_lock(&xef->exec_queue.lock);
+	xa_for_each(&xef->exec_queue.xa, i, q) {
+		if (!exec_queue_class_is_tracked(q->class))
+			continue;
+
+		err = exec_queue_create_event(d, xef, q);
+		if (err)
+			break;
+	}
+	mutex_unlock(&xef->exec_queue.lock);
+
 	return err;
 }
 
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index df577b581364..44b20549eb6d 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -10,6 +10,7 @@ struct drm_file;
 struct xe_device;
 struct xe_file;
 struct xe_vm;
+struct xe_exec_queue;
 
 int xe_eudebug_connect_ioctl(struct drm_device *dev,
 			     void *data,
@@ -24,4 +25,7 @@ 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);
 
+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);
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 202ddf41a325..6e3c23023933 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -50,7 +50,9 @@ struct xe_eudebug_resource {
 
 #define XE_EUDEBUG_RES_TYPE_CLIENT	0
 #define XE_EUDEBUG_RES_TYPE_VM		1
-#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_VM + 1)
+#define XE_EUDEBUG_RES_TYPE_EXEC_QUEUE	2
+#define XE_EUDEBUG_RES_TYPE_LRC		3
+#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_LRC + 1)
 
 /**
  * struct xe_eudebug_resources - eudebug resources for all types
@@ -173,4 +175,31 @@ struct xe_eudebug_event_vm {
 	u64 vm_handle;
 };
 
+/**
+ * struct xe_eudebug_event_exec_queue - Internal event for
+ * exec_queue create/destroy
+ */
+struct xe_eudebug_event_exec_queue {
+	/** @base: base event */
+	struct xe_eudebug_event base;
+
+	/** @client_handle: client for the engine create/destroy */
+	u64 client_handle;
+
+	/** @vm_handle: vm handle for the engine create/destroy */
+	u64 vm_handle;
+
+	/** @exec_queue_handle: engine handle */
+	u64 exec_queue_handle;
+
+	/** @engine_handle: engine class */
+	u32 engine_class;
+
+	/** @width: submission width (number BB per exec) for this exec queue */
+	u32 width;
+
+	/** @lrc_handles: handles for each logical ring context created with this exec queue */
+	u64 lrc_handle[];
+};
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index 956dc15b432a..26ae2fdbf682 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -22,6 +22,7 @@
 #include "xe_ring_ops_types.h"
 #include "xe_trace.h"
 #include "xe_vm.h"
+#include "xe_eudebug.h"
 
 enum xe_exec_queue_sched_prop {
 	XE_EXEC_QUEUE_JOB_TIMEOUT = 0,
@@ -626,6 +627,8 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
 	args->exec_queue_id = id;
 	q->xef = xe_file_get(xef);
 
+	xe_eudebug_exec_queue_create(xef, q);
+
 	return 0;
 
 kill_exec_queue:
@@ -797,6 +800,8 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
 	if (XE_IOCTL_DBG(xe, !q))
 		return -ENOENT;
 
+	xe_eudebug_exec_queue_destroy(xef, q);
+
 	xe_exec_queue_kill(q);
 
 	trace_xe_exec_queue_close(q);
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index a1cad9c005fc..25dddb8b22f4 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -26,7 +26,8 @@ struct drm_xe_eudebug_event {
 #define DRM_XE_EUDEBUG_EVENT_READ		1
 #define DRM_XE_EUDEBUG_EVENT_OPEN		2
 #define DRM_XE_EUDEBUG_EVENT_VM			3
-#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM
+#define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE		4
+#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
 
 	__u16 flags;
 #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
@@ -50,6 +51,17 @@ struct drm_xe_eudebug_event_vm {
 	__u64 vm_handle;
 };
 
+struct drm_xe_eudebug_event_exec_queue {
+	struct drm_xe_eudebug_event base;
+
+	__u64 client_handle;
+	__u64 vm_handle;
+	__u64 exec_queue_handle;
+	__u32 engine_class;
+	__u32 width;
+	__u64 lrc_handle[];
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (6 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 07/21] drm/xe/eudebug: Introduce exec_queue events Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-29 19:05   ` Lucas De Marchi
  2024-07-26 14:08 ` [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
                   ` (21 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: 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 needs to be programmed. Implement eudebug
mode enabling including eudebug related workarounds.

1) Enable exceptions only on platforms that does not have per context
   debugging functionality

2) Fixup 22015693276:
   Use lineage HSD instead of per platform specific, be precise defining
   graphics range.

Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/xe/regs/xe_engine_regs.h |  4 ++
 drivers/gpu/drm/xe/regs/xe_gt_regs.h     | 10 +++++
 drivers/gpu/drm/xe/xe_eudebug.c          | 50 ++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_eudebug.h          |  2 +
 drivers/gpu/drm/xe/xe_hw_engine.c        |  2 +
 5 files changed, 68 insertions(+)

diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
index c38db2a74614..fd31f3fb2b4c 100644
--- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
@@ -114,6 +114,10 @@
 
 #define INDIRECT_RING_STATE(base)		XE_REG((base) + 0x108)
 
+#define CS_DEBUG_MODE2(base)			XE_REG((base) + 0xd8, XE_REG_OPTION_MASKED)
+#define   INST_STATE_CACHE_INVALIDATE		REG_BIT(6)
+#define   GLOBAL_DEBUG_ENABLE			REG_BIT(5)
+
 #define RING_BBADDR(base)			XE_REG((base) + 0x140)
 #define RING_BBADDR_UDW(base)			XE_REG((base) + 0x168)
 
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 8a94a94d2267..96a59a96dd4c 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -425,6 +425,14 @@
 #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)
@@ -450,11 +458,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)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index db55e449049a..9611acedeee9 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -11,13 +11,19 @@
 
 #include <drm/drm_managed.h>
 
+#include "regs/xe_gt_regs.h"
+#include "regs/xe_engine_regs.h"
 #include "xe_device.h"
 #include "xe_assert.h"
 #include "xe_macros.h"
+#include "xe_gt.h"
 #include "xe_eudebug_types.h"
 #include "xe_eudebug.h"
 #include "xe_exec_queue_types.h"
+#include "xe_module.h"
+#include "xe_rtp.h"
 #include "xe_vm.h"
+#include "xe_wa.h"
 
 /*
  * If there is no detected event read by userspace, during this period, assume
@@ -925,6 +931,50 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
 	return ret;
 }
 
+#undef XE_REG_MCR
+#define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
+
+void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
+{
+	const struct xe_rtp_entry_sr eudebug_was[] = {
+		{ XE_RTP_NAME("GlobalDebugEnable"),
+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
+			       ENGINE_CLASS(RENDER)),
+		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
+				     GLOBAL_DEBUG_ENABLE))
+		},
+		{ XE_RTP_NAME("TdCtlDebugEnable"),
+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(SET(TD_CTL,
+				     TD_CTL_BREAKPOINT_ENABLE |
+				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
+				     TD_CTL_FEH_AND_FEE_ENABLE))
+		},
+		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
+		},
+		{ XE_RTP_NAME("18022722726"),
+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
+		},
+		{ XE_RTP_NAME("14015527279"),
+		  XE_RTP_RULES(PLATFORM(PVC),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
+		},
+		{}
+	};
+	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
+	struct xe_device *xe = gt_to_xe(hwe->gt);
+
+	if (xe->eudebug.available)
+		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
+}
+
 void xe_eudebug_init(struct xe_device *xe)
 {
 	spin_lock_init(&xe->eudebug.lock);
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 44b20549eb6d..ac89a3d1ee1d 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -11,6 +11,7 @@ struct xe_device;
 struct xe_file;
 struct xe_vm;
 struct xe_exec_queue;
+struct xe_hw_engine;
 
 int xe_eudebug_connect_ioctl(struct drm_device *dev,
 			     void *data,
@@ -18,6 +19,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
 
 void xe_eudebug_init(struct xe_device *xe);
 void xe_eudebug_fini(struct xe_device *xe);
+void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
 
 void xe_eudebug_file_open(struct xe_file *xef);
 void xe_eudebug_file_close(struct xe_file *xef);
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index 20c4fdf40790..0d8b871b47fe 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -15,6 +15,7 @@
 #include "xe_assert.h"
 #include "xe_bo.h"
 #include "xe_device.h"
+#include "xe_eudebug.h"
 #include "xe_execlist.h"
 #include "xe_force_wake.h"
 #include "xe_gsc.h"
@@ -503,6 +504,7 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
 	xe_tuning_process_engine(hwe);
 	xe_wa_process_engine(hwe);
 	hw_engine_setup_default_state(hwe);
+	xe_eudebug_init_hw_engine(hwe);
 
 	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
 	xe_reg_whitelist_process_engine(hwe);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (7 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 18:35   ` Matthew Brost
  2024-07-27  0:54   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
                   ` (20 subsequent siblings)
  29 siblings, 2 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Introduce exec queue immutable property of eudebug
with a flags as value to enable eudebug specific feature(s).

For now engine lrc will use this flag to set up runalone
hw feature. Runalone is used to ensure that only one hw engine
of group [rcs0, ccs0-3] is active on a tile.

Note: unlike the i915, xe allows user to set runalone
also on devices with single render/compute engine. It should not
make much difference, but leave control to the user.

v2: use exec queue flags (Mika)
v3: eudebug enable as flags (Mika)
v4: adapt to lrc_create (Mika)
v5: EUDEBUG property space squash (Mika)
v6: runalone as rmw (Dominik)

Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/xe/regs/xe_engine_regs.h |  1 +
 drivers/gpu/drm/xe/xe_exec_queue.c       | 35 ++++++++++++++++++++++--
 drivers/gpu/drm/xe/xe_exec_queue_types.h |  7 +++++
 drivers/gpu/drm/xe/xe_hw_engine.c        |  2 +-
 drivers/gpu/drm/xe/xe_lrc.c              | 16 +++++++++--
 drivers/gpu/drm/xe/xe_lrc.h              |  4 ++-
 include/uapi/drm/xe_drm.h                |  3 +-
 7 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
index fd31f3fb2b4c..764c270599d0 100644
--- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
@@ -136,6 +136,7 @@
 #define	  CTX_CTRL_OAC_CONTEXT_ENABLE		REG_BIT(8)
 #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
 #define	  CTX_CTRL_INDIRECT_RING_STATE_ENABLE	REG_BIT(4)
+#define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
 #define	  CTX_CTRL_INHIBIT_SYN_CTX_SWITCH	REG_BIT(3)
 #define	  CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT	REG_BIT(0)
 
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index 26ae2fdbf682..bc2edade5e5b 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -106,10 +106,14 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
 
 static int __xe_exec_queue_init(struct xe_exec_queue *q)
 {
+	u32 flags = 0;
 	int i, err;
 
+	if (q->eudebug_flags & EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)
+		flags |= LRC_CREATE_RUNALONE;
+
 	for (i = 0; i < q->width; ++i) {
-		q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K);
+		q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K, flags);
 		if (IS_ERR(q->lrc[i])) {
 			err = PTR_ERR(q->lrc[i]);
 			goto err_lrc;
@@ -336,6 +340,31 @@ static int exec_queue_set_timeslice(struct xe_device *xe, struct xe_exec_queue *
 	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;
+
+	/*
+	 * We want to explicitly set the global feature if
+	 * property is set.
+	 */
+	if (XE_IOCTL_DBG(xe,
+			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
+		return -EINVAL;
+
+	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
+
+	return 0;
+}
+
 typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
 					     struct xe_exec_queue *q,
 					     u64 value);
@@ -343,6 +372,7 @@ typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
 static const xe_exec_queue_set_property_fn exec_queue_set_property_funcs[] = {
 	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY] = exec_queue_set_priority,
 	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE] = exec_queue_set_timeslice,
+	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG] = exec_queue_set_eudebug,
 };
 
 static int exec_queue_user_ext_set_property(struct xe_device *xe,
@@ -362,7 +392,8 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe,
 			 ARRAY_SIZE(exec_queue_set_property_funcs)) ||
 	    XE_IOCTL_DBG(xe, ext.pad) ||
 	    XE_IOCTL_DBG(xe, ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY &&
-			 ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE))
+			 ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE &&
+			 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_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h
index 1408b02eea53..48e1190c2b58 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue_types.h
+++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h
@@ -90,6 +90,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/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index 0d8b871b47fe..74813bc20787 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -532,7 +532,7 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe,
 		goto err_name;
 	}
 
-	hwe->kernel_lrc = xe_lrc_create(hwe, NULL, SZ_16K);
+	hwe->kernel_lrc = xe_lrc_create(hwe, NULL, SZ_16K, 0);
 	if (IS_ERR(hwe->kernel_lrc)) {
 		err = PTR_ERR(hwe->kernel_lrc);
 		goto err_hwsp;
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index 94ff62e1d95e..563b57f5b9ee 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -890,7 +890,7 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
 #define PVC_CTX_ACC_CTR_THOLD	(0x2a + 1)
 
 static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
-		       struct xe_vm *vm, u32 ring_size)
+		       struct xe_vm *vm, u32 ring_size, u32 flags)
 {
 	struct xe_gt *gt = hwe->gt;
 	struct xe_tile *tile = gt_to_tile(gt);
@@ -1007,6 +1007,16 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
 	map = __xe_lrc_start_seqno_map(lrc);
 	xe_map_write32(lrc_to_xe(lrc), &map, lrc->fence_ctx.next_seqno - 1);
 
+	if (flags & LRC_CREATE_RUNALONE) {
+		u32 ctx_control = xe_lrc_read_ctx_reg(lrc, CTX_CONTEXT_CONTROL);
+
+		drm_dbg(&xe->drm, "read CTX_CONTEXT_CONTROL: 0x%x\n", ctx_control);
+		ctx_control |= _MASKED_BIT_ENABLE(CTX_CTRL_RUN_ALONE);
+		drm_dbg(&xe->drm, "written CTX_CONTEXT_CONTROL: 0x%x\n", ctx_control);
+
+		xe_lrc_write_ctx_reg(lrc, CTX_CONTEXT_CONTROL, ctx_control);
+	}
+
 	return 0;
 
 err_lrc_finish:
@@ -1026,7 +1036,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
  * upon failure.
  */
 struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
-			     u32 ring_size)
+			     u32 ring_size, u32 flags)
 {
 	struct xe_lrc *lrc;
 	int err;
@@ -1035,7 +1045,7 @@ struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
 	if (!lrc)
 		return ERR_PTR(-ENOMEM);
 
-	err = xe_lrc_init(lrc, hwe, vm, ring_size);
+	err = xe_lrc_init(lrc, hwe, vm, ring_size, flags);
 	if (err) {
 		kfree(lrc);
 		return ERR_PTR(err);
diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
index c24542e89318..d2429a26fb22 100644
--- a/drivers/gpu/drm/xe/xe_lrc.h
+++ b/drivers/gpu/drm/xe/xe_lrc.h
@@ -22,8 +22,10 @@ struct xe_vm;
 
 #define LRC_PPHWSP_SCRATCH_ADDR (0x34 * 4)
 
+#define LRC_CREATE_RUNALONE     BIT(0)
+
 struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
-			     u32 ring_size);
+			     u32 ring_size, u32 flags);
 void xe_lrc_destroy(struct kref *ref);
 
 /**
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index a68734ff12f4..61c4c061bd75 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -1110,7 +1110,8 @@ struct drm_xe_exec_queue_create {
 #define DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY		0
 #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY		0
 #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE		1
-
+#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG		2
+#define     DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE		(1 << 0)
 	/** @extensions: Pointer to the first extension struct, if any */
 	__u64 extensions;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (8 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-27  5:08   ` Matthew Brost
  2024-07-27  5:39   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 11/21] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
                   ` (19 subsequent siblings)
  29 siblings, 2 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe
  Cc: Dominik Grzegorzek, Christoph Manszewski, Maciej Patelczyk,
	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 10 times slower when there is no debugger
connection open. Send attention event whenever we see attention with
debugger presence. If there is no debugger connection active - reset.

Based on work by authors and other folks who were part of attentions in
i915.

- v2 Do not validate potentially active hwe against engine->hwe.
  Whenever the engine has width > 1, this field contains only the first
  hwe of the class.
- squash dss walking and semaphore to mutex
- v3 error path fix in xe_send_gt_attention (Christoph)
- v4 runalone active fix (Mika)
- v5 q->lrc changes (Mika)
- v6 Use C99 flexible arrays (Maciej, checkpatch)
     function with 'for_each' in name (Maciej, checkpatch)
- v7 long running active fix (Dominik)
- v8 resource handling errors rebase (Mika)
- v9 find out lrc handles first before sending event (Mika)
- v10 adjust runalone shift according to hw

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>
---
 drivers/gpu/drm/xe/Makefile              |   1 +
 drivers/gpu/drm/xe/regs/xe_engine_regs.h |   3 +
 drivers/gpu/drm/xe/regs/xe_gt_regs.h     |   7 +
 drivers/gpu/drm/xe/xe_device.c           |   2 +
 drivers/gpu/drm/xe/xe_device_types.h     |   3 +
 drivers/gpu/drm/xe/xe_eudebug.c          | 389 ++++++++++++++++++++++-
 drivers/gpu/drm/xe/xe_eudebug.h          |   1 +
 drivers/gpu/drm/xe/xe_eudebug_types.h    |  32 ++
 drivers/gpu/drm/xe/xe_gt_debug.c         | 152 +++++++++
 drivers/gpu/drm/xe/xe_gt_debug.h         |  21 ++
 include/uapi/drm/xe_drm_eudebug.h        |  15 +-
 11 files changed, 624 insertions(+), 2 deletions(-)
 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 06badc5f99af..b7b6b047c02c 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -49,6 +49,7 @@ xe-y += xe_bb.o \
 	xe_gt_debugfs.o \
 	xe_gt_freq.o \
 	xe_gt_idle.o \
+	xe_gt_debug.o \
 	xe_gt_mcr.o \
 	xe_gt_pagefault.o \
 	xe_gt_sysfs.o \
diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
index 764c270599d0..b9d713a2061d 100644
--- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
@@ -132,6 +132,9 @@
 #define RING_EXECLIST_STATUS_LO(base)		XE_REG((base) + 0x234)
 #define RING_EXECLIST_STATUS_HI(base)		XE_REG((base) + 0x234 + 4)
 
+#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_OAC_CONTEXT_ENABLE		REG_BIT(8)
 #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 96a59a96dd4c..03e83ce3e35d 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -437,6 +437,8 @@
 #define   DISABLE_ECC				REG_BIT(5)
 #define   ENABLE_PREFETCH_INTO_IC		REG_BIT(3)
 
+#define TD_ATT(x)				XE_REG_MCR(0xe470 + (x) * 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)
@@ -516,6 +518,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 FORCEWAKE_ACK_GT			XE_REG(0x130044)
 
 /* Applicable for all FORCEWAKE_DOMAIN and FORCEWAKE_ACK_DOMAIN regs */
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 90bb0a8b1881..ba1c80089906 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -768,6 +768,8 @@ int xe_device_probe(struct xe_device *xe)
 
 	xe_debugfs_register(xe);
 
+	xe_eudebug_init_late(xe);
+
 	xe_hwmon_register(xe);
 
 	for_each_gt(gt, xe, id)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 4dcfd39cb909..3b33add576be 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -516,6 +516,9 @@ struct xe_device {
 
 		/** @ordered_wq: used to discovery */
 		struct workqueue_struct *ordered_wq;
+
+		/** @attention_scan: attention scan worker */
+		struct delayed_work attention_scan;
 	} eudebug;
 
 	/* private: */
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 9611acedeee9..c2de001cc33a 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -11,19 +11,29 @@
 
 #include <drm/drm_managed.h>
 
-#include "regs/xe_gt_regs.h"
 #include "regs/xe_engine_regs.h"
+#include "regs/xe_gt_regs.h"
 #include "xe_device.h"
 #include "xe_assert.h"
 #include "xe_macros.h"
 #include "xe_gt.h"
+#include "xe_gt_debug.h"
+#include "xe_lrc.h"
+#include "xe_hw_engine.h"
+#include "xe_exec_queue.h"
 #include "xe_eudebug_types.h"
 #include "xe_eudebug.h"
 #include "xe_exec_queue_types.h"
+#include "xe_guc_exec_queue_types.h"
+#include "xe_execlist_types.h"
+#include "xe_mmio.h"
 #include "xe_module.h"
+#include "xe_pm.h"
 #include "xe_rtp.h"
+#include "xe_sched_job.h"
 #include "xe_vm.h"
 #include "xe_wa.h"
+#include "xe_force_wake.h"
 
 /*
  * If there is no detected event read by userspace, during this period, assume
@@ -843,6 +853,371 @@ static const struct file_operations fops = {
 	.unlocked_ioctl	= xe_eudebug_ioctl,
 };
 
+static bool queue_has_active_job(struct xe_exec_queue *q)
+{
+
+	struct drm_gpu_scheduler *sched;
+	struct drm_sched_job *drm_job;
+
+	if (xe_device_uc_enabled(gt_to_xe(q->gt)))
+		sched = &q->guc->sched.base;
+	else
+		sched = &q->execlist->sched;
+
+	drm_job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list);
+
+	if (drm_job) {
+		struct xe_sched_job *job = to_xe_sched_job(drm_job);
+
+		return xe_sched_job_started(job) && !xe_sched_job_completed(job);
+	} else if (xe_exec_queue_is_lr(q) &&
+		   (xe_lrc_ring_head(q->lrc[0]) != xe_lrc_ring_tail(q->lrc[0]))) {
+		return true;
+	}
+
+	return false;
+}
+
+static int current_lrc(struct xe_hw_engine *hwe, u32 *lrc_hw)
+{
+	u32 lrc_reg;
+	int err;
+
+	err = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
+	if (err)
+		return err;
+
+	lrc_reg = hw_engine_mmio_read32(hwe, RING_CURRENT_LRCA(0));
+
+	xe_force_wake_put(gt_to_fw(hwe->gt), hwe->domain);
+
+	if (!(lrc_reg & CURRENT_LRCA_VALID))
+		return -ENOENT;
+
+	*lrc_hw = lrc_reg & GENMASK(31, 12);
+
+	return 0;
+}
+
+static int match_engine_lrc(struct xe_exec_queue *q, u32 lrc_hw)
+{
+	int i;
+	u32 lrc_ggtt;
+
+	for (i = 0; i < q->width; i++) {
+		lrc_ggtt = lower_32_bits(xe_lrc_descriptor(q->lrc[i]));
+		lrc_ggtt &= GENMASK(31, 12);
+		if (lrc_ggtt == lrc_hw)
+			return i;
+	}
+
+	return -1;
+}
+
+static u32 engine_status(const struct xe_hw_engine * const hwe,
+			 u32 rcu_debug1)
+{
+	const bool xe1 = GRAPHICS_VER(gt_to_xe(hwe->gt)) < 20;
+	unsigned int shift;
+
+	if (hwe->class == XE_ENGINE_CLASS_RENDER) {
+		shift = 7;
+		XE_WARN_ON(hwe->instance != 0);
+	} else if (hwe->class == XE_ENGINE_CLASS_COMPUTE) {
+		XE_WARN_ON(hwe->instance > 3);
+
+		if (xe1)
+			shift = 10 + (hwe->instance * 3);
+		else
+			shift = 11 + (hwe->instance * 4);
+	} else {
+		XE_WARN_ON(hwe->class);
+		return 0;
+	}
+
+	return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
+}
+
+static bool engine_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_context_set(const struct xe_hw_engine * const hwe,
+			       u32 rcu_debug1)
+{
+	return engine_status(hwe, rcu_debug1) & RCU_DEBUG_1_CONTEXT_ACTIVE;
+}
+
+static bool engine_has_runalone(const struct xe_hw_engine * const hwe)
+{
+	return hwe->class == XE_ENGINE_CLASS_RENDER ||
+		hwe->class == XE_ENGINE_CLASS_COMPUTE;
+}
+
+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;
+	u32 val;
+
+	if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GT)) {
+		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone failed to get force wake\n");
+		return NULL;
+	}
+
+	val = xe_mmio_read32(gt, RCU_DEBUG_1);
+	xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
+
+	drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone RCU_DEBUG_1 = 0x%08x\n", val);
+
+	num_active = 0;
+	for_each_hw_engine(hwe, gt, id) {
+		bool runalone, ctx;
+
+		if (!engine_has_runalone(hwe))
+			continue;
+
+		runalone = engine_runalone_set(hwe, val);
+		ctx = engine_context_set(hwe, val);
+
+		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: engine %s: runalone=%s, context=%s",
+			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(&gt_to_xe(gt)->drm, "eudbg: runalone engine %s %s",
+				hwe->name, first ? "selected" : "found");
+			if (!first)
+				first = hwe;
+		}
+	}
+
+	if (num_active > 1)
+		drm_err(&gt_to_xe(gt)->drm, "eudbg: %d runalone engines active!",
+			num_active);
+
+	return first;
+}
+
+static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
+{
+	struct xe_device *xe = gt_to_xe(gt);
+	struct xe_exec_queue *q, *found = NULL;
+	struct xe_hw_engine *active;
+	struct xe_file *xef, *tmp;
+	unsigned long i;
+	int idx, err;
+	u32 lrc_hw;
+
+	active = get_runalone_active_hw_engine(gt);
+	if (!active) {
+		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
+		return ERR_PTR(-ENOENT);
+	}
+
+	err = current_lrc(active, &lrc_hw);
+	if (err)
+		return ERR_PTR(err);
+
+	mutex_lock(&xe->files.lock);
+	list_for_each_entry_safe(xef, tmp, &xe->files.list, link) {
+		mutex_lock(&xef->exec_queue.lock);
+		xa_for_each(&xef->exec_queue.xa, i, q) {
+			if (q->gt != gt)
+				continue;
+
+			if (q->class != active->class)
+				continue;
+
+			if (!queue_has_active_job(q))
+				continue;
+
+			idx = match_engine_lrc(q, lrc_hw);
+			if (idx < 0)
+				continue;
+
+			xe_exec_queue_get(q);
+			found = q;
+
+			if (lrc_idx)
+				*lrc_idx = idx;
+
+			break;
+		}
+		mutex_unlock(&xef->exec_queue.lock);
+
+		if (found)
+			break;
+	}
+	mutex_unlock(&xe->files.lock);
+
+	if (!found)
+		return ERR_PTR(-ENOENT);
+
+	if (XE_WARN_ON(current_lrc(active, &lrc_hw)) &&
+	    XE_WARN_ON(match_engine_lrc(found, lrc_hw) < 0)) {
+		xe_exec_queue_put(found);
+		return ERR_PTR(-ENOENT);
+	}
+
+	return found;
+}
+
+static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, int lrc_idx)
+{
+	struct xe_eudebug_event_eu_attention *ea;
+	struct xe_eudebug_event *event;
+	int h_c, h_queue, h_lrc;
+	u32 size = xe_gt_eu_attention_bitmap_size(q->gt);
+	u32 sz = struct_size(ea, bitmask, size);
+	int ret;
+
+	XE_WARN_ON(lrc_idx < 0 || lrc_idx >= q->width);
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, q->vm->xef);
+	if (h_c < 0)
+		return h_c;
+
+	h_queue = find_handle(d->res, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q);
+	if (h_queue < 0)
+		return h_queue;
+
+	h_lrc = find_handle(d->res, XE_EUDEBUG_RES_TYPE_LRC, q->lrc[lrc_idx]);
+	if (h_lrc < 0)
+		return h_lrc;
+
+	event = __xe_eudebug_create_event(d, 0, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+					  DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, sz, GFP_KERNEL);
+
+	if (!event)
+		return -ENOSPC;
+
+	ea = cast_event(ea, event);
+	write_member(struct drm_xe_eudebug_event_eu_attention, ea, client_handle, (u64)h_c);
+	write_member(struct drm_xe_eudebug_event_eu_attention, ea, exec_queue_handle, (u64)h_queue);
+	write_member(struct drm_xe_eudebug_event_eu_attention, ea, lrc_handle, (u64)h_lrc);
+	write_member(struct drm_xe_eudebug_event_eu_attention, ea, bitmask_size, size);
+
+	mutex_lock(&d->eu_lock);
+	event->seqno = atomic_long_inc_return(&d->events.seqno);
+	ret = xe_gt_eu_attention_bitmap(q->gt, &ea->bitmask[0], ea->bitmask_size);
+	mutex_unlock(&d->eu_lock);
+
+	if (ret)
+		return ret;
+
+	return xe_eudebug_queue_event(d, event);
+}
+
+
+static int xe_send_gt_attention(struct xe_gt *gt)
+{
+	struct xe_eudebug *d;
+	struct xe_exec_queue *q;
+	int ret, lrc_idx;
+
+	if (list_empty_careful(&gt_to_xe(gt)->eudebug.list))
+		return -ENOTCONN;
+
+	q = runalone_active_queue_get(gt, &lrc_idx);
+	if (IS_ERR(q))
+		return PTR_ERR(q);
+
+	d = xe_eudebug_get(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);
+	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)
+{
+	int ret;
+
+	ret = xe_gt_eu_threads_needing_attention(gt);
+	if (ret <= 0)
+		return ret;
+
+	ret = xe_send_gt_attention(gt);
+
+	/* Discovery in progress, fake it */
+	if (ret == -EBUSY)
+		return 0;
+
+	return ret;
+}
+
+#define XE_EUDEBUG_ATTENTION_INTERVAL 100
+static void attention_scan_fn(struct work_struct *work)
+{
+	struct xe_device *xe = container_of(work, typeof(*xe), eudebug.attention_scan.work);
+	long delay = msecs_to_jiffies(XE_EUDEBUG_ATTENTION_INTERVAL);
+	struct xe_gt *gt;
+	u8 gt_id;
+
+	if (list_empty_careful(&xe->eudebug.list))
+		delay *= 10;
+
+	if (delay >= HZ)
+		delay = round_jiffies_up_relative(delay);
+
+	if (pm_runtime_active(xe->drm.dev)) {
+		for_each_gt(gt, xe, gt_id) {
+			int ret;
+
+			ret = xe_eudebug_handle_gt_attention(gt);
+			if (ret) {
+				// TODO: error capture
+				drm_info(&gt_to_xe(gt)->drm,
+					 "gt:%d unable to handle eu attention ret=%d\n",
+					 gt_id, ret);
+
+				xe_gt_reset_async(gt);
+			}
+		}
+	}
+
+	schedule_delayed_work(&xe->eudebug.attention_scan, delay);
+}
+
+static void attention_scan_cancel(struct xe_device *xe)
+{
+	cancel_delayed_work_sync(&xe->eudebug.attention_scan);
+}
+
+static void attention_scan_flush(struct xe_device *xe)
+{
+	mod_delayed_work(system_wq, &xe->eudebug.attention_scan, 0);
+}
+
 static void discovery_work_fn(struct work_struct *work);
 
 static int
@@ -877,6 +1252,7 @@ xe_eudebug_connect(struct xe_device *xe,
 
 	kref_init(&d->ref);
 	spin_lock_init(&d->connection.lock);
+	mutex_init(&d->eu_lock);
 	init_waitqueue_head(&d->events.write_done);
 	init_waitqueue_head(&d->events.read_done);
 	init_completion(&d->discovery);
@@ -903,6 +1279,7 @@ xe_eudebug_connect(struct xe_device *xe,
 
 	kref_get(&d->ref);
 	queue_work(xe->eudebug.ordered_wq, &d->discovery_work);
+	attention_scan_flush(xe);
 
 	eu_dbg(d, "connected session %lld", d->session);
 
@@ -979,12 +1356,22 @@ void xe_eudebug_init(struct xe_device *xe)
 {
 	spin_lock_init(&xe->eudebug.lock);
 	INIT_LIST_HEAD(&xe->eudebug.list);
+	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
 
 	xe->eudebug.available = true;
 }
 
+void xe_eudebug_init_late(struct xe_device *xe)
+{
+	if (!xe->eudebug.available)
+		return;
+
+	attention_scan_flush(xe);
+}
+
 void xe_eudebug_fini(struct xe_device *xe)
 {
+	attention_scan_cancel(xe);
 	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
 }
 
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index ac89a3d1ee1d..1e233c4683d6 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -18,6 +18,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
 			     struct drm_file *file);
 
 void xe_eudebug_init(struct xe_device *xe);
+void xe_eudebug_init_late(struct xe_device *xe);
 void xe_eudebug_fini(struct xe_device *xe);
 void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
 
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 6e3c23023933..16667b4dfe45 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -105,6 +105,9 @@ struct xe_eudebug {
 	/** @discovery_work: worker to discover resources for target_task */
 	struct work_struct discovery_work;
 
+	/** eu_lock: guards operations on eus (eu thread control and attention) */
+	struct mutex eu_lock;
+
 	/** @events: kfifo queue of to-be-delivered events */
 	struct {
 		/** @lock: guards access to fifo */
@@ -202,4 +205,33 @@ struct xe_eudebug_event_exec_queue {
 	u64 lrc_handle[];
 };
 
+/**
+ * struct xe_eudebug_event_eu_attention - Internal event for EU attention
+ */
+struct xe_eudebug_event_eu_attention {
+	/** @base: base event */
+	struct xe_eudebug_event base;
+
+	/** @client_handle: client for the attention */
+	u64 client_handle;
+
+	/** @exec_queue_handle: handle of exec_queue which raised attention */
+	u64 exec_queue_handle;
+
+	/** @lrc_handle: lrc handle of the workload which raised attention */
+	u64 lrc_handle;
+
+	/** @flags: eu attention event flags, currently MBZ */
+	u32 flags;
+
+	/** @bitmask_size: size of the bitmask, specific to device */
+	u32 bitmask_size;
+
+	/**
+	 * @bitmask: reflects threads currently signalling attention,
+	 * starting from natural hardware order of DSS=0, eu=0
+	 */
+	u8 bitmask[];
+};
+
 #endif
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..04d2d43ce249
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_gt_debug.c
@@ -0,0 +1,152 @@
+// 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"
+
+static int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
+					    int (*fn)(struct xe_gt *gt,
+						      void *data,
+						      u16 group,
+						      u16 instance),
+					    void *data)
+{
+	const enum xe_force_wake_domains fw_domains = XE_FW_GT | XE_FW_RENDER;
+	unsigned int dss;
+	u16 group, instance;
+	int ret;
+
+	xe_pm_runtime_get(gt_to_xe(gt));
+	ret = xe_force_wake_get(gt_to_fw(gt), fw_domains);
+	if (ret)
+		goto pm_runtime_put;
+
+	for_each_dss_steering(dss, gt, group, instance) {
+		ret = fn(gt, data, group, instance);
+		if (ret)
+			break;
+	}
+
+	xe_force_wake_put(gt_to_fw(gt), fw_domains);
+pm_runtime_put:
+	xe_pm_runtime_put(gt_to_xe(gt));
+
+	return ret;
+}
+
+static int read_first_attention_mcr(struct xe_gt *gt, void *data,
+				    u16 group, u16 instance)
+{
+	unsigned int row;
+
+	for (row = 0; row < 2; row++) {
+		u32 val;
+
+		val = xe_gt_mcr_unicast_read(gt, TD_ATT(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);
+
+	return  bitmap_weight(dss_mask, XE_MAX_DSS_FUSE_BITS) *
+		TD_EU_ATTENTION_MAX_ROWS * 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)
+{
+	struct attn_read_iter * const iter = data;
+	unsigned int row;
+
+	for (row = 0; row < TD_EU_ATTENTION_MAX_ROWS; row++) {
+		u32 val;
+
+		if (iter->i >= iter->size)
+			return 0;
+
+		XE_WARN_ON(iter->i + sizeof(val) > xe_gt_eu_attention_bitmap_size(gt));
+
+		val = xe_gt_mcr_unicast_read(gt, TD_ATT(row), group, instance);
+
+
+		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
+	};
+
+	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..3f13dbb17a5f
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_gt_debug.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __XE_GT_DEBUG_
+#define __XE_GT_DEBUG_
+
+#define TD_EU_ATTENTION_MAX_ROWS 2u
+
+#include "xe_gt_types.h"
+
+#define XE_GT_ATTENTION_TIMEOUT_MS 100
+
+int xe_gt_eu_threads_needing_attention(struct xe_gt *gt);
+
+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/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 25dddb8b22f4..453269ac8307 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -27,13 +27,15 @@ struct drm_xe_eudebug_event {
 #define DRM_XE_EUDEBUG_EVENT_OPEN		2
 #define DRM_XE_EUDEBUG_EVENT_VM			3
 #define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE		4
-#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
+#define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
+#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
 
 	__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)
+
 	__u64 seqno;
 	__u64 reserved;
 };
@@ -62,6 +64,17 @@ struct drm_xe_eudebug_event_exec_queue {
 	__u64 lrc_handle[];
 };
 
+struct drm_xe_eudebug_event_eu_attention {
+	struct drm_xe_eudebug_event base;
+
+	__u64 client_handle;
+	__u64 exec_queue_handle;
+	__u64 lrc_handle;
+	__u32 flags;
+	__u32 bitmask_size;
+	__u8 bitmask[];
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 11/21] drm/xe/eudebug: Introduce EU control interface
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (9 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 14:08 ` [PATCH 12/21] drm/xe/eudebug: Add vm bind and vm bind ops Mika Kuoppala
                   ` (18 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Maciej Patelczyk, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Introduce EU control functionality, which allows EU debugger
to interrupt, resume, and inform about the current state of
EU threads during execution. Provide an abstraction layer,
so in the future guc will only need to provide appropriate callbacks.

Based on implementation created by authors and other folks within
i915 driver.

v2: checkpatch (Maciej)
v3: lrc index off by one fix (Mika)

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/regs/xe_gt_regs.h  |   2 +
 drivers/gpu/drm/xe/xe_eudebug.c       | 559 ++++++++++++++++++++++++--
 drivers/gpu/drm/xe/xe_eudebug_types.h |  23 ++
 drivers/gpu/drm/xe/xe_gt_debug.c      |  12 +-
 drivers/gpu/drm/xe/xe_gt_debug.h      |   6 +
 include/uapi/drm/xe_drm_eudebug.h     |  21 +-
 6 files changed, 586 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 03e83ce3e35d..546bb7cc2337 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -448,6 +448,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 TD_CLR(i)				XE_REG_MCR(0xe490 + (i) * 4)
+
 #define ROW_CHICKEN3				XE_REG_MCR(0xe49c, XE_REG_OPTION_MASKED)
 #define   XE2_EUPEND_CHK_FLUSH_DIS		REG_BIT(14)
 #define   DIS_FIX_EOT1_FLUSH			REG_BIT(9)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index c2de001cc33a..582805bebf26 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -18,6 +18,7 @@
 #include "xe_macros.h"
 #include "xe_gt.h"
 #include "xe_gt_debug.h"
+#include "xe_gt_mcr.h"
 #include "xe_lrc.h"
 #include "xe_hw_engine.h"
 #include "xe_exec_queue.h"
@@ -575,6 +576,70 @@ static int find_handle(struct xe_eudebug_resources *res,
 	return id;
 }
 
+static struct xe_eudebug_handle *__find_resource(struct xe_eudebug_resources *res,
+						 const int type,
+						 const u32 id)
+{
+	struct xe_eudebug_resource *r;
+
+	r = resource_from_type(res, type);
+
+	return xa_load(&r->xa, id);
+}
+
+static struct xe_eudebug_handle *find_resource(struct xe_eudebug_resources *res,
+					       const int type,
+					       const u32 id)
+{
+	struct xe_eudebug_handle *h;
+
+	mutex_lock(&res->lock);
+	h = __find_resource(res, type, id);
+	mutex_unlock(&res->lock);
+
+	return h;
+}
+
+static struct xe_file *find_client(struct xe_eudebug *d, const u32 id)
+{
+	struct xe_eudebug_handle *h;
+
+	h = find_resource(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, id);
+	if (h)
+		return (void *)h->key;
+
+	return NULL;
+}
+
+static struct xe_exec_queue *find_exec_queue_get(struct xe_eudebug *d,
+						 u32 id)
+{
+	struct xe_exec_queue *q = NULL;
+	struct xe_eudebug_handle *h;
+
+	mutex_lock(&d->res->lock);
+	h = __find_resource(d->res, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, id);
+	if (h) {
+		q = (struct xe_exec_queue *)h->key;
+		xe_exec_queue_get(q);
+	}
+	mutex_unlock(&d->res->lock);
+
+	return q;
+}
+
+static struct xe_lrc *find_lrc(struct xe_eudebug *d, const u32 id)
+{
+	struct xe_lrc *l = NULL;
+	struct xe_eudebug_handle *h;
+
+	h = find_resource(d->res, XE_EUDEBUG_RES_TYPE_LRC, id);
+	if (h)
+		return (void *)h->key;
+
+	return l;
+}
+
 static int _xe_eudebug_add_handle(struct xe_eudebug *d,
 				  int type,
 				  void *p,
@@ -824,6 +889,171 @@ static long xe_eudebug_read_event(struct xe_eudebug *d,
 	return ret;
 }
 
+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;
+	u8 *bits = NULL;
+	unsigned int hw_attn_size, attn_size;
+	struct xe_exec_queue *q;
+	struct xe_file *xef;
+	struct xe_lrc *lrc;
+	u64 seqno;
+	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;
+
+	xef = find_client(d, arg->client_handle);
+	if (XE_IOCTL_DBG(xe, !xef))
+		return -EINVAL;
+
+	q = find_exec_queue_get(d, arg->exec_queue_handle);
+	if (XE_IOCTL_DBG(xe, !q))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe,
+			 !(q->eudebug_flags & EXEC_QUEUE_EUDEBUG_FLAG_ENABLE))) {
+		ret = -EINVAL;
+		goto queue_put;
+	}
+
+	if (XE_IOCTL_DBG(xe, xef != q->vm->xef)) {
+		ret = -EINVAL;
+		goto queue_put;
+	}
+
+	lrc = find_lrc(d, arg->lrc_handle);
+	if (XE_IOCTL_DBG(xe, !lrc)) {
+		ret = -EINVAL;
+		goto queue_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 queue_put;
+		}
+
+		if (copy_from_user(bits, bitmask_ptr, attn_size)) {
+			ret = -EFAULT;
+			goto out_free;
+		}
+	}
+
+	if (!pm_runtime_active(xe->drm.dev)) {
+		ret = -EIO;
+		goto out_free;
+	}
+
+	ret = -EINVAL;
+	mutex_lock(&d->eu_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, q, lrc);
+		break;
+	case DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED:
+		ret = d->ops->stopped(d, q, lrc, bits, attn_size);
+		break;
+	case DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME:
+		ret = d->ops->resume(d, q, lrc, bits, attn_size);
+		break;
+	default:
+		break;
+	}
+
+	if (ret == 0)
+		seqno = atomic_long_inc_return(&d->events.seqno);
+
+	mutex_unlock(&d->eu_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);
+queue_put:
+	xe_exec_queue_put(q);
+
+	return ret;
+}
+
+static 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 (!access_ok(u64_to_user_ptr(user_arg.bitmask_ptr), user_arg.bitmask_size))
+		return -EFAULT;
+
+	eu_dbg(d,
+	       "eu_control: client_handle=%llu, cmd=%u, flags=0x%x, exec_queue_handle=%llu, bitmask_size=%u\n",
+	       user_arg.client_handle, user_arg.cmd, user_arg.flags, user_arg.exec_queue_handle,
+	       user_arg.bitmask_size);
+
+	if (XE_IOCTL_DBG(xe, IS_ERR(find_client(d, user_arg.client_handle))))
+		return -EINVAL; /* As this is user input */
+
+	ret = do_eu_control(d, &user_arg, user_ptr);
+
+	eu_dbg(d,
+	       "eu_control: client_handle=%llu, cmd=%u, flags=0x%x, exec_queue_handle=%llu, bitmask_size=%u ret=%d\n",
+	       user_arg.client_handle, user_arg.cmd, user_arg.flags, user_arg.exec_queue_handle,
+	       user_arg.bitmask_size, ret);
+
+	return ret;
+}
+
 static long xe_eudebug_ioctl(struct file *file,
 			     unsigned int cmd,
 			     unsigned long arg)
@@ -836,6 +1066,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_EU_CONTROL:
+		ret = xe_eudebug_eu_control(d, arg);
+		eu_dbg(d, "ioctl cmd=EU_CONTROL ret=%ld\n", ret);
+		break;
 
 	default:
 		ret = -EINVAL;
@@ -878,19 +1112,12 @@ static bool queue_has_active_job(struct xe_exec_queue *q)
 	return false;
 }
 
-static int current_lrc(struct xe_hw_engine *hwe, u32 *lrc_hw)
+static int __current_lrca(struct xe_hw_engine *hwe, u32 *lrc_hw)
 {
 	u32 lrc_reg;
-	int err;
-
-	err = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
-	if (err)
-		return err;
 
 	lrc_reg = hw_engine_mmio_read32(hwe, RING_CURRENT_LRCA(0));
 
-	xe_force_wake_put(gt_to_fw(hwe->gt), hwe->domain);
-
 	if (!(lrc_reg & CURRENT_LRCA_VALID))
 		return -ENOENT;
 
@@ -899,17 +1126,33 @@ static int current_lrc(struct xe_hw_engine *hwe, u32 *lrc_hw)
 	return 0;
 }
 
-static int match_engine_lrc(struct xe_exec_queue *q, u32 lrc_hw)
+static int current_lrca(struct xe_hw_engine *hwe, u32 *lrc_hw)
+{
+	int ret;
+
+	ret = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
+	if (ret)
+		return ret;
+
+	ret = __current_lrca(hwe, lrc_hw);
+
+	xe_force_wake_put(gt_to_fw(hwe->gt), hwe->domain);
+
+	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;
-	u32 lrc_ggtt;
 
-	for (i = 0; i < q->width; i++) {
-		lrc_ggtt = lower_32_bits(xe_lrc_descriptor(q->lrc[i]));
-		lrc_ggtt &= GENMASK(31, 12);
-		if (lrc_ggtt == lrc_hw)
+	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;
 }
@@ -1010,23 +1253,17 @@ static struct xe_hw_engine *get_runalone_active_hw_engine(struct xe_gt *gt)
 	return first;
 }
 
-static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
+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(gt);
+	struct xe_device *xe = gt_to_xe(hwe->gt);
+	struct xe_gt *gt = hwe->gt;
 	struct xe_exec_queue *q, *found = NULL;
-	struct xe_hw_engine *active;
 	struct xe_file *xef, *tmp;
 	unsigned long i;
 	int idx, err;
 	u32 lrc_hw;
 
-	active = get_runalone_active_hw_engine(gt);
-	if (!active) {
-		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
-		return ERR_PTR(-ENOENT);
-	}
-
-	err = current_lrc(active, &lrc_hw);
+	err = current_lrca(hwe, &lrc_hw);
 	if (err)
 		return ERR_PTR(err);
 
@@ -1037,13 +1274,13 @@ static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lr
 			if (q->gt != gt)
 				continue;
 
-			if (q->class != active->class)
+			if (q->class != hwe->class)
 				continue;
 
 			if (!queue_has_active_job(q))
 				continue;
 
-			idx = match_engine_lrc(q, lrc_hw);
+			idx = match_exec_queue_lrca(q, lrc_hw);
 			if (idx < 0)
 				continue;
 
@@ -1065,8 +1302,8 @@ static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lr
 	if (!found)
 		return ERR_PTR(-ENOENT);
 
-	if (XE_WARN_ON(current_lrc(active, &lrc_hw)) &&
-	    XE_WARN_ON(match_engine_lrc(found, lrc_hw) < 0)) {
+	if (XE_WARN_ON(current_lrca(hwe, &lrc_hw)) &&
+	    XE_WARN_ON(match_exec_queue_lrca(found, lrc_hw) < 0)) {
 		xe_exec_queue_put(found);
 		return ERR_PTR(-ENOENT);
 	}
@@ -1074,6 +1311,19 @@ static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lr
 	return found;
 }
 
+static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
+{
+	struct xe_hw_engine *active;
+
+	active = get_runalone_active_hw_engine(gt);
+	if (!active) {
+		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
+		return ERR_PTR(-ENOENT);
+	}
+
+	return active_hwe_to_exec_queue(active, lrc_idx);
+}
+
 static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, int lrc_idx)
 {
 	struct xe_eudebug_event_eu_attention *ea;
@@ -1120,7 +1370,6 @@ static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, i
 	return xe_eudebug_queue_event(d, event);
 }
 
-
 static int xe_send_gt_attention(struct xe_gt *gt)
 {
 	struct xe_eudebug *d;
@@ -1218,6 +1467,255 @@ static void attention_scan_flush(struct xe_device *xe)
 	mod_delayed_work(system_wq, &xe->eudebug.attention_scan, 0);
 }
 
+static int xe_eu_control_interrupt_all(struct xe_eudebug *d,
+				       struct xe_exec_queue *q,
+				       struct xe_lrc *lrc)
+{
+	struct xe_gt *gt = q->hwe->gt;
+	struct xe_device *xe = d->xe;
+	struct xe_exec_queue *active;
+	struct xe_hw_engine *hwe;
+	int lrc_idx, ret;
+	u32 lrc_hw;
+	u32 td_ctl;
+
+	hwe = get_runalone_active_hw_engine(gt);
+	if (XE_IOCTL_DBG(xe, !hwe)) {
+		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
+		return -EINVAL;
+	}
+
+	active = active_hwe_to_exec_queue(hwe, &lrc_idx);
+	if (XE_IOCTL_DBG(xe, IS_ERR(active)))
+		return PTR_ERR(active);
+
+	if (XE_IOCTL_DBG(xe, q != active)) {
+		xe_exec_queue_put(active);
+		return -EINVAL;
+	}
+	xe_exec_queue_put(active);
+
+	if (XE_IOCTL_DBG(xe, lrc_idx >= q->width || q->lrc[lrc_idx] != lrc)) {
+		ret = -EINVAL;
+		goto put_fw;
+	}
+
+	ret = xe_force_wake_get(gt_to_fw(gt), hwe->domain);
+	if (ret)
+		goto put_fw;
+
+	/* Additional check just before issuing MMIO writes */
+	ret = __current_lrca(hwe, &lrc_hw);
+	if (ret)
+		goto put_fw;
+
+	if (!lrca_equals(lower_32_bits(xe_lrc_descriptor(lrc)), lrc_hw)) {
+		ret = -EBUSY;
+		goto put_fw;
+	}
+
+	td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+
+	/* Halt on next thread dispatch */
+	if (!(td_ctl & TD_CTL_FORCE_EXTERNAL_HALT))
+		xe_gt_mcr_multicast_write(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.
+	 */
+	udelay(100);
+
+	/* Halt regardless of thread dependencies */
+	if (!(td_ctl & TD_CTL_FORCE_EXCEPTION))
+		xe_gt_mcr_multicast_write(gt, TD_CTL,
+					  td_ctl | TD_CTL_FORCE_EXCEPTION);
+	else
+		eu_warn(d, "TD_CTL force exception bit already set!\n");
+
+	udelay(100);
+
+	xe_gt_mcr_multicast_write(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.
+	 */
+	ret = __current_lrca(hwe, &lrc_hw);
+	if (ret || !lrca_equals(lower_32_bits(xe_lrc_descriptor(lrc)), lrc_hw))
+		eu_warn(d, "xe_eudebug: interrupted wrong context.");
+
+put_fw:
+	xe_force_wake_put(gt_to_fw(gt), q->hwe->domain);
+
+	return ret;
+}
+
+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)
+{
+	struct ss_iter *iter = data;
+	struct xe_eudebug *d = iter->debugger;
+	unsigned int row;
+
+	for (row = 0; row < TD_EU_ATTENTION_MAX_ROWS; row++) {
+		u32 val, cur = 0;
+
+		if (iter->i >= iter->size)
+			return 0;
+
+		if (XE_WARN_ON((iter->i + sizeof(val)) >
+				(xe_gt_eu_attention_bitmap_size(gt))))
+			return -EIO;
+
+		memcpy(&val, &iter->bits[iter->i], sizeof(val));
+		iter->i += sizeof(val);
+
+		cur = xe_gt_mcr_unicast_read(gt, TD_ATT(row), group, instance);
+
+		if ((val | cur) != cur) {
+			eu_dbg(d,
+				"WRONG CLEAR (%u:%u:%u) TD_CRL: 0x%08x; TD_ATT: 0x%08x\n",
+				group, instance, row, val, cur);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int clear_attn_mcr(struct xe_gt *gt, void *data,
+			  u16 group, u16 instance)
+{
+	struct ss_iter *iter = data;
+	struct xe_eudebug *d = iter->debugger;
+	unsigned int row;
+
+	for (row = 0; row < TD_EU_ATTENTION_MAX_ROWS; row++) {
+		u32 val;
+
+		if (iter->i >= iter->size)
+			return 0;
+
+		if (XE_WARN_ON((iter->i + sizeof(val)) >
+				(xe_gt_eu_attention_bitmap_size(gt))))
+			return -EIO;
+
+		memcpy(&val, &iter->bits[iter->i], sizeof(val));
+		iter->i += sizeof(val);
+
+		if (!val)
+			continue;
+
+		xe_gt_mcr_unicast_write(gt, TD_CLR(row), val,
+					group, instance);
+
+		eu_dbg(d,
+		       "TD_CLR: (%u:%u:%u): 0x%08x\n",
+		       group, instance, row, val);
+	}
+
+	return 0;
+}
+
+static int xe_eu_control_resume(struct xe_eudebug *d,
+				struct xe_exec_queue *q,
+				struct xe_lrc *lrc,
+				u8 *bits, unsigned int bitmask_size)
+{
+	struct xe_device *xe = d->xe;
+	struct ss_iter iter = {
+		.debugger = d,
+		.i = 0,
+		.size = bitmask_size,
+		.bits = bits
+	};
+	int ret = 0;
+	struct xe_exec_queue *active;
+	int lrc_idx;
+
+	active = runalone_active_queue_get(q->gt, &lrc_idx);
+	if (IS_ERR(active))
+		return PTR_ERR(active);
+
+	if (XE_IOCTL_DBG(xe, q != active)) {
+		xe_exec_queue_put(active);
+		return -EBUSY;
+	}
+	xe_exec_queue_put(active);
+
+	if (XE_IOCTL_DBG(xe, lrc_idx >= q->width || q->lrc[lrc_idx] != lrc))
+		return -EBUSY;
+
+	/*
+	 * 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) {
+		ret = xe_gt_foreach_dss_group_instance(q->gt, check_attn_mcr, &iter);
+		if (ret)
+			return ret;
+
+		iter.i = 0;
+	}
+
+	xe_gt_foreach_dss_group_instance(q->gt, clear_attn_mcr, &iter);
+	return 0;
+}
+
+static int xe_eu_control_stopped(struct xe_eudebug *d,
+				 struct xe_exec_queue *q,
+				 struct xe_lrc *lrc,
+				 u8 *bits, unsigned int bitmask_size)
+{
+	struct xe_device *xe = d->xe;
+	struct xe_exec_queue *active;
+	int lrc_idx;
+
+	if (XE_WARN_ON(!q) || XE_WARN_ON(!q->gt))
+		return -EINVAL;
+
+	active = runalone_active_queue_get(q->gt, &lrc_idx);
+	if (IS_ERR(active))
+		return PTR_ERR(active);
+
+	if (active) {
+		if (XE_IOCTL_DBG(xe, q != active)) {
+			xe_exec_queue_put(active);
+			return -EBUSY;
+		}
+
+		if (XE_IOCTL_DBG(xe, lrc_idx >= q->width || q->lrc[lrc_idx] != lrc)) {
+			xe_exec_queue_put(active);
+			return -EBUSY;
+		}
+	}
+
+	xe_exec_queue_put(active);
+
+	return xe_gt_eu_attention_bitmap(q->gt, bits, bitmask_size);
+}
+
+static 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,
+};
+
 static void discovery_work_fn(struct work_struct *work);
 
 static int
@@ -1280,6 +1778,7 @@ xe_eudebug_connect(struct xe_device *xe,
 	kref_get(&d->ref);
 	queue_work(xe->eudebug.ordered_wq, &d->discovery_work);
 	attention_scan_flush(xe);
+	d->ops = &eu_control;
 
 	eu_dbg(d, "connected session %lld", d->session);
 
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 16667b4dfe45..a75986180d71 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -18,8 +18,12 @@
 
 struct xe_device;
 struct task_struct;
+struct xe_eudebug;
 struct xe_eudebug_event;
+struct xe_hw_engine;
 struct workqueue_struct;
+struct xe_exec_queue;
+struct xe_lrc;
 
 #define CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE 64
 
@@ -65,6 +69,23 @@ struct xe_eudebug_resources {
 	struct xe_eudebug_resource rt[XE_EUDEBUG_RES_TYPE_COUNT];
 };
 
+/**
+ * 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
  */
@@ -128,6 +149,8 @@ struct xe_eudebug {
 		atomic_long_t seqno;
 	} events;
 
+	/** @ops operations for eu_control */
+	struct xe_eudebug_eu_control_ops *ops;
 };
 
 /**
diff --git a/drivers/gpu/drm/xe/xe_gt_debug.c b/drivers/gpu/drm/xe/xe_gt_debug.c
index 04d2d43ce249..6716722cb4c0 100644
--- a/drivers/gpu/drm/xe/xe_gt_debug.c
+++ b/drivers/gpu/drm/xe/xe_gt_debug.c
@@ -13,12 +13,12 @@
 #include "xe_pm.h"
 #include "xe_macros.h"
 
-static int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
-					    int (*fn)(struct xe_gt *gt,
-						      void *data,
-						      u16 group,
-						      u16 instance),
-					    void *data)
+int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
+				     int (*fn)(struct xe_gt *gt,
+					       void *data,
+					       u16 group,
+					       u16 instance),
+				     void *data)
 {
 	const enum xe_force_wake_domains fw_domains = XE_FW_GT | XE_FW_RENDER;
 	unsigned int dss;
diff --git a/drivers/gpu/drm/xe/xe_gt_debug.h b/drivers/gpu/drm/xe/xe_gt_debug.h
index 3f13dbb17a5f..342082699ff6 100644
--- a/drivers/gpu/drm/xe/xe_gt_debug.h
+++ b/drivers/gpu/drm/xe/xe_gt_debug.h
@@ -13,6 +13,12 @@
 #define XE_GT_ATTENTION_TIMEOUT_MS 100
 
 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),
+				     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,
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 453269ac8307..c33c207ffd62 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -15,7 +15,8 @@ extern "C" {
  *
  * This ioctl is available in debug version 1.
  */
-#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
+#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
+#define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
 
 /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
 struct drm_xe_eudebug_event {
@@ -75,6 +76,24 @@ struct drm_xe_eudebug_event_eu_attention {
 	__u8 bitmask[];
 };
 
+struct drm_xe_eudebug_eu_control {
+	__u64 client_handle;
+
+#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;
+	__u32 flags;
+
+	__u64 seqno;
+
+	__u64 exec_queue_handle;
+	__u64 lrc_handle;
+	__u32 reserved;
+	__u32 bitmask_size;
+	__u64 bitmask_ptr;
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 12/21] drm/xe/eudebug: Add vm bind and vm bind ops
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (10 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 11/21] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 14:08 ` [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks Mika Kuoppala
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Christoph Manszewski, Mika Kuoppala

From: Christoph Manszewski <christoph.manszewski@intel.com>

Add events dedicated to track vma bind and vma unbind operations. The
events are generated for operations performed on xe_vma MAP and UNMAP
for boss and userptrs.

As one bind can result in multiple operations and fail in the middle,
we want to store the events until full successful chain of operations
can be relayed to debugger.

v2: !bind_ref warning in wrong spot (Christoph, Maciej)
v3: vm bind flags
v4: _packed fixed in event_vm_bind (jcavitt)
v6: vmbind ops without map/unmaps handled (Mika)
v7: guard ref with spinlock (Mika)
v8: teardown events on vm destroy to avoid leak (Mika)

Co-developed-by: Mika Kuoppala <mika.kuoppala@linux.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/xe_eudebug.c       | 297 ++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_eudebug.h       |   7 +
 drivers/gpu/drm/xe/xe_eudebug_types.h |  29 +++
 drivers/gpu/drm/xe/xe_vm.c            |  18 +-
 drivers/gpu/drm/xe/xe_vm_types.h      |  11 +
 include/uapi/drm/xe_drm_eudebug.h     |  66 +++++-
 6 files changed, 425 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 582805bebf26..8f0e6a56a65e 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -2210,6 +2210,303 @@ void xe_eudebug_exec_queue_destroy(struct xe_file *xef, struct xe_exec_queue *q)
 	xe_eudebug_event_put(d, exec_queue_destroy_event(d, xef, q));
 }
 
+static int xe_eudebug_queue_bind_event(struct xe_eudebug *d,
+				       struct xe_vm *vm,
+				       struct xe_eudebug_event *event)
+{
+	struct xe_eudebug_event_envelope *env;
+
+	lockdep_assert_held_write(&vm->lock);
+
+	env = kmalloc(sizeof(*env), GFP_KERNEL);
+	if (!env)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&env->link);
+	env->event = event;
+
+	spin_lock(&vm->eudebug_bind.lock);
+	list_add_tail(&env->link, &vm->eudebug_bind.events);
+
+	if (event->type == DRM_XE_EUDEBUG_EVENT_VM_BIND_OP)
+		++vm->eudebug_bind.ops;
+	spin_unlock(&vm->eudebug_bind.lock);
+
+	return 0;
+}
+
+static int queue_vm_bind_event(struct xe_eudebug *d,
+			       struct xe_vm *vm,
+			       u64 client_handle,
+			       u64 vm_handle,
+			       u32 bind_flags,
+			       u32 num_ops, u64 *seqno)
+{
+	struct xe_eudebug_event_vm_bind *e;
+	struct xe_eudebug_event *event;
+	const u32 sz = sizeof(*e);
+	const u32 base_flags = DRM_XE_EUDEBUG_EVENT_STATE_CHANGE;
+
+	*seqno = atomic_long_inc_return(&d->events.seqno);
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND,
+					*seqno, base_flags, sz, GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	e = cast_event(e, event);
+	write_member(struct drm_xe_eudebug_event_vm_bind, e, client_handle, client_handle);
+	write_member(struct drm_xe_eudebug_event_vm_bind, e, vm_handle, vm_handle);
+	write_member(struct drm_xe_eudebug_event_vm_bind, e, flags, bind_flags);
+	write_member(struct drm_xe_eudebug_event_vm_bind, e, num_binds, num_ops);
+
+	/* If in discovery, no need to collect ops */
+	if (!completion_done(&d->discovery)) {
+		XE_WARN_ON(!num_ops);
+		return xe_eudebug_queue_event(d, event);
+	}
+
+	return xe_eudebug_queue_bind_event(d, vm, event);
+}
+
+static int vm_bind_event(struct xe_eudebug *d,
+			 struct xe_vm *vm,
+			 u32 num_ops,
+			 u64 *seqno)
+{
+	int h_c, h_vm;
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, vm->xef);
+	if (h_c < 0)
+		return h_c;
+
+	h_vm = find_handle(d->res, XE_EUDEBUG_RES_TYPE_VM, vm);
+	if (h_vm < 0)
+		return h_vm;
+
+	return queue_vm_bind_event(d, vm, h_c, h_vm, 0,
+				   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,
+			    u64 addr, u64 range,
+			    u64 *op_seqno)
+{
+	struct xe_eudebug_event_vm_bind_op *e;
+	struct xe_eudebug_event *event;
+	const u32 sz = sizeof(*e);
+
+	*op_seqno = atomic_long_inc_return(&d->events.seqno);
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_OP,
+					*op_seqno, flags, sz, GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	e = cast_event(e, event);
+
+	write_member(struct drm_xe_eudebug_event_vm_bind_op, e, vm_bind_ref_seqno, bind_ref_seqno);
+	write_member(struct drm_xe_eudebug_event_vm_bind_op, e, num_extensions, num_extensions);
+	write_member(struct drm_xe_eudebug_event_vm_bind_op, e, addr, addr);
+	write_member(struct drm_xe_eudebug_event_vm_bind_op, e, range, range);
+
+	/* If in discovery, no need to collect ops */
+	if (!completion_done(&d->discovery))
+		return xe_eudebug_queue_event(d, event);
+
+	return xe_eudebug_queue_bind_event(d, vm, event);
+}
+
+static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
+		      const u32 flags, const u64 bind_ref_seqno,
+		      u64 addr, u64 range)
+{
+	u64 op_seqno = 0;
+	u64 num_extensions = 0;
+	int ret;
+
+	ret = vm_bind_op_event(d, vm, flags, bind_ref_seqno, num_extensions,
+			       addr, range, &op_seqno);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void xe_eudebug_vm_bind_start(struct xe_vm *vm)
+{
+	struct xe_eudebug *d;
+	u64 seqno = 0;
+	int err;
+
+	d = xe_eudebug_get(vm->xef);
+	if (!d)
+		return;
+
+	lockdep_assert_held_write(&vm->lock);
+
+	if (XE_WARN_ON(!list_empty(&vm->eudebug_bind.events)) ||
+	    XE_WARN_ON(vm->eudebug_bind.ops) ||
+	    XE_WARN_ON(vm->eudebug_bind.ref)) {
+		eu_err(d, "bind busy on %s",  __func__);
+		xe_eudebug_disconnect(d, -EINVAL);
+	}
+
+	err = vm_bind_event(d, vm, 0, &seqno);
+	if (err) {
+		eu_err(d, "error %d on %s", err, __func__);
+		xe_eudebug_disconnect(d, err);
+	}
+
+	spin_lock(&vm->eudebug_bind.lock);
+	XE_WARN_ON(vm->eudebug_bind.ref);
+	vm->eudebug_bind.ref = seqno;
+	vm->eudebug_bind.ops = 0;
+	spin_unlock(&vm->eudebug_bind.lock);
+
+	xe_eudebug_put(d);
+}
+
+void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range)
+{
+	struct xe_eudebug *d;
+	u32 flags;
+
+	switch (op) {
+	case DRM_XE_VM_BIND_OP_MAP:
+	case DRM_XE_VM_BIND_OP_MAP_USERPTR:
+	{
+		flags = DRM_XE_EUDEBUG_EVENT_CREATE;
+		break;
+	}
+	case DRM_XE_VM_BIND_OP_UNMAP:
+	case DRM_XE_VM_BIND_OP_UNMAP_ALL:
+		flags = DRM_XE_EUDEBUG_EVENT_DESTROY;
+		break;
+	default:
+		flags = 0;
+		break;
+	}
+
+	if (!flags)
+		return;
+
+	d = xe_eudebug_get(vm->xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, vm_bind_op(d, vm, flags, 0, addr, range));
+}
+
+static struct xe_eudebug_event *fetch_bind_event(struct xe_vm * const vm)
+{
+	struct xe_eudebug_event_envelope *env;
+	struct xe_eudebug_event *e = NULL;
+
+	spin_lock(&vm->eudebug_bind.lock);
+	env = list_first_entry_or_null(&vm->eudebug_bind.events,
+				       struct xe_eudebug_event_envelope, link);
+	if (env) {
+		e = env->event;
+		list_del(&env->link);
+	}
+	spin_unlock(&vm->eudebug_bind.lock);
+
+	kfree(env);
+
+	return e;
+}
+
+static void fill_vm_bind_fields(struct xe_vm *vm,
+				struct xe_eudebug_event *e,
+				bool ufence,
+				u32 bind_ops)
+{
+	struct xe_eudebug_event_vm_bind *eb = cast_event(eb, e);
+
+	eb->flags = ufence ?
+		DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE : 0;
+	eb->num_binds = bind_ops;
+}
+
+static void fill_vm_bind_op_fields(struct xe_vm *vm,
+				   struct xe_eudebug_event *e,
+				   u64 ref_seqno)
+{
+	struct xe_eudebug_event_vm_bind_op *op;
+
+	if (e->type != DRM_XE_EUDEBUG_EVENT_VM_BIND_OP)
+		return;
+
+	op = cast_event(op, e);
+	op->vm_bind_ref_seqno = ref_seqno;
+}
+
+void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int bind_err)
+{
+	struct xe_eudebug_event *e;
+	struct xe_eudebug *d;
+	u32 bind_ops;
+	u64 ref;
+
+	spin_lock(&vm->eudebug_bind.lock);
+	ref = vm->eudebug_bind.ref;
+	vm->eudebug_bind.ref = 0;
+	bind_ops = vm->eudebug_bind.ops;
+	vm->eudebug_bind.ops = 0;
+	spin_unlock(&vm->eudebug_bind.lock);
+
+	e = fetch_bind_event(vm);
+	if (!e)
+		return;
+
+	d = NULL;
+	if (!bind_err && ref) {
+		d = xe_eudebug_get(vm->xef);
+		if (d) {
+			if (bind_ops) {
+				fill_vm_bind_fields(vm, e, has_ufence, bind_ops);
+			} else {
+				/*
+				 * If there was no ops we are interested in,
+				 * we can omit the whole sequence
+				 */
+				xe_eudebug_put(d);
+				d = NULL;
+			}
+		}
+	}
+
+	while (e) {
+		int err = 0;
+
+		if (d) {
+			err = xe_eudebug_queue_event(d, e);
+			if (!err)
+				e = NULL;
+		}
+
+		if (err) {
+			xe_eudebug_disconnect(d, err);
+			xe_eudebug_put(d);
+			d = NULL;
+		}
+
+		kfree(e);
+
+		e = fetch_bind_event(vm);
+		if (e && ref)
+			fill_vm_bind_op_fields(vm, e, ref);
+	}
+
+	if (d)
+		xe_eudebug_put(d);
+}
+
 static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 {
 	struct xe_exec_queue *q;
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 1e233c4683d6..2cab90773b21 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -5,11 +5,14 @@
 
 #ifndef _XE_EUDEBUG_H_
 
+#include <linux/types.h>
+
 struct drm_device;
 struct drm_file;
 struct xe_device;
 struct xe_file;
 struct xe_vm;
+struct xe_vma;
 struct xe_exec_queue;
 struct xe_hw_engine;
 
@@ -31,4 +34,8 @@ void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm);
 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_start(struct xe_vm *vm);
+void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range);
+void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int err);
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index a75986180d71..1ffe33f15409 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -176,6 +176,11 @@ struct xe_eudebug_event {
 	u8 data[];
 };
 
+struct xe_eudebug_event_envelope {
+	struct list_head link;
+	struct xe_eudebug_event *event;
+};
+
 /**
  * struct xe_eudebug_event_open - Internal event for client open/close
  */
@@ -257,4 +262,28 @@ struct xe_eudebug_event_eu_attention {
 	u8 bitmask[];
 };
 
+/**
+ * struct xe_eudebug_event_vm_bind - Internal event for vm bind/unbind operation
+ */
+struct xe_eudebug_event_vm_bind {
+	/** @base: base event */
+	struct xe_eudebug_event base;
+
+	u64 client_handle;
+	u64 vm_handle;
+
+	u32 flags;
+	u32 num_binds;
+};
+
+struct xe_eudebug_event_vm_bind_op {
+	/** @base: base event */
+	struct xe_eudebug_event base;
+	u64 vm_bind_ref_seqno;
+	u64 num_extensions;
+
+	u64 addr; /* Zero for unmap all ? */
+	u64 range; /* Zero for unmap all ? */
+};
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 9e101c992d9c..657a54b74eea 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1411,6 +1411,9 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
 	for_each_tile(tile, xe, id)
 		xe_range_fence_tree_init(&vm->rftree[id]);
 
+	INIT_LIST_HEAD(&vm->eudebug_bind.events);
+	spin_lock_init(&vm->eudebug_bind.lock);
+
 	vm->pt_ops = &xelp_pt_ops;
 
 	/*
@@ -1656,6 +1659,8 @@ static void vm_destroy_work_func(struct work_struct *w)
 	struct xe_tile *tile;
 	u8 id;
 
+	xe_eudebug_vm_bind_end(vm, 0, 0);
+
 	/* xe_vm_close_and_put was not called? */
 	xe_assert(xe, !vm->size);
 
@@ -2675,7 +2680,7 @@ static void vm_bind_ioctl_ops_fini(struct xe_vm *vm, struct xe_vma_ops *vops,
 				   struct dma_fence *fence)
 {
 	struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, vops->q);
-	struct xe_user_fence *ufence;
+	struct xe_user_fence *ufence = NULL;
 	struct xe_vma_op *op;
 	int i;
 
@@ -2690,6 +2695,9 @@ static void vm_bind_ioctl_ops_fini(struct xe_vm *vm, struct xe_vma_ops *vops,
 			xe_vma_destroy(gpuva_to_vma(op->base.remap.unmap->va),
 				       fence);
 	}
+
+	xe_eudebug_vm_bind_end(vm, ufence, 0);
+
 	if (ufence)
 		xe_sync_ufence_put(ufence);
 	for (i = 0; i < vops->num_syncs; i++)
@@ -3067,6 +3075,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	}
 
 	xe_vma_ops_init(&vops, vm, q, syncs, num_syncs);
+
 	for (i = 0; i < args->num_binds; ++i) {
 		u64 range = bind_ops[i].range;
 		u64 addr = bind_ops[i].addr;
@@ -3089,6 +3098,8 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 		if (err)
 			goto unwind_ops;
 
+		xe_eudebug_vm_bind_op_add(vm, op, addr, range);
+
 #ifdef TEST_VM_OPS_ERROR
 		if (flags & FORCE_OP_ERROR) {
 			vops.inject_error = true;
@@ -3112,8 +3123,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	err = vm_bind_ioctl_ops_execute(vm, &vops);
 
 unwind_ops:
-	if (err && err != -ENODATA)
+	if (err && err != -ENODATA) {
+		xe_eudebug_vm_bind_end(vm, num_ufence > 0, err);
 		vm_bind_ioctl_ops_unwind(vm, ops, args->num_binds);
+	}
+
 	xe_vma_ops_fini(&vops);
 	for (i = args->num_binds - 1; i >= 0; --i)
 		if (ops[i])
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index 7f9a303e51d8..da9d7ef6ab8f 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -282,6 +282,17 @@ struct xe_vm {
 	bool batch_invalidate_tlb;
 	/** @xef: XE file handle for tracking this VM's drm client */
 	struct xe_file *xef;
+
+	struct {
+		/** @lock: Lock for eudebug_bind members */
+		spinlock_t lock;
+		/** @events: List of vm bind ops gathered */
+		struct list_head events;
+		/** @ops: How many operations we have stored */
+		u32 ops;
+		/** @ref: Reference to the VM_BIND that the ops relate */
+		u64 ref;
+	} eudebug_bind;
 };
 
 /** struct xe_vma_op_map - VMA map operation */
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index c33c207ffd62..789c8aa81c09 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -29,7 +29,9 @@ struct drm_xe_eudebug_event {
 #define DRM_XE_EUDEBUG_EVENT_VM			3
 #define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE		4
 #define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
-#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND		6
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP		7
+#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_OP
 
 	__u16 flags;
 #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
@@ -94,6 +96,68 @@ struct drm_xe_eudebug_eu_control {
 	__u64 bitmask_ptr;
 };
 
+/*
+ *  When client (debuggee) does vm_bind_ioctl() following event
+ *  sequence will be created (for the debugger):
+ *
+ *  ┌───────────────────────┐
+ *  │  EVENT_VM_BIND        ├───────┬─┬─┐
+ *  └───────────────────────┘       │ │ │
+ *      ┌───────────────────────┐   │ │ │
+ *      │ EVENT_VM_BIND_OP #1   ├───┘ │ │
+ *      └───────────────────────┘     │ │
+ *                 ...                │ │
+ *      ┌───────────────────────┐     │ │
+ *      │ EVENT_VM_BIND_OP #n   ├─────┘ │
+ *      └───────────────────────┘       │
+ *                                      │
+ *      ┌───────────────────────┐       │
+ *      │ EVENT_UFENCE          ├───────┘
+ *      └───────────────────────┘
+ *
+ * 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 {
+	struct drm_xe_eudebug_event base;
+
+	__u64 client_handle;
+	__u64 vm_handle;
+
+	__u32 flags;
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE (1 << 0)
+
+	__u32 num_binds;
+};
+
+struct drm_xe_eudebug_event_vm_bind_op {
+	struct drm_xe_eudebug_event base;
+	__u64 vm_bind_ref_seqno; /* *_event_vm_bind.base.seqno */
+	__u64 num_extensions;
+
+	__u64 addr; /* XXX: Zero for unmap all? */
+	__u64 range; /* XXX: Zero for unmap all? */
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (11 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 12/21] drm/xe/eudebug: Add vm bind and vm bind ops Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-27  0:40   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 14/21] drm/xe/eudebug: vm open/pread/pwrite Mika Kuoppala
                   ` (16 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Mika Kuoppala

When vma is in place, debugger needs to intercept before
userspace proceeds with the workload. For example to install
a breakpoint in a eu shader.

Attach debugger in xe_user_fence, send UFENCE event
and stall normal user fence signal path to yield if
there is debugger attached to ufence.

When ack (ioctl) is received for the corresponding seqno,
signal ufence.

v2: ufence worker in own workqueue

Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/xe/xe_eudebug.c       | 239 +++++++++++++++++++++++++-
 drivers/gpu/drm/xe/xe_eudebug.h       |   6 +
 drivers/gpu/drm/xe/xe_eudebug_types.h |  12 ++
 drivers/gpu/drm/xe/xe_exec.c          |   2 +-
 drivers/gpu/drm/xe/xe_sync.c          |  49 ++++--
 drivers/gpu/drm/xe/xe_sync.h          |   8 +-
 drivers/gpu/drm/xe/xe_sync_types.h    |  26 ++-
 drivers/gpu/drm/xe/xe_vm.c            |   4 +-
 include/uapi/drm/xe_drm_eudebug.h     |  15 +-
 9 files changed, 333 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 8f0e6a56a65e..5dcb7c9464e9 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -35,6 +35,7 @@
 #include "xe_vm.h"
 #include "xe_wa.h"
 #include "xe_force_wake.h"
+#include "xe_sync.h"
 
 /*
  * If there is no detected event read by userspace, during this period, assume
@@ -240,11 +241,115 @@ static void xe_eudebug_free(struct kref *ref)
 	kfree_rcu(d, rcu);
 }
 
-static void xe_eudebug_put(struct xe_eudebug *d)
+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);
+
+	if (READ_ONCE(ufence->signalled))
+		xe_sync_ufence_signal(ufence);
+
+	xe_sync_ufence_put(ufence);
+}
+
+static void kick_ufence_worker(struct xe_user_fence *f)
+{
+	INIT_WORK(&f->eudebug.worker, ufence_signal_worker);
+	queue_work(f->xe->eudebug.ordered_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;
+	u64 signaller_ack, signalled_by;
+
+	signaller_ack = cmpxchg64(&f->eudebug.signalled_seqno, 0, ack->seqno);
+	signalled_by = f->eudebug.signalled_seqno;
+
+	if (!signaller_ack)
+		kick_ufence_worker(f);
+	else
+		xe_sync_ufence_put(f);
+
+	eu_dbg(d, "ACK: seqno=%llu: %ssignalled by %s (%llu) (held %lluus)",
+	       ack->seqno, signaller_ack ? "already " : "",
+	       on_disconnect ? "disconnect" : "debugger",
+	       signalled_by,
+	       ktime_us_delta(ktime_get(), ack->ts_insert));
+
+	kfree(ack);
+}
+
+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 struct task_struct *find_get_target(const pid_t nr)
 {
 	struct task_struct *task;
@@ -328,6 +433,8 @@ static bool xe_eudebug_detach(struct xe_device *xe,
 
 	eu_dbg(d, "session %lld detached with %d", d->session, err);
 
+	release_acks(d);
+
 	/* Our ref with the connection_link */
 	xe_eudebug_put(d);
 
@@ -428,7 +535,7 @@ static struct task_struct *find_task_get(struct xe_file *xef)
 	return task;
 }
 
-static struct xe_eudebug *
+struct xe_eudebug *
 xe_eudebug_get(struct xe_file *xef)
 {
 	struct task_struct *task;
@@ -889,6 +996,44 @@ static long xe_eudebug_read_event(struct xe_eudebug *d,
 	return ret;
 }
 
+static long
+xe_eudebug_ack_event_ioctl(struct xe_eudebug *d,
+			   const unsigned int cmd,
+			   const u64 arg)
+{
+	struct drm_xe_eudebug_ack_event __user * const user_ptr =
+		u64_to_user_ptr(arg);
+	struct drm_xe_eudebug_ack_event user_arg;
+	struct xe_eudebug_ack *ack;
+	struct xe_device *xe = d->xe;
+
+	if (XE_IOCTL_DBG(xe, _IOC_SIZE(cmd) < sizeof(user_arg)))
+		return -EINVAL;
+
+	/* Userland write */
+	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(cmd) & _IOC_WRITE)))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, 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, 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;
+}
+
 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)
@@ -1070,7 +1215,10 @@ static long xe_eudebug_ioctl(struct file *file,
 		ret = xe_eudebug_eu_control(d, arg);
 		eu_dbg(d, "ioctl cmd=EU_CONTROL ret=%ld\n", ret);
 		break;
-
+	case DRM_XE_EUDEBUG_IOCTL_ACK_EVENT:
+		ret = xe_eudebug_ack_event_ioctl(d, cmd, arg);
+		eu_dbg(d, "ioctl cmd=EVENT_ACK ret=%ld\n", ret);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -1759,6 +1907,9 @@ xe_eudebug_connect(struct xe_device *xe,
 	INIT_KFIFO(d->events.fifo);
 	INIT_WORK(&d->discovery_work, discovery_work_fn);
 
+	spin_lock_init(&d->acks.lock);
+	d->acks.tree = RB_ROOT;
+
 	d->res = xe_eudebug_resources_alloc();
 	if (IS_ERR(d->res)) {
 		err = PTR_ERR(d->res);
@@ -2337,6 +2488,70 @@ static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
 	return 0;
 }
 
+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(sizeof(*ack), GFP_KERNEL);
+	if (!ack)
+		return -ENOMEM;
+
+	ack->seqno = seqno;
+	ack->ts_insert = ktime_get();
+
+	spin_lock(&d->acks.lock);
+	old = rb_find_add(&ack->rb_node,
+			  &d->acks.tree, ack_insert_cmp);
+	if (!old) {
+		kref_get(&f->refcount);
+		ack->ufence = f;
+	}
+	spin_unlock(&d->acks.lock);
+
+	if (old) {
+		eu_dbg(d, "ACK: seqno=%llu: already exists", seqno);
+		kfree(ack);
+		return -EEXIST;
+	}
+
+	eu_dbg(d, "ACK: seqno=%llu: tracking started", seqno);
+
+	return 0;
+}
+
+static int vm_bind_ufence_event(struct xe_eudebug *d,
+				struct xe_user_fence *ufence)
+{
+	struct xe_eudebug_event *event;
+	struct 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;
+
+	seqno = atomic_long_inc_return(&d->events.seqno);
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+					seqno, flags, sz, GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	e = cast_event(e, event);
+
+	write_member(struct drm_xe_eudebug_event_vm_bind_ufence,
+		     e, vm_bind_ref_seqno, ufence->eudebug.bind_ref_seqno);
+
+	ret = xe_eudebug_track_ufence(d, ufence, seqno);
+	if (!ret)
+		ret = xe_eudebug_queue_event(d, event);
+
+	return ret;
+}
+
 void xe_eudebug_vm_bind_start(struct xe_vm *vm)
 {
 	struct xe_eudebug *d;
@@ -2507,6 +2722,24 @@ void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int bind_err)
 		xe_eudebug_put(d);
 }
 
+int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence)
+{
+	struct xe_eudebug *d;
+	int err;
+
+	d = ufence->eudebug.debugger;
+	if (!d || xe_eudebug_detached(d))
+		return -ENOTCONN;
+
+	err = vm_bind_ufence_event(d, ufence);
+	if (err) {
+		eu_err(d, "error %d on %s", err, __func__);
+		xe_eudebug_disconnect(d, err);
+	}
+
+	return 0;
+}
+
 static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 {
 	struct xe_exec_queue *q;
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 2cab90773b21..3de54802a6ca 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -15,6 +15,7 @@ struct xe_vm;
 struct xe_vma;
 struct xe_exec_queue;
 struct xe_hw_engine;
+struct xe_user_fence;
 
 int xe_eudebug_connect_ioctl(struct drm_device *dev,
 			     void *data,
@@ -38,4 +39,9 @@ void xe_eudebug_vm_bind_start(struct xe_vm *vm);
 void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range);
 void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int err);
 
+int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence);
+
+struct xe_eudebug *xe_eudebug_get(struct xe_file *xef);
+void xe_eudebug_put(struct xe_eudebug *d);
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index 1ffe33f15409..a32c51416b5f 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -86,6 +86,7 @@ struct xe_eudebug_eu_control_ops {
 	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
  */
@@ -149,6 +150,12 @@ struct xe_eudebug {
 		atomic_long_t seqno;
 	} events;
 
+	/* user fences tracked by this debugger */
+	struct {
+		spinlock_t lock;
+		struct rb_root tree;
+	} acks;
+
 	/** @ops operations for eu_control */
 	struct xe_eudebug_eu_control_ops *ops;
 };
@@ -286,4 +293,9 @@ struct xe_eudebug_event_vm_bind_op {
 	u64 range; /* Zero for unmap all ? */
 };
 
+struct xe_eudebug_event_vm_bind_ufence {
+	struct xe_eudebug_event base;
+	u64 vm_bind_ref_seqno;
+};
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
index f36980aa26e6..400cb576f3b9 100644
--- a/drivers/gpu/drm/xe/xe_exec.c
+++ b/drivers/gpu/drm/xe/xe_exec.c
@@ -157,7 +157,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	vm = q->vm;
 
 	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
-		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
+		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
 					  &syncs_user[num_syncs], SYNC_PARSE_FLAG_EXEC |
 					  (xe_vm_in_lr_mode(vm) ?
 					   SYNC_PARSE_FLAG_LR_MODE : 0));
diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
index 533246f42256..52d56bfdf932 100644
--- a/drivers/gpu/drm/xe/xe_sync.c
+++ b/drivers/gpu/drm/xe/xe_sync.c
@@ -18,17 +18,7 @@
 #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;
-};
+#include "xe_eudebug.h"
 
 static void user_fence_destroy(struct kref *kref)
 {
@@ -36,6 +26,10 @@ static void user_fence_destroy(struct kref *kref)
 						 refcount);
 
 	mmdrop(ufence->mm);
+
+	if (ufence->eudebug.debugger)
+		xe_eudebug_put(ufence->eudebug.debugger);
+
 	kfree(ufence);
 }
 
@@ -49,7 +43,10 @@ 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,
+					       struct xe_file *xef,
+					       struct xe_vm *vm,
+					       u64 addr,
 					       u64 value)
 {
 	struct xe_user_fence *ufence;
@@ -58,7 +55,7 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
 	if (!access_ok(ptr, sizeof(ptr)))
 		return ERR_PTR(-EFAULT);
 
-	ufence = kmalloc(sizeof(*ufence), GFP_KERNEL);
+	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
 	if (!ufence)
 		return ERR_PTR(-ENOMEM);
 
@@ -69,12 +66,17 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
 	ufence->mm = current->mm;
 	mmgrab(ufence->mm);
 
+	if (vm->eudebug_bind.ref) {
+		ufence->eudebug.debugger = xe_eudebug_get(xef);
+		ufence->eudebug.bind_ref_seqno = vm->eudebug_bind.ref;
+	}
+
 	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);
+	XE_WARN_ON(!ufence->signalled);
 
 	if (mmget_not_zero(ufence->mm)) {
 		kthread_use_mm(ufence->mm);
@@ -85,7 +87,20 @@ static void user_fence_worker(struct work_struct *w)
 	}
 
 	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);
+	int ret;
+
 	WRITE_ONCE(ufence->signalled, 1);
+
+	/* Lets see if debugger wants to track this */
+	ret = xe_eudebug_vm_bind_ufence(ufence);
+	if (ret)
+		xe_sync_ufence_signal(ufence);
+
 	user_fence_put(ufence);
 }
 
@@ -104,6 +119,7 @@ static void user_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
 }
 
 int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
+			struct xe_vm *vm,
 			struct xe_sync_entry *sync,
 			struct drm_xe_sync __user *sync_user,
 			unsigned int flags)
@@ -185,7 +201,8 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
 		if (exec) {
 			sync->addr = sync_in.addr;
 		} else {
-			sync->ufence = user_fence_create(xe, sync_in.addr,
+			sync->ufence = user_fence_create(xe, xef, vm,
+							 sync_in.addr,
 							 sync_in.timeline_value);
 			if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence)))
 				return PTR_ERR(sync->ufence);
diff --git a/drivers/gpu/drm/xe/xe_sync.h b/drivers/gpu/drm/xe/xe_sync.h
index 256ffc1e54dc..f5bec2b1b4f6 100644
--- a/drivers/gpu/drm/xe/xe_sync.h
+++ b/drivers/gpu/drm/xe/xe_sync.h
@@ -9,8 +9,12 @@
 #include "xe_sync_types.h"
 
 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;
 
@@ -19,6 +23,7 @@ struct xe_vm;
 #define SYNC_PARSE_FLAG_DISALLOW_USER_FENCE	BIT(2)
 
 int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
+			struct xe_vm *vm,
 			struct xe_sync_entry *sync,
 			struct drm_xe_sync __user *sync_user,
 			unsigned int flags);
@@ -40,5 +45,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 30ac3f51993b..907c601a6d8c 100644
--- a/drivers/gpu/drm/xe/xe_sync_types.h
+++ b/drivers/gpu/drm/xe/xe_sync_types.h
@@ -7,12 +7,28 @@
 #define _XE_SYNC_TYPES_H_
 
 #include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/dma-fence-array.h>
 
-struct drm_syncobj;
-struct dma_fence;
-struct dma_fence_chain;
-struct drm_xe_sync;
-struct user_fence;
+struct xe_eudebug;
+
+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;
+	struct {
+		struct xe_eudebug *debugger;
+		u64 bind_ref_seqno;
+		u64 signalled_seqno;
+		struct work_struct worker;
+	} eudebug;
+};
 
 struct xe_sync_entry {
 	struct drm_syncobj *syncobj;
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 657a54b74eea..b117a892e386 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3049,9 +3049,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 		}
 	}
 
+	xe_eudebug_vm_bind_start(vm);
+
 	syncs_user = u64_to_user_ptr(args->syncs);
 	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
-		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
+		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
 					  &syncs_user[num_syncs],
 					  (xe_vm_in_lr_mode(vm) ?
 					   SYNC_PARSE_FLAG_LR_MODE : 0) |
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 789c8aa81c09..1875192e92bd 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -17,6 +17,7 @@ extern "C" {
  */
 #define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
 #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
+#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
 
 /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
 struct drm_xe_eudebug_event {
@@ -31,7 +32,8 @@ struct drm_xe_eudebug_event {
 #define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
 #define DRM_XE_EUDEBUG_EVENT_VM_BIND		6
 #define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP		7
-#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_OP
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE	8
+#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
 
 	__u16 flags;
 #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
@@ -158,6 +160,17 @@ struct drm_xe_eudebug_event_vm_bind_op {
 	__u64 range; /* XXX: Zero for unmap all? */
 };
 
+struct drm_xe_eudebug_event_vm_bind_ufence {
+	struct drm_xe_eudebug_event base;
+	__u64 vm_bind_ref_seqno; /* *_event_vm_bind.base.seqno */
+};
+
+struct drm_xe_eudebug_ack_event {
+	__u32 type;
+	__u32 flags; /* MBZ */
+	__u64 seqno;
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 14/21] drm/xe/eudebug: vm open/pread/pwrite
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (12 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 18:59   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access Mika Kuoppala
                   ` (15 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Mika Kuoppala, Maciej Patelczyk

Debugger needs access to the client's vm to read and write. For
example inspecting ISA/ELF and setting up breakpoints.

Add ioctl to open target vm with debugger client and vm_handle
and hook up pread/pwrite possibility.

Open will take 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 following patch.

v2: checkpatch (Maciej)

Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
---
 drivers/gpu/drm/xe/regs/xe_gt_regs.h |  24 ++
 drivers/gpu/drm/xe/xe_eudebug.c      | 470 +++++++++++++++++++++++++++
 include/uapi/drm/xe_drm_eudebug.h    |  18 +
 3 files changed, 512 insertions(+)

diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 546bb7cc2337..0d688189a2b3 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -520,6 +520,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 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)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 5dcb7c9464e9..aa383accc468 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -8,7 +8,10 @@
 #include <linux/anon_inodes.h>
 #include <linux/poll.h>
 #include <linux/delay.h>
+#include <linux/file.h>
+#include <linux/vmalloc.h>
 
+#include <drm/drm_drv.h>
 #include <drm/drm_managed.h>
 
 #include "regs/xe_engine_regs.h"
@@ -36,6 +39,7 @@
 #include "xe_wa.h"
 #include "xe_force_wake.h"
 #include "xe_sync.h"
+#include "xe_bo.h"
 
 /*
  * If there is no detected event read by userspace, during this period, assume
@@ -747,6 +751,17 @@ static struct xe_lrc *find_lrc(struct xe_eudebug *d, const u32 id)
 	return l;
 }
 
+static struct xe_vm *find_vm(struct xe_eudebug *d, const u32 id)
+{
+	struct xe_eudebug_handle *h;
+
+	h = find_resource(d->res, XE_EUDEBUG_RES_TYPE_VM, id);
+	if (h)
+		return (void *)h->key;
+
+	return NULL;
+}
+
 static int _xe_eudebug_add_handle(struct xe_eudebug *d,
 				  int type,
 				  void *p,
@@ -1199,6 +1214,8 @@ static long xe_eudebug_eu_control(struct xe_eudebug *d, const u64 arg)
 	return ret;
 }
 
+static long xe_eudebug_vm_open_ioctl(struct xe_eudebug *d, unsigned long arg);
+
 static long xe_eudebug_ioctl(struct file *file,
 			     unsigned int cmd,
 			     unsigned long arg)
@@ -1219,6 +1236,11 @@ static long xe_eudebug_ioctl(struct file *file,
 		ret = xe_eudebug_ack_event_ioctl(d, cmd, 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;
 	}
@@ -2829,3 +2851,451 @@ static void discovery_work_fn(struct work_struct *work)
 
 	xe_eudebug_put(d);
 }
+
+static int xe_eudebug_bovma_access(struct xe_bo *bo, u64 offset,
+				   void *buf, u64 len, bool write)
+{
+	struct xe_device * const xe = xe_bo_device(bo);
+	struct iosys_map src;
+	int ret;
+
+	dma_resv_lock(bo->ttm.base.resv, NULL);
+
+	ret = ttm_bo_vmap(&bo->ttm, &src);
+	if (!ret) {
+		if (write)
+			xe_map_memcpy_to(xe, &src, offset, buf, len);
+		else
+			xe_map_memcpy_from(xe, buf, &src, offset, len);
+
+		ttm_bo_vunmap(&bo->ttm, &src);
+
+		ret = len;
+	}
+
+	dma_resv_unlock(bo->ttm.base.resv);
+
+	return ret;
+}
+
+static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
+				 void *buf, u64 len, bool write)
+{
+	struct xe_bo *bo;
+	u64 bytes;
+
+	if (XE_WARN_ON(offset >= xe_vma_size(vma)))
+		return -EINVAL;
+
+	bytes = min_t(u64, len, xe_vma_size(vma) - offset);
+	if (!bytes)
+		return 0;
+
+	bo = xe_vma_bo(vma);
+	if (bo)
+		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
+
+	return -EOPNOTSUPP;
+}
+
+static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
+				void *buf, u64 len, bool write)
+{
+	struct xe_vma *vma;
+	int ret;
+
+	down_write(&vm->lock);
+
+	vma = xe_vm_find_overlapping_vma(vm, offset, len);
+	if (vma) {
+#ifdef VERBOSE_VM_ACCESS
+		drm_dbg(&xe_vma_vm(vma)->xe->drm,
+			"eudbg: offset: 0x%llx: vma start 0x%llx, size 0x%llx, offset_in_vma 0x%llx",
+			offset, xe_vma_start(vma), xe_vma_size(vma), offset - xe_vma_start(vma));
+#endif
+		/* XXX: why find overlapping returns below start? */
+		if (offset < xe_vma_start(vma) ||
+		    offset >= (xe_vma_start(vma) + xe_vma_size(vma))) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/* Offset into vma */
+		offset -= xe_vma_start(vma);
+		ret = xe_eudebug_vma_access(vma, 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 client_id;
+	u64 vm_handle;
+	u64 timeout_ns;
+};
+
+static ssize_t __vm_read_write(struct xe_vm *vm,
+			       void *bb,
+			       char __user *r_buffer,
+			       const char __user *w_buffer,
+			       unsigned long offset,
+			       unsigned long 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 != NULL;
+	struct xe_vm *vm;
+	ssize_t copied = 0;
+	ssize_t bytes_left = count;
+	ssize_t ret;
+	unsigned long alloc_len;
+	loff_t pos = *__pos;
+	void *k_buffer;
+
+#ifdef VERBOSE_VM_ACCESS
+	eu_dbg(d, "vm_access(%s): client_handle=%llu, vm_handle=%llu, flags=0x%llx, pos=0x%llx, count=0x%lx",
+	       write ? "write" : "read",
+	       vmf->client_id, vmf->vm_handle, vmf->flags, pos, count);
+#endif
+	if (XE_IOCTL_DBG(xe, write && r_buffer))
+		return -EINVAL;
+
+	vm = find_vm(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 client_handle=%llu, vm_handle=%llu, flags=0x%llx, pos=%llu, count=%lu\n",
+			write ? "write" : "read",
+			vmf->client_id, vmf->vm_handle, vmf->flags, pos, count);
+		return -EINVAL;
+	}
+
+	if (!count)
+		return 0;
+
+	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))
+		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,
+				      pos + copied,
+				      len,
+				      write);
+#ifdef VERBOSE_VM_ACCESS
+		eu_dbg(d, "vm_access(%s): pos=0x%llx, len=0x%lx, copied=%lu bytes_left=%lu, ret=%ld",
+		       write ? "write" : "read", pos + copied, len, copied, bytes_left, ret);
+#endif
+		if (ret <= 0)
+			break;
+
+		bytes_left -= ret;
+		copied += ret;
+	} while (bytes_left > 0);
+
+	vfree(k_buffer);
+
+	if (XE_WARN_ON(copied < 0))
+		copied = 0;
+
+	*__pos += copied;
+
+#ifdef VERBOSE_VM_ACCESS
+	eu_dbg(d, "vm_access(%s): pos=0x%llx, count=0x%lx, copied=%lu bytes_left=%lu, ret=%ld",
+	       write ? "write" : "read", pos, count, copied, bytes_left, copied ?: ret);
+#endif
+
+	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;
+	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;
+
+	ret = xe_force_wake_get(gt_to_fw(gt), hwe->domain);
+	if (ret)
+		return ret;
+
+	/* Prevent concurrent flushes */
+	mutex_lock(&d->eu_lock);
+	psmi_ctrl = xe_mmio_read32(gt, psmi_addr);
+	if (!(psmi_ctrl & IDLE_MSG_DISABLE))
+		xe_mmio_write32(gt, psmi_addr, _MASKED_BIT_ENABLE(IDLE_MSG_DISABLE));
+
+	ret = xe_mmio_wait32(gt, RCU_ASYNC_FLUSH,
+			     RCU_ASYNC_FLUSH_IN_PROGRESS, 0,
+			     timeout_us, NULL, false);
+	if (ret)
+		goto out;
+
+	xe_mmio_write32(gt, RCU_ASYNC_FLUSH, mask);
+
+	ret = xe_mmio_wait32(gt, RCU_ASYNC_FLUSH,
+			     RCU_ASYNC_FLUSH_IN_PROGRESS, 0,
+			     timeout_us, NULL, false);
+out:
+	if (!(psmi_ctrl & IDLE_MSG_DISABLE))
+		xe_mmio_write32(gt, psmi_addr, _MASKED_BIT_DISABLE(IDLE_MSG_DISABLE));
+
+	mutex_unlock(&d->eu_lock);
+	xe_force_wake_put(gt_to_fw(gt), hwe->domain);
+
+	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: client_handle=%llu, vm_handle=%llu, flags=0x%llx, start=%llu, end=%llu datasync=%d\n",
+	       vmf->client_id, vmf->vm_handle, vmf->flags, start, end, 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? */
+		for_each_hw_engine(hwe, gt, id) {
+			if (hwe->class != XE_ENGINE_CLASS_RENDER &&
+			    hwe->class != XE_ENGINE_CLASS_COMPUTE)
+				continue;
+
+			ret = engine_rcu_flush(d, hwe, vmf->timeout_ns / 1000ull);
+			if (ret)
+				break;
+		}
+	}
+
+	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: client_handle=%llu, vm_handle=%llu, flags=0x%llx",
+	       vmf->client_id, vmf->vm_handle, vmf->flags);
+
+	drm_dev_get(&d->xe->drm);
+	xe_vm_put(vmf->vm);
+	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,
+};
+
+static 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 xe_eudebug *d_ref = NULL;
+	struct vm_file *vmf = NULL;
+	struct xe_file *xef;
+	struct xe_vm *vm;
+	struct file *file;
+	long ret = 0;
+	int fd;
+
+	if (XE_IOCTL_DBG(xe, _IOC_SIZE(DRM_XE_EUDEBUG_IOCTL_VM_OPEN) != sizeof(param)))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(DRM_XE_EUDEBUG_IOCTL_VM_OPEN) & _IOC_WRITE)))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, copy_from_user(&param, (void __user *)arg, sizeof(param))))
+		return -EFAULT;
+
+	if (XE_IOCTL_DBG(xe, param.flags))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, xe_eudebug_detached(d)))
+		return -ENOTCONN;
+
+	vm = NULL;
+	mutex_lock(&d->xe->files.lock);
+	xef = find_client(d, param.client_handle);
+	if (XE_IOCTL_DBG(xe, !xef)) {
+		mutex_unlock(&d->xe->files.lock);
+		return -EINVAL;
+	}
+
+	d_ref = xe_eudebug_get(xef);
+	if (XE_IOCTL_DBG(xe, !d_ref)) {
+		mutex_unlock(&d->xe->files.lock);
+		return -EINVAL;
+	}
+
+	mutex_lock(&xef->vm.lock);
+	vm = find_vm(d, param.vm_handle);
+	if (vm)
+		xe_vm_get(vm);
+	mutex_unlock(&xef->vm.lock);
+	mutex_unlock(&d->xe->files.lock);
+
+	XE_WARN_ON(d != d_ref);
+
+	if (XE_IOCTL_DBG(xe, !vm)) {
+		ret = -EINVAL;
+		goto out_eudebug_put;
+	}
+
+	vmf = kmalloc(sizeof(*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;
+	}
+
+	vmf->debugger = d_ref;
+	vmf->vm = vm;
+	vmf->flags = param.flags;
+	vmf->client_id = param.client_handle;
+	vmf->vm_handle = param.vm_handle;
+	vmf->timeout_ns = param.timeout_ns;
+
+	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_file_put;
+	}
+
+	drm_dev_get(&d->xe->drm);
+
+	file->f_mode |= FMODE_PREAD | FMODE_PWRITE |
+		FMODE_READ | FMODE_WRITE | FMODE_LSEEK;
+
+	fd_install(fd, file);
+
+	eu_dbg(d, "vm_open: client_handle=%llu, handle=%llu, flags=0x%llx, fd=%d",
+	       vmf->client_id, vmf->vm_handle, vmf->flags, fd);
+
+	XE_WARN_ON(ret);
+
+	return fd;
+
+out_file_put:
+	put_unused_fd(fd);
+out_free:
+	kfree(vmf);
+out_vm_put:
+	xe_vm_put(vm);
+out_eudebug_put:
+	xe_eudebug_put(d_ref);
+
+	return ret;
+}
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index 1875192e92bd..df79eafb6136 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -18,6 +18,7 @@ extern "C" {
 #define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
 #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
 #define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
+#define DRM_XE_EUDEBUG_IOCTL_VM_OPEN		_IOW('j', 0x1, struct drm_xe_eudebug_vm_open)
 
 /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
 struct drm_xe_eudebug_event {
@@ -171,6 +172,23 @@ struct drm_xe_eudebug_ack_event {
 	__u64 seqno;
 };
 
+struct drm_xe_eudebug_vm_open {
+	/** @extensions: Pointer to the first extension struct, if any */
+	__u64 extensions;
+
+	/** @client_handle: id of client */
+	__u64 client_handle;
+
+	/** @vm_handle: id of vm */
+	__u64 vm_handle;
+
+	/** @flags: flags */
+	__u64 flags;
+
+	/** @timeout_ns: Timeout value in nanoseconds operations (fsync) */
+	__u64 timeout_ns;
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (13 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 14/21] drm/xe/eudebug: vm open/pread/pwrite Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 18:46   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 16/21] drm/xe: Debug metadata create/destroy ioctls Mika Kuoppala
                   ` (14 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Andrzej Hajda, Maciej Patelczyk, Mika Kuoppala

From: Andrzej Hajda <andrzej.hajda@intel.com>

Debugger needs to read/write program's vmas including userptr_vma.
Since hmm_range_fault is used to pin userptr vmas, it is possible
to map those vmas from debugger context.

v2: kmap to kmap_local (Maciej)

Signed-off-by: Andrzej Hajda <andrzej.hajda@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 | 56 ++++++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index aa383accc468..947331c19f43 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -33,6 +33,7 @@
 #include "xe_mmio.h"
 #include "xe_module.h"
 #include "xe_pm.h"
+#include "xe_res_cursor.h"
 #include "xe_rtp.h"
 #include "xe_sched_job.h"
 #include "xe_vm.h"
@@ -2852,6 +2853,58 @@ static void discovery_work_fn(struct work_struct *work)
 	xe_eudebug_put(d);
 }
 
+static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
+				  void *buf, u64 len, bool write)
+{
+	struct xe_vm *vm = xe_vma_vm(&uvma->vma);
+	struct xe_userptr *up = &uvma->userptr;
+	struct xe_res_cursor cur = {};
+	int cur_len, ret = 0;
+
+	/* lock notifier in non-invalidation state */
+	for (unsigned long nseq = uvma->userptr.notifier_seq; true;
+	     nseq = mmu_interval_read_begin(&uvma->userptr.notifier)) {
+		down_read(&vm->userptr.notifier_lock);
+		if (!mmu_interval_read_retry(&uvma->userptr.notifier, nseq))
+			break;
+		up_read(&vm->userptr.notifier_lock);
+	}
+
+	/* re-pin if necessary */
+	if (xe_vma_userptr_check_repin(uvma)) {
+		spin_lock(&vm->userptr.invalidated_lock);
+		list_del_init(&uvma->userptr.invalidate_link);
+		spin_unlock(&vm->userptr.invalidated_lock);
+
+		ret = xe_vma_userptr_pin_pages(uvma);
+		if (ret)
+			goto out_unlock_notifier;
+	}
+
+	if (!up->sg) {
+		ret = -EINVAL;
+		goto out_unlock_notifier;
+	}
+
+	for (xe_res_first_sg(up->sg, offset, len, &cur); cur.remaining;
+	     xe_res_next(&cur, cur_len)) {
+		void *ptr = kmap_local_page(sg_page(cur.sgl)) + cur.start;
+
+		cur_len = min(cur.size, cur.remaining);
+		if (write)
+			memcpy(ptr, buf, cur_len);
+		else
+			memcpy(buf, ptr, cur_len);
+		kunmap_local(ptr);
+		buf += cur_len;
+	}
+	ret = len;
+
+out_unlock_notifier:
+	up_read(&vm->userptr.notifier_lock);
+	return ret;
+}
+
 static int xe_eudebug_bovma_access(struct xe_bo *bo, u64 offset,
 				   void *buf, u64 len, bool write)
 {
@@ -2895,7 +2948,8 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
 	if (bo)
 		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
 
-	return -EOPNOTSUPP;
+	return xe_eudebug_uvma_access(to_userptr_vma(vma), offset,
+				      buf, bytes, write);
 }
 
 static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 16/21] drm/xe: Debug metadata create/destroy ioctls
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (14 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 14:08 ` [PATCH 17/21] drm/xe: Attach debug metadata to vma Mika Kuoppala
                   ` (13 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Ad a part of eu debug feature introduce debug metadata objects.
These are to be used to pass metadata between client and debugger,
by attaching them to vm_bind operations.

todo: WORK_IN_PROGRESS_* defines need to be reworded/refined when
      the real usage and need is established by l0+gdb.

Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/xe/Makefile                  |   1 +
 drivers/gpu/drm/xe/xe_debug_metadata.c       | 107 +++++++++++++++++++
 drivers/gpu/drm/xe/xe_debug_metadata.h       |  23 ++++
 drivers/gpu/drm/xe/xe_debug_metadata_types.h |  28 +++++
 drivers/gpu/drm/xe/xe_device.c               |  17 +++
 drivers/gpu/drm/xe/xe_device_types.h         |   8 ++
 include/uapi/drm/xe_drm.h                    |  53 ++++++++-
 7 files changed, 236 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.c
 create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.h
 create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata_types.h

diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index b7b6b047c02c..2300525861ce 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -29,6 +29,7 @@ xe-y += xe_bb.o \
 	xe_bo.o \
 	xe_bo_evict.o \
 	xe_debugfs.o \
+	xe_debug_metadata.o \
 	xe_devcoredump.o \
 	xe_device.o \
 	xe_device_sysfs.o \
diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.c b/drivers/gpu/drm/xe/xe_debug_metadata.c
new file mode 100644
index 000000000000..8d99170d3591
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_metadata.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+#include "xe_debug_metadata.h"
+
+#include <drm/drm_device.h>
+#include <drm/drm_file.h>
+#include <drm/xe_drm.h>
+
+#include "xe_device.h"
+#include "xe_macros.h"
+
+static void xe_debug_metadata_release(struct kref *ref)
+{
+	struct xe_debug_metadata *mdata = container_of(ref, struct xe_debug_metadata, refcount);
+
+	kvfree(mdata->ptr);
+	kfree(mdata);
+}
+
+void xe_debug_metadata_put(struct xe_debug_metadata *mdata)
+{
+	kref_put(&mdata->refcount, xe_debug_metadata_release);
+}
+
+int xe_debug_metadata_create_ioctl(struct drm_device *dev,
+				   void *data,
+				   struct drm_file *file)
+{
+	struct xe_device *xe = to_xe_device(dev);
+	struct xe_file *xef = to_xe_file(file);
+	struct drm_xe_debug_metadata_create *args = data;
+	struct xe_debug_metadata *mdata;
+	int err;
+	u32 id;
+
+	if (XE_IOCTL_DBG(xe, args->extensions))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, args->type > DRM_XE_DEBUG_METADATA_PROGRAM_MODULE))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, !args->user_addr || !args->len))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, !access_ok(u64_to_user_ptr(args->user_addr), args->len)))
+		return -EFAULT;
+
+	mdata = kzalloc(sizeof(*mdata), GFP_KERNEL);
+	if (!mdata)
+		return -ENOMEM;
+
+	mdata->len = args->len;
+	mdata->type = args->type;
+
+	mdata->ptr = kvmalloc(mdata->len, GFP_KERNEL);
+	if (!mdata->ptr) {
+		kfree(mdata);
+		return -ENOMEM;
+	}
+	kref_init(&mdata->refcount);
+
+	err = copy_from_user(mdata->ptr, u64_to_user_ptr(args->user_addr), mdata->len);
+	if (err) {
+		err = -EFAULT;
+		goto put_mdata;
+	}
+
+	mutex_lock(&xef->debug_metadata.lock);
+	err = xa_alloc(&xef->debug_metadata.xa, &id, mdata, xa_limit_32b, GFP_KERNEL);
+	mutex_unlock(&xef->debug_metadata.lock);
+
+	args->metadata_id = id;
+	mdata->id = id;
+
+	if (err)
+		goto put_mdata;
+
+	return 0;
+
+put_mdata:
+	xe_debug_metadata_put(mdata);
+	return err;
+}
+
+int xe_debug_metadata_destroy_ioctl(struct drm_device *dev,
+				    void *data,
+				    struct drm_file *file)
+{
+	struct xe_device *xe = to_xe_device(dev);
+	struct xe_file *xef = to_xe_file(file);
+	struct drm_xe_debug_metadata_destroy * const args = data;
+	struct xe_debug_metadata *mdata;
+
+	if (XE_IOCTL_DBG(xe, args->extensions))
+		return -EINVAL;
+
+	mutex_lock(&xef->debug_metadata.lock);
+	mdata = xa_erase(&xef->debug_metadata.xa, args->metadata_id);
+	mutex_unlock(&xef->debug_metadata.lock);
+	if (XE_IOCTL_DBG(xe, !mdata))
+		return -ENOENT;
+
+	xe_debug_metadata_put(mdata);
+	return 0;
+}
diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.h b/drivers/gpu/drm/xe/xe_debug_metadata.h
new file mode 100644
index 000000000000..abaea076c12d
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_metadata.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef _XE_DEBUG_METADATA_H_
+#define _XE_DEBUG_METADATA_H_
+
+#include "xe_debug_metadata_types.h"
+
+struct drm_device;
+struct drm_file;
+
+void xe_debug_metadata_put(struct xe_debug_metadata *mdata);
+
+int xe_debug_metadata_create_ioctl(struct drm_device *dev,
+				   void *data,
+				   struct drm_file *file);
+
+int xe_debug_metadata_destroy_ioctl(struct drm_device *dev,
+				    void *data,
+				    struct drm_file *file);
+#endif
diff --git a/drivers/gpu/drm/xe/xe_debug_metadata_types.h b/drivers/gpu/drm/xe/xe_debug_metadata_types.h
new file mode 100644
index 000000000000..508f2fdbbc42
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_debug_metadata_types.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef _XE_DEBUG_METADATA_TYPES_H_
+#define _XE_DEBUG_METADATA_TYPES_H_
+
+#include <linux/kref.h>
+
+struct xe_debug_metadata {
+	/** @type: type of given metadata */
+	u64 type;
+
+	/** @ptr: copy of userptr, given as a metadata payload */
+	void *ptr;
+
+	/** @len: length, in bytes of the metadata */
+	u64 len;
+
+	/** @id */
+	u64 id;
+
+	/** @ref: reference count */
+	struct kref refcount;
+};
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index ba1c80089906..268faa1800c4 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -24,6 +24,7 @@
 #include "xe_bo.h"
 #include "xe_debugfs.h"
 #include "xe_devcoredump.h"
+#include "xe_debug_metadata.h"
 #include "xe_dma_buf.h"
 #include "xe_drm_client.h"
 #include "xe_drv.h"
@@ -91,6 +92,9 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
 	xe->clients.count++;
 	spin_unlock(&xe->clients.lock);
 
+	mutex_init(&xef->debug_metadata.lock);
+	xa_init_flags(&xef->debug_metadata.xa, XA_FLAGS_ALLOC1);
+
 	file->driver_priv = xef;
 	kref_init(&xef->refcount);
 
@@ -122,6 +126,9 @@ static void xe_file_destroy(struct kref *ref)
 	xa_destroy(&xef->vm.xa);
 	mutex_destroy(&xef->vm.lock);
 
+	xa_destroy(&xef->debug_metadata.xa);
+	mutex_destroy(&xef->debug_metadata.lock);
+
 	spin_lock(&xe->clients.lock);
 	xe->clients.count--;
 	spin_unlock(&xe->clients.lock);
@@ -163,6 +170,7 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
 	struct xe_file *xef = file->driver_priv;
 	struct xe_vm *vm;
 	struct xe_exec_queue *q;
+	struct xe_debug_metadata *mdata;
 	unsigned long idx;
 
 	xe_pm_runtime_get(xe);
@@ -188,6 +196,11 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
 		xe_vm_close_and_put(vm);
 	mutex_unlock(&xef->vm.lock);
 
+	mutex_lock(&xef->debug_metadata.lock);
+	xa_for_each(&xef->debug_metadata.xa, idx, mdata)
+		xe_debug_metadata_put(mdata);
+	mutex_unlock(&xef->debug_metadata.lock);
+
 	xe_file_put(xef);
 
 	xe_pm_runtime_put(xe);
@@ -212,6 +225,10 @@ static const struct drm_ioctl_desc xe_ioctls[] = {
 			  DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(XE_OBSERVATION, xe_observation_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(XE_EUDEBUG_CONNECT, xe_eudebug_connect_ioctl, DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(XE_DEBUG_METADATA_CREATE, xe_debug_metadata_create_ioctl,
+			  DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(XE_DEBUG_METADATA_DESTROY, xe_debug_metadata_destroy_ioctl,
+			  DRM_RENDER_ALLOW),
 };
 
 static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 3b33add576be..beb1f3c8dc63 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -628,6 +628,14 @@ struct xe_file {
 
 	/** @link: link into xe_device.client.list */
 	struct list_head link;
+
+	/** @debug_metadata: array of debug metadata for file */
+	struct {
+		/** @xa: xarray to store engines */
+		struct xarray xa;
+		/** @lock: protects file engine state */
+		struct mutex lock;
+	} debug_metadata;
 };
 
 #endif
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index 61c4c061bd75..cddc36c9be02 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -103,7 +103,8 @@ extern "C" {
 #define DRM_XE_WAIT_USER_FENCE		0x0a
 #define DRM_XE_OBSERVATION		0x0b
 #define DRM_XE_EUDEBUG_CONNECT		0x0c
-
+#define DRM_XE_DEBUG_METADATA_CREATE	0x0d
+#define DRM_XE_DEBUG_METADATA_DESTROY	0x0e
 /* Must be kept compact -- no holes */
 
 #define DRM_IOCTL_XE_DEVICE_QUERY		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_DEVICE_QUERY, struct drm_xe_device_query)
@@ -119,6 +120,8 @@ extern "C" {
 #define DRM_IOCTL_XE_WAIT_USER_FENCE		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence)
 #define DRM_IOCTL_XE_OBSERVATION		DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param)
 #define DRM_IOCTL_XE_EUDEBUG_CONNECT		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)
+#define DRM_IOCTL_XE_DEBUG_METADATA_CREATE	 DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_DEBUG_METADATA_CREATE, struct drm_xe_debug_metadata_create)
+#define DRM_IOCTL_XE_DEBUG_METADATA_DESTROY	 DRM_IOW(DRM_COMMAND_BASE + DRM_XE_DEBUG_METADATA_DESTROY, struct drm_xe_debug_metadata_destroy)
 
 /**
  * DOC: Xe IOCTL Extensions
@@ -1714,6 +1717,54 @@ struct drm_xe_eudebug_connect {
 	__u32 version; /* output: current ABI (ioctl / events) version */
 };
 
+/*
+ * struct drm_xe_debug_metadata_create - Create debug metadata
+ *
+ * Add a region of user memory to be marked as debug metadata.
+ * When the debugger attaches, the metadata regions will be delivered
+ * for debugger. Debugger can then map these regions to help decode
+ * the program state.
+ *
+ * Returns handle to created metadata entry.
+ */
+struct drm_xe_debug_metadata_create {
+	/** @extensions: Pointer to the first extension struct, if any */
+	__u64 extensions;
+
+#define DRM_XE_DEBUG_METADATA_ELF_BINARY     0
+#define DRM_XE_DEBUG_METADATA_PROGRAM_MODULE 1
+#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_MODULE_AREA 2
+#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SBA_AREA 3
+#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA 4
+#define WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM (1 + \
+	  WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_SIP_AREA)
+
+	/** @type: Type of metadata */
+	__u64 type;
+
+	/** @user_addr: pointer to start of the metadata */
+	__u64 user_addr;
+
+	/** @len: length, in bytes of the medata */
+	__u64 len;
+
+	/** @metadata_id: created metadata handle (out) */
+	__u32 metadata_id;
+};
+
+/**
+ * struct drm_xe_debug_metadata_destroy - Destroy debug metadata
+ *
+ * Destroy debug metadata.
+ */
+struct drm_xe_debug_metadata_destroy {
+	/** @extensions: Pointer to the first extension struct, if any */
+	__u64 extensions;
+
+	/** @metadata_id: metadata handle to destroy */
+	__u32 metadata_id;
+};
+
 #include "xe_drm_eudebug.h"
 
 #if defined(__cplusplus)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 17/21] drm/xe: Attach debug metadata to vma
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (15 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 16/21] drm/xe: Debug metadata create/destroy ioctls Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 21:25   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 18/21] drm/xe/eudebug: Add debug metadata support for xe_eudebug Mika Kuoppala
                   ` (12 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Maciej Patelczyk, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Introduces a vm_bind_op extension, enabling users to attach metadata objects
to each [OP_MAP|OP_MAP_USERPTR] operation. This interface will be utilized
by the EU debugger to relay information about the contents of specified
VMAs from the debugee to the debugger process.

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_debug_metadata.c |  13 ++
 drivers/gpu/drm/xe/xe_debug_metadata.h |   2 +
 drivers/gpu/drm/xe/xe_vm.c             | 198 ++++++++++++++++++++++++-
 drivers/gpu/drm/xe/xe_vm_types.h       |  15 ++
 include/uapi/drm/xe_drm.h              |  19 +++
 5 files changed, 243 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.c b/drivers/gpu/drm/xe/xe_debug_metadata.c
index 8d99170d3591..daffc13c58d6 100644
--- a/drivers/gpu/drm/xe/xe_debug_metadata.c
+++ b/drivers/gpu/drm/xe/xe_debug_metadata.c
@@ -24,6 +24,19 @@ void xe_debug_metadata_put(struct xe_debug_metadata *mdata)
 	kref_put(&mdata->refcount, xe_debug_metadata_release);
 }
 
+struct xe_debug_metadata *xe_debug_metadata_get(struct xe_file *xef, u32 id)
+{
+	struct xe_debug_metadata *mdata;
+
+	mutex_lock(&xef->debug_metadata.lock);
+	mdata = xa_load(&xef->debug_metadata.xa, id);
+	if (mdata)
+		kref_get(&mdata->refcount);
+	mutex_unlock(&xef->debug_metadata.lock);
+
+	return mdata;
+}
+
 int xe_debug_metadata_create_ioctl(struct drm_device *dev,
 				   void *data,
 				   struct drm_file *file)
diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.h b/drivers/gpu/drm/xe/xe_debug_metadata.h
index abaea076c12d..deca24fa2cba 100644
--- a/drivers/gpu/drm/xe/xe_debug_metadata.h
+++ b/drivers/gpu/drm/xe/xe_debug_metadata.h
@@ -10,7 +10,9 @@
 
 struct drm_device;
 struct drm_file;
+struct xe_file;
 
+struct xe_debug_metadata *xe_debug_metadata_get(struct xe_file *xef, u32 id);
 void xe_debug_metadata_put(struct xe_debug_metadata *mdata);
 
 int xe_debug_metadata_create_ioctl(struct drm_device *dev,
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index b117a892e386..9e27ae9d64e6 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_metadata.h"
 #include "xe_device.h"
 #include "xe_drm_client.h"
 #include "xe_exec_queue.h"
@@ -940,6 +941,8 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
 			vma->gpuva.gem.obj = &bo->ttm.base;
 	}
 
+	INIT_LIST_HEAD(&vma->debug_metadata);
+
 	INIT_LIST_HEAD(&vma->combined_links.rebind);
 
 	INIT_LIST_HEAD(&vma->gpuva.gem.entry);
@@ -1003,6 +1006,48 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
 	return vma;
 }
 
+static void vma_free_debug_metadata(struct list_head *debug_metadata)
+{
+	struct xe_vma_debug_metadata *vmad, *tmp;
+
+	list_for_each_entry_safe(vmad, tmp, debug_metadata, link) {
+		list_del(&vmad->link);
+		kfree(vmad);
+	}
+}
+
+static struct xe_vma_debug_metadata *
+vma_new_debug_metadata(u32 metadata_id, u64 cookie)
+{
+	struct xe_vma_debug_metadata *vmad;
+
+	vmad = kzalloc(sizeof(*vmad), GFP_KERNEL);
+	if (!vmad)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&vmad->link);
+
+	vmad->metadata_id = metadata_id;
+	vmad->cookie = cookie;
+
+	return vmad;
+}
+
+static int vma_debug_metadata_copy(struct xe_vma *from,
+				   struct xe_vma *to)
+{
+	struct xe_vma_debug_metadata *vmad, *vma;
+
+	list_for_each_entry(vmad, &from->debug_metadata, link) {
+		vma = vma_new_debug_metadata(vmad->metadata_id, vmad->cookie);
+		if (IS_ERR(vma))
+			return PTR_ERR(vma);
+
+		list_add_tail(&vmad->link, &to->debug_metadata);
+	}
+	return 0;
+}
+
 static void xe_vma_destroy_late(struct xe_vma *vma)
 {
 	struct xe_vm *vm = xe_vma_vm(vma);
@@ -1032,6 +1077,7 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
 		xe_bo_put(xe_vma_bo(vma));
 	}
 
+	vma_free_debug_metadata(&vma->debug_metadata);
 	xe_vma_free(vma);
 }
 
@@ -2005,6 +2051,8 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_bo *bo,
 			op->map.is_null = flags & DRM_XE_VM_BIND_FLAG_NULL;
 			op->map.dumpable = flags & DRM_XE_VM_BIND_FLAG_DUMPABLE;
 			op->map.pat_index = pat_index;
+
+			INIT_LIST_HEAD(&op->map.debug_metadata);
 		} else if (__op->op == DRM_GPUVA_OP_PREFETCH) {
 			op->prefetch.region = prefetch_region;
 		}
@@ -2195,11 +2243,11 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
 			flags |= op->map.dumpable ?
 				VMA_CREATE_FLAG_DUMPABLE : 0;
 
-			vma = new_vma(vm, &op->base.map, op->map.pat_index,
-				      flags);
+			vma = new_vma(vm, &op->base.map, op->map.pat_index, flags);
 			if (IS_ERR(vma))
 				return PTR_ERR(vma);
 
+			list_splice_tail_init(&op->map.debug_metadata, &vma->debug_metadata);
 			op->map.vma = vma;
 			if (op->map.immediate || !xe_vm_in_fault_mode(vm))
 				xe_vma_ops_incr_pt_update_ops(vops,
@@ -2230,6 +2278,8 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
 				if (IS_ERR(vma))
 					return PTR_ERR(vma);
 
+				list_splice_tail_init(&old->debug_metadata, &vma->debug_metadata);
+
 				op->remap.prev = vma;
 
 				/*
@@ -2269,6 +2319,16 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
 				if (IS_ERR(vma))
 					return PTR_ERR(vma);
 
+				if (op->base.remap.prev) {
+					err = vma_debug_metadata_copy(op->remap.prev,
+								      vma);
+					if (err)
+						return err;
+				} else {
+					list_splice_tail_init(&old->debug_metadata,
+							      &vma->debug_metadata);
+				}
+
 				op->remap.next = vma;
 
 				/*
@@ -2319,6 +2379,7 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
 	switch (op->base.op) {
 	case DRM_GPUVA_OP_MAP:
 		if (op->map.vma) {
+			vma_free_debug_metadata(&op->map.debug_metadata);
 			prep_vma_destroy(vm, op->map.vma, post_commit);
 			xe_vma_destroy_unlocked(op->map.vma);
 		}
@@ -2557,6 +2618,120 @@ static int vm_ops_setup_tile_args(struct xe_vm *vm, struct xe_vma_ops *vops)
 	}
 
 	return number_tiles;
+};
+
+static int vma_new_debug_metadata_op(struct xe_vma_op *op,
+				     u32 metadata_id, u64 cookie,
+				     u64 flags)
+{
+	struct xe_vma_debug_metadata *vmad;
+
+	vmad = vma_new_debug_metadata(metadata_id, cookie);
+	if (IS_ERR(vmad))
+		return PTR_ERR(vmad);
+
+	list_add_tail(&vmad->link, &op->map.debug_metadata);
+	return 0;
+}
+
+typedef int (*xe_vm_bind_op_user_extension_fn)(struct xe_device *xe,
+					       struct xe_file *xef,
+					       struct drm_gpuva_ops *ops,
+					       u32 operation, u64 extension);
+
+static int vm_bind_op_ext_attach_debug(struct xe_device *xe,
+				       struct xe_file *xef,
+				       struct drm_gpuva_ops *ops,
+				       u32 operation, u64 extension)
+{
+	u64 __user *address = u64_to_user_ptr(extension);
+	struct drm_xe_vm_bind_op_ext_attach_debug ext;
+	struct xe_debug_metadata *mdata;
+	struct drm_gpuva_op *__op;
+	int err;
+
+	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_MAP_USERPTR &&
+			 operation != DRM_XE_VM_BIND_OP_MAP))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, ext.flags))
+		return -EINVAL;
+
+	mdata = xe_debug_metadata_get(xef, (u32)ext.metadata_id);
+	if (XE_IOCTL_DBG(xe, !mdata))
+		return -ENOENT;
+
+	/* care about metadata existence only on the time of attach */
+	xe_debug_metadata_put(mdata);
+
+	if (!ops)
+		return 0;
+
+	drm_gpuva_for_each_op(__op, ops) {
+		struct xe_vma_op *op = gpuva_op_to_vma_op(__op);
+
+		if (op->base.op == DRM_GPUVA_OP_MAP) {
+			err = vma_new_debug_metadata_op(op,
+							ext.metadata_id,
+							ext.cookie,
+							ext.flags);
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
+static const xe_vm_bind_op_user_extension_fn vm_bind_op_extension_funcs[] = {
+	[XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG] = vm_bind_op_ext_attach_debug,
+};
+
+#define MAX_USER_EXTENSIONS	16
+static int vm_bind_op_user_extensions(struct xe_device *xe,
+				      struct xe_file *xef,
+				      struct drm_gpuva_ops *ops,
+				      u32 operation,
+				      u64 extensions, int ext_number)
+{
+	u64 __user *address = u64_to_user_ptr(extensions);
+	struct drm_xe_user_extension ext;
+	int err;
+
+	if (XE_IOCTL_DBG(xe, ext_number >= 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, ext.pad) ||
+	    XE_IOCTL_DBG(xe, ext.name >=
+			 ARRAY_SIZE(vm_bind_op_extension_funcs)))
+		return -EINVAL;
+
+	err = vm_bind_op_extension_funcs[ext.name](xe, xef, ops,
+						   operation, extensions);
+	if (XE_IOCTL_DBG(xe, err))
+		return err;
+
+	if (ext.next_extension)
+		return vm_bind_op_user_extensions(xe, xef, ops,
+						  operation, ext.next_extension,
+						  ++ext_number);
+
+	return 0;
+}
+
+static int vm_bind_op_user_extensions_check(struct xe_device *xe,
+					    struct xe_file *xef,
+					    u32 operation, u64 extensions)
+{
+	return vm_bind_op_user_extensions(xe, xef, NULL, operation, extensions, 0);
 }
 
 static struct dma_fence *ops_execute(struct xe_vm *vm,
@@ -2753,6 +2928,7 @@ static int vm_bind_ioctl_ops_execute(struct xe_vm *vm,
 #define ALL_DRM_XE_SYNCS_FLAGS (DRM_XE_SYNCS_FLAG_WAIT_FOR_OP)
 
 static int vm_bind_ioctl_check_args(struct xe_device *xe,
+				    struct xe_file *xef,
 				    struct drm_xe_vm_bind *args,
 				    struct drm_xe_vm_bind_op **bind_ops)
 {
@@ -2796,6 +2972,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe,
 		u64 obj_offset = (*bind_ops)[i].obj_offset;
 		u32 prefetch_region = (*bind_ops)[i].prefetch_mem_region_instance;
 		bool is_null = flags & DRM_XE_VM_BIND_FLAG_NULL;
+		u64 extensions = (*bind_ops)[i].extensions;
 		u16 pat_index = (*bind_ops)[i].pat_index;
 		u16 coh_mode;
 
@@ -2856,6 +3033,13 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe,
 			err = -EINVAL;
 			goto free_bind_ops;
 		}
+
+		if (extensions) {
+			err = vm_bind_op_user_extensions_check(xe, xef, op, extensions);
+			if (err)
+				goto free_bind_ops;
+		}
+
 	}
 
 	return 0;
@@ -2958,7 +3142,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	int err;
 	int i;
 
-	err = vm_bind_ioctl_check_args(xe, args, &bind_ops);
+	err = vm_bind_ioctl_check_args(xe, xef, args, &bind_ops);
 	if (err)
 		return err;
 
@@ -3086,11 +3270,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, bos[i], obj_offset,
 						  addr, range, op, flags,
 						  prefetch_region, pat_index);
-		if (IS_ERR(ops[i])) {
+		if (!IS_ERR(ops[i]) && extensions) {
+			err = vm_bind_op_user_extensions(xe, xef, ops[i],
+							 op, extensions, 0);
+			if (err)
+				goto unwind_ops;
+		} else if (IS_ERR(ops[i])) {
 			err = PTR_ERR(ops[i]);
 			ops[i] = NULL;
 			goto unwind_ops;
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index da9d7ef6ab8f..fe64ce6ed1d9 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -121,6 +121,9 @@ struct xe_vma {
 	 * Needs to be signalled before UNMAP can be processed.
 	 */
 	struct xe_user_fence *ufence;
+
+	/** @debug_metadata: List of vma debug metadata */
+	struct list_head debug_metadata;
 };
 
 /**
@@ -309,6 +312,8 @@ struct xe_vma_op_map {
 	bool dumpable;
 	/** @pat_index: The pat index to use for this operation. */
 	u16 pat_index;
+	/** @debug_metadata: List of attached debug metadata */
+	struct list_head debug_metadata;
 };
 
 /** struct xe_vma_op_remap - VMA remap operation */
@@ -386,4 +391,14 @@ struct xe_vma_ops {
 #endif
 };
 
+struct xe_vma_debug_metadata {
+	/** @debug.metadata: id of attached xe_debug_metadata */
+	u32 metadata_id;
+	/** @debug.cookie: user defined cookie */
+	u64 cookie;
+
+	/** @link: list of metadata attached to vma */
+	struct list_head link;
+};
+
 #endif
diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
index cddc36c9be02..eab503754735 100644
--- a/include/uapi/drm/xe_drm.h
+++ b/include/uapi/drm/xe_drm.h
@@ -886,6 +886,23 @@ struct drm_xe_vm_destroy {
 	__u64 reserved[2];
 };
 
+struct drm_xe_vm_bind_op_ext_attach_debug {
+	/** @base: base user extension */
+	struct drm_xe_user_extension base;
+
+	/** @id: Debug object id from create metadata */
+	__u64 metadata_id;
+
+	/** @flags: Flags */
+	__u64 flags;
+
+	/** @cookie: Cookie */
+	__u64 cookie;
+
+	/** @reserved: Reserved */
+	__u64 reserved;
+};
+
 /**
  * struct drm_xe_vm_bind_op - run bind operations
  *
@@ -910,7 +927,9 @@ struct drm_xe_vm_destroy {
  *    handle MBZ, and the BO offset MBZ. This flag is intended to
  *    implement VK sparse bindings.
  */
+
 struct drm_xe_vm_bind_op {
+#define XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG 0
 	/** @extensions: Pointer to the first extension struct, if any */
 	__u64 extensions;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 18/21] drm/xe/eudebug: Add debug metadata support for xe_eudebug
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (16 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 17/21] drm/xe: Attach debug metadata to vma Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 14:08 ` [PATCH 19/21] drm/xe/eudebug: Implement vm_bind_op discovery Mika Kuoppala
                   ` (11 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Dominik Grzegorzek, Maciej Patelczyk, Mika Kuoppala

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

Reflect debug metadata resource creation/destroy as events passed to the
debugger. Introduce ioctl allowing to read metadata content on demand.

Each VMA can have multiple metadata attached and it is passed from user
on BIND or it's copied on internal remap.

Xe EU Debugger on VM BIND will inform about VMA metadata attachements
during bind IOCTL sending proper OP event.

v2: checkpatch (Maciej) v2: struct alignment (Matthew)
v3: squash and typos (Mika)

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_debug_metadata.c |   7 +-
 drivers/gpu/drm/xe/xe_eudebug.c        | 326 ++++++++++++++++++++++++-
 drivers/gpu/drm/xe/xe_eudebug.h        |   8 +-
 drivers/gpu/drm/xe/xe_eudebug_types.h  |  27 +-
 drivers/gpu/drm/xe/xe_vm.c             |   2 +-
 include/uapi/drm/xe_drm_eudebug.h      |  32 ++-
 6 files changed, 392 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.c b/drivers/gpu/drm/xe/xe_debug_metadata.c
index daffc13c58d6..31e943248cfc 100644
--- a/drivers/gpu/drm/xe/xe_debug_metadata.c
+++ b/drivers/gpu/drm/xe/xe_debug_metadata.c
@@ -9,6 +9,7 @@
 #include <drm/xe_drm.h>
 
 #include "xe_device.h"
+#include "xe_eudebug.h"
 #include "xe_macros.h"
 
 static void xe_debug_metadata_release(struct kref *ref)
@@ -51,7 +52,7 @@ int xe_debug_metadata_create_ioctl(struct drm_device *dev,
 	if (XE_IOCTL_DBG(xe, args->extensions))
 		return -EINVAL;
 
-	if (XE_IOCTL_DBG(xe, args->type > DRM_XE_DEBUG_METADATA_PROGRAM_MODULE))
+	if (XE_IOCTL_DBG(xe, args->type >= WORK_IN_PROGRESS_DRM_XE_DEBUG_METADATA_NUM))
 		return -EINVAL;
 
 	if (XE_IOCTL_DBG(xe, !args->user_addr || !args->len))
@@ -90,6 +91,8 @@ int xe_debug_metadata_create_ioctl(struct drm_device *dev,
 	if (err)
 		goto put_mdata;
 
+	xe_eudebug_debug_metadata_create(xef, mdata);
+
 	return 0;
 
 put_mdata:
@@ -115,6 +118,8 @@ int xe_debug_metadata_destroy_ioctl(struct drm_device *dev,
 	if (XE_IOCTL_DBG(xe, !mdata))
 		return -ENOENT;
 
+	xe_eudebug_debug_metadata_destroy(xef, mdata);
+
 	xe_debug_metadata_put(mdata);
 	return 0;
 }
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 947331c19f43..f0bec8c8bba1 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -28,6 +28,7 @@
 #include "xe_eudebug_types.h"
 #include "xe_eudebug.h"
 #include "xe_exec_queue_types.h"
+#include "xe_debug_metadata.h"
 #include "xe_guc_exec_queue_types.h"
 #include "xe_execlist_types.h"
 #include "xe_mmio.h"
@@ -763,6 +764,23 @@ static struct xe_vm *find_vm(struct xe_eudebug *d, const u32 id)
 	return NULL;
 }
 
+static struct xe_debug_metadata *find_metadata_get(struct xe_eudebug *d,
+						   u32 id)
+{
+	struct xe_debug_metadata *m = NULL;
+	struct xe_eudebug_handle *h;
+
+	mutex_lock(&d->res->lock);
+	h = __find_resource(d->res, XE_EUDEBUG_RES_TYPE_METADATA, id);
+	if (h) {
+		m = (struct xe_debug_metadata *)h->key;
+		kref_get(&m->refcount);
+	}
+	mutex_unlock(&d->res->lock);
+
+	return m;
+}
+
 static int _xe_eudebug_add_handle(struct xe_eudebug *d,
 				  int type,
 				  void *p,
@@ -1215,6 +1233,73 @@ static long xe_eudebug_eu_control(struct xe_eudebug *d, const u64 arg)
 	return ret;
 }
 
+static long xe_eudebug_read_metadata(struct xe_eudebug *d,
+				     unsigned int cmd,
+				     const u64 arg)
+{
+	struct drm_xe_eudebug_read_metadata user_arg;
+	struct xe_debug_metadata *mdata;
+	struct xe_file *xef;
+	struct xe_device *xe = d->xe;
+	long ret = 0;
+
+	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(cmd) & _IOC_WRITE)))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(cmd) & _IOC_READ)))
+		return -EINVAL;
+
+	if (XE_IOCTL_DBG(xe, _IOC_SIZE(cmd) < sizeof(user_arg)))
+		return -EINVAL;
+
+	if (copy_from_user(&user_arg, u64_to_user_ptr(arg), sizeof(user_arg)))
+		return -EFAULT;
+
+	if (XE_IOCTL_DBG(xe, user_arg.flags))
+		return -EINVAL;
+
+	if (!access_ok(u64_to_user_ptr(user_arg.ptr), user_arg.size))
+		return -EFAULT;
+
+	if (xe_eudebug_detached(d))
+		return -ENOTCONN;
+
+	eu_dbg(d,
+	       "read metadata: client_handle=%llu, metadata_handle=%llu, flags=0x%x",
+	       user_arg.client_handle, user_arg.metadata_handle, user_arg.flags);
+
+	xef = find_client(d, user_arg.client_handle);
+	if (XE_IOCTL_DBG(xe, !xef))
+		return -EINVAL;
+
+	mdata = find_metadata_get(d, (u32)user_arg.metadata_handle);
+	if (XE_IOCTL_DBG(xe, !mdata))
+		return -EINVAL;
+
+	if (user_arg.size) {
+		if (user_arg.size < mdata->len) {
+			ret = -EINVAL;
+			goto metadata_put;
+		}
+
+		/* This limits us to a maximum payload size of 2G */
+		if (copy_to_user(u64_to_user_ptr(user_arg.ptr),
+				 mdata->ptr, mdata->len)) {
+			ret = -EFAULT;
+			goto metadata_put;
+		}
+	}
+
+	user_arg.size = mdata->len;
+
+	if (copy_to_user(u64_to_user_ptr(arg), &user_arg, sizeof(user_arg)))
+		ret = -EFAULT;
+
+metadata_put:
+	xe_debug_metadata_put(mdata);
+	return ret;
+}
+
 static long xe_eudebug_vm_open_ioctl(struct xe_eudebug *d, unsigned long arg);
 
 static long xe_eudebug_ioctl(struct file *file,
@@ -1241,7 +1326,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_READ_METADATA:
+		ret = xe_eudebug_read_metadata(d, cmd, arg);
+		eu_dbg(d, "ioctl cmd=READ_METADATA ret=%ld\n", ret);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -2495,19 +2583,145 @@ static int vm_bind_op_event(struct xe_eudebug *d,
 	return xe_eudebug_queue_bind_event(d, vm, event);
 }
 
+static int vm_bind_op_metadata_event(struct xe_eudebug *d,
+				     struct xe_vm *vm,
+				     u32 flags,
+				     u64 ref_seqno,
+				     u64 metadata_handle,
+				     u64 metadata_cookie)
+{
+	struct xe_eudebug_event_vm_bind_op_metadata *e;
+	struct xe_eudebug_event *event;
+	const u32 sz = sizeof(*e);
+	u64 seqno;
+
+	seqno = atomic_long_inc_return(&d->events.seqno);
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA,
+					seqno, flags, sz, GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	e = cast_event(e, event);
+
+	write_member(struct drm_xe_eudebug_event_vm_bind_op_metadata, e,
+		     vm_bind_op_ref_seqno, ref_seqno);
+	write_member(struct drm_xe_eudebug_event_vm_bind_op_metadata, e,
+		     metadata_handle, metadata_handle);
+	write_member(struct drm_xe_eudebug_event_vm_bind_op_metadata, e,
+		     metadata_cookie, metadata_cookie);
+
+	/* If in discovery, no need to collect ops */
+	if (!completion_done(&d->discovery))
+		return xe_eudebug_queue_event(d, event);
+
+	return xe_eudebug_queue_bind_event(d, vm, event);
+}
+
+static int vm_bind_op_metadata_count(struct xe_eudebug *d,
+				     struct xe_vm *vm,
+				     struct list_head *debug_metadata)
+{
+	struct xe_vma_debug_metadata *metadata;
+	struct xe_debug_metadata *mdata;
+	int h_m = 0, metadata_count = 0;
+
+	if (!debug_metadata)
+		return 0;
+
+	list_for_each_entry(metadata, debug_metadata, link) {
+		mdata = xe_debug_metadata_get(vm->xef, metadata->metadata_id);
+		if (mdata) {
+			h_m = find_handle(d->res, XE_EUDEBUG_RES_TYPE_METADATA, mdata);
+			xe_debug_metadata_put(mdata);
+		}
+
+		if (!mdata || h_m < 0) {
+			if (!mdata)
+				eu_err(d, "Metadata::%u not found.",
+				       metadata->metadata_id);
+			else
+				eu_err(d, "Metadata::%u not in the xe debugger",
+				       metadata->metadata_id);
+			xe_eudebug_disconnect(d, -ENOENT);
+			return -ENOENT;
+		}
+		metadata_count++;
+	}
+	return metadata_count;
+}
+
+
+static int vm_bind_op_metadata(struct xe_eudebug *d, struct xe_vm *vm,
+			       const u32 flags,
+			       const u64 op_ref_seqno,
+			       struct list_head *debug_metadata)
+{
+	struct xe_vma_debug_metadata *metadata;
+	int h_m = 0; /* handle space range = <1, MAX_INT>, return 0 if metadata not attached */
+	int metadata_count = 0;
+	int ret;
+
+	if (!debug_metadata)
+		return 0;
+
+	XE_WARN_ON(flags != DRM_XE_EUDEBUG_EVENT_CREATE);
+
+	list_for_each_entry(metadata, debug_metadata, link) {
+		struct xe_debug_metadata *mdata;
+
+		mdata = xe_debug_metadata_get(vm->xef, metadata->metadata_id);
+		if (mdata) {
+			h_m = find_handle(d->res, XE_EUDEBUG_RES_TYPE_METADATA, mdata);
+			xe_debug_metadata_put(mdata);
+		}
+
+		if (!mdata || h_m < 0) {
+			eu_err(d, "Attached debug metadata::%u not found!\n",
+			       metadata->metadata_id);
+			return -ENOENT;
+		}
+
+		ret = vm_bind_op_metadata_event(d, vm, flags, op_ref_seqno,
+						h_m, metadata->cookie);
+		if (ret < 0)
+			return ret;
+
+		metadata_count++;
+	}
+
+	return metadata_count;
+}
+
 static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
 		      const u32 flags, const u64 bind_ref_seqno,
-		      u64 addr, u64 range)
+		      u64 addr, u64 range,
+		      struct list_head *debug_metadata)
 {
 	u64 op_seqno = 0;
-	u64 num_extensions = 0;
+	u64 num_extensions;
 	int ret;
 
+	ret = vm_bind_op_metadata_count(d, vm, debug_metadata);
+	if (ret < 0)
+		return ret;
+
+	num_extensions = ret;
+
 	ret = vm_bind_op_event(d, vm, flags, bind_ref_seqno, num_extensions,
 			       addr, range, &op_seqno);
 	if (ret)
 		return ret;
 
+	ret = vm_bind_op_metadata(d, vm, flags, op_seqno, debug_metadata);
+	if (ret < 0)
+		return ret;
+
+	if (ret != num_extensions) {
+		eu_err(d, "Inconsistency in metadata detected.");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -2609,16 +2823,28 @@ void xe_eudebug_vm_bind_start(struct xe_vm *vm)
 	xe_eudebug_put(d);
 }
 
-void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range)
+void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range,
+			       struct drm_gpuva_ops *ops)
 {
 	struct xe_eudebug *d;
+	struct list_head *debug_metadata = NULL;
 	u32 flags;
 
 	switch (op) {
 	case DRM_XE_VM_BIND_OP_MAP:
 	case DRM_XE_VM_BIND_OP_MAP_USERPTR:
 	{
+		struct drm_gpuva_op *__op;
+
 		flags = DRM_XE_EUDEBUG_EVENT_CREATE;
+
+		/* OP_MAP will be last and singleton */
+		drm_gpuva_for_each_op(__op, ops) {
+			struct xe_vma_op *op = gpuva_op_to_vma_op(__op);
+
+			if (op->base.op == DRM_GPUVA_OP_MAP)
+				debug_metadata = &op->map.vma->debug_metadata;
+		}
 		break;
 	}
 	case DRM_XE_VM_BIND_OP_UNMAP:
@@ -2637,7 +2863,8 @@ void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range)
 	if (!d)
 		return;
 
-	xe_eudebug_event_put(d, vm_bind_op(d, vm, flags, 0, addr, range));
+	xe_eudebug_event_put(d, vm_bind_op(d, vm, flags, 0, addr, range,
+					   debug_metadata));
 }
 
 static struct xe_eudebug_event *fetch_bind_event(struct xe_vm * const vm)
@@ -2763,8 +2990,89 @@ int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence)
 	return 0;
 }
 
+static int send_debug_metadata_event(struct xe_eudebug *d, u32 flags,
+				     u64 client_handle, u64 metadata_handle,
+				     u64 type, u64 len, u64 seqno)
+{
+	struct xe_eudebug_event *event;
+	struct xe_eudebug_event_metadata *e;
+
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_METADATA, seqno,
+				       flags, sizeof(*e), GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	e = cast_event(e, event);
+
+	write_member(struct drm_xe_eudebug_event_metadata, e, client_handle, client_handle);
+	write_member(struct drm_xe_eudebug_event_metadata, e, metadata_handle, metadata_handle);
+	write_member(struct drm_xe_eudebug_event_metadata, e, type, type);
+	write_member(struct drm_xe_eudebug_event_metadata, e, len, len);
+
+	return xe_eudebug_queue_event(d, event);
+}
+
+static int debug_metadata_create_event(struct xe_eudebug *d,
+				       struct xe_file *xef, struct xe_debug_metadata *m)
+{
+	int h_c, h_m;
+	u64 seqno;
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
+	if (h_c < 0)
+		return h_c;
+
+	h_m = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_METADATA, m, &seqno);
+	if (h_m <= 0)
+		return h_m;
+
+	return send_debug_metadata_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
+					 h_c, h_m, m->type, m->len, seqno);
+}
+
+static int debug_metadata_destroy_event(struct xe_eudebug *d,
+				       struct xe_file *xef, struct xe_debug_metadata *m)
+{
+	int h_c, h_m;
+	u64 seqno;
+
+	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
+	if (h_c < 0)
+		return h_c;
+
+	h_m = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_METADATA, m, &seqno);
+	if (h_m < 0)
+		return h_m;
+
+	return send_debug_metadata_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY,
+					 h_c, h_m, m->type, m->len, seqno);
+}
+
+void xe_eudebug_debug_metadata_create(struct xe_file *xef, struct xe_debug_metadata *m)
+{
+	struct xe_eudebug *d;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, debug_metadata_create_event(d, xef, m));
+}
+
+void xe_eudebug_debug_metadata_destroy(struct xe_file *xef, struct xe_debug_metadata *m)
+{
+	struct xe_eudebug *d;
+
+	d = xe_eudebug_get(xef);
+	if (!d)
+		return;
+
+	xe_eudebug_event_put(d, debug_metadata_destroy_event(d, xef, m));
+}
+
 static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 {
+	struct xe_debug_metadata *m;
 	struct xe_exec_queue *q;
 	struct xe_vm *vm;
 	unsigned long i;
@@ -2774,6 +3082,14 @@ static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 	if (err)
 		return err;
 
+	mutex_lock(&xef->debug_metadata.lock);
+	xa_for_each(&xef->debug_metadata.xa, i, m) {
+		err = debug_metadata_create_event(d, xef, m);
+		if (err)
+			break;
+	}
+	mutex_unlock(&xef->debug_metadata.lock);
+
 	mutex_lock(&xef->vm.lock);
 	xa_for_each(&xef->vm.xa, i, vm) {
 		err = vm_create_event(d, xef, vm);
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 3de54802a6ca..02c9ba56e752 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -16,6 +16,8 @@ struct xe_vma;
 struct xe_exec_queue;
 struct xe_hw_engine;
 struct xe_user_fence;
+struct xe_debug_metadata;
+struct drm_gpuva_ops;
 
 int xe_eudebug_connect_ioctl(struct drm_device *dev,
 			     void *data,
@@ -36,7 +38,8 @@ 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_start(struct xe_vm *vm);
-void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range);
+void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range,
+			       struct drm_gpuva_ops *ops);
 void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int err);
 
 int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence);
@@ -44,4 +47,7 @@ int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence);
 struct xe_eudebug *xe_eudebug_get(struct xe_file *xef);
 void xe_eudebug_put(struct xe_eudebug *d);
 
+void xe_eudebug_debug_metadata_create(struct xe_file *xef, struct xe_debug_metadata *m);
+void xe_eudebug_debug_metadata_destroy(struct xe_file *xef, struct xe_debug_metadata *m);
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
index a32c51416b5f..073629eb4809 100644
--- a/drivers/gpu/drm/xe/xe_eudebug_types.h
+++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
@@ -56,7 +56,8 @@ struct xe_eudebug_resource {
 #define XE_EUDEBUG_RES_TYPE_VM		1
 #define XE_EUDEBUG_RES_TYPE_EXEC_QUEUE	2
 #define XE_EUDEBUG_RES_TYPE_LRC		3
-#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_LRC + 1)
+#define XE_EUDEBUG_RES_TYPE_METADATA	4
+#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_METADATA + 1)
 
 /**
  * struct xe_eudebug_resources - eudebug resources for all types
@@ -298,4 +299,28 @@ struct xe_eudebug_event_vm_bind_ufence {
 	u64 vm_bind_ref_seqno;
 };
 
+struct xe_eudebug_event_metadata {
+	struct xe_eudebug_event base;
+
+	/** @client_handle: client for the attention */
+	u64 client_handle;
+
+	/** @metadata_handle: debug metadata handle it's created/destroyed */
+	u64 metadata_handle;
+
+	/* @type: metadata type, refer to xe_drm.h for options */
+	u64 type;
+
+	/* @len: size of metadata paylad */
+	u64 len;
+};
+
+struct xe_eudebug_event_vm_bind_op_metadata {
+	struct xe_eudebug_event base;
+	u64 vm_bind_op_ref_seqno;
+
+	u64 metadata_handle;
+	u64 metadata_cookie;
+};
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 9e27ae9d64e6..26f34055f5f8 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3290,7 +3290,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 		if (err)
 			goto unwind_ops;
 
-		xe_eudebug_vm_bind_op_add(vm, op, addr, range);
+		xe_eudebug_vm_bind_op_add(vm, op, addr, range, ops[i]);
 
 #ifdef TEST_VM_OPS_ERROR
 		if (flags & FORCE_OP_ERROR) {
diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
index df79eafb6136..2dcd1ae106b1 100644
--- a/include/uapi/drm/xe_drm_eudebug.h
+++ b/include/uapi/drm/xe_drm_eudebug.h
@@ -19,6 +19,7 @@ extern "C" {
 #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
 #define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
 #define DRM_XE_EUDEBUG_IOCTL_VM_OPEN		_IOW('j', 0x1, struct drm_xe_eudebug_vm_open)
+#define DRM_XE_EUDEBUG_IOCTL_READ_METADATA	_IOWR('j', 0x3, struct drm_xe_eudebug_read_metadata)
 
 /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
 struct drm_xe_eudebug_event {
@@ -34,7 +35,9 @@ struct drm_xe_eudebug_event {
 #define DRM_XE_EUDEBUG_EVENT_VM_BIND		6
 #define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP		7
 #define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE	8
-#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
+#define DRM_XE_EUDEBUG_EVENT_METADATA		9
+#define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA 10
+#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA
 
 	__u16 flags;
 #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
@@ -189,6 +192,33 @@ struct drm_xe_eudebug_vm_open {
 	__u64 timeout_ns;
 };
 
+struct drm_xe_eudebug_read_metadata {
+	__u64 client_handle;
+	__u64 metadata_handle;
+	__u32 flags;
+	__u32 reserved;
+	__u64 ptr;
+	__u64 size;
+};
+
+struct drm_xe_eudebug_event_metadata {
+	struct drm_xe_eudebug_event base;
+
+	__u64 client_handle;
+	__u64 metadata_handle;
+	/* XXX: Refer to xe_drm.h for fields */
+	__u64 type;
+	__u64 len;
+};
+
+struct drm_xe_eudebug_event_vm_bind_op_metadata {
+	struct drm_xe_eudebug_event base;
+	__u64 vm_bind_op_ref_seqno; /* *_event_vm_bind_op.base.seqno */
+
+	__u64 metadata_handle;
+	__u64 metadata_cookie;
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 19/21] drm/xe/eudebug: Implement vm_bind_op discovery
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (17 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 18/21] drm/xe/eudebug: Add debug metadata support for xe_eudebug Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-27  4:39   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality Mika Kuoppala
                   ` (10 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Mika Kuoppala

Follow the vm bind, vm_bind op sequence for
discovery process of a vm with the vmas it has.
Send events for ops and attach metadata if available.

v2: Fix bad op ref seqno (Christoph)

Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/xe/xe_eudebug.c | 40 +++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index f0bec8c8bba1..a80ffb64df15 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -3070,6 +3070,42 @@ void xe_eudebug_debug_metadata_destroy(struct xe_file *xef, struct xe_debug_meta
 	xe_eudebug_event_put(d, debug_metadata_destroy_event(d, xef, m));
 }
 
+static int vm_discover_binds(struct xe_eudebug *d, struct xe_vm *vm)
+{
+	struct drm_gpuva *va;
+	unsigned int num_ops = 0, send_ops = 0;
+	u64 ref_seqno = 0;
+	int err;
+
+	/* Currently only vm_bind_ioctl inserts vma's */
+	drm_gpuvm_for_each_va(va, &vm->gpuvm)
+		num_ops++;
+
+	if (!num_ops)
+		return 0;
+
+	err = vm_bind_event(d, vm, num_ops, &ref_seqno);
+	if (err)
+		return err;
+
+	drm_gpuvm_for_each_va(va, &vm->gpuvm) {
+		struct xe_vma *vma = container_of(va, struct xe_vma, gpuva);
+
+		if (send_ops >= num_ops)
+			break;
+
+		err = vm_bind_op(d, vm, DRM_XE_EUDEBUG_EVENT_CREATE, ref_seqno,
+				 xe_vma_start(vma), xe_vma_size(vma),
+				 &vma->debug_metadata);
+		if (err)
+			return err;
+
+		send_ops++;
+	}
+
+	return num_ops == send_ops ? 0 : -EINVAL;
+}
+
 static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 {
 	struct xe_debug_metadata *m;
@@ -3095,6 +3131,10 @@ static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
 		err = vm_create_event(d, xef, vm);
 		if (err)
 			break;
+
+		err = vm_discover_binds(d, vm);
+		if (err)
+			break;
 	}
 	mutex_unlock(&xef->vm.lock);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (18 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 19/21] drm/xe/eudebug: Implement vm_bind_op discovery Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-28  4:50   ` Matthew Brost
  2024-07-26 14:08 ` [PATCH 21/21] drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test Mika Kuoppala
                   ` (9 subsequent siblings)
  29 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe
  Cc: Christoph Manszewski, Dominik Grzegorzek, Mika Kuoppala,
	Maciej Patelczyk

From: Christoph Manszewski <christoph.manszewski@intel.com>

Make it possible to dynamically enable/disable debugger funtionality,
including the setting and unsetting of required hw register values via a
sysfs entry located at '/sys/class/drm/card<X>/device/enable_eudebug'.

This entry uses 'kstrtobool' and as such it accepts inputs as documented
by this function, in particular '0' and '1'.

1) Adjust to xe_rtp graphics ranges changes.
2) Fix pile placement. Wa 14019869343 (aka. 16021232320) was
added later in the pile, move disablement to appropriate commit.
3) flush reset (Christoph)
4) dont allow exec queue enable if feature is disabled (Dominik)
5) bind to drm sysfs functions (Maciej)

Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
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/xe_device.c       |   2 -
 drivers/gpu/drm/xe/xe_device_types.h |   5 +
 drivers/gpu/drm/xe/xe_eudebug.c      | 174 +++++++++++++++++++++++----
 drivers/gpu/drm/xe/xe_eudebug.h      |   2 -
 drivers/gpu/drm/xe/xe_exec_queue.c   |   3 +
 drivers/gpu/drm/xe/xe_hw_engine.c    |   1 -
 drivers/gpu/drm/xe/xe_reg_sr.c       |  21 +++-
 drivers/gpu/drm/xe/xe_reg_sr.h       |   4 +-
 drivers/gpu/drm/xe/xe_rtp.c          |   2 +-
 drivers/gpu/drm/xe/xe_rtp_types.h    |   1 +
 10 files changed, 178 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 268faa1800c4..30a2bf2a7e00 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -785,8 +785,6 @@ int xe_device_probe(struct xe_device *xe)
 
 	xe_debugfs_register(xe);
 
-	xe_eudebug_init_late(xe);
-
 	xe_hwmon_register(xe);
 
 	for_each_gt(gt, xe, id)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index beb1f3c8dc63..17aedbba3130 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -517,6 +517,11 @@ struct xe_device {
 		/** @ordered_wq: used to discovery */
 		struct workqueue_struct *ordered_wq;
 
+		/** @enable_lock: protects the enable toggle */
+		struct mutex enable_lock;
+		/** @enable: is the debugging functionality enabled */
+		bool enable;
+
 		/** @attention_scan: attention scan worker */
 		struct delayed_work attention_scan;
 	} eudebug;
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index a80ffb64df15..80066f787ec2 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -2000,9 +2000,6 @@ xe_eudebug_connect(struct xe_device *xe,
 
 	param->version = DRM_XE_EUDEBUG_VERSION;
 
-	if (!xe->eudebug.available)
-		return -EOPNOTSUPP;
-
 	d = kzalloc(sizeof(*d), GFP_KERNEL);
 	if (!d)
 		return -ENOMEM;
@@ -2064,70 +2061,199 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
 	struct drm_xe_eudebug_connect * const param = data;
 	int ret = 0;
 
+	mutex_lock(&xe->eudebug.enable_lock);
+
+	if (!xe->eudebug.enable) {
+		mutex_unlock(&xe->eudebug.enable_lock);
+		return -ENODEV;
+	}
+
 	ret = xe_eudebug_connect(xe, param);
 
+	mutex_unlock(&xe->eudebug.enable_lock);
+
 	return ret;
 }
 
 #undef XE_REG_MCR
 #define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
 
-void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
+static void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
 {
 	const struct xe_rtp_entry_sr eudebug_was[] = {
-		{ XE_RTP_NAME("GlobalDebugEnable"),
-		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
-			       ENGINE_CLASS(RENDER)),
-		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
-				     GLOBAL_DEBUG_ENABLE))
-		},
 		{ XE_RTP_NAME("TdCtlDebugEnable"),
 		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
 			       FUNC(xe_rtp_match_first_render_or_compute)),
 		  XE_RTP_ACTIONS(SET(TD_CTL,
 				     TD_CTL_BREAKPOINT_ENABLE |
 				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
-				     TD_CTL_FEH_AND_FEE_ENABLE))
+				     TD_CTL_FEH_AND_FEE_ENABLE,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
 		},
 		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
 		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
 			       FUNC(xe_rtp_match_first_render_or_compute)),
-		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
+		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
 		},
 		{ XE_RTP_NAME("18022722726"),
 		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
 			       FUNC(xe_rtp_match_first_render_or_compute)),
-		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
+		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
 		},
 		{ XE_RTP_NAME("14015527279"),
 		  XE_RTP_RULES(PLATFORM(PVC),
 			       FUNC(xe_rtp_match_first_render_or_compute)),
-		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
+		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
 		},
 		{}
 	};
 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
-	struct xe_device *xe = gt_to_xe(hwe->gt);
 
-	if (xe->eudebug.available)
-		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
+	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
+}
+
+static void xe_eudebug_fini_hw_engine(struct xe_hw_engine *hwe)
+{
+	const struct xe_rtp_entry_sr eudebug_was[] = {
+		{ XE_RTP_NAME("TdCtlDebugEnable"),
+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(CLR(TD_CTL,
+				     TD_CTL_BREAKPOINT_ENABLE |
+				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
+				     TD_CTL_FEH_AND_FEE_ENABLE,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
+		},
+		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(CLR(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
+		},
+		{ XE_RTP_NAME("18022722726"),
+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
+		},
+		{ XE_RTP_NAME("14015527279"),
+		  XE_RTP_RULES(PLATFORM(PVC),
+			       FUNC(xe_rtp_match_first_render_or_compute)),
+		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
+				     XE_RTP_ACTION_FLAG(OVERWRITE)))
+		},
+		{}
+	};
+	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
+
+	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
+}
+
+static int xe_eudebug_enable(struct xe_device *xe, bool enable)
+{
+	struct xe_gt *gt;
+	int i;
+	u8 id;
+
+	if (!xe->eudebug.available)
+		return -EOPNOTSUPP;
+
+	/* XXX: TODO hold list lock? */
+	mutex_lock(&xe->eudebug.enable_lock);
+
+	if (!enable && !list_empty(&xe->eudebug.list)) {
+		mutex_unlock(&xe->eudebug.enable_lock);
+		return -EBUSY;
+	}
+
+	if (enable == xe->eudebug.enable) {
+		mutex_unlock(&xe->eudebug.enable_lock);
+		return 0;
+	}
+
+	for_each_gt(gt, xe, id) {
+		for (i = 0; i < ARRAY_SIZE(gt->hw_engines); i++) {
+			if (!(gt->info.engine_mask & BIT(i)))
+				continue;
+
+			if (enable)
+				xe_eudebug_init_hw_engine(&gt->hw_engines[i]);
+			else
+				xe_eudebug_fini_hw_engine(&gt->hw_engines[i]);
+		}
+
+		xe_gt_reset_async(gt);
+		flush_work(&gt->reset.worker);
+	}
+
+	if (enable)
+		attention_scan_flush(xe);
+	else
+		attention_scan_cancel(xe);
+
+	xe->eudebug.enable = enable;
+	mutex_unlock(&xe->eudebug.enable_lock);
+
+	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.enable);
+}
+
+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;
+
+	sysfs_remove_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
 }
 
 void xe_eudebug_init(struct xe_device *xe)
 {
+	struct device *dev = xe->drm.dev;
+	int ret;
+
 	spin_lock_init(&xe->eudebug.lock);
 	INIT_LIST_HEAD(&xe->eudebug.list);
 	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
 
-	xe->eudebug.available = true;
-}
+	drmm_mutex_init(&xe->drm, &xe->eudebug.enable_lock);
+	xe->eudebug.enable = false;
 
-void xe_eudebug_init_late(struct xe_device *xe)
-{
-	if (!xe->eudebug.available)
-		return;
 
-	attention_scan_flush(xe);
+	ret = sysfs_create_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
+	if (ret)
+		drm_warn(&xe->drm, "eudebug sysfs init failed: %d, debugger unavailable\n", ret);
+	else
+		devm_add_action_or_reset(dev, xe_eudebug_sysfs_fini, xe);
+
+	xe->eudebug.available = ret == 0;
 }
 
 void xe_eudebug_fini(struct xe_device *xe)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
index 02c9ba56e752..2f66aa87a0f6 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.h
+++ b/drivers/gpu/drm/xe/xe_eudebug.h
@@ -24,9 +24,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
 			     struct drm_file *file);
 
 void xe_eudebug_init(struct xe_device *xe);
-void xe_eudebug_init_late(struct xe_device *xe);
 void xe_eudebug_fini(struct xe_device *xe);
-void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
 
 void xe_eudebug_file_open(struct xe_file *xef);
 void xe_eudebug_file_close(struct xe_file *xef);
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index bc2edade5e5b..b6fc65ab8aa9 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -360,6 +360,9 @@ static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
 			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
 		return -EINVAL;
 
+	if (XE_IOCTL_DBG(xe, !xe->eudebug.enable))
+		return -EPERM;
+
 	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
 
 	return 0;
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index 74813bc20787..0f90416be0ba 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -504,7 +504,6 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
 	xe_tuning_process_engine(hwe);
 	xe_wa_process_engine(hwe);
 	hw_engine_setup_default_state(hwe);
-	xe_eudebug_init_hw_engine(hwe);
 
 	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
 	xe_reg_whitelist_process_engine(hwe);
diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
index 440ac572f6e5..a7671722a84e 100644
--- a/drivers/gpu/drm/xe/xe_reg_sr.c
+++ b/drivers/gpu/drm/xe/xe_reg_sr.c
@@ -92,22 +92,31 @@ static void reg_sr_inc_error(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);
 	int ret;
 
 	if (pentry) {
-		if (!compatible_entries(pentry, e)) {
+		if (overwrite && e->set_bits) {
+			pentry->clr_bits |= e->clr_bits;
+			pentry->set_bits |= e->set_bits;
+			pentry->read_mask |= e->read_mask;
+		} else if (overwrite && !e->set_bits) {
+			pentry->clr_bits |= e->clr_bits;
+			pentry->set_bits &= ~e->clr_bits;
+			pentry->read_mask |= e->read_mask;
+		} else if (!compatible_entries(pentry, e)) {
 			ret = -EINVAL;
 			goto fail;
+		} else {
+			pentry->clr_bits |= e->clr_bits;
+			pentry->set_bits |= e->set_bits;
+			pentry->read_mask |= e->read_mask;
 		}
 
-		pentry->clr_bits |= e->clr_bits;
-		pentry->set_bits |= e->set_bits;
-		pentry->read_mask |= e->read_mask;
-
 		return 0;
 	}
 
diff --git a/drivers/gpu/drm/xe/xe_reg_sr.h b/drivers/gpu/drm/xe/xe_reg_sr.h
index 51fbba423e27..d67fafdcd847 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_
 #define _XE_REG_SR_
 
+#include <linux/types.h>
+
 /*
  * Reg save/restore bookkeeping
  */
@@ -21,7 +23,7 @@ int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe)
 void xe_reg_sr_dump(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_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
index 02e28274282f..5643bcde52bd 100644
--- a/drivers/gpu/drm/xe/xe_rtp.c
+++ b/drivers/gpu/drm/xe/xe_rtp.c
@@ -153,7 +153,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, action->flags & XE_RTP_ACTION_FLAG_OVERWRITE);
 }
 
 static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry,
diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h
index 1b76b947c706..20d228067da3 100644
--- a/drivers/gpu/drm/xe/xe_rtp_types.h
+++ b/drivers/gpu/drm/xe/xe_rtp_types.h
@@ -33,6 +33,7 @@ struct xe_rtp_action {
 	/** @read_mask: mask for bits to consider when reading value back */
 	u32			read_mask;
 #define XE_RTP_ACTION_FLAG_ENGINE_BASE		BIT(0)
+#define XE_RTP_ACTION_FLAG_OVERWRITE		BIT(1)
 	/** @flags: flags to apply on rule evaluation or action */
 	u8			flags;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH 21/21] drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (19 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality Mika Kuoppala
@ 2024-07-26 14:08 ` Mika Kuoppala
  2024-07-26 14:32 ` ✓ CI.Patch_applied: success for GPU debug support (eudebug) Patchwork
                   ` (8 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-26 14:08 UTC (permalink / raw)
  To: intel-xe; +Cc: Christoph Manszewski, Mika Kuoppala

From: Christoph Manszewski <christoph.manszewski@intel.com>

Introduce kunit test for eudebug. For now it checks the dynamic
application of WAs.

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.c       | 170 ++++++++++++++++++++
 drivers/gpu/drm/xe/tests/xe_live_test_mod.c |   2 +
 drivers/gpu/drm/xe/xe_eudebug.c             |   4 +
 3 files changed, 176 insertions(+)
 create mode 100644 drivers/gpu/drm/xe/tests/xe_eudebug.c

diff --git a/drivers/gpu/drm/xe/tests/xe_eudebug.c b/drivers/gpu/drm/xe/tests/xe_eudebug.c
new file mode 100644
index 000000000000..dc9ea6abc4e4
--- /dev/null
+++ b/drivers/gpu/drm/xe/tests/xe_eudebug.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0 AND MIT
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+#include <kunit/visibility.h>
+
+#include "tests/xe_pci_test.h"
+#include "tests/xe_test.h"
+
+#undef XE_REG_MCR
+#define XE_REG_MCR(r_, ...)	((const struct xe_reg_mcr){					\
+				 .__reg = XE_REG_INITIALIZER(r_,  ##__VA_ARGS__, .mcr = 1)	\
+				 })
+
+static const char *reg_to_str(struct xe_reg reg)
+{
+	if (reg.raw == TD_CTL.__reg.raw)
+		return "TD_CTL";
+	else if (reg.raw == CS_DEBUG_MODE2(RENDER_RING_BASE).raw)
+		return "CS_DEBUG_MODE2";
+	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 = kunit_get_current_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 == CS_DEBUG_MODE2(RENDER_RING_BASE).raw) {
+		val = 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_warn(test, "Invalid register selection: %u\n", reg.raw);
+	}
+
+	return val;
+}
+
+static u32 get_reg_expected(struct xe_device *xe, struct xe_reg reg, bool enable_eudebug)
+{
+	u32 reg_mask = get_reg_mask(xe, reg);
+	u32 reg_bits = 0;
+
+	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 = kunit_get_current_test();
+	struct xe_device *xe = gt_to_xe(gt);
+	u32 reg_bits_expected = get_reg_expected(xe, reg, enable_eudebug);
+	u32 reg_mask = get_reg_mask(xe, reg);
+	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(gt, reg);
+
+	reg_bits &= reg_mask;
+
+	kunit_printk(KERN_DEBUG, test, "%s bits: expected == 0x%x; actual == 0x%x\n",
+		     reg_to_str(reg), reg_bits_expected, reg_bits);
+	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 xe_device *xe = gt_to_xe(gt);
+
+	if (GRAPHICS_VERx100(xe) >= 1200)
+		check_reg(gt, enable_eudebug, TD_CTL.__reg);
+
+	if (GRAPHICS_VERx100(xe) >= 1250 && GRAPHICS_VERx100(xe) <= 1274)
+		check_reg(gt, enable_eudebug, ROW_CHICKEN.__reg);
+
+	if (xe->info.platform == XE_PVC)
+		check_reg(gt, enable_eudebug, ROW_CHICKEN2.__reg);
+
+	if (GRAPHICS_VERx100(xe) >= 2000 && GRAPHICS_VERx100(xe) <= 2004)
+		check_reg(gt, enable_eudebug, ROW_CHICKEN3.__reg);
+}
+
+static void check_regs(struct xe_device *xe, bool enable_eudebug)
+{
+	struct kunit *test = kunit_get_current_test();
+	struct xe_gt *gt;
+	u8 id;
+	int ret = 0;
+
+	kunit_printk(KERN_DEBUG, test, "Check regs for eudebug %s\n",
+		     enable_eudebug ? "enabled" : "disabled");
+
+	xe_pm_runtime_get(xe);
+	for_each_gt(gt, xe, id) {
+		if (xe_gt_is_media_type(gt))
+			continue;
+
+		ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_RENDER);
+		KUNIT_ASSERT_EQ_MSG(test, ret, 0, "Forcewake failed.\n");
+
+		__check_regs(gt, enable_eudebug);
+
+		xe_force_wake_put(gt_to_fw(gt), XE_FW_RENDER);
+	}
+	xe_pm_runtime_put(xe);
+}
+
+static int toggle_reg_value(struct xe_device *xe)
+{
+	struct kunit *test = kunit_get_current_test();
+	bool enable_eudebug = xe->eudebug.enable;
+
+	kunit_printk(KERN_DEBUG, test, "Test eudebug WAs for graphics version: %u\n",
+		     GRAPHICS_VERx100(xe));
+
+	check_regs(xe, enable_eudebug);
+
+	xe_eudebug_enable(xe, !enable_eudebug);
+	check_regs(xe, !enable_eudebug);
+
+	xe_eudebug_enable(xe, enable_eudebug);
+	check_regs(xe, enable_eudebug);
+
+	return 0;
+}
+
+static void xe_eudebug_toggle_reg_kunit(struct kunit *test)
+{
+	xe_call_for_each_device(toggle_reg_value);
+}
+
+static struct kunit_case xe_eudebug_tests[] = {
+	KUNIT_CASE(xe_eudebug_toggle_reg_kunit),
+	{}
+};
+
+VISIBLE_IF_KUNIT
+struct kunit_suite xe_eudebug_test_suite = {
+	.name = "xe_eudebug",
+	.test_cases = xe_eudebug_tests,
+};
+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 5f14737c8210..6e93d1426bd6 100644
--- a/drivers/gpu/drm/xe/tests/xe_live_test_mod.c
+++ b/drivers/gpu/drm/xe/tests/xe_live_test_mod.c
@@ -9,11 +9,13 @@ extern struct kunit_suite xe_bo_test_suite;
 extern struct kunit_suite xe_dma_buf_test_suite;
 extern struct kunit_suite xe_migrate_test_suite;
 extern struct kunit_suite xe_mocs_test_suite;
+extern struct kunit_suite xe_eudebug_test_suite;
 
 kunit_test_suite(xe_bo_test_suite);
 kunit_test_suite(xe_dma_buf_test_suite);
 kunit_test_suite(xe_migrate_test_suite);
 kunit_test_suite(xe_mocs_test_suite);
+kunit_test_suite(xe_eudebug_test_suite);
 
 MODULE_AUTHOR("Intel Corporation");
 MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 80066f787ec2..3ab2b596de52 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -3835,3 +3835,7 @@ xe_eudebug_vm_open_ioctl(struct xe_eudebug *d, unsigned long arg)
 
 	return ret;
 }
+
+#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
+#include "tests/xe_eudebug.c"
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* ✓ CI.Patch_applied: success for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (20 preceding siblings ...)
  2024-07-26 14:08 ` [PATCH 21/21] drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test Mika Kuoppala
@ 2024-07-26 14:32 ` Patchwork
  2024-07-26 14:33 ` ✗ CI.checkpatch: warning " Patchwork
                   ` (7 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-26 14:32 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
State : success

== Summary ==

=== Applying kernel patches on branch 'drm-tip' with base: ===
Base commit: 220554a8ef7a drm-tip: 2024y-07m-26d-13h-05m-21s UTC integration manifest
=== git am output follows ===
Applying: drm/xe: Export xe_hw_engine's mmio accessors
Applying: drm/xe: Move and export xe_hw_engine lookup.
Applying: drm/xe/eudebug: Introduce eudebug support
Applying: kernel: export ptrace_may_access
Applying: drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach
Applying: drm/xe/eudebug: Introduce discovery for resources
Applying: drm/xe/eudebug: Introduce exec_queue events
Applying: drm/xe/eudebug: hw enablement for eudebug
Applying: drm/xe: Add EUDEBUG_ENABLE exec queue property
Applying: drm/xe/eudebug: Introduce per device attention scan worker
Applying: drm/xe/eudebug: Introduce EU control interface
Applying: drm/xe/eudebug: Add vm bind and vm bind ops
Applying: drm/xe/eudebug: Add UFENCE events with acks
Applying: drm/xe/eudebug: vm open/pread/pwrite
Applying: drm/xe/eudebug: implement userptr_vma access
Applying: drm/xe: Debug metadata create/destroy ioctls
Applying: drm/xe: Attach debug metadata to vma
Applying: drm/xe/eudebug: Add debug metadata support for xe_eudebug
Applying: drm/xe/eudebug: Implement vm_bind_op discovery
Applying: drm/xe/eudebug: Dynamically toggle debugger functionality
Applying: drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test



^ permalink raw reply	[flat|nested] 78+ messages in thread

* ✗ CI.checkpatch: warning for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (21 preceding siblings ...)
  2024-07-26 14:32 ` ✓ CI.Patch_applied: success for GPU debug support (eudebug) Patchwork
@ 2024-07-26 14:33 ` Patchwork
  2024-07-26 14:34 ` ✓ CI.KUnit: success " Patchwork
                   ` (6 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-26 14:33 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
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
5ce3e132caaa5b45e5e50201b574a097d130967c
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ git log -n1
commit 9d23ac5e3fa5a7c6e67b1c1347540bd1fc57f026
Author: Christoph Manszewski <christoph.manszewski@intel.com>
Date:   Fri Jul 26 17:08:18 2024 +0300

    drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test
    
    Introduce kunit test for eudebug. For now it checks the dynamic
    application of WAs.
    
    Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
    Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
+ /mt/dim checkpatch 220554a8ef7ac26fbfc4f141816679d742a0d232 drm-intel
7d261e4b538f drm/xe: Export xe_hw_engine's mmio accessors
4fe8f7a4aa13 drm/xe: Move and export xe_hw_engine lookup.
351f7c4287f9 drm/xe/eudebug: Introduce eudebug support
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
-:194: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#194: 
new file mode 100644

-:233: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#233: FILE: drivers/gpu/drm/xe/xe_eudebug.c:35:
+#define XE_EUDEBUG_DBG_ARGS(d) (d)->session, \
+		atomic_long_read(&(d)->events.seqno), \
+		READ_ONCE(d->connection.status) <= 0 ? "disconnected" : "", \
+		current->pid, \
+		task_tgid_nr(current), \
+		(d)->target_task->pid, \
+		task_tgid_nr((d)->target_task)

-:233: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'd' - possible side-effects?
#233: FILE: drivers/gpu/drm/xe/xe_eudebug.c:35:
+#define XE_EUDEBUG_DBG_ARGS(d) (d)->session, \
+		atomic_long_read(&(d)->events.seqno), \
+		READ_ONCE(d->connection.status) <= 0 ? "disconnected" : "", \
+		current->pid, \
+		task_tgid_nr(current), \
+		(d)->target_task->pid, \
+		task_tgid_nr((d)->target_task)

-:241: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'd' - possible side-effects?
#241: FILE: drivers/gpu/drm/xe/xe_eudebug.c:43:
+#define eu_err(d, fmt, ...) drm_err(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
+				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)

-:243: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'd' - possible side-effects?
#243: FILE: drivers/gpu/drm/xe/xe_eudebug.c:45:
+#define eu_warn(d, fmt, ...) drm_warn(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
+				      XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)

-:245: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'd' - possible side-effects?
#245: FILE: drivers/gpu/drm/xe/xe_eudebug.c:47:
+#define eu_dbg(d, fmt, ...) drm_dbg(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
+				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)

-:250: CHECK:MACRO_ARG_PRECEDENCE: Macro argument 'T' may be better as '(T)' to avoid precedence issues
#250: FILE: drivers/gpu/drm/xe/xe_eudebug.c:52:
+#define struct_member(T, member) (((T *)0)->member)

-:250: CHECK:MACRO_ARG_PRECEDENCE: Macro argument 'member' may be better as '(member)' to avoid precedence issues
#250: FILE: drivers/gpu/drm/xe/xe_eudebug.c:52:
+#define struct_member(T, member) (((T *)0)->member)

-:253: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'ptr' - possible side-effects?
#253: FILE: drivers/gpu/drm/xe/xe_eudebug.c:55:
+#define write_member(T_out, ptr, member, value) { \
+	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
+	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
+		     offsetof(typeof(T_out), member)); \
+	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
+	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
+	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
+	(ptr)->member = (value); \
+	}

-:253: CHECK:MACRO_ARG_PRECEDENCE: Macro argument 'ptr' may be better as '(ptr)' to avoid precedence issues
#253: FILE: drivers/gpu/drm/xe/xe_eudebug.c:55:
+#define write_member(T_out, ptr, member, value) { \
+	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
+	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
+		     offsetof(typeof(T_out), member)); \
+	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
+	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
+	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
+	(ptr)->member = (value); \
+	}

-:253: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'member' - possible side-effects?
#253: FILE: drivers/gpu/drm/xe/xe_eudebug.c:55:
+#define write_member(T_out, ptr, member, value) { \
+	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
+	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
+		     offsetof(typeof(T_out), member)); \
+	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
+	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
+	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
+	(ptr)->member = (value); \
+	}

-:253: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'value' - possible side-effects?
#253: FILE: drivers/gpu/drm/xe/xe_eudebug.c:55:
+#define write_member(T_out, ptr, member, value) { \
+	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
+	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
+		     offsetof(typeof(T_out), member)); \
+	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
+	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
+	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
+	(ptr)->member = (value); \
+	}

-:527: CHECK:MACRO_ARG_REUSE: Macro argument reuse '_err' - possible side-effects?
#527: FILE: drivers/gpu/drm/xe/xe_eudebug.c:329:
+#define xe_eudebug_disconnect(_d, _err) ({ \
+	if (_xe_eudebug_disconnect((_d), (_err))) { \
+		if ((_err) == 0 || (_err) == -ETIMEDOUT) \
+			eu_dbg(d, "Session closed (%d)", (_err)); \
+		else \
+			eu_err(d, "Session disconnected, err = %d (%s:%d)", \
+			       (_err), __func__, __LINE__); \
+	} \
+})

-:765: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "!p"
#765: FILE: drivers/gpu/drm/xe/xe_eudebug.c:567:
+	if (XE_WARN_ON(p == NULL))

-:1159: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#1159: FILE: drivers/gpu/drm/xe/xe_eudebug.c:961:
+		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
+					     ret, seqno);

-:1178: CHECK:MACRO_ARG_REUSE: Macro argument reuse '_d' - possible side-effects?
#1178: FILE: drivers/gpu/drm/xe/xe_eudebug.c:980:
+#define xe_eudebug_event_put(_d, _err) ({ \
+	if ((_err)) \
+		xe_eudebug_disconnect((_d), (_err)); \
+	xe_eudebug_put((_d)); \
+	})

-:1178: CHECK:MACRO_ARG_REUSE: Macro argument reuse '_err' - possible side-effects?
#1178: FILE: drivers/gpu/drm/xe/xe_eudebug.c:980:
+#define xe_eudebug_event_put(_d, _err) ({ \
+	if ((_err)) \
+		xe_eudebug_disconnect((_d), (_err)); \
+	xe_eudebug_put((_d)); \
+	})

-:1549: WARNING:LONG_LINE: line length of 130 exceeds 100 columns
#1549: FILE: include/uapi/drm/xe_drm.h:121:
+#define DRM_IOCTL_XE_EUDEBUG_CONNECT		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)

total: 1 errors, 2 warnings, 15 checks, 1531 lines checked
f670c21445e9 kernel: export ptrace_may_access
b2a4a17a9993 drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach
99d7da859ca5 drm/xe/eudebug: Introduce discovery for resources
6e206ec1b909 drm/xe/eudebug: Introduce exec_queue events
-:151: CHECK:LINE_SPACING: Please don't use multiple blank lines
#151: FILE: drivers/gpu/drm/xe/xe_eudebug.c:1218:
+
+

total: 0 errors, 0 warnings, 1 checks, 310 lines checked
855870945dcb drm/xe/eudebug: hw enablement for eudebug
7202420b7699 drm/xe: Add EUDEBUG_ENABLE exec queue property
08c055a645ca drm/xe/eudebug: Introduce per device attention scan worker
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
-:154: CHECK:BRACES: Blank lines aren't necessary after an open brace '{'
#154: FILE: drivers/gpu/drm/xe/xe_eudebug.c:858:
+{
+

-:238: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#238: FILE: drivers/gpu/drm/xe/xe_eudebug.c:942:
+static bool engine_runalone_set(const struct xe_hw_engine * const hwe,
+				   u32 rcu_debug1)

-:419: CHECK:LINE_SPACING: Please don't use multiple blank lines
#419: FILE: drivers/gpu/drm/xe/xe_eudebug.c:1123:
+
+

-:620: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#620: 
new file mode 100644

-:732: CHECK:LINE_SPACING: Please don't use multiple blank lines
#732: FILE: drivers/gpu/drm/xe/xe_gt_debug.c:108:
+
+

total: 0 errors, 1 warnings, 4 checks, 744 lines checked
11671229915a drm/xe/eudebug: Introduce EU control interface
-:510: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#510: FILE: drivers/gpu/drm/xe/xe_eudebug.c:1531:
+	udelay(100);

-:519: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#519: FILE: drivers/gpu/drm/xe/xe_eudebug.c:1540:
+	udelay(100);

-:570: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#570: FILE: drivers/gpu/drm/xe/xe_eudebug.c:1591:
+			eu_dbg(d,
+				"WRONG CLEAR (%u:%u:%u) TD_CRL: 0x%08x; TD_ATT: 0x%08x\n",

total: 0 errors, 0 warnings, 3 checks, 772 lines checked
b74047948af8 drm/xe/eudebug: Add vm bind and vm bind ops
-:21: WARNING:BAD_SIGN_OFF: Co-developed-by and Signed-off-by: name/email do not match
#21: 
Co-developed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>

total: 0 errors, 1 warnings, 0 checks, 520 lines checked
28847e71da5e drm/xe/eudebug: Add UFENCE events with acks
-:371: CHECK:UNCOMMENTED_DEFINITION: spinlock_t definition without comment
#371: FILE: drivers/gpu/drm/xe/xe_eudebug_types.h:155:
+		spinlock_t lock;

total: 0 errors, 0 warnings, 1 checks, 555 lines checked
8398543a44bb drm/xe/eudebug: vm open/pread/pwrite
-:262: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "w_buffer"
#262: FILE: drivers/gpu/drm/xe/xe_eudebug.c:2991:
+	const bool write = w_buffer != NULL;

total: 0 errors, 0 warnings, 1 checks, 564 lines checked
84e7d905de17 drm/xe/eudebug: implement userptr_vma access
fe24dd12c7a2 drm/xe: Debug metadata create/destroy ioctls
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
-:29: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#29: 
new file mode 100644

-:304: WARNING:LONG_LINE: line length of 143 exceeds 100 columns
#304: FILE: include/uapi/drm/xe_drm.h:123:
+#define DRM_IOCTL_XE_DEBUG_METADATA_CREATE	 DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_DEBUG_METADATA_CREATE, struct drm_xe_debug_metadata_create)

-:305: WARNING:LONG_LINE: line length of 144 exceeds 100 columns
#305: FILE: include/uapi/drm/xe_drm.h:124:
+#define DRM_IOCTL_XE_DEBUG_METADATA_DESTROY	 DRM_IOW(DRM_COMMAND_BASE + DRM_XE_DEBUG_METADATA_DESTROY, struct drm_xe_debug_metadata_destroy)

total: 0 errors, 3 warnings, 0 checks, 303 lines checked
a990dca74af3 drm/xe: Attach debug metadata to vma
-:6: WARNING:COMMIT_LOG_LONG_LINE: Prefer a maximum 75 chars per line (possible unwrapped commit description?)
#6: 
Introduces a vm_bind_op extension, enabling users to attach metadata objects

total: 0 errors, 1 warnings, 0 checks, 386 lines checked
e1441649fa3d drm/xe/eudebug: Add debug metadata support for xe_eudebug
-:255: CHECK:LINE_SPACING: Please don't use multiple blank lines
#255: FILE: drivers/gpu/drm/xe/xe_eudebug.c:2654:
+
+

-:383: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#383: FILE: drivers/gpu/drm/xe/xe_eudebug.c:3001:
+	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_METADATA, seqno,
+				       flags, sizeof(*e), GFP_KERNEL);

-:416: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#416: FILE: drivers/gpu/drm/xe/xe_eudebug.c:3034:
+static int debug_metadata_destroy_event(struct xe_eudebug *d,
+				       struct xe_file *xef, struct xe_debug_metadata *m)

total: 0 errors, 0 warnings, 3 checks, 552 lines checked
a81fb287d1c1 drm/xe/eudebug: Implement vm_bind_op discovery
9979c431bc9c drm/xe/eudebug: Dynamically toggle debugger functionality
9d23ac5e3fa5 drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 6, in <module>
    from ply import lex, yacc
ModuleNotFoundError: No module named 'ply'
-:13: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#13: 
new file mode 100644

-:196: WARNING:AVOID_EXTERNS: externs should be avoided in .c files
#196: FILE: drivers/gpu/drm/xe/tests/xe_live_test_mod.c:12:
+extern struct kunit_suite xe_eudebug_test_suite;

total: 0 errors, 2 warnings, 0 checks, 190 lines checked



^ permalink raw reply	[flat|nested] 78+ messages in thread

* ✓ CI.KUnit: success for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (22 preceding siblings ...)
  2024-07-26 14:33 ` ✗ CI.checkpatch: warning " Patchwork
@ 2024-07-26 14:34 ` Patchwork
  2024-07-26 14:46 ` ✓ CI.Build: " Patchwork
                   ` (5 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-26 14:34 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
State : success

== Summary ==

+ trap cleanup EXIT
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/xe/.kunitconfig
[14:33:24] Configuring KUnit Kernel ...
Generating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[14:33:28] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make ARCH=um O=.kunit --jobs=48
../lib/iomap.c:156:5: warning: no previous prototype for ‘ioread64_lo_hi’ [-Wmissing-prototypes]
  156 | u64 ioread64_lo_hi(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~
../lib/iomap.c:163:5: warning: no previous prototype for ‘ioread64_hi_lo’ [-Wmissing-prototypes]
  163 | u64 ioread64_hi_lo(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~
../lib/iomap.c:170:5: warning: no previous prototype for ‘ioread64be_lo_hi’ [-Wmissing-prototypes]
  170 | u64 ioread64be_lo_hi(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~~~
../lib/iomap.c:178:5: warning: no previous prototype for ‘ioread64be_hi_lo’ [-Wmissing-prototypes]
  178 | u64 ioread64be_hi_lo(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~~~
../lib/iomap.c:264:6: warning: no previous prototype for ‘iowrite64_lo_hi’ [-Wmissing-prototypes]
  264 | void iowrite64_lo_hi(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~
../lib/iomap.c:272:6: warning: no previous prototype for ‘iowrite64_hi_lo’ [-Wmissing-prototypes]
  272 | void iowrite64_hi_lo(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~
../lib/iomap.c:280:6: warning: no previous prototype for ‘iowrite64be_lo_hi’ [-Wmissing-prototypes]
  280 | void iowrite64be_lo_hi(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~~~
../lib/iomap.c:288:6: warning: no previous prototype for ‘iowrite64be_hi_lo’ [-Wmissing-prototypes]
  288 | void iowrite64be_hi_lo(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~~~

[14:33:54] Starting KUnit Kernel (1/1)...
[14:33:54] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[14:33:54] =================== guc_dbm (7 subtests) ===================
[14:33:54] [PASSED] test_empty
[14:33:54] [PASSED] test_default
[14:33:54] ======================== test_size  ========================
[14:33:54] [PASSED] 4
[14:33:54] [PASSED] 8
[14:33:54] [PASSED] 32
[14:33:54] [PASSED] 256
[14:33:54] ==================== [PASSED] test_size ====================
[14:33:54] ======================= test_reuse  ========================
[14:33:54] [PASSED] 4
[14:33:54] [PASSED] 8
[14:33:54] [PASSED] 32
[14:33:54] [PASSED] 256
[14:33:54] =================== [PASSED] test_reuse ====================
[14:33:54] =================== test_range_overlap  ====================
[14:33:54] [PASSED] 4
[14:33:54] [PASSED] 8
[14:33:54] [PASSED] 32
[14:33:54] [PASSED] 256
[14:33:54] =============== [PASSED] test_range_overlap ================
[14:33:54] =================== test_range_compact  ====================
[14:33:54] [PASSED] 4
[14:33:54] [PASSED] 8
[14:33:54] [PASSED] 32
[14:33:54] [PASSED] 256
[14:33:54] =============== [PASSED] test_range_compact ================
[14:33:54] ==================== test_range_spare  =====================
[14:33:54] [PASSED] 4
[14:33:54] [PASSED] 8
[14:33:54] [PASSED] 32
[14:33:54] [PASSED] 256
[14:33:54] ================ [PASSED] test_range_spare =================
[14:33:54] ===================== [PASSED] guc_dbm =====================
[14:33:54] =================== guc_idm (6 subtests) ===================
[14:33:54] [PASSED] bad_init
[14:33:54] [PASSED] no_init
[14:33:54] [PASSED] init_fini
[14:33:54] [PASSED] check_used
[14:33:54] [PASSED] check_quota
[14:33:54] [PASSED] check_all
[14:33:54] ===================== [PASSED] guc_idm =====================
[14:33:54] ================== no_relay (3 subtests) ===================
[14:33:54] [PASSED] xe_drops_guc2pf_if_not_ready
[14:33:54] [PASSED] xe_drops_guc2vf_if_not_ready
[14:33:54] [PASSED] xe_rejects_send_if_not_ready
[14:33:54] ==================== [PASSED] no_relay =====================
[14:33:54] ================== pf_relay (14 subtests) ==================
[14:33:54] [PASSED] pf_rejects_guc2pf_too_short
[14:33:54] [PASSED] pf_rejects_guc2pf_too_long
[14:33:54] [PASSED] pf_rejects_guc2pf_no_payload
[14:33:54] [PASSED] pf_fails_no_payload
[14:33:54] [PASSED] pf_fails_bad_origin
[14:33:54] [PASSED] pf_fails_bad_type
[14:33:54] [PASSED] pf_txn_reports_error
[14:33:54] [PASSED] pf_txn_sends_pf2guc
[14:33:54] [PASSED] pf_sends_pf2guc
[14:33:54] [SKIPPED] pf_loopback_nop
[14:33:54] [SKIPPED] pf_loopback_echo
[14:33:54] [SKIPPED] pf_loopback_fail
[14:33:54] [SKIPPED] pf_loopback_busy
[14:33:54] [SKIPPED] pf_loopback_retry
[14:33:54] ==================== [PASSED] pf_relay =====================
[14:33:54] ================== vf_relay (3 subtests) ===================
[14:33:54] [PASSED] vf_rejects_guc2vf_too_short
[14:33:54] [PASSED] vf_rejects_guc2vf_too_long
[14:33:54] [PASSED] vf_rejects_guc2vf_no_payload
[14:33:54] ==================== [PASSED] vf_relay =====================
[14:33:54] ================= pf_service (11 subtests) =================
[14:33:54] [PASSED] pf_negotiate_any
[14:33:54] [PASSED] pf_negotiate_base_match
[14:33:54] [PASSED] pf_negotiate_base_newer
[14:33:54] [PASSED] pf_negotiate_base_next
[14:33:54] [SKIPPED] pf_negotiate_base_older
[14:33:54] [PASSED] pf_negotiate_base_prev
[14:33:54] [PASSED] pf_negotiate_latest_match
[14:33:54] [PASSED] pf_negotiate_latest_newer
[14:33:54] [PASSED] pf_negotiate_latest_next
[14:33:54] [SKIPPED] pf_negotiate_latest_older
[14:33:54] [SKIPPED] pf_negotiate_latest_prev
[14:33:54] =================== [PASSED] pf_service ====================
[14:33:54] ===================== lmtt (1 subtest) =====================
[14:33:54] ======================== test_ops  =========================
[14:33:54] [PASSED] 2-level
[14:33:54] [PASSED] multi-level
[14:33:54] ==================== [PASSED] test_ops =====================
[14:33:54] ====================== [PASSED] lmtt =======================
[14:33:54] ================== xe_eudebug (1 subtest) ==================
[14:33:54] [SKIPPED] xe_eudebug_toggle_reg_kunit
[14:33:54] =================== [SKIPPED] xe_eudebug ===================
[14:33:54] =================== xe_mocs (2 subtests) ===================
[14:33:54] ================ xe_live_mocs_kernel_kunit  ================
[14:33:54] =========== [SKIPPED] xe_live_mocs_kernel_kunit ============
[14:33:54] ================ xe_live_mocs_reset_kunit  =================
[14:33:54] ============ [SKIPPED] xe_live_mocs_reset_kunit ============
[14:33:54] ==================== [SKIPPED] xe_mocs =====================
[14:33:54] ================= xe_migrate (2 subtests) ==================
[14:33:54] ================= xe_migrate_sanity_kunit  =================
[14:33:54] ============ [SKIPPED] xe_migrate_sanity_kunit =============
[14:33:54] ================== xe_validate_ccs_kunit  ==================
[14:33:54] ============= [SKIPPED] xe_validate_ccs_kunit ==============
[14:33:54] =================== [SKIPPED] xe_migrate ===================
[14:33:54] ================== xe_dma_buf (1 subtest) ==================
[14:33:54] ==================== xe_dma_buf_kunit  =====================
[14:33:54] ================ [SKIPPED] xe_dma_buf_kunit ================
[14:33:54] =================== [SKIPPED] xe_dma_buf ===================
[14:33:54] ==================== xe_bo (2 subtests) ====================
[14:33:54] ================== xe_ccs_migrate_kunit  ===================
[14:33:54] ============== [SKIPPED] xe_ccs_migrate_kunit ==============
[14:33:54] ==================== xe_bo_evict_kunit  ====================
[14:33:54] =============== [SKIPPED] xe_bo_evict_kunit ================
[14:33:54] ===================== [SKIPPED] xe_bo ======================
[14:33:54] ==================== args (11 subtests) ====================
[14:33:54] [PASSED] count_args_test
[14:33:54] [PASSED] call_args_example
[14:33:54] [PASSED] call_args_test
[14:33:54] [PASSED] drop_first_arg_example
[14:33:54] [PASSED] drop_first_arg_test
[14:33:54] [PASSED] first_arg_example
[14:33:54] [PASSED] first_arg_test
[14:33:54] [PASSED] last_arg_example
[14:33:54] [PASSED] last_arg_test
[14:33:54] [PASSED] pick_arg_example
stty: 'standard input': Inappropriate ioctl for device
[14:33:54] [PASSED] sep_comma_example
[14:33:54] ====================== [PASSED] args =======================
[14:33:54] =================== xe_pci (2 subtests) ====================
[14:33:54] [PASSED] xe_gmdid_graphics_ip
[14:33:54] [PASSED] xe_gmdid_media_ip
[14:33:54] ===================== [PASSED] xe_pci ======================
[14:33:54] ==================== xe_rtp (1 subtest) ====================
[14:33:54] ================== xe_rtp_process_tests  ===================
[14:33:54] [PASSED] coalesce-same-reg
[14:33:54] [PASSED] no-match-no-add
[14:33:54] [PASSED] match-or
[14:33:54] [PASSED] match-or-xfail
[14:33:54] [PASSED] no-match-no-add-multiple-rules
[14:33:54] [PASSED] two-regs-two-entries
[14:33:54] [PASSED] clr-one-set-other
[14:33:54] [PASSED] set-field
[14:33:54] [PASSED] conflict-duplicate
[14:33:54] [PASSED] conflict-not-disjoint
[14:33:54] [PASSED] conflict-reg-type
[14:33:54] ============== [PASSED] xe_rtp_process_tests ===============
[14:33:54] ===================== [PASSED] xe_rtp ======================
[14:33:54] ==================== xe_wa (1 subtest) =====================
[14:33:54] ======================== xe_wa_gt  =========================
[14:33:54] [PASSED] TIGERLAKE (B0)
[14:33:54] [PASSED] DG1 (A0)
[14:33:54] [PASSED] DG1 (B0)
[14:33:54] [PASSED] ALDERLAKE_S (A0)
[14:33:54] [PASSED] ALDERLAKE_S (B0)
[14:33:54] [PASSED] ALDERLAKE_S (C0)
[14:33:54] [PASSED] ALDERLAKE_S (D0)
[14:33:54] [PASSED] ALDERLAKE_P (A0)
[14:33:54] [PASSED] ALDERLAKE_P (B0)
[14:33:54] [PASSED] ALDERLAKE_P (C0)
[14:33:54] [PASSED] ALDERLAKE_S_RPLS (D0)
[14:33:54] [PASSED] ALDERLAKE_P_RPLU (E0)
[14:33:54] [PASSED] DG2_G10 (C0)
[14:33:54] [PASSED] DG2_G11 (B1)
[14:33:54] [PASSED] DG2_G12 (A1)
[14:33:54] [PASSED] METEORLAKE (g:A0, m:A0)
[14:33:54] [PASSED] METEORLAKE (g:A0, m:A0)
[14:33:54] [PASSED] METEORLAKE (g:A0, m:A0)
[14:33:54] [PASSED] LUNARLAKE (g:A0, m:A0)
[14:33:54] [PASSED] LUNARLAKE (g:B0, m:A0)
[14:33:54] ==================== [PASSED] xe_wa_gt =====================
[14:33:54] ====================== [PASSED] xe_wa ======================
[14:33:54] ============================================================
[14:33:54] Testing complete. Ran 113 tests: passed: 97, skipped: 16
[14:33:54] Elapsed time: 30.721s total, 4.306s configuring, 26.145s building, 0.218s running

+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/tests/.kunitconfig
[14:33:54] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[14:33:56] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make ARCH=um O=.kunit --jobs=48
../lib/iomap.c:156:5: warning: no previous prototype for ‘ioread64_lo_hi’ [-Wmissing-prototypes]
  156 | u64 ioread64_lo_hi(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~
../lib/iomap.c:163:5: warning: no previous prototype for ‘ioread64_hi_lo’ [-Wmissing-prototypes]
  163 | u64 ioread64_hi_lo(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~
../lib/iomap.c:170:5: warning: no previous prototype for ‘ioread64be_lo_hi’ [-Wmissing-prototypes]
  170 | u64 ioread64be_lo_hi(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~~~
../lib/iomap.c:178:5: warning: no previous prototype for ‘ioread64be_hi_lo’ [-Wmissing-prototypes]
  178 | u64 ioread64be_hi_lo(const void __iomem *addr)
      |     ^~~~~~~~~~~~~~~~
../lib/iomap.c:264:6: warning: no previous prototype for ‘iowrite64_lo_hi’ [-Wmissing-prototypes]
  264 | void iowrite64_lo_hi(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~
../lib/iomap.c:272:6: warning: no previous prototype for ‘iowrite64_hi_lo’ [-Wmissing-prototypes]
  272 | void iowrite64_hi_lo(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~
../lib/iomap.c:280:6: warning: no previous prototype for ‘iowrite64be_lo_hi’ [-Wmissing-prototypes]
  280 | void iowrite64be_lo_hi(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~~~
../lib/iomap.c:288:6: warning: no previous prototype for ‘iowrite64be_hi_lo’ [-Wmissing-prototypes]
  288 | void iowrite64be_hi_lo(u64 val, void __iomem *addr)
      |      ^~~~~~~~~~~~~~~~~

[14:34:18] Starting KUnit Kernel (1/1)...
[14:34:18] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[14:34:18] ============ drm_test_pick_cmdline (2 subtests) ============
[14:34:18] [PASSED] drm_test_pick_cmdline_res_1920_1080_60
[14:34:18] =============== drm_test_pick_cmdline_named  ===============
[14:34:18] [PASSED] NTSC
[14:34:18] [PASSED] NTSC-J
[14:34:18] [PASSED] PAL
[14:34:18] [PASSED] PAL-M
[14:34:18] =========== [PASSED] drm_test_pick_cmdline_named ===========
[14:34:18] ============== [PASSED] drm_test_pick_cmdline ==============
[14:34:18] ================== drm_buddy (7 subtests) ==================
[14:34:18] [PASSED] drm_test_buddy_alloc_limit
[14:34:18] [PASSED] drm_test_buddy_alloc_optimistic
[14:34:18] [PASSED] drm_test_buddy_alloc_pessimistic
[14:34:18] [PASSED] drm_test_buddy_alloc_pathological
[14:34:18] [PASSED] drm_test_buddy_alloc_contiguous
[14:34:18] [PASSED] drm_test_buddy_alloc_clear
[14:34:18] [PASSED] drm_test_buddy_alloc_range_bias
[14:34:18] ==================== [PASSED] drm_buddy ====================
[14:34:18] ============= drm_cmdline_parser (40 subtests) =============
[14:34:18] [PASSED] drm_test_cmdline_force_d_only
[14:34:18] [PASSED] drm_test_cmdline_force_D_only_dvi
[14:34:18] [PASSED] drm_test_cmdline_force_D_only_hdmi
[14:34:18] [PASSED] drm_test_cmdline_force_D_only_not_digital
[14:34:18] [PASSED] drm_test_cmdline_force_e_only
[14:34:18] [PASSED] drm_test_cmdline_res
[14:34:18] [PASSED] drm_test_cmdline_res_vesa
[14:34:18] [PASSED] drm_test_cmdline_res_vesa_rblank
[14:34:18] [PASSED] drm_test_cmdline_res_rblank
[14:34:18] [PASSED] drm_test_cmdline_res_bpp
[14:34:18] [PASSED] drm_test_cmdline_res_refresh
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh_margins
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh_force_off
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_analog
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_digital
[14:34:18] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on
[14:34:18] [PASSED] drm_test_cmdline_res_margins_force_on
[14:34:18] [PASSED] drm_test_cmdline_res_vesa_margins
[14:34:18] [PASSED] drm_test_cmdline_name
[14:34:18] [PASSED] drm_test_cmdline_name_bpp
[14:34:18] [PASSED] drm_test_cmdline_name_option
[14:34:18] [PASSED] drm_test_cmdline_name_bpp_option
[14:34:18] [PASSED] drm_test_cmdline_rotate_0
[14:34:18] [PASSED] drm_test_cmdline_rotate_90
[14:34:18] [PASSED] drm_test_cmdline_rotate_180
[14:34:18] [PASSED] drm_test_cmdline_rotate_270
[14:34:18] [PASSED] drm_test_cmdline_hmirror
[14:34:18] [PASSED] drm_test_cmdline_vmirror
[14:34:18] [PASSED] drm_test_cmdline_margin_options
[14:34:18] [PASSED] drm_test_cmdline_multiple_options
[14:34:18] [PASSED] drm_test_cmdline_bpp_extra_and_option
[14:34:18] [PASSED] drm_test_cmdline_extra_and_option
[14:34:18] [PASSED] drm_test_cmdline_freestanding_options
[14:34:18] [PASSED] drm_test_cmdline_freestanding_force_e_and_options
[14:34:18] [PASSED] drm_test_cmdline_panel_orientation
[14:34:18] ================ drm_test_cmdline_invalid  =================
[14:34:18] [PASSED] margin_only
[14:34:18] [PASSED] interlace_only
[14:34:18] [PASSED] res_missing_x
[14:34:18] [PASSED] res_missing_y
[14:34:18] [PASSED] res_bad_y
[14:34:18] [PASSED] res_missing_y_bpp
[14:34:18] [PASSED] res_bad_bpp
[14:34:18] [PASSED] res_bad_refresh
[14:34:18] [PASSED] res_bpp_refresh_force_on_off
[14:34:18] [PASSED] res_invalid_mode
[14:34:18] [PASSED] res_bpp_wrong_place_mode
[14:34:18] [PASSED] name_bpp_refresh
[14:34:18] [PASSED] name_refresh
[14:34:18] [PASSED] name_refresh_wrong_mode
[14:34:18] [PASSED] name_refresh_invalid_mode
[14:34:18] [PASSED] rotate_multiple
[14:34:18] [PASSED] rotate_invalid_val
[14:34:18] [PASSED] rotate_truncated
[14:34:18] [PASSED] invalid_option
[14:34:18] [PASSED] invalid_tv_option
[14:34:18] [PASSED] truncated_tv_option
[14:34:18] ============ [PASSED] drm_test_cmdline_invalid =============
[14:34:18] =============== drm_test_cmdline_tv_options  ===============
[14:34:18] [PASSED] NTSC
[14:34:18] [PASSED] NTSC_443
[14:34:18] [PASSED] NTSC_J
[14:34:18] [PASSED] PAL
[14:34:18] [PASSED] PAL_M
[14:34:18] [PASSED] PAL_N
[14:34:18] [PASSED] SECAM
[14:34:18] [PASSED] MONO_525
[14:34:18] [PASSED] MONO_625
[14:34:18] =========== [PASSED] drm_test_cmdline_tv_options ===========
[14:34:18] =============== [PASSED] drm_cmdline_parser ================
[14:34:18] ========== drmm_connector_hdmi_init (19 subtests) ==========
[14:34:18] [PASSED] drm_test_connector_hdmi_init_valid
[14:34:18] [PASSED] drm_test_connector_hdmi_init_bpc_8
[14:34:18] [PASSED] drm_test_connector_hdmi_init_bpc_10
[14:34:18] [PASSED] drm_test_connector_hdmi_init_bpc_12
[14:34:18] [PASSED] drm_test_connector_hdmi_init_bpc_invalid
[14:34:18] [PASSED] drm_test_connector_hdmi_init_bpc_null
[14:34:18] [PASSED] drm_test_connector_hdmi_init_formats_empty
[14:34:18] [PASSED] drm_test_connector_hdmi_init_formats_no_rgb
[14:34:18] [PASSED] drm_test_connector_hdmi_init_null_ddc
[14:34:18] [PASSED] drm_test_connector_hdmi_init_null_product
[14:34:18] [PASSED] drm_test_connector_hdmi_init_null_vendor
[14:34:18] [PASSED] drm_test_connector_hdmi_init_product_length_exact
[14:34:18] [PASSED] drm_test_connector_hdmi_init_product_length_too_long
[14:34:18] [PASSED] drm_test_connector_hdmi_init_product_valid
[14:34:18] [PASSED] drm_test_connector_hdmi_init_vendor_length_exact
[14:34:18] [PASSED] drm_test_connector_hdmi_init_vendor_length_too_long
[14:34:18] [PASSED] drm_test_connector_hdmi_init_vendor_valid
[14:34:18] ========= drm_test_connector_hdmi_init_type_valid  =========
[14:34:18] [PASSED] HDMI-A
[14:34:18] [PASSED] HDMI-B
[14:34:18] ===== [PASSED] drm_test_connector_hdmi_init_type_valid =====
[14:34:18] ======== drm_test_connector_hdmi_init_type_invalid  ========
[14:34:18] [PASSED] Unknown
[14:34:18] [PASSED] VGA
[14:34:18] [PASSED] DVI-I
[14:34:18] [PASSED] DVI-D
[14:34:18] [PASSED] DVI-A
[14:34:18] [PASSED] Composite
[14:34:18] [PASSED] SVIDEO
[14:34:18] [PASSED] LVDS
[14:34:18] [PASSED] Component
[14:34:18] [PASSED] DIN
[14:34:18] [PASSED] DP
[14:34:18] [PASSED] TV
[14:34:18] [PASSED] eDP
[14:34:18] [PASSED] Virtual
[14:34:18] [PASSED] DSI
[14:34:18] [PASSED] DPI
[14:34:18] [PASSED] Writeback
[14:34:18] [PASSED] SPI
[14:34:18] [PASSED] USB
[14:34:18] ==== [PASSED] drm_test_connector_hdmi_init_type_invalid ====
[14:34:18] ============ [PASSED] drmm_connector_hdmi_init =============
[14:34:18] ============= drmm_connector_init (3 subtests) =============
[14:34:18] [PASSED] drm_test_drmm_connector_init
[14:34:18] [PASSED] drm_test_drmm_connector_init_null_ddc
[14:34:18] ========= drm_test_drmm_connector_init_type_valid  =========
[14:34:18] [PASSED] Unknown
[14:34:18] [PASSED] VGA
[14:34:18] [PASSED] DVI-I
[14:34:18] [PASSED] DVI-D
[14:34:18] [PASSED] DVI-A
[14:34:18] [PASSED] Composite
[14:34:18] [PASSED] SVIDEO
[14:34:18] [PASSED] LVDS
[14:34:18] [PASSED] Component
[14:34:18] [PASSED] DIN
[14:34:18] [PASSED] DP
[14:34:18] [PASSED] HDMI-A
[14:34:18] [PASSED] HDMI-B
[14:34:18] [PASSED] TV
[14:34:18] [PASSED] eDP
[14:34:18] [PASSED] Virtual
[14:34:18] [PASSED] DSI
[14:34:18] [PASSED] DPI
[14:34:18] [PASSED] Writeback
[14:34:18] [PASSED] SPI
[14:34:18] [PASSED] USB
[14:34:18] ===== [PASSED] drm_test_drmm_connector_init_type_valid =====
[14:34:18] =============== [PASSED] drmm_connector_init ===============
[14:34:18] = drm_connector_attach_broadcast_rgb_property (2 subtests) =
[14:34:18] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property
[14:34:18] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector
[14:34:18] === [PASSED] drm_connector_attach_broadcast_rgb_property ===
[14:34:18] ========== drm_get_tv_mode_from_name (2 subtests) ==========
[14:34:18] ========== drm_test_get_tv_mode_from_name_valid  ===========
[14:34:18] [PASSED] NTSC
[14:34:18] [PASSED] NTSC-443
[14:34:18] [PASSED] NTSC-J
[14:34:18] [PASSED] PAL
[14:34:18] [PASSED] PAL-M
[14:34:18] [PASSED] PAL-N
[14:34:18] [PASSED] SECAM
[14:34:18] [PASSED] Mono
[14:34:18] ====== [PASSED] drm_test_get_tv_mode_from_name_valid =======
[14:34:18] [PASSED] drm_test_get_tv_mode_from_name_truncated
[14:34:18] ============ [PASSED] drm_get_tv_mode_from_name ============
[14:34:18] = drm_test_connector_hdmi_compute_mode_clock (12 subtests) =
[14:34:18] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb
[14:34:18] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc
[14:34:18] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1
[14:34:18] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc
[14:34:18] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1
[14:34:18] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_double
[14:34:18] = drm_test_connector_hdmi_compute_mode_clock_yuv420_valid  =
[14:34:18] [PASSED] VIC 96
[14:34:18] [PASSED] VIC 97
[14:34:18] [PASSED] VIC 101
[14:34:18] [PASSED] VIC 102
[14:34:18] [PASSED] VIC 106
[14:34:18] [PASSED] VIC 107
[14:34:18] === [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_valid ===
[14:34:18] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc
[14:34:18] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc
[14:34:18] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc
[14:34:18] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc
[14:34:18] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc
[14:34:18] === [PASSED] drm_test_connector_hdmi_compute_mode_clock ====
[14:34:18] == drm_hdmi_connector_get_broadcast_rgb_name (2 subtests) ==
[14:34:18] === drm_test_drm_hdmi_connector_get_broadcast_rgb_name  ====
[14:34:18] [PASSED] Automatic
[14:34:18] [PASSED] Full
[14:34:18] [PASSED] Limited 16:235
[14:34:18] === [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name ===
[14:34:18] [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid
[14:34:18] ==== [PASSED] drm_hdmi_connector_get_broadcast_rgb_name ====
[14:34:18] == drm_hdmi_connector_get_output_format_name (2 subtests) ==
[14:34:18] === drm_test_drm_hdmi_connector_get_output_format_name  ====
[14:34:18] [PASSED] RGB
[14:34:18] [PASSED] YUV 4:2:0
[14:34:18] [PASSED] YUV 4:2:2
[14:34:18] [PASSED] YUV 4:4:4
[14:34:18] === [PASSED] drm_test_drm_hdmi_connector_get_output_format_name ===
[14:34:18] [PASSED] drm_test_drm_hdmi_connector_get_output_format_name_invalid
[14:34:18] ==== [PASSED] drm_hdmi_connector_get_output_format_name ====
[14:34:18] ============= drm_damage_helper (21 subtests) ==============
[14:34:18] [PASSED] drm_test_damage_iter_no_damage
[14:34:18] [PASSED] drm_test_damage_iter_no_damage_fractional_src
[14:34:18] [PASSED] drm_test_damage_iter_no_damage_src_moved
[14:34:18] [PASSED] drm_test_damage_iter_no_damage_fractional_src_moved
[14:34:18] [PASSED] drm_test_damage_iter_no_damage_not_visible
[14:34:18] [PASSED] drm_test_damage_iter_no_damage_no_crtc
[14:34:18] [PASSED] drm_test_damage_iter_no_damage_no_fb
[14:34:18] [PASSED] drm_test_damage_iter_simple_damage
[14:34:18] [PASSED] drm_test_damage_iter_single_damage
[14:34:18] [PASSED] drm_test_damage_iter_single_damage_intersect_src
[14:34:18] [PASSED] drm_test_damage_iter_single_damage_outside_src
[14:34:18] [PASSED] drm_test_damage_iter_single_damage_fractional_src
[14:34:18] [PASSED] drm_test_damage_iter_single_damage_intersect_fractional_src
[14:34:18] [PASSED] drm_test_damage_iter_single_damage_outside_fractional_src
[14:34:18] [PASSED] drm_test_damage_iter_single_damage_src_moved
[14:34:18] [PASSED] drm_test_damage_iter_single_damage_fractional_src_moved
[14:34:18] [PASSED] drm_test_damage_iter_damage
[14:34:18] [PASSED] drm_test_damage_iter_damage_one_intersect
[14:34:18] [PASSED] drm_test_damage_iter_damage_one_outside
[14:34:18] [PASSED] drm_test_damage_iter_damage_src_moved
[14:34:18] [PASSED] drm_test_damage_iter_damage_not_visible
[14:34:18] ================ [PASSED] drm_damage_helper ================
[14:34:18] ============== drm_dp_mst_helper (3 subtests) ==============
[14:34:18] ============== drm_test_dp_mst_calc_pbn_mode  ==============
[14:34:18] [PASSED] Clock 154000 BPP 30 DSC disabled
[14:34:18] [PASSED] Clock 234000 BPP 30 DSC disabled
[14:34:18] [PASSED] Clock 297000 BPP 24 DSC disabled
[14:34:18] [PASSED] Clock 332880 BPP 24 DSC enabled
[14:34:18] [PASSED] Clock 324540 BPP 24 DSC enabled
[14:34:18] ========== [PASSED] drm_test_dp_mst_calc_pbn_mode ==========
[14:34:18] ============== drm_test_dp_mst_calc_pbn_div  ===============
[14:34:18] [PASSED] Link rate 2000000 lane count 4
[14:34:18] [PASSED] Link rate 2000000 lane count 2
[14:34:18] [PASSED] Link rate 2000000 lane count 1
[14:34:18] [PASSED] Link rate 1350000 lane count 4
[14:34:18] [PASSED] Link rate 1350000 lane count 2
[14:34:18] [PASSED] Link rate 1350000 lane count 1
[14:34:18] [PASSED] Link rate 1000000 lane count 4
[14:34:18] [PASSED] Link rate 1000000 lane count 2
[14:34:18] [PASSED] Link rate 1000000 lane count 1
[14:34:18] [PASSED] Link rate 810000 lane count 4
[14:34:18] [PASSED] Link rate 810000 lane count 2
[14:34:18] [PASSED] Link rate 810000 lane count 1
[14:34:18] [PASSED] Link rate 540000 lane count 4
[14:34:18] [PASSED] Link rate 540000 lane count 2
[14:34:18] [PASSED] Link rate 540000 lane count 1
[14:34:18] [PASSED] Link rate 270000 lane count 4
[14:34:18] [PASSED] Link rate 270000 lane count 2
[14:34:18] [PASSED] Link rate 270000 lane count 1
[14:34:18] [PASSED] Link rate 162000 lane count 4
[14:34:18] [PASSED] Link rate 162000 lane count 2
[14:34:18] [PASSED] Link rate 162000 lane count 1
[14:34:18] ========== [PASSED] drm_test_dp_mst_calc_pbn_div ===========
[14:34:18] ========= drm_test_dp_mst_sideband_msg_req_decode  =========
[14:34:18] [PASSED] DP_ENUM_PATH_RESOURCES with port number
[14:34:18] [PASSED] DP_POWER_UP_PHY with port number
[14:34:18] [PASSED] DP_POWER_DOWN_PHY with port number
[14:34:18] [PASSED] DP_ALLOCATE_PAYLOAD with SDP stream sinks
[14:34:18] [PASSED] DP_ALLOCATE_PAYLOAD with port number
[14:34:18] [PASSED] DP_ALLOCATE_PAYLOAD with VCPI
[14:34:18] [PASSED] DP_ALLOCATE_PAYLOAD with PBN
[14:34:18] [PASSED] DP_QUERY_PAYLOAD with port number
[14:34:18] [PASSED] DP_QUERY_PAYLOAD with VCPI
[14:34:18] [PASSED] DP_REMOTE_DPCD_READ with port number
[14:34:18] [PASSED] DP_REMOTE_DPCD_READ with DPCD address
[14:34:18] [PASSED] DP_REMOTE_DPCD_READ with max number of bytes
[14:34:18] [PASSED] DP_REMOTE_DPCD_WRITE with port number
[14:34:18] [PASSED] DP_REMOTE_DPCD_WRITE with DPCD address
[14:34:18] [PASSED] DP_REMOTE_DPCD_WRITE with data array
[14:34:18] [PASSED] DP_REMOTE_I2C_READ with port number
[14:34:18] [PASSED] DP_REMOTE_I2C_READ with I2C device ID
[14:34:18] [PASSED] DP_REMOTE_I2C_READ with transactions array
[14:34:18] [PASSED] DP_REMOTE_I2C_WRITE with port number
[14:34:18] [PASSED] DP_REMOTE_I2C_WRITE with I2C device ID
[14:34:18] [PASSED] DP_REMOTE_I2C_WRITE with data array
[14:34:18] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream ID
[14:34:18] [PASSED] DP_QUERY_STREAM_ENC_STATUS with client ID
[14:34:18] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream event
[14:34:18] [PASSED] DP_QUERY_STREAM_ENC_STATUS with valid stream event
[14:34:18] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream behavior
[14:34:18] [PASSED] DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior
[14:34:18] ===== [PASSED] drm_test_dp_mst_sideband_msg_req_decode =====
[14:34:18] ================ [PASSED] drm_dp_mst_helper ================
[14:34:18] ================== drm_exec (7 subtests) ===================
[14:34:18] [PASSED] sanitycheck
[14:34:18] [PASSED] test_lock
[14:34:18] [PASSED] test_lock_unlock
[14:34:18] [PASSED] test_duplicates
[14:34:18] [PASSED] test_prepare
[14:34:18] [PASSED] test_prepare_array
[14:34:18] [PASSED] test_multiple_loops
[14:34:18] ==================== [PASSED] drm_exec =====================
[14:34:18] =========== drm_format_helper_test (17 subtests) ===========
[14:34:18] ============== drm_test_fb_xrgb8888_to_gray8  ==============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ========== [PASSED] drm_test_fb_xrgb8888_to_gray8 ==========
[14:34:18] ============= drm_test_fb_xrgb8888_to_rgb332  ==============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb332 ==========
[14:34:18] ============= drm_test_fb_xrgb8888_to_rgb565  ==============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb565 ==========
[14:34:18] ============ drm_test_fb_xrgb8888_to_xrgb1555  =============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======== [PASSED] drm_test_fb_xrgb8888_to_xrgb1555 =========
[14:34:18] ============ drm_test_fb_xrgb8888_to_argb1555  =============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======== [PASSED] drm_test_fb_xrgb8888_to_argb1555 =========
[14:34:18] ============ drm_test_fb_xrgb8888_to_rgba5551  =============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======== [PASSED] drm_test_fb_xrgb8888_to_rgba5551 =========
[14:34:18] ============= drm_test_fb_xrgb8888_to_rgb888  ==============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb888 ==========
[14:34:18] ============ drm_test_fb_xrgb8888_to_argb8888  =============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======== [PASSED] drm_test_fb_xrgb8888_to_argb8888 =========
[14:34:18] =========== drm_test_fb_xrgb8888_to_xrgb2101010  ===========
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======= [PASSED] drm_test_fb_xrgb8888_to_xrgb2101010 =======
[14:34:18] =========== drm_test_fb_xrgb8888_to_argb2101010  ===========
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======= [PASSED] drm_test_fb_xrgb8888_to_argb2101010 =======
[14:34:18] ============== drm_test_fb_xrgb8888_to_mono  ===============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ========== [PASSED] drm_test_fb_xrgb8888_to_mono ===========
[14:34:18] ==================== drm_test_fb_swab  =====================
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ================ [PASSED] drm_test_fb_swab =================
[14:34:18] ============ drm_test_fb_xrgb8888_to_xbgr8888  =============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======== [PASSED] drm_test_fb_xrgb8888_to_xbgr8888 =========
[14:34:18] ============ drm_test_fb_xrgb8888_to_abgr8888  =============
[14:34:18] [PASSED] single_pixel_source_buffer
[14:34:18] [PASSED] single_pixel_clip_rectangle
[14:34:18] [PASSED] well_known_colors
[14:34:18] [PASSED] destination_pitch
[14:34:18] ======== [PASSED] drm_test_fb_xrgb8888_to_abgr8888 =========
[14:34:18] ================= drm_test_fb_clip_offset  =================
[14:34:18] [PASSED] pass through
[14:34:18] [PASSED] horizontal offset
[14:34:18] [PASSED] vertical offset
[14:34:18] [PASSED] horizontal and vertical offset
[14:34:18] [PASSED] horizontal offset (custom pitch)
[14:34:18] [PASSED] vertical offset (custom pitch)
[14:34:18] [PASSED] horizontal and vertical offset (custom pitch)
[14:34:18] ============= [PASSED] drm_test_fb_clip_offset =============
[14:34:18] ============== drm_test_fb_build_fourcc_list  ==============
[14:34:18] [PASSED] no native formats
[14:34:18] [PASSED] XRGB8888 as native format
[14:34:18] [PASSED] remove duplicates
[14:34:18] [PASSED] convert alpha formats
[14:34:18] [PASSED] random formats
[14:34:18] ========== [PASSED] drm_test_fb_build_fourcc_list ==========
[14:34:18] =================== drm_test_fb_memcpy  ====================
[14:34:18] [PASSED] single_pixel_source_buffer: XR24 little-endian (0x34325258)
[14:34:18] [PASSED] single_pixel_source_buffer: XRA8 little-endian (0x38415258)
[14:34:18] [PASSED] single_pixel_source_buffer: YU24 little-endian (0x34325559)
[14:34:18] [PASSED] single_pixel_clip_rectangle: XB24 little-endian (0x34324258)
[14:34:18] [PASSED] single_pixel_clip_rectangle: XRA8 little-endian (0x38415258)
[14:34:18] [PASSED] single_pixel_clip_rectangle: YU24 little-endian (0x34325559)
[14:34:18] [PASSED] well_known_colors: XB24 little-endian (0x34324258)
[14:34:18] [PASSED] well_known_colors: XRA8 little-endian (0x38415258)
[14:34:18] [PASSED] well_known_colors: YU24 little-endian (0x34325559)
[14:34:18] [PASSED] destination_pitch: XB24 little-endian (0x34324258)
[14:34:18] [PASSED] destination_pitch: XRA8 little-endian (0x38415258)
[14:34:18] [PASSED] destination_pitch: YU24 little-endian (0x34325559)
[14:34:18] =============== [PASSED] drm_test_fb_memcpy ================
[14:34:18] ============= [PASSED] drm_format_helper_test ==============
[14:34:18] ================= drm_format (18 subtests) =================
[14:34:18] [PASSED] drm_test_format_block_width_invalid
[14:34:18] [PASSED] drm_test_format_block_width_one_plane
[14:34:18] [PASSED] drm_test_format_block_width_two_plane
[14:34:18] [PASSED] drm_test_format_block_width_three_plane
[14:34:18] [PASSED] drm_test_format_block_width_tiled
[14:34:18] [PASSED] drm_test_format_block_height_invalid
[14:34:18] [PASSED] drm_test_format_block_height_one_plane
[14:34:18] [PASSED] drm_test_format_block_height_two_plane
[14:34:18] [PASSED] drm_test_format_block_height_three_plane
[14:34:18] [PASSED] drm_test_format_block_height_tiled
[14:34:18] [PASSED] drm_test_format_min_pitch_invalid
[14:34:18] [PASSED] drm_test_format_min_pitch_one_plane_8bpp
[14:34:18] [PASSED] drm_test_format_min_pitch_one_plane_16bpp
[14:34:18] [PASSED] drm_test_format_min_pitch_one_plane_24bpp
[14:34:18] [PASSED] drm_test_format_min_pitch_one_plane_32bpp
[14:34:18] [PASSED] drm_test_format_min_pitch_two_plane
[14:34:18] [PASSED] drm_test_format_min_pitch_three_plane_8bpp
[14:34:18] [PASSED] drm_test_format_min_pitch_tiled
[14:34:18] =================== [PASSED] drm_format ====================
[14:34:18] =============== drm_framebuffer (1 subtest) ================
[14:34:18] =============== drm_test_framebuffer_create  ===============
[14:34:18] [PASSED] ABGR8888 normal sizes
[14:34:18] [PASSED] ABGR8888 max sizes
[14:34:18] [PASSED] ABGR8888 pitch greater than min required
[14:34:18] [PASSED] ABGR8888 pitch less than min required
[14:34:18] [PASSED] ABGR8888 Invalid width
[14:34:18] [PASSED] ABGR8888 Invalid buffer handle
[14:34:18] [PASSED] No pixel format
[14:34:18] [PASSED] ABGR8888 Width 0
[14:34:18] [PASSED] ABGR8888 Height 0
[14:34:18] [PASSED] ABGR8888 Out of bound height * pitch combination
[14:34:18] [PASSED] ABGR8888 Large buffer offset
[14:34:18] [PASSED] ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers
[14:34:18] [PASSED] ABGR8888 Valid buffer modifier
[14:34:18] [PASSED] ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
[14:34:18] [PASSED] ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS
[14:34:18] [PASSED] ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS
[14:34:18] [PASSED] NV12 Normal sizes
[14:34:18] [PASSED] NV12 Max sizes
[14:34:18] [PASSED] NV12 Invalid pitch
[14:34:18] [PASSED] NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag
[14:34:18] [PASSED] NV12 different  modifier per-plane
[14:34:18] [PASSED] NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
[14:34:18] [PASSED] NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS
[14:34:18] [PASSED] NV12 Modifier for inexistent plane
[14:34:18] [PASSED] NV12 Handle for inexistent plane
[14:34:18] [PASSED] NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS
[14:34:18] [PASSED] YVU420 DRM_MODE_FB_MODIFIERS set without modifier
[14:34:18] [PASSED] YVU420 Normal sizes
[14:34:18] [PASSED] YVU420 Max sizes
[14:34:18] [PASSED] YVU420 Invalid pitch
[14:34:18] [PASSED] YVU420 Different pitches
[14:34:18] [PASSED] YVU420 Different buffer offsets/pitches
[14:34:18] [PASSED] YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS
[14:34:18] [PASSED] YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS
[14:34:18] [PASSED] YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS
[14:34:18] [PASSED] YVU420 Valid modifier
[14:34:18] [PASSED] YVU420 Different modifiers per plane
[14:34:18] [PASSED] YVU420 Modifier for inexistent plane
[14:34:18] [PASSED] X0L2 Normal sizes
[14:34:18] [PASSED] X0L2 Max sizes
[14:34:18] [PASSED] X0L2 Invalid pitch
[14:34:18] [PASSED] X0L2 Pitch greater than minimum required
[14:34:18] [PASSED] X0L2 Handle for inexistent plane
[14:34:18] [PASSED] X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set
[14:34:18] [PASSED] X0L2 Modifier without DRM_MODE_FB_MODIFIERS set
[14:34:18] [PASSED] X0L2 Valid modifier
[14:34:18] [PASSED] X0L2 Modifier for inexistent plane
[14:34:18] =========== [PASSED] drm_test_framebuffer_create ===========
[14:34:18] ================= [PASSED] drm_framebuffer =================
[14:34:18] ================ drm_gem_shmem (8 subtests) ================
[14:34:18] [PASSED] drm_gem_shmem_test_obj_create
[14:34:18] [PASSED] drm_gem_shmem_test_obj_create_private
[14:34:18] [PASSED] drm_gem_shmem_test_pin_pages
[14:34:18] [PASSED] drm_gem_shmem_test_vmap
[14:34:18] [PASSED] drm_gem_shmem_test_get_pages_sgt
[14:34:18] [PASSED] drm_gem_shmem_test_get_sg_table
[14:34:18] [PASSED] drm_gem_shmem_test_madvise
[14:34:18] [PASSED] drm_gem_shmem_test_purge
[14:34:18] ================== [PASSED] drm_gem_shmem ==================
[14:34:18] === drm_atomic_helper_connector_hdmi_check (22 subtests) ===
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode_vic_1
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode_vic_1
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode_vic_1
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_changed
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_not_changed
[14:34:18] [PASSED] drm_test_check_hdmi_funcs_reject_rate
[14:34:18] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback
[14:34:18] [PASSED] drm_test_check_max_tmds_rate_format_fallback
[14:34:18] [PASSED] drm_test_check_output_bpc_crtc_mode_changed
[14:34:18] [PASSED] drm_test_check_output_bpc_crtc_mode_not_changed
[14:34:18] [PASSED] drm_test_check_output_bpc_dvi
[14:34:18] [PASSED] drm_test_check_output_bpc_format_vic_1
[14:34:18] [PASSED] drm_test_check_output_bpc_format_display_8bpc_only
[14:34:18] [PASSED] drm_test_check_output_bpc_format_display_rgb_only
[14:34:18] [PASSED] drm_test_check_output_bpc_format_driver_8bpc_only
[14:34:18] [PASSED] drm_test_check_output_bpc_format_driver_rgb_only
[14:34:18] [PASSED] drm_test_check_tmds_char_rate_rgb_8bpc
[14:34:18] [PASSED] drm_test_check_tmds_char_rate_rgb_10bpc
[14:34:18] [PASSED] drm_test_check_tmds_char_rate_rgb_12bpc
[14:34:18] ===== [PASSED] drm_atomic_helper_connector_hdmi_check ======
[14:34:18] === drm_atomic_helper_connector_hdmi_reset (6 subtests) ====
[14:34:18] [PASSED] drm_test_check_broadcast_rgb_value
[14:34:18] [PASSED] drm_test_check_bpc_8_value
[14:34:18] [PASSED] drm_test_check_bpc_10_value
[14:34:18] [PASSED] drm_test_check_bpc_12_value
[14:34:18] [PASSED] drm_test_check_format_value
[14:34:18] [PASSED] drm_test_check_tmds_char_value
[14:34:18] ===== [PASSED] drm_atomic_helper_connector_hdmi_reset ======
[14:34:18] ================= drm_managed (2 subtests) =================
[14:34:18] [PASSED] drm_test_managed_release_action
[14:34:18] [PASSED] drm_test_managed_run_action
[14:34:18] =================== [PASSED] drm_managed ===================
[14:34:18] =================== drm_mm (6 subtests) ====================
[14:34:18] [PASSED] drm_test_mm_init
[14:34:18] [PASSED] drm_test_mm_debug
[14:34:18] [PASSED] drm_test_mm_align32
[14:34:18] [PASSED] drm_test_mm_align64
[14:34:18] [PASSED] drm_test_mm_lowest
[14:34:18] [PASSED] drm_test_mm_highest
[14:34:18] ===================== [PASSED] drm_mm ======================
[14:34:18] ============= drm_modes_analog_tv (5 subtests) =============
[14:34:18] [PASSED] drm_test_modes_analog_tv_mono_576i
[14:34:18] [PASSED] drm_test_modes_analog_tv_ntsc_480i
[14:34:18] [PASSED] drm_test_modes_analog_tv_ntsc_480i_inlined
[14:34:18] [PASSED] drm_test_modes_analog_tv_pal_576i
[14:34:18] [PASSED] drm_test_modes_analog_tv_pal_576i_inlined
[14:34:18] =============== [PASSED] drm_modes_analog_tv ===============
[14:34:18] ============== drm_plane_helper (2 subtests) ===============
[14:34:18] =============== drm_test_check_plane_state  ================
[14:34:18] [PASSED] clipping_simple
[14:34:18] [PASSED] clipping_rotate_reflect
[14:34:18] [PASSED] positioning_simple
[14:34:18] [PASSED] upscaling
[14:34:18] [PASSED] downscaling
[14:34:18] [PASSED] rounding1
[14:34:18] [PASSED] rounding2
[14:34:18] [PASSED] rounding3
[14:34:18] [PASSED] rounding4
[14:34:18] =========== [PASSED] drm_test_check_plane_state ============
[14:34:18] =========== drm_test_check_invalid_plane_state  ============
[14:34:18] [PASSED] positioning_invalid
[14:34:18] [PASSED] upscaling_invalid
stty: 'standard input': Inappropriate ioctl for device
[14:34:18] [PASSED] downscaling_invalid
[14:34:18] ======= [PASSED] drm_test_check_invalid_plane_state ========
[14:34:18] ================ [PASSED] drm_plane_helper =================
[14:34:18] ====== drm_connector_helper_tv_get_modes (1 subtest) =======
[14:34:18] ====== drm_test_connector_helper_tv_get_modes_check  =======
[14:34:18] [PASSED] None
[14:34:18] [PASSED] PAL
[14:34:18] [PASSED] NTSC
[14:34:18] [PASSED] Both, NTSC Default
[14:34:18] [PASSED] Both, PAL Default
[14:34:18] [PASSED] Both, NTSC Default, with PAL on command-line
[14:34:18] [PASSED] Both, PAL Default, with NTSC on command-line
[14:34:18] == [PASSED] drm_test_connector_helper_tv_get_modes_check ===
[14:34:18] ======== [PASSED] drm_connector_helper_tv_get_modes ========
[14:34:18] ================== drm_rect (9 subtests) ===================
[14:34:18] [PASSED] drm_test_rect_clip_scaled_div_by_zero
[14:34:18] [PASSED] drm_test_rect_clip_scaled_not_clipped
[14:34:18] [PASSED] drm_test_rect_clip_scaled_clipped
[14:34:18] [PASSED] drm_test_rect_clip_scaled_signed_vs_unsigned
[14:34:18] ================= drm_test_rect_intersect  =================
[14:34:18] [PASSED] top-left x bottom-right: 2x2+1+1 x 2x2+0+0
[14:34:18] [PASSED] top-right x bottom-left: 2x2+0+0 x 2x2+1-1
[14:34:18] [PASSED] bottom-left x top-right: 2x2+1-1 x 2x2+0+0
[14:34:18] [PASSED] bottom-right x top-left: 2x2+0+0 x 2x2+1+1
[14:34:18] [PASSED] right x left: 2x1+0+0 x 3x1+1+0
[14:34:18] [PASSED] left x right: 3x1+1+0 x 2x1+0+0
[14:34:18] [PASSED] up x bottom: 1x2+0+0 x 1x3+0-1
[14:34:18] [PASSED] bottom x up: 1x3+0-1 x 1x2+0+0
[14:34:18] [PASSED] touching corner: 1x1+0+0 x 2x2+1+1
[14:34:18] [PASSED] touching side: 1x1+0+0 x 1x1+1+0
[14:34:18] [PASSED] equal rects: 2x2+0+0 x 2x2+0+0
[14:34:18] [PASSED] inside another: 2x2+0+0 x 1x1+1+1
[14:34:18] [PASSED] far away: 1x1+0+0 x 1x1+3+6
[14:34:18] [PASSED] points intersecting: 0x0+5+10 x 0x0+5+10
[14:34:18] [PASSED] points not intersecting: 0x0+0+0 x 0x0+5+10
[14:34:18] ============= [PASSED] drm_test_rect_intersect =============
[14:34:18] ================ drm_test_rect_calc_hscale  ================
[14:34:18] [PASSED] normal use
[14:34:18] [PASSED] out of max range
[14:34:18] [PASSED] out of min range
[14:34:18] [PASSED] zero dst
[14:34:18] [PASSED] negative src
[14:34:18] [PASSED] negative dst
[14:34:18] ============ [PASSED] drm_test_rect_calc_hscale ============
[14:34:18] ================ drm_test_rect_calc_vscale  ================
[14:34:18] [PASSED] normal use
[14:34:18] [PASSED] out of max range
[14:34:18] [PASSED] out of min range
[14:34:18] [PASSED] zero dst
[14:34:18] [PASSED] negative src
[14:34:18] [PASSED] negative dst
[14:34:18] ============ [PASSED] drm_test_rect_calc_vscale ============
[14:34:18] ================== drm_test_rect_rotate  ===================
[14:34:18] [PASSED] reflect-x
[14:34:18] [PASSED] reflect-y
[14:34:18] [PASSED] rotate-0
[14:34:18] [PASSED] rotate-90
[14:34:18] [PASSED] rotate-180
[14:34:18] [PASSED] rotate-270
[14:34:18] ============== [PASSED] drm_test_rect_rotate ===============
[14:34:18] ================ drm_test_rect_rotate_inv  =================
[14:34:18] [PASSED] reflect-x
[14:34:18] [PASSED] reflect-y
[14:34:18] [PASSED] rotate-0
[14:34:18] [PASSED] rotate-90
[14:34:18] [PASSED] rotate-180
[14:34:18] [PASSED] rotate-270
[14:34:18] ============ [PASSED] drm_test_rect_rotate_inv =============
[14:34:18] ==================== [PASSED] drm_rect =====================
[14:34:18] ============================================================
[14:34:18] Testing complete. Ran 515 tests: passed: 515
[14:34:18] Elapsed time: 23.396s total, 1.729s configuring, 21.448s building, 0.200s running

+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig
[14:34:18] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[14:34:20] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make ARCH=um O=.kunit --jobs=48
[14:34:28] Starting KUnit Kernel (1/1)...
[14:34:28] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[14:34:29] ================= ttm_device (5 subtests) ==================
[14:34:29] [PASSED] ttm_device_init_basic
[14:34:29] [PASSED] ttm_device_init_multiple
[14:34:29] [PASSED] ttm_device_fini_basic
[14:34:29] [PASSED] ttm_device_init_no_vma_man
[14:34:29] ================== ttm_device_init_pools  ==================
[14:34:29] [PASSED] No DMA allocations, no DMA32 required
[14:34:29] [PASSED] DMA allocations, DMA32 required
[14:34:29] [PASSED] No DMA allocations, DMA32 required
[14:34:29] [PASSED] DMA allocations, no DMA32 required
[14:34:29] ============== [PASSED] ttm_device_init_pools ==============
[14:34:29] =================== [PASSED] ttm_device ====================
[14:34:29] ================== ttm_pool (8 subtests) ===================
[14:34:29] ================== ttm_pool_alloc_basic  ===================
[14:34:29] [PASSED] One page
[14:34:29] [PASSED] More than one page
[14:34:29] [PASSED] Above the allocation limit
[14:34:29] [PASSED] One page, with coherent DMA mappings enabled
[14:34:29] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[14:34:29] ============== [PASSED] ttm_pool_alloc_basic ===============
[14:34:29] ============== ttm_pool_alloc_basic_dma_addr  ==============
[14:34:29] [PASSED] One page
[14:34:29] [PASSED] More than one page
[14:34:29] [PASSED] Above the allocation limit
[14:34:29] [PASSED] One page, with coherent DMA mappings enabled
[14:34:29] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[14:34:29] ========== [PASSED] ttm_pool_alloc_basic_dma_addr ==========
[14:34:29] [PASSED] ttm_pool_alloc_order_caching_match
[14:34:29] [PASSED] ttm_pool_alloc_caching_mismatch
[14:34:29] [PASSED] ttm_pool_alloc_order_mismatch
[14:34:29] [PASSED] ttm_pool_free_dma_alloc
[14:34:29] [PASSED] ttm_pool_free_no_dma_alloc
[14:34:29] [PASSED] ttm_pool_fini_basic
[14:34:29] ==================== [PASSED] ttm_pool =====================
[14:34:29] ================ ttm_resource (8 subtests) =================
[14:34:29] ================= ttm_resource_init_basic  =================
[14:34:29] [PASSED] Init resource in TTM_PL_SYSTEM
[14:34:29] [PASSED] Init resource in TTM_PL_VRAM
[14:34:29] [PASSED] Init resource in a private placement
[14:34:29] [PASSED] Init resource in TTM_PL_SYSTEM, set placement flags
[14:34:29] ============= [PASSED] ttm_resource_init_basic =============
[14:34:29] [PASSED] ttm_resource_init_pinned
[14:34:29] [PASSED] ttm_resource_fini_basic
[14:34:29] [PASSED] ttm_resource_manager_init_basic
[14:34:29] [PASSED] ttm_resource_manager_usage_basic
[14:34:29] [PASSED] ttm_resource_manager_set_used_basic
[14:34:29] [PASSED] ttm_sys_man_alloc_basic
[14:34:29] [PASSED] ttm_sys_man_free_basic
[14:34:29] ================== [PASSED] ttm_resource ===================
[14:34:29] =================== ttm_tt (15 subtests) ===================
[14:34:29] ==================== ttm_tt_init_basic  ====================
[14:34:29] [PASSED] Page-aligned size
[14:34:29] [PASSED] Extra pages requested
[14:34:29] ================ [PASSED] ttm_tt_init_basic ================
[14:34:29] [PASSED] ttm_tt_init_misaligned
[14:34:29] [PASSED] ttm_tt_fini_basic
[14:34:29] [PASSED] ttm_tt_fini_sg
[14:34:29] [PASSED] ttm_tt_fini_shmem
[14:34:29] [PASSED] ttm_tt_create_basic
[14:34:29] [PASSED] ttm_tt_create_invalid_bo_type
[14:34:29] [PASSED] ttm_tt_create_ttm_exists
[14:34:29] [PASSED] ttm_tt_create_failed
[14:34:29] [PASSED] ttm_tt_destroy_basic
[14:34:29] [PASSED] ttm_tt_populate_null_ttm
[14:34:29] [PASSED] ttm_tt_populate_populated_ttm
[14:34:29] [PASSED] ttm_tt_unpopulate_basic
[14:34:29] [PASSED] ttm_tt_unpopulate_empty_ttm
[14:34:29] [PASSED] ttm_tt_swapin_basic
[14:34:29] ===================== [PASSED] ttm_tt ======================
[14:34:29] =================== ttm_bo (14 subtests) ===================
[14:34:29] =========== ttm_bo_reserve_optimistic_no_ticket  ===========
[14:34:29] [PASSED] Cannot be interrupted and sleeps
[14:34:29] [PASSED] Cannot be interrupted, locks straight away
[14:34:29] [PASSED] Can be interrupted, sleeps
[14:34:29] ======= [PASSED] ttm_bo_reserve_optimistic_no_ticket =======
[14:34:29] [PASSED] ttm_bo_reserve_locked_no_sleep
[14:34:29] [PASSED] ttm_bo_reserve_no_wait_ticket
[14:34:29] [PASSED] ttm_bo_reserve_double_resv
[14:34:29] [PASSED] ttm_bo_reserve_interrupted
[14:34:29] [PASSED] ttm_bo_reserve_deadlock
[14:34:29] [PASSED] ttm_bo_unreserve_basic
[14:34:29] [PASSED] ttm_bo_unreserve_pinned
[14:34:29] [PASSED] ttm_bo_unreserve_bulk
[14:34:29] [PASSED] ttm_bo_put_basic
[14:34:29] [PASSED] ttm_bo_put_shared_resv
[14:34:29] [PASSED] ttm_bo_pin_basic
[14:34:29] [PASSED] ttm_bo_pin_unpin_resource
[14:34:29] [PASSED] ttm_bo_multiple_pin_one_unpin
[14:34:29] ===================== [PASSED] ttm_bo ======================
[14:34:29] ============== ttm_bo_validate (22 subtests) ===============
[14:34:29] ============== ttm_bo_init_reserved_sys_man  ===============
[14:34:29] [PASSED] Buffer object for userspace
[14:34:29] [PASSED] Kernel buffer object
[14:34:29] [PASSED] Shared buffer object
[14:34:29] ========== [PASSED] ttm_bo_init_reserved_sys_man ===========
[14:34:29] ============== ttm_bo_init_reserved_mock_man  ==============
[14:34:29] [PASSED] Buffer object for userspace
[14:34:29] [PASSED] Kernel buffer object
[14:34:29] [PASSED] Shared buffer object
[14:34:29] ========== [PASSED] ttm_bo_init_reserved_mock_man ==========
[14:34:29] [PASSED] ttm_bo_init_reserved_resv
[14:34:29] ================== ttm_bo_validate_basic  ==================
[14:34:29] [PASSED] Buffer object for userspace
[14:34:29] [PASSED] Kernel buffer object
[14:34:29] [PASSED] Shared buffer object
[14:34:29] ============== [PASSED] ttm_bo_validate_basic ==============
[14:34:29] [PASSED] ttm_bo_validate_invalid_placement
[14:34:29] ============= ttm_bo_validate_same_placement  ==============
[14:34:29] [PASSED] System manager
[14:34:29] [PASSED] VRAM manager
[14:34:29] ========= [PASSED] ttm_bo_validate_same_placement ==========
[14:34:29] [PASSED] ttm_bo_validate_failed_alloc
[14:34:29] [PASSED] ttm_bo_validate_pinned
[14:34:29] [PASSED] ttm_bo_validate_busy_placement
[14:34:29] ================ ttm_bo_validate_multihop  =================
[14:34:29] [PASSED] Buffer object for userspace
[14:34:29] [PASSED] Kernel buffer object
[14:34:29] [PASSED] Shared buffer object
[14:34:29] ============ [PASSED] ttm_bo_validate_multihop =============
[14:34:29] ========== ttm_bo_validate_no_placement_signaled  ==========
[14:34:29] [PASSED] Buffer object in system domain, no page vector
[14:34:29] [PASSED] Buffer object in system domain with an existing page vector
[14:34:29] ====== [PASSED] ttm_bo_validate_no_placement_signaled ======
[14:34:29] ======== ttm_bo_validate_no_placement_not_signaled  ========
[14:34:29] [PASSED] Buffer object for userspace
[14:34:29] [PASSED] Kernel buffer object
[14:34:29] [PASSED] Shared buffer object
[14:34:29] ==== [PASSED] ttm_bo_validate_no_placement_not_signaled ====
[14:34:29] [PASSED] ttm_bo_validate_move_fence_signaled
[14:34:29] ========= ttm_bo_validate_move_fence_not_signaled  =========
[14:34:29] [PASSED] Waits for GPU
[14:34:29] [PASSED] Tries to lock straight away
[14:34:29] ===== [PASSED] ttm_bo_validate_move_fence_not_signaled =====
[14:34:29] [PASSED] ttm_bo_validate_swapout
[14:34:29] [PASSED] ttm_bo_validate_happy_evict
[14:34:29] [PASSED] ttm_bo_validate_all_pinned_evict
[14:34:29] [PASSED] ttm_bo_validate_allowed_only_evict
[14:34:29] [PASSED] ttm_bo_validate_deleted_evict
[14:34:29] [PASSED] ttm_bo_validate_busy_domain_evict
[14:34:29] [PASSED] ttm_bo_validate_evict_gutting
[14:34:29] [PASSED] ttm_bo_validate_recrusive_evict
stty: 'standard input': Inappropriate ioctl for device
[14:34:29] ================= [PASSED] ttm_bo_validate =================
[14:34:29] ============================================================
[14:34:29] Testing complete. Ran 102 tests: passed: 102
[14:34:29] Elapsed time: 11.093s total, 1.698s configuring, 8.773s building, 0.532s running

+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel



^ permalink raw reply	[flat|nested] 78+ messages in thread

* ✓ CI.Build: success for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (23 preceding siblings ...)
  2024-07-26 14:34 ` ✓ CI.KUnit: success " Patchwork
@ 2024-07-26 14:46 ` Patchwork
  2024-07-26 14:48 ` ✗ CI.Hooks: failure " Patchwork
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-26 14:46 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
State : success

== Summary ==

lib/modules/6.10.0-rc7-xe/kernel/sound/core/seq/
lib/modules/6.10.0-rc7-xe/kernel/sound/core/seq/snd-seq.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/core/snd-seq-device.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/core/snd-hwdep.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/core/snd.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/core/snd-pcm.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/core/snd-compress.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/core/snd-timer.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soundcore.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/atom/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/atom/snd-soc-sst-atom-hifi2-platform.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/atom/sst/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/atom/sst/snd-intel-sst-acpi.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/atom/sst/snd-intel-sst-core.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/common/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/intel/common/snd-soc-acpi-intel-match.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/amd/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/amd/snd-acp-config.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-pci-intel-tgl.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-intel-hda-mlink.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-pci-intel-cnl.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-pci-intel-lnl.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-intel-hda-common.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-intel-hda-generic.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-intel-hda.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/intel/snd-sof-pci-intel-mtl.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/amd/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/amd/snd-sof-amd-renoir.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/amd/snd-sof-amd-acp.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/snd-sof-utils.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/snd-sof-pci.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/snd-sof.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/snd-sof-probes.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/xtensa/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/sof/xtensa/snd-sof-xtensa-dsp.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/snd-soc-core.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/snd-soc-acpi.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/codecs/
lib/modules/6.10.0-rc7-xe/kernel/sound/soc/codecs/snd-soc-hdac-hda.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/hda/
lib/modules/6.10.0-rc7-xe/kernel/sound/hda/snd-intel-sdw-acpi.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/hda/ext/
lib/modules/6.10.0-rc7-xe/kernel/sound/hda/ext/snd-hda-ext-core.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/hda/snd-intel-dspcfg.ko
lib/modules/6.10.0-rc7-xe/kernel/sound/hda/snd-hda-core.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/kernel/
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/kernel/msr.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/kernel/cpuid.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/sha512-ssse3.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/crct10dif-pclmul.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/ghash-clmulni-intel.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/sha1-ssse3.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/crc32-pclmul.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/sha256-ssse3.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/aesni-intel.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/crypto/polyval-clmulni.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/events/
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/events/intel/
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/events/intel/intel-cstate.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/events/rapl.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/kvm/
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/kvm/kvm.ko
lib/modules/6.10.0-rc7-xe/kernel/arch/x86/kvm/kvm-intel.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/
lib/modules/6.10.0-rc7-xe/kernel/crypto/crypto_simd.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/cmac.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/ccm.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/cryptd.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/polyval-generic.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/async_tx/
lib/modules/6.10.0-rc7-xe/kernel/crypto/async_tx/async_xor.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/async_tx/async_tx.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/async_tx/async_memcpy.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/async_tx/async_pq.ko
lib/modules/6.10.0-rc7-xe/kernel/crypto/async_tx/async_raid6_recov.ko
lib/modules/6.10.0-rc7-xe/build
lib/modules/6.10.0-rc7-xe/modules.alias.bin
lib/modules/6.10.0-rc7-xe/modules.builtin
lib/modules/6.10.0-rc7-xe/modules.softdep
lib/modules/6.10.0-rc7-xe/modules.alias
lib/modules/6.10.0-rc7-xe/modules.order
lib/modules/6.10.0-rc7-xe/modules.symbols
lib/modules/6.10.0-rc7-xe/modules.dep.bin
+ mv kernel-nodebug.tar.gz ..
+ cd ..
+ rm -rf archive
++ date +%s
^[[0Ksection_end:1722005172:package_x86_64_nodebug
^[[0K
+ echo -e '\e[0Ksection_end:1722005172:package_x86_64_nodebug\r\e[0K'
+ sync
+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel



^ permalink raw reply	[flat|nested] 78+ messages in thread

* ✗ CI.Hooks: failure for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (24 preceding siblings ...)
  2024-07-26 14:46 ` ✓ CI.Build: " Patchwork
@ 2024-07-26 14:48 ` Patchwork
  2024-07-26 14:49 ` ✓ CI.checksparse: success " Patchwork
                   ` (3 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-26 14:48 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
State : failure

== Summary ==

run-parts: executing /workspace/ci/hooks/00-showenv
+ export
+ grep -Ei '(^|\W)CI_'
declare -x CI_KERNEL_BUILD_DIR="/workspace/kernel/build64-default"
declare -x CI_KERNEL_SRC_DIR="/workspace/kernel"
declare -x CI_TOOLS_SRC_DIR="/workspace/ci"
declare -x CI_WORKSPACE_DIR="/workspace"
run-parts: executing /workspace/ci/hooks/10-build-W1
+ SRC_DIR=/workspace/kernel
+ RESTORE_DISPLAY_CONFIG=0
+ '[' -n /workspace/kernel/build64-default ']'
+ BUILD_DIR=/workspace/kernel/build64-default
+ cd /workspace/kernel
++ nproc
+ make -j48 O=/workspace/kernel/build64-default modules_prepare
make[1]: Entering directory '/workspace/kernel/build64-default'
  GEN     Makefile
  UPD     include/generated/compile.h
  UPD     include/config/kernel.release
mkdir -p /workspace/kernel/build64-default/tools/objtool && make O=/workspace/kernel/build64-default subdir=tools/objtool --no-print-directory -C objtool 
  UPD     include/generated/utsrelease.h
  HOSTCC  /workspace/kernel/build64-default/tools/objtool/fixdep.o
  CALL    ../scripts/checksyscalls.sh
  HOSTLD  /workspace/kernel/build64-default/tools/objtool/fixdep-in.o
  LINK    /workspace/kernel/build64-default/tools/objtool/fixdep
  INSTALL libsubcmd_headers
  CC      /workspace/kernel/build64-default/tools/objtool/libsubcmd/exec-cmd.o
  CC      /workspace/kernel/build64-default/tools/objtool/libsubcmd/help.o
  CC      /workspace/kernel/build64-default/tools/objtool/libsubcmd/pager.o
  CC      /workspace/kernel/build64-default/tools/objtool/libsubcmd/parse-options.o
  CC      /workspace/kernel/build64-default/tools/objtool/libsubcmd/run-command.o
  CC      /workspace/kernel/build64-default/tools/objtool/libsubcmd/subcmd-config.o
  CC      /workspace/kernel/build64-default/tools/objtool/libsubcmd/sigchain.o
  LD      /workspace/kernel/build64-default/tools/objtool/libsubcmd/libsubcmd-in.o
  AR      /workspace/kernel/build64-default/tools/objtool/libsubcmd/libsubcmd.a
  CC      /workspace/kernel/build64-default/tools/objtool/weak.o
  CC      /workspace/kernel/build64-default/tools/objtool/check.o
  CC      /workspace/kernel/build64-default/tools/objtool/special.o
  CC      /workspace/kernel/build64-default/tools/objtool/builtin-check.o
  CC      /workspace/kernel/build64-default/tools/objtool/elf.o
  CC      /workspace/kernel/build64-default/tools/objtool/objtool.o
  CC      /workspace/kernel/build64-default/tools/objtool/orc_gen.o
  CC      /workspace/kernel/build64-default/tools/objtool/orc_dump.o
  CC      /workspace/kernel/build64-default/tools/objtool/libstring.o
  CC      /workspace/kernel/build64-default/tools/objtool/libctype.o
  CC      /workspace/kernel/build64-default/tools/objtool/str_error_r.o
  CC      /workspace/kernel/build64-default/tools/objtool/librbtree.o
  CC      /workspace/kernel/build64-default/tools/objtool/arch/x86/special.o
  CC      /workspace/kernel/build64-default/tools/objtool/arch/x86/decode.o
  CC      /workspace/kernel/build64-default/tools/objtool/arch/x86/orc.o
  LD      /workspace/kernel/build64-default/tools/objtool/arch/x86/objtool-in.o
  LD      /workspace/kernel/build64-default/tools/objtool/objtool-in.o
  LINK    /workspace/kernel/build64-default/tools/objtool/objtool
make[1]: Leaving directory '/workspace/kernel/build64-default'
++ nproc
+ make -j48 O=/workspace/kernel/build64-default W=1 drivers/gpu/drm/xe
make[1]: Entering directory '/workspace/kernel/build64-default'
make[2]: Nothing to be done for 'drivers/gpu/drm/xe'.
make[1]: Leaving directory '/workspace/kernel/build64-default'
run-parts: executing /workspace/ci/hooks/11-build-32b
+++ realpath /workspace/ci/hooks/11-build-32b
++ dirname /workspace/ci/hooks/11-build-32b
+ THIS_SCRIPT_DIR=/workspace/ci/hooks
+ SRC_DIR=/workspace/kernel
+ TOOLS_SRC_DIR=/workspace/ci
+ '[' -n /workspace/kernel/build64-default ']'
+ BUILD_DIR=/workspace/kernel/build64-default
+ BUILD_DIR=/workspace/kernel/build64-default/build32
+ cd /workspace/kernel
+ mkdir -p /workspace/kernel/build64-default/build32
++ nproc
+ make -j48 ARCH=i386 O=/workspace/kernel/build64-default/build32 defconfig
make[1]: Entering directory '/workspace/kernel/build64-default/build32'
  GEN     Makefile
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/confdata.o
  HOSTCC  scripts/kconfig/expr.o
  LEX     scripts/kconfig/lexer.lex.c
  YACC    scripts/kconfig/parser.tab.[ch]
  HOSTCC  scripts/kconfig/menu.o
  HOSTCC  scripts/kconfig/preprocess.o
  HOSTCC  scripts/kconfig/symbol.o
  HOSTCC  scripts/kconfig/util.o
  HOSTCC  scripts/kconfig/lexer.lex.o
  HOSTCC  scripts/kconfig/parser.tab.o
  HOSTLD  scripts/kconfig/conf
*** Default configuration is based on 'i386_defconfig'
#
# configuration written to .config
#
make[1]: Leaving directory '/workspace/kernel/build64-default/build32'
+ cd /workspace/kernel/build64-default/build32
+ /workspace/kernel/scripts/kconfig/merge_config.sh .config /workspace/ci/kernel/10-xe.fragment
Using .config as base
Merging /workspace/ci/kernel/10-xe.fragment
Value of CONFIG_DRM_XE is redefined by fragment /workspace/ci/kernel/10-xe.fragment:
Previous value: # CONFIG_DRM_XE is not set
New value: CONFIG_DRM_XE=m

Value of CONFIG_SND_DEBUG is redefined by fragment /workspace/ci/kernel/10-xe.fragment:
Previous value: # CONFIG_SND_DEBUG is not set
New value: CONFIG_SND_DEBUG=y

Value of CONFIG_SND_HDA_INTEL is redefined by fragment /workspace/ci/kernel/10-xe.fragment:
Previous value: CONFIG_SND_HDA_INTEL=y
New value: CONFIG_SND_HDA_INTEL=m

Value of CONFIG_SND_HDA_CODEC_HDMI is redefined by fragment /workspace/ci/kernel/10-xe.fragment:
Previous value: # CONFIG_SND_HDA_CODEC_HDMI is not set
New value: CONFIG_SND_HDA_CODEC_HDMI=m

  GEN     Makefile

WARNING: unmet direct dependencies detected for FB_IOMEM_HELPERS
  Depends on [n]: HAS_IOMEM [=y] && FB_CORE [=n]
  Selected by [m]:
  - DRM_XE_DISPLAY [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_XE [=m] && DRM_XE [=m]=m [=m]
#
# configuration written to .config
#
Value requested for CONFIG_HAVE_UID16 not in final .config
Requested value:  CONFIG_HAVE_UID16=y
Actual value:     

Value requested for CONFIG_UID16 not in final .config
Requested value:  CONFIG_UID16=y
Actual value:     

Value requested for CONFIG_X86_32 not in final .config
Requested value:  CONFIG_X86_32=y
Actual value:     

Value requested for CONFIG_OUTPUT_FORMAT not in final .config
Requested value:  CONFIG_OUTPUT_FORMAT="elf32-i386"
Actual value:     CONFIG_OUTPUT_FORMAT="elf64-x86-64"

Value requested for CONFIG_ARCH_MMAP_RND_BITS_MIN not in final .config
Requested value:  CONFIG_ARCH_MMAP_RND_BITS_MIN=8
Actual value:     CONFIG_ARCH_MMAP_RND_BITS_MIN=28

Value requested for CONFIG_ARCH_MMAP_RND_BITS_MAX not in final .config
Requested value:  CONFIG_ARCH_MMAP_RND_BITS_MAX=16
Actual value:     CONFIG_ARCH_MMAP_RND_BITS_MAX=32

Value requested for CONFIG_PGTABLE_LEVELS not in final .config
Requested value:  CONFIG_PGTABLE_LEVELS=2
Actual value:     CONFIG_PGTABLE_LEVELS=5

Value requested for CONFIG_X86_BIGSMP not in final .config
Requested value:  # CONFIG_X86_BIGSMP is not set
Actual value:     

Value requested for CONFIG_X86_INTEL_QUARK not in final .config
Requested value:  # CONFIG_X86_INTEL_QUARK is not set
Actual value:     

Value requested for CONFIG_X86_RDC321X not in final .config
Requested value:  # CONFIG_X86_RDC321X is not set
Actual value:     

Value requested for CONFIG_X86_32_NON_STANDARD not in final .config
Requested value:  # CONFIG_X86_32_NON_STANDARD is not set
Actual value:     

Value requested for CONFIG_X86_32_IRIS not in final .config
Requested value:  # CONFIG_X86_32_IRIS is not set
Actual value:     

Value requested for CONFIG_M486SX not in final .config
Requested value:  # CONFIG_M486SX is not set
Actual value:     

Value requested for CONFIG_M486 not in final .config
Requested value:  # CONFIG_M486 is not set
Actual value:     

Value requested for CONFIG_M586 not in final .config
Requested value:  # CONFIG_M586 is not set
Actual value:     

Value requested for CONFIG_M586TSC not in final .config
Requested value:  # CONFIG_M586TSC is not set
Actual value:     

Value requested for CONFIG_M586MMX not in final .config
Requested value:  # CONFIG_M586MMX is not set
Actual value:     

Value requested for CONFIG_M686 not in final .config
Requested value:  CONFIG_M686=y
Actual value:     

Value requested for CONFIG_MPENTIUMII not in final .config
Requested value:  # CONFIG_MPENTIUMII is not set
Actual value:     

Value requested for CONFIG_MPENTIUMIII not in final .config
Requested value:  # CONFIG_MPENTIUMIII is not set
Actual value:     

Value requested for CONFIG_MPENTIUMM not in final .config
Requested value:  # CONFIG_MPENTIUMM is not set
Actual value:     

Value requested for CONFIG_MPENTIUM4 not in final .config
Requested value:  # CONFIG_MPENTIUM4 is not set
Actual value:     

Value requested for CONFIG_MK6 not in final .config
Requested value:  # CONFIG_MK6 is not set
Actual value:     

Value requested for CONFIG_MK7 not in final .config
Requested value:  # CONFIG_MK7 is not set
Actual value:     

Value requested for CONFIG_MCRUSOE not in final .config
Requested value:  # CONFIG_MCRUSOE is not set
Actual value:     

Value requested for CONFIG_MEFFICEON not in final .config
Requested value:  # CONFIG_MEFFICEON is not set
Actual value:     

Value requested for CONFIG_MWINCHIPC6 not in final .config
Requested value:  # CONFIG_MWINCHIPC6 is not set
Actual value:     

Value requested for CONFIG_MWINCHIP3D not in final .config
Requested value:  # CONFIG_MWINCHIP3D is not set
Actual value:     

Value requested for CONFIG_MELAN not in final .config
Requested value:  # CONFIG_MELAN is not set
Actual value:     

Value requested for CONFIG_MGEODEGX1 not in final .config
Requested value:  # CONFIG_MGEODEGX1 is not set
Actual value:     

Value requested for CONFIG_MGEODE_LX not in final .config
Requested value:  # CONFIG_MGEODE_LX is not set
Actual value:     

Value requested for CONFIG_MCYRIXIII not in final .config
Requested value:  # CONFIG_MCYRIXIII is not set
Actual value:     

Value requested for CONFIG_MVIAC3_2 not in final .config
Requested value:  # CONFIG_MVIAC3_2 is not set
Actual value:     

Value requested for CONFIG_MVIAC7 not in final .config
Requested value:  # CONFIG_MVIAC7 is not set
Actual value:     

Value requested for CONFIG_X86_GENERIC not in final .config
Requested value:  # CONFIG_X86_GENERIC is not set
Actual value:     

Value requested for CONFIG_X86_INTERNODE_CACHE_SHIFT not in final .config
Requested value:  CONFIG_X86_INTERNODE_CACHE_SHIFT=5
Actual value:     CONFIG_X86_INTERNODE_CACHE_SHIFT=6

Value requested for CONFIG_X86_L1_CACHE_SHIFT not in final .config
Requested value:  CONFIG_X86_L1_CACHE_SHIFT=5
Actual value:     CONFIG_X86_L1_CACHE_SHIFT=6

Value requested for CONFIG_X86_USE_PPRO_CHECKSUM not in final .config
Requested value:  CONFIG_X86_USE_PPRO_CHECKSUM=y
Actual value:     

Value requested for CONFIG_X86_MINIMUM_CPU_FAMILY not in final .config
Requested value:  CONFIG_X86_MINIMUM_CPU_FAMILY=6
Actual value:     CONFIG_X86_MINIMUM_CPU_FAMILY=64

Value requested for CONFIG_CPU_SUP_TRANSMETA_32 not in final .config
Requested value:  CONFIG_CPU_SUP_TRANSMETA_32=y
Actual value:     

Value requested for CONFIG_CPU_SUP_VORTEX_32 not in final .config
Requested value:  CONFIG_CPU_SUP_VORTEX_32=y
Actual value:     

Value requested for CONFIG_HPET_TIMER not in final .config
Requested value:  # CONFIG_HPET_TIMER is not set
Actual value:     CONFIG_HPET_TIMER=y

Value requested for CONFIG_NR_CPUS_RANGE_END not in final .config
Requested value:  CONFIG_NR_CPUS_RANGE_END=8
Actual value:     CONFIG_NR_CPUS_RANGE_END=512

Value requested for CONFIG_NR_CPUS_DEFAULT not in final .config
Requested value:  CONFIG_NR_CPUS_DEFAULT=8
Actual value:     CONFIG_NR_CPUS_DEFAULT=64

Value requested for CONFIG_X86_ANCIENT_MCE not in final .config
Requested value:  # CONFIG_X86_ANCIENT_MCE is not set
Actual value:     

Value requested for CONFIG_X86_LEGACY_VM86 not in final .config
Requested value:  # CONFIG_X86_LEGACY_VM86 is not set
Actual value:     

Value requested for CONFIG_X86_ESPFIX32 not in final .config
Requested value:  CONFIG_X86_ESPFIX32=y
Actual value:     

Value requested for CONFIG_TOSHIBA not in final .config
Requested value:  # CONFIG_TOSHIBA is not set
Actual value:     

Value requested for CONFIG_X86_REBOOTFIXUPS not in final .config
Requested value:  # CONFIG_X86_REBOOTFIXUPS is not set
Actual value:     

Value requested for CONFIG_MICROCODE_INITRD32 not in final .config
Requested value:  CONFIG_MICROCODE_INITRD32=y
Actual value:     

Value requested for CONFIG_NOHIGHMEM not in final .config
Requested value:  # CONFIG_NOHIGHMEM is not set
Actual value:     

Value requested for CONFIG_HIGHMEM4G not in final .config
Requested value:  CONFIG_HIGHMEM4G=y
Actual value:     

Value requested for CONFIG_HIGHMEM64G not in final .config
Requested value:  # CONFIG_HIGHMEM64G is not set
Actual value:     

Value requested for CONFIG_PAGE_OFFSET not in final .config
Requested value:  CONFIG_PAGE_OFFSET=0xC0000000
Actual value:     

Value requested for CONFIG_HIGHMEM not in final .config
Requested value:  CONFIG_HIGHMEM=y
Actual value:     

Value requested for CONFIG_X86_PAE not in final .config
Requested value:  # CONFIG_X86_PAE is not set
Actual value:     

Value requested for CONFIG_ARCH_FLATMEM_ENABLE not in final .config
Requested value:  CONFIG_ARCH_FLATMEM_ENABLE=y
Actual value:     

Value requested for CONFIG_ARCH_SELECT_MEMORY_MODEL not in final .config
Requested value:  CONFIG_ARCH_SELECT_MEMORY_MODEL=y
Actual value:     

Value requested for CONFIG_ILLEGAL_POINTER_VALUE not in final .config
Requested value:  CONFIG_ILLEGAL_POINTER_VALUE=0
Actual value:     CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000

Value requested for CONFIG_HIGHPTE not in final .config
Requested value:  # CONFIG_HIGHPTE is not set
Actual value:     

Value requested for CONFIG_COMPAT_VDSO not in final .config
Requested value:  # CONFIG_COMPAT_VDSO is not set
Actual value:     

Value requested for CONFIG_FUNCTION_PADDING_CFI not in final .config
Requested value:  CONFIG_FUNCTION_PADDING_CFI=0
Actual value:     CONFIG_FUNCTION_PADDING_CFI=11

Value requested for CONFIG_FUNCTION_PADDING_BYTES not in final .config
Requested value:  CONFIG_FUNCTION_PADDING_BYTES=4
Actual value:     CONFIG_FUNCTION_PADDING_BYTES=16

Value requested for CONFIG_APM not in final .config
Requested value:  # CONFIG_APM is not set
Actual value:     

Value requested for CONFIG_X86_POWERNOW_K6 not in final .config
Requested value:  # CONFIG_X86_POWERNOW_K6 is not set
Actual value:     

Value requested for CONFIG_X86_POWERNOW_K7 not in final .config
Requested value:  # CONFIG_X86_POWERNOW_K7 is not set
Actual value:     

Value requested for CONFIG_X86_GX_SUSPMOD not in final .config
Requested value:  # CONFIG_X86_GX_SUSPMOD is not set
Actual value:     

Value requested for CONFIG_X86_SPEEDSTEP_ICH not in final .config
Requested value:  # CONFIG_X86_SPEEDSTEP_ICH is not set
Actual value:     

Value requested for CONFIG_X86_SPEEDSTEP_SMI not in final .config
Requested value:  # CONFIG_X86_SPEEDSTEP_SMI is not set
Actual value:     

Value requested for CONFIG_X86_CPUFREQ_NFORCE2 not in final .config
Requested value:  # CONFIG_X86_CPUFREQ_NFORCE2 is not set
Actual value:     

Value requested for CONFIG_X86_LONGRUN not in final .config
Requested value:  # CONFIG_X86_LONGRUN is not set
Actual value:     

Value requested for CONFIG_X86_LONGHAUL not in final .config
Requested value:  # CONFIG_X86_LONGHAUL is not set
Actual value:     

Value requested for CONFIG_X86_E_POWERSAVER not in final .config
Requested value:  # CONFIG_X86_E_POWERSAVER is not set
Actual value:     

Value requested for CONFIG_PCI_GOBIOS not in final .config
Requested value:  # CONFIG_PCI_GOBIOS is not set
Actual value:     

Value requested for CONFIG_PCI_GOMMCONFIG not in final .config
Requested value:  # CONFIG_PCI_GOMMCONFIG is not set
Actual value:     

Value requested for CONFIG_PCI_GODIRECT not in final .config
Requested value:  # CONFIG_PCI_GODIRECT is not set
Actual value:     

Value requested for CONFIG_PCI_GOANY not in final .config
Requested value:  CONFIG_PCI_GOANY=y
Actual value:     

Value requested for CONFIG_PCI_BIOS not in final .config
Requested value:  CONFIG_PCI_BIOS=y
Actual value:     

Value requested for CONFIG_ISA not in final .config
Requested value:  # CONFIG_ISA is not set
Actual value:     

Value requested for CONFIG_SCx200 not in final .config
Requested value:  # CONFIG_SCx200 is not set
Actual value:     

Value requested for CONFIG_OLPC not in final .config
Requested value:  # CONFIG_OLPC is not set
Actual value:     

Value requested for CONFIG_ALIX not in final .config
Requested value:  # CONFIG_ALIX is not set
Actual value:     

Value requested for CONFIG_NET5501 not in final .config
Requested value:  # CONFIG_NET5501 is not set
Actual value:     

Value requested for CONFIG_GEOS not in final .config
Requested value:  # CONFIG_GEOS is not set
Actual value:     

Value requested for CONFIG_COMPAT_32 not in final .config
Requested value:  CONFIG_COMPAT_32=y
Actual value:     

Value requested for CONFIG_HAVE_ATOMIC_IOMAP not in final .config
Requested value:  CONFIG_HAVE_ATOMIC_IOMAP=y
Actual value:     

Value requested for CONFIG_ARCH_32BIT_OFF_T not in final .config
Requested value:  CONFIG_ARCH_32BIT_OFF_T=y
Actual value:     

Value requested for CONFIG_ARCH_WANT_IPC_PARSE_VERSION not in final .config
Requested value:  CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
Actual value:     

Value requested for CONFIG_MODULES_USE_ELF_REL not in final .config
Requested value:  CONFIG_MODULES_USE_ELF_REL=y
Actual value:     

Value requested for CONFIG_ARCH_MMAP_RND_BITS not in final .config
Requested value:  CONFIG_ARCH_MMAP_RND_BITS=8
Actual value:     CONFIG_ARCH_MMAP_RND_BITS=28

Value requested for CONFIG_CLONE_BACKWARDS not in final .config
Requested value:  CONFIG_CLONE_BACKWARDS=y
Actual value:     

Value requested for CONFIG_OLD_SIGSUSPEND3 not in final .config
Requested value:  CONFIG_OLD_SIGSUSPEND3=y
Actual value:     

Value requested for CONFIG_OLD_SIGACTION not in final .config
Requested value:  CONFIG_OLD_SIGACTION=y
Actual value:     

Value requested for CONFIG_ARCH_SPLIT_ARG64 not in final .config
Requested value:  CONFIG_ARCH_SPLIT_ARG64=y
Actual value:     

Value requested for CONFIG_FUNCTION_ALIGNMENT not in final .config
Requested value:  CONFIG_FUNCTION_ALIGNMENT=4
Actual value:     CONFIG_FUNCTION_ALIGNMENT=16

Value requested for CONFIG_SELECT_MEMORY_MODEL not in final .config
Requested value:  CONFIG_SELECT_MEMORY_MODEL=y
Actual value:     

Value requested for CONFIG_FLATMEM_MANUAL not in final .config
Requested value:  CONFIG_FLATMEM_MANUAL=y
Actual value:     

Value requested for CONFIG_SPARSEMEM_MANUAL not in final .config
Requested value:  # CONFIG_SPARSEMEM_MANUAL is not set
Actual value:     

Value requested for CONFIG_FLATMEM not in final .config
Requested value:  CONFIG_FLATMEM=y
Actual value:     

Value requested for CONFIG_SPARSEMEM_STATIC not in final .config
Requested value:  CONFIG_SPARSEMEM_STATIC=y
Actual value:     

Value requested for CONFIG_BOUNCE not in final .config
Requested value:  CONFIG_BOUNCE=y
Actual value:     

Value requested for CONFIG_KMAP_LOCAL not in final .config
Requested value:  CONFIG_KMAP_LOCAL=y
Actual value:     

Value requested for CONFIG_HOTPLUG_PCI_COMPAQ not in final .config
Requested value:  # CONFIG_HOTPLUG_PCI_COMPAQ is not set
Actual value:     

Value requested for CONFIG_HOTPLUG_PCI_IBM not in final .config
Requested value:  # CONFIG_HOTPLUG_PCI_IBM is not set
Actual value:     

Value requested for CONFIG_EFI_CAPSULE_QUIRK_QUARK_CSH not in final .config
Requested value:  CONFIG_EFI_CAPSULE_QUIRK_QUARK_CSH=y
Actual value:     

Value requested for CONFIG_PCH_PHUB not in final .config
Requested value:  # CONFIG_PCH_PHUB is not set
Actual value:     

Value requested for CONFIG_SCSI_NSP32 not in final .config
Requested value:  # CONFIG_SCSI_NSP32 is not set
Actual value:     

Value requested for CONFIG_PATA_CS5520 not in final .config
Requested value:  # CONFIG_PATA_CS5520 is not set
Actual value:     

Value requested for CONFIG_PATA_CS5530 not in final .config
Requested value:  # CONFIG_PATA_CS5530 is not set
Actual value:     

Value requested for CONFIG_PATA_CS5535 not in final .config
Requested value:  # CONFIG_PATA_CS5535 is not set
Actual value:     

Value requested for CONFIG_PATA_CS5536 not in final .config
Requested value:  # CONFIG_PATA_CS5536 is not set
Actual value:     

Value requested for CONFIG_PATA_SC1200 not in final .config
Requested value:  # CONFIG_PATA_SC1200 is not set
Actual value:     

Value requested for CONFIG_PCH_GBE not in final .config
Requested value:  # CONFIG_PCH_GBE is not set
Actual value:     

Value requested for CONFIG_INPUT_WISTRON_BTNS not in final .config
Requested value:  # CONFIG_INPUT_WISTRON_BTNS is not set
Actual value:     

Value requested for CONFIG_SERIAL_TIMBERDALE not in final .config
Requested value:  # CONFIG_SERIAL_TIMBERDALE is not set
Actual value:     

Value requested for CONFIG_SERIAL_PCH_UART not in final .config
Requested value:  # CONFIG_SERIAL_PCH_UART is not set
Actual value:     

Value requested for CONFIG_HW_RANDOM_GEODE not in final .config
Requested value:  CONFIG_HW_RANDOM_GEODE=y
Actual value:     

Value requested for CONFIG_SONYPI not in final .config
Requested value:  # CONFIG_SONYPI is not set
Actual value:     

Value requested for CONFIG_PC8736x_GPIO not in final .config
Requested value:  # CONFIG_PC8736x_GPIO is not set
Actual value:     

Value requested for CONFIG_NSC_GPIO not in final .config
Requested value:  # CONFIG_NSC_GPIO is not set
Actual value:     

Value requested for CONFIG_I2C_EG20T not in final .config
Requested value:  # CONFIG_I2C_EG20T is not set
Actual value:     

Value requested for CONFIG_SCx200_ACB not in final .config
Requested value:  # CONFIG_SCx200_ACB is not set
Actual value:     

Value requested for CONFIG_PTP_1588_CLOCK_PCH not in final .config
Requested value:  # CONFIG_PTP_1588_CLOCK_PCH is not set
Actual value:     

Value requested for CONFIG_SBC8360_WDT not in final .config
Requested value:  # CONFIG_SBC8360_WDT is not set
Actual value:     

Value requested for CONFIG_SBC7240_WDT not in final .config
Requested value:  # CONFIG_SBC7240_WDT is not set
Actual value:     

Value requested for CONFIG_MFD_CS5535 not in final .config
Requested value:  # CONFIG_MFD_CS5535 is not set
Actual value:     

Value requested for CONFIG_AGP_ALI not in final .config
Requested value:  # CONFIG_AGP_ALI is not set
Actual value:     

Value requested for CONFIG_AGP_ATI not in final .config
Requested value:  # CONFIG_AGP_ATI is not set
Actual value:     

Value requested for CONFIG_AGP_AMD not in final .config
Requested value:  # CONFIG_AGP_AMD is not set
Actual value:     

Value requested for CONFIG_AGP_NVIDIA not in final .config
Requested value:  # CONFIG_AGP_NVIDIA is not set
Actual value:     

Value requested for CONFIG_AGP_SWORKS not in final .config
Requested value:  # CONFIG_AGP_SWORKS is not set
Actual value:     

Value requested for CONFIG_AGP_EFFICEON not in final .config
Requested value:  # CONFIG_AGP_EFFICEON is not set
Actual value:     

Value requested for CONFIG_SND_PCM not in final .config
Requested value:  CONFIG_SND_PCM=y
Actual value:     CONFIG_SND_PCM=m

Value requested for CONFIG_SND_HWDEP not in final .config
Requested value:  CONFIG_SND_HWDEP=y
Actual value:     CONFIG_SND_HWDEP=m

Value requested for CONFIG_SND_DYNAMIC_MINORS not in final .config
Requested value:  # CONFIG_SND_DYNAMIC_MINORS is not set
Actual value:     CONFIG_SND_DYNAMIC_MINORS=y

Value requested for CONFIG_SND_CS5530 not in final .config
Requested value:  # CONFIG_SND_CS5530 is not set
Actual value:     

Value requested for CONFIG_SND_CS5535AUDIO not in final .config
Requested value:  # CONFIG_SND_CS5535AUDIO is not set
Actual value:     

Value requested for CONFIG_SND_SIS7019 not in final .config
Requested value:  # CONFIG_SND_SIS7019 is not set
Actual value:     

Value requested for CONFIG_SND_HDA not in final .config
Requested value:  CONFIG_SND_HDA=y
Actual value:     CONFIG_SND_HDA=m

Value requested for CONFIG_SND_HDA_CORE not in final .config
Requested value:  CONFIG_SND_HDA_CORE=y
Actual value:     CONFIG_SND_HDA_CORE=m

Value requested for CONFIG_SND_INTEL_DSP_CONFIG not in final .config
Requested value:  CONFIG_SND_INTEL_DSP_CONFIG=y
Actual value:     CONFIG_SND_INTEL_DSP_CONFIG=m

Value requested for CONFIG_SND_INTEL_SOUNDWIRE_ACPI not in final .config
Requested value:  CONFIG_SND_INTEL_SOUNDWIRE_ACPI=y
Actual value:     CONFIG_SND_INTEL_SOUNDWIRE_ACPI=m

Value requested for CONFIG_LEDS_OT200 not in final .config
Requested value:  # CONFIG_LEDS_OT200 is not set
Actual value:     

Value requested for CONFIG_PCH_DMA not in final .config
Requested value:  # CONFIG_PCH_DMA is not set
Actual value:     

Value requested for CONFIG_CLKSRC_I8253 not in final .config
Requested value:  CONFIG_CLKSRC_I8253=y
Actual value:     

Value requested for CONFIG_MAILBOX not in final .config
Requested value:  # CONFIG_MAILBOX is not set
Actual value:     CONFIG_MAILBOX=y

Value requested for CONFIG_CRYPTO_SERPENT_SSE2_586 not in final .config
Requested value:  # CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
Actual value:     

Value requested for CONFIG_CRYPTO_TWOFISH_586 not in final .config
Requested value:  # CONFIG_CRYPTO_TWOFISH_586 is not set
Actual value:     

Value requested for CONFIG_CRYPTO_DEV_GEODE not in final .config
Requested value:  # CONFIG_CRYPTO_DEV_GEODE is not set
Actual value:     

Value requested for CONFIG_CRYPTO_DEV_HIFN_795X not in final .config
Requested value:  # CONFIG_CRYPTO_DEV_HIFN_795X is not set
Actual value:     

Value requested for CONFIG_CRYPTO_LIB_POLY1305_RSIZE not in final .config
Requested value:  CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
Actual value:     CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11

Value requested for CONFIG_AUDIT_GENERIC not in final .config
Requested value:  CONFIG_AUDIT_GENERIC=y
Actual value:     

Value requested for CONFIG_GENERIC_VDSO_32 not in final .config
Requested value:  CONFIG_GENERIC_VDSO_32=y
Actual value:     

Value requested for CONFIG_DEBUG_KMAP_LOCAL not in final .config
Requested value:  # CONFIG_DEBUG_KMAP_LOCAL is not set
Actual value:     

Value requested for CONFIG_DEBUG_HIGHMEM not in final .config
Requested value:  # CONFIG_DEBUG_HIGHMEM is not set
Actual value:     

Value requested for CONFIG_HAVE_DEBUG_STACKOVERFLOW not in final .config
Requested value:  CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
Actual value:     

Value requested for CONFIG_DEBUG_STACKOVERFLOW not in final .config
Requested value:  # CONFIG_DEBUG_STACKOVERFLOW is not set
Actual value:     

Value requested for CONFIG_HAVE_FUNCTION_GRAPH_TRACER not in final .config
Requested value:  CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
Actual value:     

Value requested for CONFIG_HAVE_FUNCTION_GRAPH_RETVAL not in final .config
Requested value:  CONFIG_HAVE_FUNCTION_GRAPH_RETVAL=y
Actual value:     

Value requested for CONFIG_DRM_KUNIT_TEST not in final .config
Requested value:  CONFIG_DRM_KUNIT_TEST=m
Actual value:     

Value requested for CONFIG_DRM_XE_WERROR not in final .config
Requested value:  CONFIG_DRM_XE_WERROR=y
Actual value:     

Value requested for CONFIG_DRM_XE_DEBUG not in final .config
Requested value:  CONFIG_DRM_XE_DEBUG=y
Actual value:     

Value requested for CONFIG_DRM_XE_DEBUG_MEM not in final .config
Requested value:  CONFIG_DRM_XE_DEBUG_MEM=y
Actual value:     

Value requested for CONFIG_DRM_XE_KUNIT_TEST not in final .config
Requested value:  CONFIG_DRM_XE_KUNIT_TEST=m
Actual value:     

++ nproc
+ make -j48 ARCH=i386 olddefconfig
  GEN     Makefile

WARNING: unmet direct dependencies detected for FB_IOMEM_HELPERS
  Depends on [n]: HAS_IOMEM [=y] && FB_CORE [=n]
  Selected by [m]:
  - DRM_XE_DISPLAY [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_XE [=m] && DRM_XE [=m]=m [=m]
#
# configuration written to .config
#
++ nproc
+ make -j48 ARCH=i386
  SYNC    include/config/auto.conf.cmd
  GEN     Makefile

WARNING: unmet direct dependencies detected for FB_IOMEM_HELPERS
  Depends on [n]: HAS_IOMEM [=y] && FB_CORE [=n]
  Selected by [m]:
  - DRM_XE_DISPLAY [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_XE [=m] && DRM_XE [=m]=m [=m]

WARNING: unmet direct dependencies detected for FB_IOMEM_HELPERS
  Depends on [n]: HAS_IOMEM [=y] && FB_CORE [=n]
  Selected by [m]:
  - DRM_XE_DISPLAY [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_XE [=m] && DRM_XE [=m]=m [=m]

WARNING: unmet direct dependencies detected for FB_IOMEM_HELPERS
  Depends on [n]: HAS_IOMEM [=y] && FB_CORE [=n]
  Selected by [m]:
  - DRM_XE_DISPLAY [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_XE [=m] && DRM_XE [=m]=m [=m]
  GEN     Makefile
  WRAP    arch/x86/include/generated/uapi/asm/bpf_perf_event.h
  WRAP    arch/x86/include/generated/uapi/asm/errno.h
  WRAP    arch/x86/include/generated/uapi/asm/fcntl.h
  UPD     include/generated/uapi/linux/version.h
  WRAP    arch/x86/include/generated/uapi/asm/ioctl.h
  WRAP    arch/x86/include/generated/uapi/asm/ioctls.h
  WRAP    arch/x86/include/generated/uapi/asm/ipcbuf.h
  WRAP    arch/x86/include/generated/uapi/asm/param.h
  WRAP    arch/x86/include/generated/uapi/asm/poll.h
  WRAP    arch/x86/include/generated/uapi/asm/resource.h
  WRAP    arch/x86/include/generated/uapi/asm/socket.h
  WRAP    arch/x86/include/generated/uapi/asm/sockios.h
  WRAP    arch/x86/include/generated/uapi/asm/termbits.h
  WRAP    arch/x86/include/generated/uapi/asm/termios.h
  WRAP    arch/x86/include/generated/uapi/asm/types.h
  SYSHDR  arch/x86/include/generated/uapi/asm/unistd_32.h
  SYSHDR  arch/x86/include/generated/uapi/asm/unistd_64.h
  SYSHDR  arch/x86/include/generated/uapi/asm/unistd_x32.h
  SYSTBL  arch/x86/include/generated/asm/syscalls_32.h
  UPD     include/generated/compile.h
  WRAP    arch/x86/include/generated/asm/early_ioremap.h
  WRAP    arch/x86/include/generated/asm/mcs_spinlock.h
  WRAP    arch/x86/include/generated/asm/irq_regs.h
  WRAP    arch/x86/include/generated/asm/kmap_size.h
  WRAP    arch/x86/include/generated/asm/local64.h
  HOSTCC  arch/x86/tools/relocs_32.o
  HOSTCC  arch/x86/tools/relocs_64.o
  WRAP    arch/x86/include/generated/asm/mmiowb.h
  HOSTCC  arch/x86/tools/relocs_common.o
  WRAP    arch/x86/include/generated/asm/module.lds.h
  WRAP    arch/x86/include/generated/asm/unaligned.h
  WRAP    arch/x86/include/generated/asm/rwonce.h
  HOSTCC  scripts/kallsyms
  HOSTCC  scripts/sorttable
  HOSTCC  scripts/asn1_compiler
  HOSTCC  scripts/selinux/genheaders/genheaders
  HOSTCC  scripts/selinux/mdp/mdp
  HOSTLD  arch/x86/tools/relocs
  UPD     include/config/kernel.release
  UPD     include/generated/utsrelease.h
  CC      scripts/mod/empty.o
  HOSTCC  scripts/mod/mk_elfconfig
  CC      scripts/mod/devicetable-offsets.s
  UPD     scripts/mod/devicetable-offsets.h
  MKELF   scripts/mod/elfconfig.h
  HOSTCC  scripts/mod/modpost.o
  HOSTCC  scripts/mod/file2alias.o
  HOSTCC  scripts/mod/sumversion.o
  HOSTCC  scripts/mod/symsearch.o
  HOSTLD  scripts/mod/modpost
  CC      kernel/bounds.s
  CHKSHA1 /workspace/kernel/include/linux/atomic/atomic-arch-fallback.h
  CHKSHA1 /workspace/kernel/include/linux/atomic/atomic-instrumented.h
  CHKSHA1 /workspace/kernel/include/linux/atomic/atomic-long.h
  UPD     include/generated/timeconst.h
  UPD     include/generated/bounds.h
  CC      arch/x86/kernel/asm-offsets.s
  UPD     include/generated/asm-offsets.h
  CALL    /workspace/kernel/scripts/checksyscalls.sh
  LDS     scripts/module.lds
  CC      ipc/util.o
  CC      ipc/msgutil.o
  CC      init/main.o
  HOSTCC  usr/gen_init_cpio
  CC      ipc/msg.o
  CC      init/do_mounts.o
  CC      ipc/sem.o
  CC      certs/system_keyring.o
  CC      ipc/shm.o
  CC      init/do_mounts_initrd.o
  CC      ipc/syscall.o
  AS      arch/x86/lib/atomic64_cx8_32.o
  CC      security/commoncap.o
  CC      init/initramfs.o
  UPD     init/utsversion-tmp.h
  AS      arch/x86/lib/checksum_32.o
  CC      block/bdev.o
  CC      ipc/ipc_sysctl.o
  CC      io_uring/io_uring.o
  CC      init/calibrate.o
  CC      mm/filemap.o
  CC      arch/x86/realmode/init.o
  CC      block/partitions/core.o
  CC      arch/x86/power/cpu.o
  AR      arch/x86/crypto/built-in.a
  CC      arch/x86/pci/i386.o
  CC      arch/x86/video/video-common.o
  AR      drivers/cache/built-in.a
  CC      lib/math/div64.o
  AR      arch/x86/net/built-in.a
  GEN     security/selinux/flask.h security/selinux/av_permissions.h
  CC      security/keys/gc.o
  AR      virt/lib/built-in.a
  AR      sound/i2c/other/built-in.a
  AR      arch/x86/platform/atom/built-in.a
  CC      net/core/sock.o
  CC      arch/x86/mm/pat/set_memory.o
  CC      arch/x86/events/amd/core.o
  CC      fs/nfs_common/nfsacl.o
  CC      security/integrity/iint.o
  AR      sound/drivers/opl3/built-in.a
  CC      security/selinux/avc.o
  AR      sound/isa/ad1816a/built-in.a
  CC      fs/nfs_common/grace.o
  CC      sound/core/seq/seq.o
  CC      arch/x86/kernel/fpu/init.o
  AR      virt/built-in.a
  CC      fs/notify/dnotify/dnotify.o
  AR      drivers/irqchip/built-in.a
  CC      lib/crypto/mpi/generic_mpih-lshift.o
  CC      arch/x86/mm/pat/memtype.o
  AR      arch/x86/platform/ce4100/built-in.a
  AR      sound/i2c/built-in.a
  AR      sound/drivers/opl4/built-in.a
  CC      arch/x86/lib/cmdline.o
  AR      sound/isa/ad1848/built-in.a
  AR      sound/isa/cs423x/built-in.a
  CC      arch/x86/entry/vdso/vma.o
  CC      block/fops.o
  CC      arch/x86/mm/init.o
  CC      kernel/sched/core.o
  CC      arch/x86/platform/efi/memmap.o
  AR      sound/isa/es1688/built-in.a
  AR      sound/drivers/mpu401/built-in.a
  AR      drivers/bus/mhi/built-in.a
  AR      sound/isa/galaxy/built-in.a
  CC      arch/x86/events/amd/lbr.o
  AR      drivers/bus/built-in.a
  AR      sound/drivers/vx/built-in.a
  AR      sound/isa/gus/built-in.a
  CC      crypto/asymmetric_keys/asymmetric_type.o
  AR      sound/drivers/pcsp/built-in.a
  AR      sound/isa/msnd/built-in.a
  AR      drivers/pwm/built-in.a
  AR      sound/isa/opti9xx/built-in.a
  AR      sound/drivers/built-in.a
  CC      lib/math/gcd.o
  CC      drivers/pci/msi/pcidev_msi.o
  AR      sound/isa/sb/built-in.a
  AR      sound/isa/wavefront/built-in.a
  CC      crypto/api.o
  AS      arch/x86/lib/cmpxchg8b_emu.o
  AR      sound/isa/wss/built-in.a
  CC      arch/x86/lib/cpu.o
  AR      sound/isa/built-in.a
  CC      lib/math/lcm.o
  CC      block/bio.o
  CC      lib/math/int_log.o
  CC      arch/x86/events/amd/ibs.o
  GEN     usr/initramfs_data.cpio
  COPY    usr/initramfs_inc_data
  AS      usr/initramfs_data.o
  AR      usr/built-in.a
  HOSTCC  certs/extract-cert
  CC      arch/x86/mm/init_32.o
  CC      arch/x86/kernel/fpu/bugs.o
  CC      lib/math/int_pow.o
  CC      lib/math/int_sqrt.o
  CC      arch/x86/kernel/fpu/core.o
  CC      ipc/mqueue.o
  CC      lib/math/reciprocal_div.o
  CC      sound/core/seq/seq_lock.o
  AS      arch/x86/realmode/rm/header.o
  AR      arch/x86/video/built-in.a
  AS      arch/x86/realmode/rm/trampoline_32.o
  CC      lib/crypto/mpi/generic_mpih-mul1.o
  CC      arch/x86/lib/delay.o
  CC      kernel/locking/mutex.o
  AS      arch/x86/realmode/rm/stack.o
  CERT    certs/x509_certificate_list
  CERT    certs/signing_key.x509
  AS      certs/system_certificates.o
  AS      arch/x86/realmode/rm/reboot.o
  CC      lib/math/rational.o
  AR      certs/built-in.a
  AS      arch/x86/realmode/rm/wakeup_asm.o
  CC      kernel/locking/semaphore.o
  CC      lib/crypto/mpi/generic_mpih-mul2.o
  CC      arch/x86/realmode/rm/wakemain.o
  CC      lib/crypto/memneq.o
  CC      security/integrity/integrity_audit.o
  CC      kernel/locking/rwsem.o
  CC      arch/x86/pci/init.o
  AR      fs/nfs_common/built-in.a
  CC      kernel/locking/percpu-rwsem.o
  CC      arch/x86/kernel/fpu/regset.o
  CC      security/keys/key.o
  CC      drivers/pci/msi/api.o
  AR      fs/notify/dnotify/built-in.a
  CC      arch/x86/realmode/rm/video-mode.o
  CC      arch/x86/entry/vdso/extable.o
  CC      crypto/asymmetric_keys/restrict.o
  CC      fs/notify/inotify/inotify_fsnotify.o
  CC      arch/x86/power/hibernate_32.o
  CC      arch/x86/platform/efi/quirks.o
  CC      security/keys/keyring.o
  AS      arch/x86/lib/getuser.o
  AS      arch/x86/realmode/rm/copy.o
  CC      arch/x86/kernel/fpu/signal.o
  CC      block/partitions/msdos.o
  GEN     arch/x86/lib/inat-tables.c
  AS      arch/x86/realmode/rm/bioscall.o
  CC      sound/core/seq/seq_clientmgr.o
  CC      arch/x86/realmode/rm/regs.o
  CC      arch/x86/kernel/fpu/xstate.o
  AR      lib/math/built-in.a
  CC      arch/x86/events/amd/uncore.o
  CC      arch/x86/lib/insn-eval.o
  CC      lib/crypto/mpi/generic_mpih-mul3.o
  CC      arch/x86/pci/pcbios.o
  CC      arch/x86/realmode/rm/video-vga.o
  CC      net/core/request_sock.o
  CC      block/partitions/efi.o
  CC      lib/crypto/utils.o
  CC      init/init_task.o
  AR      arch/x86/platform/geode/built-in.a
  CC      arch/x86/realmode/rm/video-vesa.o
  CC      drivers/pci/pcie/portdrv.o
  CC      drivers/pci/hotplug/pci_hotplug_core.o
  AR      arch/x86/platform/iris/built-in.a
  CC      drivers/pci/hotplug/acpi_pcihp.o
  CC      kernel/sched/fair.o
  CC      ipc/namespace.o
  CC      kernel/sched/build_policy.o
  CC      crypto/asymmetric_keys/signature.o
  CC      arch/x86/realmode/rm/video-bios.o
  CC      block/elevator.o
  CC      lib/crypto/mpi/generic_mpih-rshift.o
  CC      arch/x86/mm/pat/memtype_interval.o
  PASYMS  arch/x86/realmode/rm/pasyms.h
  CC      fs/notify/inotify/inotify_user.o
  LDS     arch/x86/realmode/rm/realmode.lds
  LDS     arch/x86/entry/vdso/vdso32/vdso32.lds
  LD      arch/x86/realmode/rm/realmode.elf
  CC      security/selinux/hooks.o
  RELOCS  arch/x86/realmode/rm/realmode.relocs
  CC      crypto/asymmetric_keys/public_key.o
  OBJCOPY arch/x86/realmode/rm/realmode.bin
  CC      kernel/locking/spinlock.o
  AS      arch/x86/realmode/rmpiggy.o
  AR      arch/x86/realmode/built-in.a
  CC      kernel/locking/osq_lock.o
  CC      arch/x86/pci/mmconfig_32.o
  CC      drivers/pci/msi/msi.o
  CC      block/blk-core.o
  AS      arch/x86/entry/vdso/vdso32/note.o
  AR      security/integrity/built-in.a
  CC      block/blk-sysfs.o
  AS      arch/x86/power/hibernate_asm_32.o
  AR      arch/x86/virt/svm/built-in.a
  AS      arch/x86/entry/vdso/vdso32/system_call.o
  CC      arch/x86/power/hibernate.o
  CC      init/version.o
  AR      arch/x86/virt/vmx/built-in.a
  AS      arch/x86/entry/vdso/vdso32/sigreturn.o
  AR      arch/x86/virt/built-in.a
  AR      sound/pci/ac97/built-in.a
  CC      arch/x86/entry/vdso/vdso32/vclock_gettime.o
  AR      sound/pci/ali5451/built-in.a
  CC      ipc/mq_sysctl.o
  AR      sound/pci/asihpi/built-in.a
  AR      sound/pci/au88x0/built-in.a
  CC      security/selinux/selinuxfs.o
  AR      sound/ppc/built-in.a
  CC      security/lsm_syscalls.o
  AR      sound/pci/aw2/built-in.a
  ASN.1   crypto/asymmetric_keys/x509.asn1.[ch]
  CC      kernel/locking/qspinlock.o
  AR      sound/pci/ctxfi/built-in.a
  AR      sound/pci/ca0106/built-in.a
  AR      sound/pci/cs46xx/built-in.a
  AR      sound/pci/cs5535audio/built-in.a
  CC      kernel/locking/rtmutex_api.o
  AR      sound/pci/lola/built-in.a
  AR      sound/pci/lx6464es/built-in.a
  AR      sound/pci/echoaudio/built-in.a
  CC      arch/x86/kernel/cpu/mce/core.o
  CC      arch/x86/kernel/acpi/boot.o
  AR      sound/pci/emu10k1/built-in.a
  CC      arch/x86/platform/efi/efi.o
  CC      kernel/locking/qrwlock.o
  AR      sound/pci/hda/built-in.a
  CC      arch/x86/kernel/acpi/sleep.o
  ASN.1   crypto/asymmetric_keys/x509_akid.asn1.[ch]
  CC      crypto/asymmetric_keys/x509_loader.o
  CC [M]  sound/pci/hda/hda_bind.o
  CC      crypto/asymmetric_keys/x509_public_key.o
  CC      arch/x86/platform/efi/efi_32.o
  AR      init/built-in.a
  AS      arch/x86/platform/efi/efi_stub_32.o
  CC [M]  sound/pci/hda/hda_codec.o
  CC [M]  sound/pci/hda/hda_jack.o
  CC      arch/x86/lib/insn.o
  CC      crypto/cipher.o
  CC      lib/crypto/mpi/generic_mpih-sub1.o
  CC      arch/x86/kernel/cpu/mtrr/mtrr.o
  CC      drivers/pci/pcie/rcec.o
  CC      arch/x86/kernel/apic/apic.o
  AR      arch/x86/mm/pat/built-in.a
  CC      arch/x86/mm/fault.o
  CC      arch/x86/kernel/apic/apic_common.o
  CC      net/core/skbuff.o
  AR      drivers/pci/hotplug/built-in.a
  CC [M]  sound/pci/hda/hda_auto_parser.o
  CC      arch/x86/kernel/apic/apic_noop.o
  AR      ipc/built-in.a
  CC      arch/x86/kernel/cpu/mtrr/if.o
  AR      fs/notify/fanotify/built-in.a
  AR      block/partitions/built-in.a
  CC      fs/notify/fsnotify.o
  CC      security/keys/keyctl.o
  CC      arch/x86/platform/intel/iosf_mbi.o
  AR      arch/x86/events/amd/built-in.a
  CC      arch/x86/pci/direct.o
  CC      arch/x86/events/intel/core.o
  CC      arch/x86/pci/mmconfig-shared.o
  AR      drivers/pci/controller/dwc/built-in.a
  CC      arch/x86/lib/kaslr.o
  AR      arch/x86/kernel/fpu/built-in.a
  AR      drivers/pci/controller/mobiveil/built-in.a
  CC      arch/x86/pci/fixup.o
  AR      drivers/pci/controller/built-in.a
  CC      arch/x86/lib/memcpy_32.o
  CC      sound/core/seq/seq_memory.o
  CC      security/selinux/netlink.o
  AR      arch/x86/power/built-in.a
  CC      crypto/compress.o
  CC      arch/x86/entry/vdso/vdso32/vgetcpu.o
  AR      fs/notify/inotify/built-in.a
  CC      arch/x86/kernel/kprobes/core.o
  LDS     arch/x86/kernel/vmlinux.lds
  CC      arch/x86/kernel/kprobes/opt.o
  AS      arch/x86/kernel/head_32.o
  HOSTCC  arch/x86/entry/vdso/vdso2c
  ASN.1   crypto/asymmetric_keys/pkcs7.asn1.[ch]
  CC      lib/crypto/chacha.o
  CC      crypto/asymmetric_keys/pkcs7_trust.o
  AS      arch/x86/lib/memmove_32.o
  CC      drivers/pci/msi/irqdomain.o
  CC      arch/x86/lib/misc.o
  CC      arch/x86/lib/pc-conf-reg.o
  CC      lib/crypto/mpi/generic_mpih-add1.o
  CC      security/min_addr.o
  CC      arch/x86/kernel/cpu/mtrr/generic.o
  CC      arch/x86/kernel/cpu/mtrr/cleanup.o
  CC      arch/x86/pci/acpi.o
  CC      crypto/algapi.o
  CC      arch/x86/entry/vdso/vdso32-setup.o
  CC      lib/crypto/mpi/ec.o
  CC [M]  sound/pci/hda/hda_sysfs.o
  CC      arch/x86/kernel/apic/ipi.o
  CC      drivers/pci/pcie/aspm.o
  AS      arch/x86/lib/putuser.o
  CC      security/keys/permission.o
  AS      arch/x86/lib/retpoline.o
  AR      kernel/locking/built-in.a
  CC      drivers/pci/pcie/pme.o
  CC      security/keys/process_keys.o
  CC      arch/x86/lib/string_32.o
  CC      arch/x86/lib/strstr_32.o
  CC      arch/x86/kernel/cpu/mtrr/amd.o
  CC      arch/x86/platform/efi/runtime-map.o
  CC      crypto/asymmetric_keys/pkcs7_verify.o
  AR      arch/x86/platform/intel/built-in.a
  CC      arch/x86/lib/usercopy.o
  CC      arch/x86/kernel/cpu/mtrr/cyrix.o
  CC      block/blk-flush.o
  CC [M]  sound/pci/hda/hda_controller.o
  VDSO    arch/x86/entry/vdso/vdso32.so.dbg
  AS      arch/x86/kernel/acpi/wakeup_32.o
  OBJCOPY arch/x86/entry/vdso/vdso32.so
  VDSO2C  arch/x86/entry/vdso/vdso-image-32.c
  CC      arch/x86/entry/vdso/vdso-image-32.o
  CC      arch/x86/kernel/acpi/cstate.o
  AR      arch/x86/platform/intel-mid/built-in.a
  CC      fs/notify/notification.o
  CC      crypto/scatterwalk.o
  CC      mm/mempool.o
  CC      net/core/datagram.o
  CC      lib/crypto/mpi/mpicoder.o
  CC [M]  sound/pci/hda/hda_proc.o
  CC      mm/oom_kill.o
  CC      arch/x86/pci/legacy.o
  CC      sound/core/seq/seq_queue.o
  CC      arch/x86/lib/usercopy_32.o
  CC      arch/x86/kernel/apic/vector.o
  CC      net/core/stream.o
  CC      arch/x86/pci/irq.o
  CC      security/security.o
  AR      arch/x86/entry/vdso/built-in.a
  AR      arch/x86/entry/vsyscall/built-in.a
  AS      arch/x86/entry/entry.o
  CC      arch/x86/pci/common.o
  AR      drivers/pci/msi/built-in.a
  CC      mm/fadvise.o
  CC      crypto/asymmetric_keys/x509.asn1.o
  CC      arch/x86/mm/ioremap.o
  CC      security/selinux/nlmsgtab.o
  CC      arch/x86/lib/msr-smp.o
  AS      arch/x86/entry/entry_32.o
  CC      crypto/asymmetric_keys/x509_akid.asn1.o
  AR      arch/x86/kernel/kprobes/built-in.a
  CC      security/keys/request_key.o
  CC      crypto/asymmetric_keys/x509_cert_parser.o
  CC      security/keys/request_key_auth.o
  CC      arch/x86/entry/syscall_32.o
  CC      crypto/proc.o
  CC      lib/crypto/mpi/mpi-add.o
  CC      arch/x86/kernel/cpu/mce/severity.o
  CC      crypto/asymmetric_keys/pkcs7.asn1.o
  CC      net/core/scm.o
  CC      io_uring/opdef.o
  CC      net/core/gen_stats.o
  CC      arch/x86/kernel/cpu/mtrr/centaur.o
  CC      arch/x86/kernel/cpu/mce/genpool.o
  AR      arch/x86/kernel/acpi/built-in.a
  CC      arch/x86/kernel/head32.o
  CC      arch/x86/lib/cache-smp.o
  AR      drivers/pci/switch/built-in.a
  AR      arch/x86/platform/efi/built-in.a
  CC      crypto/aead.o
  AR      arch/x86/platform/intel-quark/built-in.a
  AR      arch/x86/platform/olpc/built-in.a
  CC      drivers/pci/access.o
  CC      fs/notify/group.o
  AR      arch/x86/platform/scx200/built-in.a
  AR      arch/x86/platform/ts5500/built-in.a
  AR      arch/x86/platform/uv/built-in.a
  CC      fs/notify/mark.o
  AR      arch/x86/platform/built-in.a
  CC      lib/zlib_inflate/inffast.o
  CC      lib/zlib_deflate/deflate.o
  CC      io_uring/kbuf.o
  CC      arch/x86/lib/msr.o
  CC      block/blk-settings.o
  CC      io_uring/rsrc.o
  CC      block/blk-ioc.o
  AR      sound/arm/built-in.a
  CC      mm/maccess.o
  AR      sound/sh/built-in.a
  AR      drivers/pci/pcie/built-in.a
  CC      arch/x86/kernel/apic/init.o
  CC      drivers/pci/bus.o
  CC      crypto/asymmetric_keys/pkcs7_parser.o
  CC      drivers/pci/probe.o
  CC      lib/zlib_inflate/inflate.o
  CC [M]  sound/pci/hda/hda_hwdep.o
  CC      sound/core/seq/seq_fifo.o
  CC      arch/x86/kernel/cpu/mce/intel.o
  CC      fs/iomap/trace.o
  CC      lib/crypto/mpi/mpi-bit.o
  CC      fs/iomap/iter.o
  CC      arch/x86/mm/extable.o
  CC      sound/core/seq/seq_prioq.o
  CC      arch/x86/kernel/cpu/mtrr/legacy.o
  CC      arch/x86/kernel/ebda.o
  CC      mm/page-writeback.o
  CC      security/keys/user_defined.o
  CC      lib/zlib_deflate/deftree.o
  CC      io_uring/notif.o
  CC      arch/x86/events/intel/bts.o
  CC      arch/x86/events/zhaoxin/core.o
  CC      arch/x86/events/core.o
  CC      arch/x86/events/probe.o
  CC      arch/x86/pci/early.o
  CC      io_uring/tctx.o
  CC      fs/notify/fdinfo.o
  AR      crypto/asymmetric_keys/built-in.a
  CC      crypto/geniv.o
  CC      security/selinux/netif.o
  AR      arch/x86/kernel/cpu/mtrr/built-in.a
  CC      security/keys/proc.o
  CC      lib/zlib_deflate/deflate_syms.o
  CC      mm/folio-compat.o
  CC      lib/zlib_inflate/infutil.o
  CC      lib/zlib_inflate/inftrees.o
  CC      arch/x86/entry/common.o
  CC      arch/x86/kernel/cpu/mce/amd.o
  AS      arch/x86/entry/thunk.o
  CC      arch/x86/kernel/apic/hw_nmi.o
  CC      arch/x86/kernel/cpu/mce/threshold.o
  AS      arch/x86/lib/msr-reg.o
  CC [M]  sound/pci/hda/patch_hdmi.o
  CC      arch/x86/lib/msr-reg-export.o
  CC      arch/x86/kernel/apic/io_apic.o
  CC      crypto/lskcipher.o
  CC      arch/x86/kernel/cpu/microcode/core.o
  CC      arch/x86/kernel/cpu/cacheinfo.o
  AR      sound/synth/emux/built-in.a
  AR      sound/synth/built-in.a
  CC      security/lsm_audit.o
  CC      lib/crypto/mpi/mpi-cmp.o
  CC      lib/crypto/mpi/mpi-sub-ui.o
  CC      block/blk-map.o
  CC      lib/crypto/aes.o
  CC      crypto/skcipher.o
  CC      arch/x86/kernel/platform-quirks.o
  CC      sound/core/seq/seq_timer.o
  CC      drivers/pci/host-bridge.o
  CC      arch/x86/kernel/cpu/microcode/intel.o
  CC      block/blk-merge.o
  AS      arch/x86/lib/hweight.o
  CC      arch/x86/lib/iomem.o
  AR      lib/zlib_deflate/built-in.a
  CC      security/device_cgroup.o
  CC      lib/zlib_inflate/inflate_syms.o
  CC      arch/x86/kernel/cpu/microcode/amd.o
  CC      arch/x86/mm/mmap.o
  CC [M]  sound/pci/hda/hda_eld.o
  CC      fs/quota/dquot.o
  CC      fs/proc/task_mmu.o
  CC      arch/x86/pci/bus_numa.o
  AR      fs/notify/built-in.a
  CC      fs/proc/inode.o
  CC      fs/quota/quota_v2.o
  CC      fs/quota/quota_tree.o
  CC      fs/kernfs/mount.o
  CC      arch/x86/events/intel/ds.o
  CC      security/keys/sysctl.o
  AR      arch/x86/events/zhaoxin/built-in.a
  CC      fs/sysfs/file.o
  CC      fs/kernfs/inode.o
  CC      fs/iomap/buffered-io.o
  CC      fs/sysfs/dir.o
  AR      lib/zlib_inflate/built-in.a
  CC      arch/x86/lib/atomic64_32.o
  CC      fs/sysfs/symlink.o
  CC      fs/kernfs/dir.o
  CC      lib/crypto/mpi/mpi-div.o
  CC      lib/crypto/mpi/mpi-inv.o
  CC      arch/x86/lib/inat.o
  CC      fs/sysfs/mount.o
  CC      lib/lzo/lzo1x_compress.o
  AR      arch/x86/entry/built-in.a
  CC      lib/crypto/arc4.o
  CC      lib/lzo/lzo1x_decompress_safe.o
  CC      io_uring/filetable.o
  CC      io_uring/rw.o
  CC      lib/lz4/lz4_decompress.o
  CC      drivers/pci/remove.o
  CC      sound/core/seq/seq_system.o
  AR      arch/x86/lib/built-in.a
  CC      kernel/sched/build_utility.o
  AR      arch/x86/lib/lib.a
  CC      arch/x86/mm/pgtable.o
  CC      lib/zstd/zstd_decompress_module.o
  CC      fs/sysfs/group.o
  CC      security/selinux/netnode.o
  CC      fs/proc/root.o
  CC      arch/x86/pci/amd_bus.o
  AR      arch/x86/kernel/cpu/microcode/built-in.a
  CC      arch/x86/kernel/cpu/scattered.o
  CC      block/blk-timeout.o
  CC      security/keys/keyctl_pkey.o
  CC      block/blk-lib.o
  CC      arch/x86/mm/physaddr.o
  CC      arch/x86/mm/tlb.o
  CC      drivers/pci/pci.o
  CC      drivers/pci/pci-driver.o
  CC      fs/proc/base.o
  CC      lib/zstd/decompress/huf_decompress.o
  CC      crypto/seqiv.o
  CC      crypto/echainiv.o
  CC      lib/crypto/mpi/mpi-mod.o
  CC      security/selinux/netport.o
  AR      lib/lzo/built-in.a
  CC      lib/crypto/mpi/mpi-mul.o
  CC      lib/crypto/mpi/mpih-cmp.o
  CC      crypto/ahash.o
  CC      fs/proc/generic.o
  CC      lib/xz/xz_dec_syms.o
  CC      lib/crypto/mpi/mpih-div.o
  CC      lib/crypto/mpi/mpih-mul.o
  CC      lib/xz/xz_dec_stream.o
  CC      lib/crypto/mpi/mpi-pow.o
  CC      sound/core/seq/seq_ports.o
  CC      lib/crypto/mpi/mpiutil.o
  AR      arch/x86/kernel/cpu/mce/built-in.a
  CC      mm/readahead.o
  CC      net/ethernet/eth.o
  CC      drivers/pci/search.o
  CC      arch/x86/kernel/cpu/topology_common.o
  CC      lib/xz/xz_dec_lzma2.o
  CC      lib/crypto/gf128mul.o
  CC      crypto/shash.o
  AR      fs/sysfs/built-in.a
  CC      io_uring/net.o
  CC      arch/x86/kernel/apic/msi.o
  CC      arch/x86/mm/cpu_entry_area.o
  CC      lib/xz/xz_dec_bcj.o
  CC      arch/x86/kernel/apic/probe_32.o
  AR      security/keys/built-in.a
  CC      io_uring/poll.o
  CC      fs/kernfs/file.o
  AR      arch/x86/pci/built-in.a
  CC      fs/proc/array.o
  CC      net/core/gen_estimator.o
  CC      arch/x86/mm/maccess.o
  CC      crypto/akcipher.o
  CC      block/blk-mq.o
  CC      arch/x86/mm/pgprot.o
  CC      crypto/sig.o
  CC      arch/x86/events/intel/knc.o
  CC      block/blk-mq-tag.o
  CC      fs/devpts/inode.o
  CC      block/blk-stat.o
  CC [M]  sound/pci/hda/hda_intel.o
  CC      block/blk-mq-sysfs.o
  AR      lib/lz4/built-in.a
  CC      arch/x86/kernel/cpu/topology_ext.o
  CC      mm/swap.o
  CC      arch/x86/kernel/cpu/topology_amd.o
  CC      arch/x86/events/utils.o
  CC      fs/quota/quota.o
  CC      mm/truncate.o
  CC      lib/crypto/blake2s.o
  AR      lib/crypto/mpi/built-in.a
  CC      lib/zstd/decompress/zstd_ddict.o
  CC      lib/zstd/decompress/zstd_decompress.o
  CC      lib/dim/dim.o
  CC      security/selinux/status.o
  AR      sound/pci/ice1712/built-in.a
  CC      lib/crypto/blake2s-generic.o
  CC      sound/core/seq/seq_info.o
  CC      fs/netfs/buffered_read.o
  AR      lib/xz/built-in.a
  CC      lib/crypto/sha1.o
  CC      drivers/pci/rom.o
  CC      arch/x86/events/intel/lbr.o
  CC      fs/netfs/buffered_write.o
  CC      io_uring/uring_cmd.o
  CC      arch/x86/events/rapl.o
  CC      arch/x86/kernel/cpu/common.o
  CC      lib/crypto/sha256.o
  CC      fs/netfs/direct_read.o
  CC      security/selinux/ss/ebitmap.o
  CC      arch/x86/mm/pgtable_32.o
  AR      arch/x86/kernel/apic/built-in.a
  CC      arch/x86/events/msr.o
  CC      security/selinux/ss/hashtab.o
  CC      drivers/pci/setup-res.o
  CC      arch/x86/events/intel/p4.o
  CC      mm/vmscan.o
  CC      fs/ext4/balloc.o
  CC      lib/dim/net_dim.o
  CC      fs/jbd2/transaction.o
  CC      fs/iomap/direct-io.o
  CC      fs/jbd2/commit.o
  CC      fs/ramfs/inode.o
  CC      fs/jbd2/recovery.o
  CC      kernel/power/qos.o
  CC      crypto/kpp.o
  CC      kernel/power/main.o
  AR      fs/devpts/built-in.a
  CC      sound/core/seq/seq_dummy.o
  CC      fs/ext4/bitmap.o
  CC      block/blk-mq-cpumap.o
  CC      arch/x86/events/intel/p6.o
  CC      fs/kernfs/symlink.o
  CC      net/core/net_namespace.o
  AR      net/ethernet/built-in.a
  ASN.1   crypto/rsapubkey.asn1.[ch]
  CC      security/selinux/ss/symtab.o
  AR      net/802/built-in.a
  CC      net/sched/sch_generic.o
  CC      fs/ext4/block_validity.o
  CC      net/sched/sch_mq.o
  CC      fs/proc/fd.o
  AR      lib/crypto/built-in.a
  CC      fs/ramfs/file-mmu.o
  CC      lib/fonts/fonts.o
  CC      lib/zstd/decompress/zstd_decompress_block.o
  CC      lib/dim/rdma_dim.o
  CC      lib/fonts/font_8x16.o
  CC      fs/proc/proc_tty.o
  CC      arch/x86/mm/iomap_32.o
  CC      fs/hugetlbfs/inode.o
  CC      block/blk-mq-sched.o
  CC      drivers/pci/irq.o
  CC      block/ioctl.o
  CC      mm/shrinker.o
  CC      fs/quota/kqid.o
  CC      block/genhd.o
  CC      kernel/power/console.o
  AR      sound/core/seq/built-in.a
  CC      sound/core/sound.o
  AR      lib/dim/built-in.a
  CC      io_uring/openclose.o
  CC      lib/argv_split.o
  CC      block/ioprio.o
  CC      fs/netfs/direct_write.o
  CC      block/badblocks.o
  LD [M]  sound/pci/hda/snd-hda-codec.o
  LD [M]  sound/pci/hda/snd-hda-codec-hdmi.o
  CC      fs/netfs/io.o
  LD [M]  sound/pci/hda/snd-hda-intel.o
  AR      lib/fonts/built-in.a
  CC      io_uring/sqpoll.o
  AR      sound/pci/korg1212/built-in.a
  CC      io_uring/xattr.o
  AR      sound/pci/mixart/built-in.a
  AR      sound/pci/nm256/built-in.a
  ASN.1   crypto/rsaprivkey.asn1.[ch]
  CC      lib/bug.o
  CC      crypto/rsa.o
  CC      mm/shmem.o
  AR      sound/pci/oxygen/built-in.a
  AR      fs/kernfs/built-in.a
  AR      sound/pci/pcxhr/built-in.a
  CC      mm/util.o
  CC      mm/mmzone.o
  AR      sound/pci/riptide/built-in.a
  CC      arch/x86/events/intel/pt.o
  AR      sound/pci/rme9652/built-in.a
  CC      fs/ext4/dir.o
  CC      security/selinux/ss/sidtab.o
  CC      drivers/pci/vpd.o
  AR      sound/pci/trident/built-in.a
  AR      fs/ramfs/built-in.a
  AR      sound/pci/ymfpci/built-in.a
  CC      fs/quota/netlink.o
  AR      sound/pci/vx222/built-in.a
  AR      sound/pci/built-in.a
  CC      arch/x86/mm/hugetlbpage.o
  CC      fs/iomap/fiemap.o
  AR      sound/usb/misc/built-in.a
  CC      fs/jbd2/checkpoint.o
  AR      sound/usb/usx2y/built-in.a
  CC      lib/zstd/zstd_common_module.o
  CC      fs/proc/cmdline.o
  AR      sound/usb/caiaq/built-in.a
  CC      fs/jbd2/revoke.o
  CC      fs/proc/consoles.o
  CC      fs/jbd2/journal.o
  AR      sound/usb/6fire/built-in.a
  CC      fs/netfs/iterator.o
  CC      arch/x86/kernel/cpu/rdrand.o
  AR      sound/usb/hiface/built-in.a
  AR      sound/usb/bcd2000/built-in.a
  CC      fs/netfs/locking.o
  AR      sound/usb/built-in.a
  CC      fs/ext4/ext4_jbd2.o
  CC      arch/x86/events/intel/uncore.o
  CC      arch/x86/kernel/cpu/match.o
  CC      net/netlink/af_netlink.o
  CC      arch/x86/kernel/process_32.o
  CC      sound/core/init.o
  CC      kernel/power/process.o
  CC      fs/fat/cache.o
  CC      arch/x86/kernel/cpu/bugs.o
  CC      arch/x86/kernel/signal.o
  CC      lib/zstd/common/debug.o
  CC      fs/isofs/namei.o
  CC      lib/buildid.o
  CC      fs/isofs/inode.o
  CC      crypto/rsa_helper.o
  CC      fs/isofs/dir.o
  CC      net/core/secure_seq.o
  CC      fs/isofs/util.o
  CC      fs/nfs/client.o
  CC      fs/proc/cpuinfo.o
  CC      fs/nfs/dir.o
  CC      crypto/rsa-pkcs1pad.o
  CC      drivers/pci/setup-bus.o
  CC      arch/x86/mm/dump_pagetables.o
  CC      lib/clz_tab.o
  CC      drivers/pci/vc.o
  AR      fs/hugetlbfs/built-in.a
  CC      lib/cmdline.o
  AR      fs/quota/built-in.a
  CC      fs/ext4/extents.o
  CC      fs/netfs/main.o
  CC      fs/iomap/seek.o
  CC      io_uring/nop.o
  CC      fs/iomap/swapfile.o
  AR      kernel/sched/built-in.a
  CC      io_uring/fs.o
  CC      fs/proc/devices.o
  CC      fs/proc/interrupts.o
  CC      net/sched/sch_frag.o
  CC      net/sched/sch_api.o
  CC      fs/ext4/extents_status.o
  CC      io_uring/splice.o
  CC      drivers/pci/mmap.o
  CC      fs/netfs/misc.o
  CC      fs/netfs/objects.o
  CC      fs/fat/dir.o
  CC      kernel/printk/printk.o
  CC      kernel/printk/printk_safe.o
  CC      lib/cpumask.o
  CC      security/selinux/ss/avtab.o
  CC      kernel/printk/nbcon.o
  CC      fs/isofs/rock.o
  CC      arch/x86/kernel/signal_32.o
  CC      kernel/printk/printk_ringbuffer.o
  CC      fs/ext4/file.o
  CC      sound/core/memory.o
  CC      crypto/acompress.o
  CC      net/sched/sch_blackhole.o
  CC      lib/ctype.o
  CC      lib/zstd/common/entropy_common.o
  CC      lib/dec_and_lock.o
  CC      fs/proc/loadavg.o
  CC      io_uring/sync.o
  CC      arch/x86/mm/highmem_32.o
  CC      kernel/rcu/update.o
  CC      kernel/irq/irqdesc.o
  CC      kernel/power/suspend.o
  AR      kernel/livepatch/built-in.a
  CC      kernel/rcu/sync.o
  CC      lib/zstd/common/error_private.o
  AR      fs/iomap/built-in.a
  CC      io_uring/msg_ring.o
  CC      kernel/power/hibernate.o
  CC      lib/zstd/common/fse_decompress.o
  CC      block/blk-rq-qos.o
  CC      fs/exportfs/expfs.o
  CC      block/disk-events.o
  CC      kernel/printk/sysctl.o
  CC      arch/x86/events/intel/uncore_nhmex.o
  CC      kernel/irq/handle.o
  CC      kernel/power/snapshot.o
  CC      drivers/pci/devres.o
  CC      io_uring/advise.o
  CC      kernel/rcu/srcutree.o
  CC      net/core/flow_dissector.o
  CC      arch/x86/kernel/traps.o
  CC      arch/x86/kernel/idt.o
  CC      crypto/scompress.o
  CC      fs/netfs/write_collect.o
  CC      fs/lockd/clntlock.o
  CC      sound/core/control.o
  CC      fs/proc/meminfo.o
  CC      fs/lockd/clntproc.o
  CC      arch/x86/kernel/cpu/aperfmperf.o
  CC      net/sched/cls_api.o
  AR      arch/x86/mm/built-in.a
  CC      fs/isofs/export.o
  CC      kernel/power/swap.o
  CC      fs/ext4/fsmap.o
  CC      fs/isofs/joliet.o
  CC      fs/lockd/clntxdr.o
  CC      lib/zstd/common/zstd_common.o
  CC      mm/vmstat.o
  CC      fs/nls/nls_base.o
  CC      io_uring/epoll.o
  CC      fs/nls/nls_cp437.o
  CC      net/sched/act_api.o
  CC      net/sched/sch_fifo.o
  AR      lib/zstd/built-in.a
  AR      fs/exportfs/built-in.a
  CC      lib/decompress.o
  CC      kernel/irq/manage.o
  CC      fs/nfs/file.o
  CC      lib/decompress_bunzip2.o
  CC      security/selinux/ss/policydb.o
  AR      fs/unicode/built-in.a
  CC      fs/autofs/init.o
  CC      kernel/irq/spurious.o
  CC      fs/autofs/inode.o
  CC      mm/backing-dev.o
  CC      block/blk-ia-ranges.o
  CC      lib/decompress_inflate.o
  CC      fs/fat/fatent.o
  CC      drivers/pci/proc.o
  CC      fs/nls/nls_ascii.o
  CC      crypto/algboss.o
  CC      security/selinux/ss/services.o
  AR      fs/jbd2/built-in.a
  CC      lib/decompress_unlz4.o
  CC      net/netlink/genetlink.o
  CC      fs/9p/vfs_super.o
  CC      lib/decompress_unlzma.o
  CC      fs/proc/stat.o
  CC      arch/x86/kernel/cpu/cpuid-deps.o
  CC      fs/autofs/root.o
  CC      net/netlink/policy.o
  CC      fs/isofs/compress.o
  CC      arch/x86/events/intel/uncore_snb.o
  CC      arch/x86/kernel/irq.o
  CC      net/sched/cls_cgroup.o
  CC      kernel/irq/resend.o
  CC      fs/nls/nls_iso8859-1.o
  CC      kernel/power/user.o
  CC      kernel/rcu/tree.o
  CC      crypto/testmgr.o
  CC      kernel/rcu/rcu_segcblist.o
  CC      io_uring/statx.o
  CC      net/sched/ematch.o
  CC      kernel/power/poweroff.o
  CC      arch/x86/kernel/cpu/umwait.o
  AR      kernel/printk/built-in.a
  MKCAP   arch/x86/kernel/cpu/capflags.c
  CC      arch/x86/events/intel/uncore_snbep.o
  CC      drivers/pci/pci-sysfs.o
  CC      drivers/pci/slot.o
  CC      kernel/dma/mapping.o
  CC      block/early-lookup.o
  CC      sound/core/misc.o
  CC      kernel/dma/direct.o
  CC      fs/netfs/write_issue.o
  CC      fs/proc/uptime.o
  CC      kernel/dma/ops_helpers.o
  CC      fs/nls/nls_utf8.o
  CC      fs/lockd/host.o
  CC      fs/9p/vfs_inode.o
  AR      net/bpf/built-in.a
  CC      fs/9p/vfs_inode_dotl.o
  CC      arch/x86/kernel/irq_32.o
  CC      kernel/entry/common.o
  CC      lib/decompress_unlzo.o
  CC      lib/decompress_unxz.o
  CC      lib/decompress_unzstd.o
  CC      arch/x86/kernel/dumpstack_32.o
  CC      kernel/irq/chip.o
  CC      kernel/irq/dummychip.o
  AR      fs/isofs/built-in.a
  CC      fs/lockd/svc.o
  CC      kernel/module/main.o
  CC      crypto/cmac.o
  CC      fs/fat/file.o
  CC      fs/autofs/symlink.o
  CC      mm/mm_init.o
  CC      kernel/module/strict_rwx.o
  AR      fs/nls/built-in.a
  CC      drivers/pci/pci-acpi.o
  AR      kernel/power/built-in.a
  CC      kernel/time/time.o
  CC      arch/x86/kernel/cpu/powerflags.o
  CC      kernel/time/timer.o
  CC      net/core/sysctl_net_core.o
  CC      net/core/dev.o
  CC      fs/proc/util.o
  CC      fs/proc/version.o
  CC      io_uring/timeout.o
  CC      sound/core/device.o
  CC      io_uring/fdinfo.o
  CC      kernel/module/kmod.o
  CC      lib/dump_stack.o
  CC      block/bounce.o
  CC      kernel/dma/dummy.o
  CC      sound/core/info.o
  CC      arch/x86/kernel/cpu/topology.o
  CC      kernel/irq/devres.o
  CC      io_uring/cancel.o
  AR      fs/hostfs/built-in.a
  CC      fs/debugfs/inode.o
  CC      crypto/hmac.o
  CC      kernel/irq/autoprobe.o
  CC      fs/ext4/fsync.o
  CC      fs/debugfs/file.o
  CC      net/core/dev_addr_lists.o
  CC      block/bsg.o
  AR      net/netlink/built-in.a
  CC      fs/tracefs/inode.o
  CC [M]  fs/efivarfs/inode.o
  CC      fs/9p/vfs_addr.o
  CC      kernel/irq/irqdomain.o
  CC      fs/autofs/waitq.o
  CC      fs/proc/softirqs.o
  CC      fs/9p/vfs_file.o
  CC      fs/nfs/getroot.o
  CC      crypto/crypto_null.o
  CC      kernel/entry/syscall_user_dispatch.o
  CC      crypto/md5.o
  AR      fs/netfs/built-in.a
  CC      security/selinux/ss/conditional.o
  CC      sound/core/isadma.o
  CC      kernel/dma/remap.o
  CC      fs/lockd/svclock.o
  CC      lib/earlycpio.o
  CC      io_uring/waitid.o
  CC      arch/x86/kernel/cpu/proc.o
  CC      kernel/irq/proc.o
  AR      net/sched/built-in.a
  CC      arch/x86/kernel/cpu/feat_ctl.o
  CC      fs/fat/inode.o
  CC      fs/fat/misc.o
  CC      lib/extable.o
  CC      fs/open.o
  CC      fs/tracefs/event_inode.o
  CC      security/selinux/ss/mls.o
  CC      kernel/module/tree_lookup.o
  CC      lib/flex_proportions.o
  CC      drivers/pci/iomap.o
  CC      lib/idr.o
  CC      fs/read_write.o
  CC      fs/proc/namespaces.o
  CC [M]  fs/efivarfs/file.o
  CC      fs/fat/nfs.o
  CC      sound/core/vmaster.o
  CC      mm/percpu.o
  CC      fs/fat/namei_vfat.o
  CC      fs/fat/namei_msdos.o
  CC      kernel/irq/migration.o
  CC      crypto/sha256_generic.o
  CC      fs/lockd/svcshare.o
  AR      kernel/entry/built-in.a
  CC      arch/x86/kernel/cpu/intel.o
  CC      security/selinux/ss/context.o
  CC      fs/autofs/expire.o
  CC      fs/autofs/dev-ioctl.o
  CC      net/core/dst.o
  CC      crypto/sha512_generic.o
  CC      fs/lockd/svcproc.o
  CC      crypto/sha3_generic.o
  CC      fs/9p/vfs_dir.o
  CC      crypto/ecb.o
  AR      kernel/dma/built-in.a
  CC      arch/x86/events/intel/uncore_discovery.o
  CC      lib/irq_regs.o
  CC      block/blk-cgroup.o
  CC      block/blk-ioprio.o
  CC      lib/is_single_threaded.o
  AR      fs/debugfs/built-in.a
  CC      block/blk-iolatency.o
  CC      kernel/futex/core.o
  CC      fs/proc/self.o
  CC      kernel/cgroup/cgroup.o
  CC      kernel/trace/trace_clock.o
  CC [M]  fs/efivarfs/super.o
  CC [M]  fs/efivarfs/vars.o
  CC      fs/lockd/svcsubs.o
  CC      drivers/pci/quirks.o
  CC      kernel/irq/cpuhotplug.o
  CC      fs/nfs/inode.o
  CC      kernel/trace/ring_buffer.o
  CC      sound/core/ctljack.o
  CC      io_uring/register.o
  CC      kernel/module/kallsyms.o
  CC      kernel/trace/trace.o
  CC      kernel/module/procfs.o
  CC      security/selinux/netlabel.o
  CC      lib/klist.o
  CC      io_uring/truncate.o
  CC      drivers/pci/pci-label.o
  CC      block/blk-iocost.o
  AR      fs/tracefs/built-in.a
  CC      drivers/pci/vgaarb.o
  CC      kernel/time/hrtimer.o
  CC      arch/x86/kernel/time.o
  CC      fs/9p/vfs_dentry.o
  CC      fs/9p/v9fs.o
  CC      arch/x86/kernel/ioport.o
  CC      kernel/futex/syscalls.o
  AR      fs/autofs/built-in.a
  CC      fs/proc/thread_self.o
  CC      sound/core/jack.o
  CC      kernel/futex/pi.o
  CC      fs/ext4/hash.o
  CC      lib/kobject.o
  CC      crypto/cbc.o
  CC      kernel/trace/trace_output.o
  CC      mm/slab_common.o
  CC      kernel/trace/trace_seq.o
  AR      fs/fat/built-in.a
  CC      io_uring/memmap.o
  CC      kernel/module/sysfs.o
  CC      fs/proc/proc_sysctl.o
  CC      fs/lockd/mon.o
  CC      fs/lockd/trace.o
  CC      arch/x86/events/intel/cstate.o
  CC      block/mq-deadline.o
  CC      kernel/irq/pm.o
  CC      kernel/irq/msi.o
  CC      fs/lockd/xdr.o
  CC      kernel/futex/requeue.o
  LD [M]  fs/efivarfs/efivarfs.o
  CC      fs/file_table.o
  CC      fs/lockd/clnt4xdr.o
  CC      fs/super.o
  CC      net/core/netevent.o
  CC      crypto/ctr.o
  CC      kernel/bpf/core.o
  CC      kernel/events/core.o
  CC      crypto/gcm.o
  CC      kernel/fork.o
  CC      fs/lockd/xdr4.o
  CC      lib/kobject_uevent.o
  CC      net/core/neighbour.o
  CC      sound/core/timer.o
  CC      fs/9p/fid.o
  CC      kernel/futex/waitwake.o
  CC      kernel/time/timekeeping.o
  CC      fs/9p/xattr.o
  CC      arch/x86/kernel/dumpstack.o
  CC      lib/logic_pio.o
  CC      net/core/rtnetlink.o
  AR      kernel/module/built-in.a
  CC      fs/ext4/ialloc.o
  CC      fs/ext4/indirect.o
  CC      lib/maple_tree.o
  CC      fs/ext4/inline.o
  AR      kernel/rcu/built-in.a
  CC      fs/nfs/super.o
  AR      security/selinux/built-in.a
  AR      security/built-in.a
  CC      fs/nfs/io.o
  CC      kernel/time/ntp.o
  CC      kernel/time/clocksource.o
  CC      io_uring/io-wq.o
  AR      arch/x86/events/intel/built-in.a
  AR      arch/x86/events/built-in.a
  CC      mm/compaction.o
  CC      fs/ext4/inode.o
  AR      sound/firewire/built-in.a
  CC      net/core/utils.o
  CC      mm/show_mem.o
  AR      sound/sparc/built-in.a
  CC      io_uring/futex.o
  CC      io_uring/napi.o
  CC      arch/x86/kernel/cpu/intel_pconfig.o
  CC      arch/x86/kernel/cpu/tsx.o
  CC      kernel/irq/affinity.o
  CC      block/kyber-iosched.o
  CC      block/blk-mq-pci.o
  CC      kernel/exec_domain.o
  AR      fs/9p/built-in.a
  AR      kernel/futex/built-in.a
  CC      block/blk-mq-virtio.o
  CC      fs/lockd/svc4proc.o
  CC      lib/memcat_p.o
  CC      lib/nmi_backtrace.o
  CC      crypto/ccm.o
  AR      drivers/pci/built-in.a
  CC      kernel/trace/trace_stat.o
  CC      drivers/video/console/dummycon.o
  AR      drivers/idle/built-in.a
  CC      drivers/video/console/vgacon.o
  CC      net/core/link_watch.o
  CC      net/core/filter.o
  CC      fs/proc/proc_net.o
  CC      fs/lockd/procfs.o
  CC      kernel/time/jiffies.o
  CC      fs/char_dev.o
  CC      mm/shmem_quota.o
  CC      fs/proc/kcore.o
  CC      lib/objpool.o
  CC      kernel/irq/matrix.o
  AR      drivers/char/ipmi/built-in.a
  CC      kernel/trace/trace_printk.o
  CC      arch/x86/kernel/nmi.o
  CC      fs/nfs/direct.o
  CC      sound/core/hrtimer.o
  CC      kernel/panic.o
  CC      kernel/cpu.o
  CC      net/ethtool/ioctl.o
  CC      kernel/time/timer_list.o
  CC      fs/proc/vmcore.o
  CC      drivers/acpi/acpica/dsargs.o
  CC      block/blk-mq-debugfs.o
  AR      drivers/acpi/pmic/built-in.a
  CC      kernel/time/timeconv.o
  CC      drivers/acpi/dptf/int340x_thermal.o
  CC      lib/plist.o
  CC      drivers/acpi/acpica/dscontrol.o
  CC      fs/nfs/pagelist.o
  CC      kernel/trace/pid_list.o
  CC      drivers/acpi/x86/apple.o
  CC      drivers/pnp/pnpacpi/core.o
  AR      drivers/amba/built-in.a
  CC      crypto/aes_generic.o
  CC      crypto/crc32c_generic.o
  CC      drivers/acpi/x86/cmos_rtc.o
  CC      drivers/pnp/core.o
  CC      block/blk-pm.o
  CC      block/holder.o
  CC      drivers/acpi/x86/lpss.o
  CC      sound/core/seq_device.o
  AR      fs/lockd/built-in.a
  CC      net/core/sock_diag.o
  CC      kernel/events/ring_buffer.o
  CC      kernel/cgroup/rstat.o
  CC      mm/interval_tree.o
  AR      drivers/video/console/built-in.a
  CC      drivers/video/backlight/backlight.o
  AR      io_uring/built-in.a
  CC      arch/x86/kernel/cpu/intel_epb.o
  CC      arch/x86/kernel/cpu/amd.o
  CC      kernel/exit.o
  AR      drivers/acpi/dptf/built-in.a
  CC      arch/x86/kernel/ldt.o
  CC      drivers/acpi/x86/s2idle.o
  CC      drivers/acpi/acpica/dsdebug.o
  CC      drivers/pnp/pnpacpi/rsparser.o
  CC      crypto/authenc.o
  CC      kernel/time/timecounter.o
  AR      drivers/video/fbdev/core/built-in.a
  AR      drivers/video/fbdev/omap/built-in.a
  CC      kernel/time/alarmtimer.o
  AR      drivers/video/fbdev/omap2/omapfb/dss/built-in.a
  CC      kernel/time/posix-timers.o
  AR      drivers/video/fbdev/omap2/omapfb/displays/built-in.a
  CC      drivers/video/aperture.o
  AR      drivers/video/fbdev/omap2/omapfb/built-in.a
  CC      drivers/acpi/x86/utils.o
  AR      drivers/video/fbdev/omap2/built-in.a
  CC      net/core/dev_ioctl.o
  AR      drivers/video/fbdev/built-in.a
  CC      arch/x86/kernel/setup.o
  CC      arch/x86/kernel/x86_init.o
  AR      kernel/irq/built-in.a
  CC      kernel/trace/trace_sched_switch.o
  CC      fs/ext4/ioctl.o
  CC      fs/ext4/mballoc.o
  AR      kernel/bpf/built-in.a
  CC      kernel/cgroup/namespace.o
  CC      kernel/cgroup/cgroup-v1.o
  CC [M]  sound/core/hwdep.o
  CC      drivers/acpi/acpica/dsfield.o
  CC      lib/radix-tree.o
  CC      kernel/softirq.o
  CC      drivers/acpi/x86/blacklist.o
  CC      fs/proc/kmsg.o
  CC      kernel/trace/trace_nop.o
  CC      fs/stat.o
  AR      block/built-in.a
  CC      kernel/cgroup/freezer.o
  CC      fs/exec.o
  CC      kernel/cgroup/legacy_freezer.o
  CC      lib/ratelimit.o
  CC      drivers/acpi/tables.o
  CC      mm/list_lru.o
  CC      mm/workingset.o
  AR      drivers/video/backlight/built-in.a
  CC      drivers/acpi/acpica/dsinit.o
  CC      net/netfilter/core.o
  CC      lib/rbtree.o
  CC      arch/x86/kernel/cpu/hygon.o
  CC      arch/x86/kernel/cpu/centaur.o
  CC      net/netfilter/nf_log.o
  CC      net/netfilter/nf_queue.o
  CC      arch/x86/kernel/cpu/transmeta.o
  AR      drivers/acpi/x86/built-in.a
  CC      fs/ext4/migrate.o
  AR      drivers/pnp/pnpacpi/built-in.a
  CC      drivers/pnp/card.o
  CC      fs/proc/page.o
  CC      crypto/authencesn.o
  CC      drivers/video/cmdline.o
  CC      kernel/time/posix-cpu-timers.o
  CC      drivers/video/nomodeset.o
  CC      lib/seq_buf.o
  CC      drivers/acpi/acpica/dsmethod.o
  CC      drivers/acpi/acpica/dsmthdat.o
  CC [M]  sound/core/pcm.o
  CC      kernel/trace/blktrace.o
  CC      kernel/trace/trace_events.o
  CC      kernel/cgroup/pids.o
  CC      mm/debug.o
  CC      mm/gup.o
  CC      net/core/tso.o
  CC      mm/mmap_lock.o
  CC      arch/x86/kernel/cpu/zhaoxin.o
  CC      kernel/resource.o
  CC      kernel/trace/trace_export.o
  CC      kernel/time/posix-clock.o
  CC      net/core/sock_reuseport.o
  CC      drivers/video/hdmi.o
  CC [M]  sound/core/pcm_native.o
  CC      net/netfilter/nf_sockopt.o
  CC      mm/highmem.o
  CC      kernel/time/itimer.o
  CC      mm/memory.o
  CC      kernel/sysctl.o
  CC      fs/ext4/mmp.o
  CC      net/netfilter/utils.o
  CC      drivers/acpi/acpica/dsobject.o
  CC      net/netfilter/nfnetlink.o
  CC      kernel/cgroup/rdma.o
  CC      arch/x86/kernel/i8259.o
  CC      drivers/acpi/osi.o
  CC      drivers/pnp/driver.o
  AR      fs/proc/built-in.a
  CC      drivers/pnp/resource.o
  CC      drivers/acpi/osl.o
  CC      drivers/pnp/manager.o
  CC      arch/x86/kernel/cpu/vortex.o
  CC      net/ethtool/common.o
  CC      kernel/cgroup/cpuset.o
  CC      mm/mincore.o
  CC      kernel/capability.o
  CC      fs/nfs/read.o
  CC      crypto/lzo.o
  CC      lib/siphash.o
  CC      drivers/pnp/support.o
  CC      drivers/acpi/acpica/dsopcode.o
  CC      drivers/pnp/interface.o
  CC      drivers/acpi/acpica/dspkginit.o
  CC      kernel/time/clockevents.o
  CC      drivers/acpi/acpica/dsutils.o
  CC      arch/x86/kernel/cpu/perfctr-watchdog.o
  CC      net/netfilter/nfnetlink_log.o
  CC      drivers/acpi/acpica/dswexec.o
  CC      net/netfilter/nf_conntrack_core.o
  CC      mm/mlock.o
  CC      arch/x86/kernel/cpu/vmware.o
  AR      drivers/video/built-in.a
  CC      mm/mmap.o
  CC      net/netfilter/nf_conntrack_standalone.o
  CC      kernel/ptrace.o
  CC      kernel/user.o
  CC      kernel/signal.o
  CC      net/core/fib_notifier.o
  CC      fs/ext4/move_extent.o
  CC      net/netfilter/nf_conntrack_expect.o
  CC      arch/x86/kernel/cpu/hypervisor.o
  CC      arch/x86/kernel/cpu/mshyperv.o
  CC      mm/mmu_gather.o
  CC      kernel/time/tick-common.o
  CC      kernel/sys.o
  CC      net/core/xdp.o
  CC      arch/x86/kernel/irqinit.o
  CC      net/ipv4/netfilter/nf_defrag_ipv4.o
  CC      crypto/lzo-rle.o
  CC      net/ipv4/netfilter/nf_reject_ipv4.o
  CC      drivers/acpi/acpica/dswload.o
  CC      arch/x86/kernel/jump_label.o
  CC      kernel/umh.o
  CC      net/xfrm/xfrm_policy.o
  CC      kernel/workqueue.o
  CC      net/ipv4/route.o
  CC      net/unix/af_unix.o
  CC      kernel/pid.o
  CC      lib/string.o
  CC      drivers/pnp/quirks.o
  CC      net/ethtool/netlink.o
  CC      kernel/task_work.o
  CC      lib/timerqueue.o
  CC      kernel/extable.o
  CC      arch/x86/kernel/cpu/debugfs.o
  CC      mm/mprotect.o
  CC      lib/vsprintf.o
  CC      kernel/cgroup/misc.o
  CC      fs/nfs/symlink.o
  CC      net/ipv4/netfilter/ip_tables.o
  CC      drivers/acpi/acpica/dswload2.o
  CC      drivers/acpi/acpica/dswscope.o
  CC      kernel/events/callchain.o
  CC      crypto/rng.o
  CC      net/ipv6/netfilter/ip6_tables.o
  CC      arch/x86/kernel/irq_work.o
  CC      arch/x86/kernel/cpu/capflags.o
  CC      drivers/acpi/utils.o
  CC      kernel/cgroup/debug.o
  CC      drivers/acpi/reboot.o
  CC      crypto/drbg.o
  CC      net/ipv6/af_inet6.o
  CC      fs/ext4/namei.o
  AR      drivers/clk/actions/built-in.a
  CC      kernel/trace/trace_event_perf.o
  AR      arch/x86/kernel/cpu/built-in.a
  CC      fs/ext4/page-io.o
  AR      drivers/clk/analogbits/built-in.a
  AR      drivers/clk/bcm/built-in.a
  AR      sound/spi/built-in.a
  AR      sound/parisc/built-in.a
  CC      net/ipv6/anycast.o
  AR      drivers/clk/imgtec/built-in.a
  AR      drivers/clk/imx/built-in.a
  AR      sound/pcmcia/vx/built-in.a
  CC      net/ipv6/ip6_output.o
  AR      drivers/clk/ingenic/built-in.a
  AR      sound/pcmcia/pdaudiocf/built-in.a
  AR      drivers/clk/mediatek/built-in.a
  AR      sound/pcmcia/built-in.a
  AR      drivers/clk/microchip/built-in.a
  CC      net/core/flow_offload.o
  CC      drivers/acpi/acpica/dswstate.o
  AR      drivers/clk/mstar/built-in.a
  CC      net/ethtool/bitset.o
  CC      drivers/pnp/system.o
  CC      kernel/params.o
  AR      drivers/clk/mvebu/built-in.a
  AR      drivers/clk/ralink/built-in.a
  CC      mm/mremap.o
  CC      kernel/time/tick-broadcast.o
  AR      drivers/clk/renesas/built-in.a
  AR      drivers/clk/socfpga/built-in.a
  CC      arch/x86/kernel/probe_roms.o
  AR      drivers/clk/sophgo/built-in.a
  AR      drivers/clk/sprd/built-in.a
  AR      drivers/clk/starfive/built-in.a
  AR      drivers/clk/sunxi-ng/built-in.a
  CC      net/ipv4/netfilter/iptable_filter.o
  AR      drivers/clk/ti/built-in.a
  AR      drivers/clk/versatile/built-in.a
  AR      drivers/clk/xilinx/built-in.a
  AR      drivers/clk/built-in.a
  CC      net/ipv4/netfilter/iptable_mangle.o
  CC      crypto/jitterentropy.o
  CC      drivers/acpi/nvs.o
  CC      crypto/jitterentropy-kcapi.o
  CC [M]  sound/core/pcm_lib.o
  CC      kernel/kthread.o
  CC      kernel/sys_ni.o
  CC      kernel/events/hw_breakpoint.o
  CC      net/ipv6/ip6_input.o
  CC      crypto/ghash-generic.o
  CC      drivers/acpi/wakeup.o
  CC      drivers/acpi/acpica/evevent.o
  CC      net/ipv6/addrconf.o
  CC      drivers/acpi/acpica/evgpe.o
  CC      drivers/acpi/sleep.o
  CC      drivers/acpi/device_sysfs.o
  CC      fs/nfs/unlink.o
  AR      drivers/pnp/built-in.a
  CC      fs/nfs/write.o
  CC      net/netfilter/nf_conntrack_helper.o
  AR      kernel/cgroup/built-in.a
  CC      arch/x86/kernel/sys_ia32.o
  CC      crypto/hash_info.o
  CC      kernel/time/tick-broadcast-hrtimer.o
  CC      kernel/trace/trace_events_filter.o
  CC      kernel/nsproxy.o
  CC      mm/msync.o
  CC      mm/page_vma_mapped.o
  AR      sound/mips/built-in.a
  AR      sound/soc/built-in.a
  CC      net/ethtool/strset.o
  CC      kernel/time/tick-oneshot.o
  CC      drivers/acpi/acpica/evgpeblk.o
  CC      fs/ext4/readpage.o
  CC      arch/x86/kernel/ksysfs.o
  CC      arch/x86/kernel/bootflag.o
  CC      crypto/rsapubkey.asn1.o
  CC      crypto/rsaprivkey.asn1.o
  CC      mm/pagewalk.o
  CC      net/core/gro.o
  CC      net/ipv6/addrlabel.o
  AR      crypto/built-in.a
  CC      kernel/time/tick-sched.o
  CC      net/core/netdev-genl.o
  CC      kernel/notifier.o
  CC      fs/nfs/namespace.o
  CC      kernel/events/uprobes.o
  CC      drivers/acpi/device_pm.o
  CC      drivers/acpi/acpica/evgpeinit.o
  CC      net/ipv4/netfilter/ipt_REJECT.o
  CC [M]  net/ipv4/netfilter/iptable_nat.o
  CC      net/core/netdev-genl-gen.o
  CC      net/core/gso.o
  CC      kernel/time/timer_migration.o
  CC      net/netfilter/nf_conntrack_proto.o
  AR      sound/atmel/built-in.a
  CC      drivers/acpi/acpica/evgpeutil.o
  CC      net/netfilter/nf_conntrack_proto_generic.o
  CC      kernel/time/vsyscall.o
  CC      net/ethtool/linkinfo.o
  CC      arch/x86/kernel/e820.o
  CC      net/ipv6/netfilter/ip6table_filter.o
  CC      net/ipv6/route.o
  CC      net/unix/garbage.o
  CC      arch/x86/kernel/pci-dma.o
  CC      net/core/net-sysfs.o
  CC      drivers/acpi/acpica/evglock.o
  CC      fs/pipe.o
  CC      net/xfrm/xfrm_state.o
  CC      net/core/hotdata.o
  CC      lib/win_minmax.o
  CC      drivers/acpi/acpica/evhandler.o
  CC      drivers/acpi/proc.o
  CC      mm/pgtable-generic.o
  CC      net/ipv6/ip6_fib.o
  CC      fs/ext4/resize.o
  CC      kernel/ksysfs.o
  CC      net/ethtool/linkmodes.o
  CC      net/netfilter/nf_conntrack_proto_tcp.o
  CC      net/ipv4/inetpeer.o
  CC      drivers/acpi/acpica/evmisc.o
  CC      net/ipv6/ipv6_sockglue.o
  CC      drivers/acpi/acpica/evregion.o
  CC [M]  sound/core/pcm_misc.o
  CC      lib/xarray.o
  CC      net/xfrm/xfrm_hash.o
  CC      net/ipv6/ndisc.o
  CC      fs/ext4/super.o
  CC      kernel/time/timekeeping_debug.o
  CC      net/ipv6/udp.o
  CC      net/ipv6/netfilter/ip6table_mangle.o
  CC      net/ipv4/protocol.o
  CC      drivers/acpi/acpica/evrgnini.o
  CC      kernel/trace/trace_events_trigger.o
  CC      drivers/acpi/bus.o
  AR      net/ipv4/netfilter/built-in.a
  CC      net/ethtool/rss.o
  CC      kernel/time/namespace.o
  CC      fs/ext4/symlink.o
  CC      net/xfrm/xfrm_input.o
  CC      lib/lockref.o
  CC      net/xfrm/xfrm_output.o
  CC      drivers/acpi/glue.o
  CC      mm/rmap.o
  CC      net/packet/af_packet.o
  CC      kernel/cred.o
  CC      kernel/reboot.o
  CC      net/core/net-procfs.o
  CC      arch/x86/kernel/quirks.o
  CC      arch/x86/kernel/kdebugfs.o
  CC      lib/bcd.o
  CC      net/ipv4/ip_input.o
  CC      net/ipv6/udplite.o
  CC      drivers/acpi/scan.o
  AR      net/dsa/built-in.a
  CC      net/ipv6/netfilter/nf_defrag_ipv6_hooks.o
  CC      net/unix/sysctl_net_unix.o
  CC      lib/sort.o
  CC      net/xfrm/xfrm_sysctl.o
  CC      drivers/acpi/acpica/evsci.o
  CC      lib/parser.o
  CC      drivers/acpi/acpica/evxface.o
  CC [M]  sound/core/pcm_memory.o
  CC      net/ipv4/ip_fragment.o
  AR      kernel/events/built-in.a
  CC      kernel/trace/trace_eprobe.o
  CC      kernel/trace/trace_kprobe.o
  CC      fs/namei.o
  CC      net/netfilter/nf_conntrack_proto_udp.o
  CC [M]  sound/core/memalloc.o
  CC      drivers/acpi/acpica/evxfevnt.o
  AR      kernel/time/built-in.a
  CC      arch/x86/kernel/alternative.o
  CC      net/core/netpoll.o
  CC      net/xfrm/xfrm_replay.o
  CC      fs/ext4/sysfs.o
  CC      kernel/async.o
  CC      net/netfilter/nf_conntrack_proto_icmp.o
  CC      mm/vmalloc.o
  CC      drivers/acpi/acpica/evxfgpe.o
  CC      lib/debug_locks.o
  CC      net/ethtool/linkstate.o
  CC      arch/x86/kernel/i8253.o
  CC      kernel/range.o
  CC      fs/fcntl.o
  CC      fs/nfs/mount_clnt.o
  CC      net/core/fib_rules.o
  CC      mm/process_vm_access.o
  CC      drivers/acpi/acpica/evxfregn.o
  CC      lib/random32.o
  CC      kernel/smpboot.o
  CC      net/xfrm/xfrm_device.o
  CC      net/ipv6/netfilter/nf_conntrack_reasm.o
  CC      kernel/ucount.o
  CC      drivers/acpi/acpica/exconcat.o
  AR      net/unix/built-in.a
  CC      net/sunrpc/auth_gss/auth_gss.o
  CC      net/sunrpc/clnt.o
  CC      net/ethtool/debug.o
  CC      net/ipv4/ip_forward.o
  CC      net/ethtool/wol.o
  AR      sound/hda/built-in.a
  CC      net/sunrpc/auth_gss/gss_generic_token.o
  CC [M]  sound/hda/hda_bus_type.o
  CC      net/ipv6/raw.o
  CC      net/ethtool/features.o
  CC      kernel/regset.o
  CC      lib/bust_spinlocks.o
  CC      fs/ioctl.o
  CC [M]  sound/core/pcm_timer.o
  CC      drivers/acpi/mipi-disco-img.o
  CC      net/ipv4/ip_options.o
  CC      net/netfilter/nf_conntrack_extend.o
  CC      mm/page_alloc.o
  CC      drivers/acpi/acpica/exconfig.o
  CC [M]  sound/hda/hdac_bus.o
  CC      net/sunrpc/xprt.o
  CC      net/ipv6/icmp.o
  CC      fs/readdir.o
  AR      sound/x86/built-in.a
  CC      kernel/trace/error_report-traces.o
  CC      net/ipv6/netfilter/nf_reject_ipv6.o
  CC      mm/init-mm.o
  CC      net/netfilter/nf_conntrack_acct.o
  CC      net/netfilter/nf_conntrack_seqadj.o
  LD [M]  sound/core/snd-hwdep.o
  CC      mm/memblock.o
  CC      net/ipv6/mcast.o
  AR      sound/xen/built-in.a
  CC      net/ipv6/reassembly.o
  CC      net/ethtool/privflags.o
  CC [M]  sound/hda/hdac_device.o
  CC      kernel/ksyms_common.o
  CC      arch/x86/kernel/hw_breakpoint.o
  CC      net/sunrpc/socklib.o
  AR      sound/core/built-in.a
  CC      net/xfrm/xfrm_algo.o
  CC      lib/kasprintf.o
  CC      kernel/groups.o
  CC      drivers/acpi/acpica/exconvrt.o
  CC      kernel/kcmp.o
  CC      net/ipv6/tcp_ipv6.o
  LD [M]  sound/core/snd-pcm.o
  CC      fs/nfs/nfstrace.o
  CC [M]  sound/hda/hdac_sysfs.o
  CC      net/netfilter/nf_conntrack_proto_icmpv6.o
  CC      arch/x86/kernel/tsc.o
  CC      net/ipv6/ping.o
  CC      net/ipv6/netfilter/ip6t_ipv6header.o
  CC      fs/select.o
  CC      drivers/acpi/resource.o
  CC      net/core/net-traces.o
  CC      lib/bitmap.o
  CC      net/ethtool/rings.o
  CC      lib/scatterlist.o
  CC      fs/nfs/export.o
  CC      kernel/trace/power-traces.o
  CC      drivers/acpi/acpica/excreate.o
  CC      fs/dcache.o
  CC      net/ethtool/channels.o
  CC      net/ipv4/ip_output.o
  CC      mm/slub.o
  CC      fs/inode.o
  CC [M]  sound/hda/hdac_regmap.o
  CC      drivers/acpi/acpi_processor.o
  CC      net/ipv4/ip_sockglue.o
  CC      net/sunrpc/auth_gss/gss_mech_switch.o
  CC      mm/madvise.o
  CC      net/sunrpc/auth_gss/svcauth_gss.o
  CC [M]  sound/hda/hdac_controller.o
  CC      drivers/acpi/acpica/exdebug.o
  CC      net/xfrm/xfrm_user.o
  CC      kernel/trace/rpm-traces.o
  AR      net/wireless/tests/built-in.a
  CC      net/wireless/core.o
  AR      net/mac80211/tests/built-in.a
  CC      net/netlabel/netlabel_user.o
  CC      net/mac80211/main.o
  CC      net/netlabel/netlabel_kapi.o
  CC      arch/x86/kernel/tsc_msr.o
  AR      net/packet/built-in.a
  CC      net/ipv6/netfilter/ip6t_REJECT.o
  CC      net/ipv6/exthdrs.o
  CC      lib/list_sort.o
  CC      mm/page_io.o
  CC      arch/x86/kernel/io_delay.o
  CC      net/sunrpc/xprtsock.o
  CC      net/netlabel/netlabel_domainhash.o
  CC      kernel/trace/trace_dynevent.o
  CC      lib/uuid.o
  CC      net/ethtool/coalesce.o
  CC      drivers/acpi/acpica/exdump.o
  CC      net/sunrpc/auth_gss/gss_rpc_upcall.o
  CC      net/ethtool/pause.o
  CC      net/sunrpc/sched.o
  CC      mm/swap_state.o
  CC [M]  sound/hda/hdac_stream.o
  CC      mm/swapfile.o
  CC      net/netfilter/nf_conntrack_netlink.o
  CC      lib/iov_iter.o
  CC      net/netlabel/netlabel_addrlist.o
  CC      net/ipv4/inet_hashtables.o
  CC      arch/x86/kernel/rtc.o
  CC      net/sunrpc/auth.o
  CC      drivers/acpi/processor_core.o
  CC      drivers/acpi/acpica/exfield.o
  CC [M]  sound/hda/array.o
  CC      fs/attr.o
  CC      net/mac80211/status.o
  CC      kernel/trace/trace_probe.o
  CC      net/netlabel/netlabel_mgmt.o
  CC      drivers/acpi/acpica/exfldio.o
  CC      fs/nfs/sysfs.o
  CC      net/core/selftests.o
  CC      arch/x86/kernel/resource.o
  CC      net/mac80211/driver-ops.o
  CC      drivers/acpi/processor_pdc.o
  CC [M]  sound/hda/hdmi_chmap.o
  CC [M]  sound/hda/trace.o
  AR      net/ipv6/netfilter/built-in.a
  CC      net/netfilter/nf_conntrack_ftp.o
  CC      drivers/dma/dw/core.o
  AS      arch/x86/kernel/irqflags.o
  CC      drivers/dma/hsu/hsu.o
  CC      arch/x86/kernel/static_call.o
  AR      drivers/dma/idxd/built-in.a
  CC      fs/ext4/xattr.o
  CC      net/netlabel/netlabel_unlabeled.o
  AR      drivers/dma/mediatek/built-in.a
  CC      net/ethtool/eee.o
  CC      net/netlabel/netlabel_cipso_v4.o
  CC      net/wireless/sysfs.o
  CC      net/sunrpc/auth_null.o
  AR      drivers/soc/apple/built-in.a
  CC      net/sunrpc/auth_tls.o
  CC      net/sunrpc/auth_gss/gss_rpc_xdr.o
  AR      drivers/soc/aspeed/built-in.a
  CC      net/ipv6/datagram.o
  AR      drivers/soc/bcm/built-in.a
  CC      net/netlabel/netlabel_calipso.o
  AR      drivers/soc/fsl/built-in.a
  AR      drivers/soc/fujitsu/built-in.a
  CC      drivers/acpi/acpica/exmisc.o
  CC      drivers/acpi/acpica/exmutex.o
  AR      drivers/soc/hisilicon/built-in.a
  CC      net/sunrpc/auth_gss/trace.o
  AR      drivers/soc/imx/built-in.a
  AR      drivers/soc/ixp4xx/built-in.a
  CC      net/sunrpc/auth_gss/gss_krb5_mech.o
  AR      drivers/soc/loongson/built-in.a
  CC      fs/ext4/xattr_hurd.o
  CC      fs/nfs/fs_context.o
  AR      drivers/soc/mediatek/built-in.a
  CC      net/rfkill/core.o
  CC      fs/nfs/nfsroot.o
  AR      drivers/soc/microchip/built-in.a
  CC      fs/ext4/xattr_trusted.o
  CC      drivers/acpi/acpica/exnames.o
  AR      drivers/soc/nuvoton/built-in.a
  AR      drivers/soc/pxa/built-in.a
  AR      drivers/soc/amlogic/built-in.a
  CC      arch/x86/kernel/process.o
  AR      drivers/soc/qcom/built-in.a
  AR      drivers/soc/renesas/built-in.a
  AR      drivers/soc/rockchip/built-in.a
  AR      drivers/soc/sunxi/built-in.a
  AR      drivers/soc/ti/built-in.a
  CC      drivers/acpi/acpica/exoparg1.o
  AR      drivers/soc/xilinx/built-in.a
  AR      drivers/soc/built-in.a
  CC      fs/ext4/xattr_user.o
  CC      drivers/acpi/acpica/exoparg2.o
  CC      drivers/acpi/acpica/exoparg3.o
  CC [M]  sound/hda/hdac_component.o
  CC      net/sunrpc/auth_unix.o
  AR      drivers/dma/hsu/built-in.a
  CC      drivers/acpi/acpica/exoparg6.o
  CC      fs/nfs/sysctl.o
  CC      fs/ext4/fast_commit.o
  CC      fs/ext4/orphan.o
  CC      lib/clz_ctz.o
  CC      net/ethtool/tsinfo.o
  CC      drivers/dma/dw/dw.o
  AR      net/xfrm/built-in.a
  CC      kernel/trace/trace_uprobe.o
  CC      kernel/trace/rethook.o
  CC      lib/bsearch.o
  CC      drivers/acpi/ec.o
  CC      net/sunrpc/svc.o
  CC      net/9p/mod.o
  CC      drivers/acpi/dock.o
  CC      drivers/acpi/pci_root.o
  CC      net/sunrpc/svcsock.o
  CC      net/ethtool/cabletest.o
  CC      net/9p/client.o
  CC      net/ipv4/inet_timewait_sock.o
  CC      net/9p/error.o
  CC      lib/find_bit.o
  CC      drivers/acpi/acpica/exprep.o
  CC      net/ethtool/tunnels.o
  CC      net/ethtool/fec.o
  CC      drivers/dma/dw/idma32.o
  CC      net/rfkill/input.o
  CC      net/mac80211/sta_info.o
  CC      net/sunrpc/svcauth.o
  CC      mm/swap_slots.o
  CC      net/netfilter/nf_conntrack_irc.o
  CC      fs/nfs/nfs3super.o
  AR      net/netlabel/built-in.a
  CC      lib/llist.o
  CC [M]  sound/hda/hdac_i915.o
  CC      net/dns_resolver/dns_key.o
  CC      net/mac80211/wep.o
  CC      fs/ext4/acl.o
  CC      drivers/acpi/acpica/exregion.o
  CC      net/9p/protocol.o
  CC      lib/lwq.o
  CC      drivers/acpi/acpica/exresnte.o
  CC      kernel/freezer.o
  CC      fs/nfs/nfs3client.o
  CC      fs/nfs/nfs3proc.o
  CC      net/ipv6/ip6_flowlabel.o
  CC      mm/dmapool.o
  CC      net/sunrpc/svcauth_unix.o
  CC      net/handshake/alert.o
  CC      net/core/ptp_classifier.o
  CC      lib/memweight.o
  AR      net/rfkill/built-in.a
  CC      net/handshake/genl.o
  CC      kernel/profile.o
  CC      mm/hugetlb.o
  CC      drivers/dma/dw/acpi.o
  CC      lib/kfifo.o
  CC      fs/nfs/nfs3xdr.o
  CC      arch/x86/kernel/ptrace.o
  CC      net/mac80211/aead_api.o
  CC      net/devres.o
  CC      drivers/acpi/acpica/exresolv.o
  CC      net/core/netprio_cgroup.o
  CC      net/handshake/netlink.o
  CC      net/dns_resolver/dns_query.o
  CC      net/netfilter/nf_conntrack_sip.o
  CC [M]  sound/hda/intel-dsp-config.o
  CC      net/wireless/radiotap.o
  CC      net/sunrpc/addr.o
  CC      arch/x86/kernel/tls.o
  CC      net/ipv4/inet_connection_sock.o
  CC      net/ethtool/eeprom.o
  CC      net/sunrpc/auth_gss/gss_krb5_seal.o
  CC [M]  sound/hda/intel-nhlt.o
  CC      net/mac80211/wpa.o
  CC      drivers/acpi/pci_link.o
  CC [M]  sound/hda/intel-sdw-acpi.o
  CC      net/sunrpc/auth_gss/gss_krb5_unseal.o
  CC      drivers/acpi/acpica/exresop.o
  CC      fs/ext4/xattr_security.o
  CC      net/ethtool/stats.o
  CC      lib/percpu-refcount.o
  CC      lib/rhashtable.o
  CC      net/mac80211/scan.o
  AR      drivers/dma/dw/built-in.a
  CC      net/handshake/request.o
  CC      fs/nfs/nfs3acl.o
  AR      drivers/dma/qcom/built-in.a
  AR      drivers/dma/ti/built-in.a
  CC      drivers/acpi/acpica/exserial.o
  CC      net/wireless/util.o
  AR      drivers/dma/xilinx/built-in.a
  CC      drivers/dma/dmaengine.o
  CC      net/wireless/reg.o
  CC      net/9p/trans_common.o
  AR      kernel/trace/built-in.a
  AR      net/dns_resolver/built-in.a
  CC      net/wireless/scan.o
  CC      kernel/stacktrace.o
  CC      net/wireless/nl80211.o
  CC      mm/mmu_notifier.o
  CC      fs/nfs/nfs4proc.o
  LD [M]  sound/hda/snd-hda-core.o
  CC      fs/bad_inode.o
  CC      net/core/netclassid_cgroup.o
  CC      drivers/acpi/acpica/exstore.o
  CC      net/9p/trans_fd.o
  LD [M]  sound/hda/snd-intel-dspcfg.o
  LD [M]  sound/hda/snd-intel-sdw-acpi.o
  CC      net/9p/trans_virtio.o
  AR      sound/virtio/built-in.a
  CC      sound/sound_core.o
  CC      net/ipv6/inet6_connection_sock.o
  CC      net/sunrpc/rpcb_clnt.o
  CC      drivers/acpi/pci_irq.o
  CC      fs/nfs/nfs4xdr.o
  CC      arch/x86/kernel/step.o
  CC      net/wireless/mlme.o
  CC      net/ipv6/udp_offload.o
  CC      net/core/dst_cache.o
  CC      net/sunrpc/auth_gss/gss_krb5_wrap.o
  CC      drivers/acpi/acpi_apd.o
  CC      fs/file.o
  CC      drivers/acpi/acpi_platform.o
  CC      drivers/dma/virt-dma.o
  CC      fs/nfs/nfs4state.o
  CC      drivers/acpi/acpica/exstoren.o
  CC      net/ipv6/seg6.o
  CC      lib/base64.o
  CC      net/ipv4/tcp.o
  CC      sound/last.o
  CC      kernel/dma.o
  CC      net/ipv4/tcp_input.o
  CC      net/sunrpc/auth_gss/gss_krb5_crypto.o
  AR      fs/ext4/built-in.a
  CC      fs/nfs/nfs4renewd.o
  CC      net/sunrpc/timer.o
  CC      net/ethtool/phc_vclocks.o
  CC      lib/once.o
  CC      net/socket.o
  CC      net/mac80211/offchannel.o
  CC      drivers/acpi/acpica/exstorob.o
  CC      arch/x86/kernel/i8237.o
  CC      net/sunrpc/xdr.o
  CC      fs/nfs/nfs4super.o
  CC      net/core/gro_cells.o
  CC      net/sunrpc/sunrpc_syms.o
  CC      net/mac80211/ht.o
  AR      sound/built-in.a
  CC      fs/nfs/nfs4file.o
  CC      drivers/dma/acpi-dma.o
  CC      kernel/smp.o
  CC      drivers/acpi/acpi_pnp.o
  CC      mm/migrate.o
  CC      kernel/uid16.o
  CC      net/netfilter/nf_nat_core.o
  CC      lib/refcount.o
  CC      net/handshake/tlshd.o
  CC      kernel/kallsyms.o
  CC      drivers/acpi/acpica/exsystem.o
  CC      arch/x86/kernel/stacktrace.o
  CC      net/core/failover.o
  CC      net/ipv4/tcp_output.o
  CC      mm/page_counter.o
  AR      net/9p/built-in.a
  CC      fs/nfs/delegation.o
  CC      fs/nfs/nfs4idmap.o
  CC      lib/rcuref.o
  CC      drivers/acpi/acpica/extrace.o
  CC      net/sysctl_net.o
  CC      drivers/virtio/virtio.o
  CC      net/ipv6/fib6_notifier.o
  CC      drivers/virtio/virtio_ring.o
  CC      lib/usercopy.o
  CC      lib/errseq.o
  CC      net/sunrpc/auth_gss/gss_krb5_keys.o
  CC      drivers/acpi/acpica/exutils.o
  CC      arch/x86/kernel/reboot.o
  CC      fs/nfs/callback.o
  CC      net/ethtool/mm.o
  CC      drivers/acpi/power.o
  CC      drivers/acpi/acpica/hwacpi.o
  AR      drivers/dma/built-in.a
  CC      drivers/tty/vt/vt_ioctl.o
  CC      drivers/tty/hvc/hvc_console.o
  CC      lib/bucket_locks.o
  CC      drivers/tty/serial/8250/8250_core.o
  AR      drivers/tty/ipwireless/built-in.a
  CC      fs/filesystems.o
  CC      fs/namespace.o
  CC      drivers/tty/serial/serial_core.o
  CC      net/handshake/trace.o
  CC      fs/seq_file.o
  CC      drivers/tty/serial/8250/8250_pnp.o
  CC      drivers/acpi/acpica/hwesleep.o
  CC      drivers/acpi/acpica/hwgpe.o
  AR      net/core/built-in.a
  CC      net/sunrpc/cache.o
  CC      drivers/virtio/virtio_anchor.o
  CC      fs/nfs/callback_xdr.o
  CC      kernel/acct.o
  CC      net/mac80211/agg-tx.o
  CC      lib/generic-radix-tree.o
  CC      lib/bitmap-str.o
  CC      drivers/acpi/event.o
  AR      net/sunrpc/auth_gss/built-in.a
  CC      net/ipv6/rpl.o
  CC      arch/x86/kernel/msr.o
  CC      net/mac80211/agg-rx.o
  CC      drivers/tty/serial/serial_base_bus.o
  CC      net/sunrpc/rpc_pipe.o
  CC      mm/hugetlb_cgroup.o
  CC      net/netfilter/nf_nat_proto.o
  CC      net/netfilter/nf_nat_helper.o
  CC      net/ethtool/module.o
  CC      drivers/acpi/acpica/hwregs.o
  CC      net/sunrpc/sysfs.o
  CC      fs/xattr.o
  CC      fs/nfs/callback_proc.o
  AR      drivers/tty/hvc/built-in.a
  CC      net/mac80211/vht.o
  CC      mm/early_ioremap.o
  CC      drivers/virtio/virtio_pci_modern_dev.o
  CC      drivers/tty/vt/vc_screen.o
  CC      net/netfilter/nf_nat_masquerade.o
  CC      drivers/tty/vt/selection.o
  CC      drivers/tty/serial/8250/8250_port.o
  CC      drivers/virtio/virtio_pci_legacy_dev.o
  CC      fs/libfs.o
  CC      fs/fs-writeback.o
  CC      fs/nfs/nfs4namespace.o
  CC      lib/string_helpers.o
  CC      fs/nfs/nfs4getroot.o
  CC      drivers/acpi/acpica/hwsleep.o
  CC      drivers/char/hw_random/core.o
  CC      arch/x86/kernel/cpuid.o
  CC      drivers/char/hw_random/intel-rng.o
  CC      kernel/vmcore_info.o
  CC      fs/nfs/nfs4client.o
  CC      fs/nfs/nfs4session.o
  AR      net/handshake/built-in.a
  CC      net/ipv6/ioam6.o
  CC      fs/nfs/dns_resolve.o
  CC      net/mac80211/he.o
  CC      kernel/elfcorehdr.o
  CC      fs/nfs/nfs4trace.o
  CC      mm/secretmem.o
  CC      drivers/char/hw_random/amd-rng.o
  CC      drivers/acpi/acpica/hwvalid.o
  CC      drivers/acpi/acpica/hwxface.o
  CC      kernel/crash_reserve.o
  CC      arch/x86/kernel/early-quirks.o
  CC      drivers/virtio/virtio_pci_modern.o
  CC      net/ethtool/pse-pd.o
  CC      drivers/tty/vt/keyboard.o
  CC      drivers/tty/vt/vt.o
  CC      net/ipv4/tcp_timer.o
  CC      arch/x86/kernel/smp.o
  CC      arch/x86/kernel/smpboot.o
  CC      lib/hexdump.o
  CC      net/ipv6/sysctl_net_ipv6.o
  CC      drivers/virtio/virtio_pci_common.o
  CC      net/ethtool/plca.o
  CC      fs/nfs/nfs4sysctl.o
  CC      drivers/tty/serial/8250/8250_dma.o
  CC      drivers/acpi/evged.o
  CC      net/sunrpc/svc_xprt.o
  CC      drivers/acpi/sysfs.o
  CC      net/sunrpc/xprtmultipath.o
  CC      drivers/acpi/acpica/hwxfsleep.o
  CC      net/wireless/ibss.o
  CC      drivers/acpi/acpica/hwpci.o
  CC      lib/kstrtox.o
  CC      net/netfilter/nf_nat_ftp.o
  CC      kernel/kexec_core.o
  CC      drivers/tty/serial/8250/8250_dwlib.o
  CC      net/mac80211/s1g.o
  CC      drivers/char/hw_random/geode-rng.o
  CC      net/netfilter/nf_nat_irc.o
  CC      drivers/acpi/acpica/nsaccess.o
  CC      net/ipv4/tcp_ipv4.o
  CC      net/sunrpc/stats.o
  CC      fs/pnode.o
  CC      mm/hmm.o
  CC      net/sunrpc/sysctl.o
  CC      drivers/acpi/property.o
  CC      drivers/tty/serial/serial_ctrl.o
  CC      drivers/acpi/debugfs.o
  CC      drivers/acpi/acpica/nsalloc.o
  CC      drivers/tty/tty_io.o
  CC      drivers/acpi/acpica/nsarguments.o
  CC      kernel/crash_core.o
  CC      lib/iomap.o
  CC      lib/iomap_copy.o
  CC      lib/devres.o
  CC      drivers/tty/serial/8250/8250_pcilib.o
  CC      lib/check_signature.o
  CC      kernel/kexec.o
  CC      kernel/utsname.o
  AR      drivers/iommu/amd/built-in.a
  AR      drivers/iommu/intel/built-in.a
  CC      drivers/acpi/acpica/nsconvert.o
  CC      kernel/pid_namespace.o
  AR      drivers/iommu/arm/arm-smmu/built-in.a
  CC      drivers/virtio/virtio_pci_legacy.o
  AR      drivers/iommu/arm/arm-smmu-v3/built-in.a
  AR      drivers/iommu/arm/built-in.a
  CC      lib/interval_tree.o
  AR      drivers/iommu/iommufd/built-in.a
  CC      drivers/iommu/iommu.o
  CC      lib/assoc_array.o
  CC      net/mac80211/ibss.o
  CC      fs/splice.o
  CC      drivers/tty/serial/8250/8250_early.o
  CC      drivers/iommu/iommu-traces.o
  CC      drivers/char/hw_random/via-rng.o
  AR      net/ethtool/built-in.a
  AR      drivers/gpu/host1x/built-in.a
  CC      net/ipv6/xfrm6_policy.o
  AR      drivers/gpu/vga/built-in.a
  CC      arch/x86/kernel/tsc_sync.o
  CC      drivers/connector/cn_queue.o
  CC      drivers/connector/connector.o
  CC      drivers/base/power/sysfs.o
  CC      drivers/connector/cn_proc.o
  CC      lib/bitrev.o
  CC      drivers/acpi/acpi_lpat.o
  CC      net/ipv6/xfrm6_state.o
  CC      lib/crc-ccitt.o
  CC      drivers/base/power/generic_ops.o
  CC      fs/sync.o
  COPY    drivers/tty/vt/defkeymap.c
  CC      drivers/tty/vt/consolemap.o
  CC      net/ipv6/xfrm6_input.o
  CC      drivers/acpi/acpica/nsdump.o
  AR      drivers/gpu/drm/tests/built-in.a
  CC      lib/crc16.o
  AR      drivers/gpu/drm/arm/built-in.a
  CC      net/ipv4/tcp_minisocks.o
  CC      net/ipv6/xfrm6_output.o
  CC      drivers/gpu/drm/display/drm_display_helper_mod.o
  CC      drivers/gpu/drm/ttm/ttm_tt.o
  CC      drivers/gpu/drm/display/drm_dp_dual_mode_helper.o
  CC      mm/memfd.o
  CC      fs/utimes.o
  CC      net/ipv4/tcp_cong.o
  AR      drivers/char/hw_random/built-in.a
  CC      net/netfilter/nf_nat_sip.o
  CC      mm/ptdump.o
  CC      drivers/char/agp/backend.o
  CC      mm/execmem.o
  CC      drivers/char/agp/generic.o
  CC      kernel/stop_machine.o
  CC      fs/d_path.o
  CC      drivers/virtio/virtio_pci_admin_legacy_io.o
  HOSTCC  lib/gen_crc32table
  CC      lib/xxhash.o
  CC      drivers/acpi/acpica/nseval.o
  CC      drivers/tty/serial/8250/8250_exar.o
  CC      drivers/virtio/virtio_input.o
  CC      arch/x86/kernel/setup_percpu.o
  CC      arch/x86/kernel/mpparse.o
  CC      drivers/virtio/virtio_dma_buf.o
  CC      fs/stack.o
  CC      drivers/acpi/acpica/nsinit.o
  CC      drivers/acpi/acpica/nsload.o
  CC      net/netfilter/x_tables.o
  CC      drivers/base/power/common.o
  CC      drivers/acpi/acpica/nsnames.o
  CC      net/ipv4/tcp_metrics.o
  CC      drivers/char/agp/isoch.o
  CC      drivers/acpi/acpica/nsobject.o
  CC      drivers/char/mem.o
  CC      drivers/char/agp/amd64-agp.o
  HOSTCC  drivers/tty/vt/conmakehash
  CC      drivers/base/power/qos.o
  CC      fs/fs_struct.o
  CC      net/ipv4/tcp_fastopen.o
  CC      drivers/tty/n_tty.o
  CC      drivers/gpu/drm/display/drm_dp_helper.o
  CC      drivers/gpu/drm/ttm/ttm_bo.o
  CC      lib/genalloc.o
  AR      drivers/connector/built-in.a
  CC      fs/statfs.o
  CC      drivers/tty/tty_ioctl.o
  CC      lib/percpu_counter.o
  CC      lib/audit.o
  CC      drivers/block/loop.o
  CC      fs/fs_pin.o
  CC      drivers/tty/tty_ldisc.o
  AR      drivers/misc/eeprom/built-in.a
  CC      drivers/tty/tty_buffer.o
  AR      mm/built-in.a
  AR      drivers/misc/cb710/built-in.a
  CC      drivers/tty/tty_port.o
  CC      kernel/audit.o
  CC      drivers/gpu/drm/ttm/ttm_bo_util.o
  CC      drivers/block/virtio_blk.o
  AR      drivers/misc/ti-st/built-in.a
  CC      drivers/tty/vt/defkeymap.o
  AR      drivers/misc/lis3lv02d/built-in.a
  AR      drivers/misc/cardreader/built-in.a
  AR      drivers/misc/built-in.a
  CC      drivers/base/power/runtime.o
  AR      drivers/virtio/built-in.a
  CONMK   drivers/tty/vt/consolemap_deftbl.c
  CC      lib/syscall.o
  CC      drivers/gpu/drm/display/drm_dp_mst_topology.o
  CC      drivers/char/agp/intel-agp.o
  CC      drivers/acpi/acpica/nsparse.o
  CC      drivers/tty/vt/consolemap_deftbl.o
  CC      net/ipv6/xfrm6_protocol.o
  AR      drivers/tty/vt/built-in.a
  CC      kernel/auditfilter.o
  CC      drivers/char/agp/intel-gtt.o
  CC      drivers/gpu/drm/display/drm_dsc_helper.o
  CC      arch/x86/kernel/trace_clock.o
  CC      drivers/acpi/acpi_pcc.o
  CC      drivers/tty/serial/8250/8250_lpss.o
  CC      drivers/tty/serial/8250/8250_mid.o
  CC      drivers/iommu/iommu-sysfs.o
  CC      net/mac80211/iface.o
  CC      drivers/acpi/ac.o
  CC      drivers/acpi/button.o
  CC      lib/errname.o
  CC      drivers/acpi/fan_core.o
  CC      drivers/tty/serial/8250/8250_pci.o
  CC      arch/x86/kernel/trace.o
  CC      drivers/tty/serial/8250/8250_pericom.o
  CC      kernel/auditsc.o
  AR      fs/nfs/built-in.a
  CC      drivers/gpu/drm/ttm/ttm_bo_vm.o
  CC      net/netfilter/xt_tcpudp.o
  CC      drivers/gpu/drm/ttm/ttm_module.o
  CC      net/ipv4/tcp_rate.o
  CC      arch/x86/kernel/rethook.o
  CC      drivers/acpi/acpica/nspredef.o
  AR      net/sunrpc/built-in.a
  AR      drivers/gpu/drm/renesas/rcar-du/built-in.a
  CC      drivers/gpu/drm/i915/i915_config.o
  AR      drivers/gpu/drm/renesas/rz-du/built-in.a
  CC      drivers/char/random.o
  AR      drivers/gpu/drm/renesas/built-in.a
  CC      lib/nlattr.o
  CC      drivers/gpu/drm/i915/i915_driver.o
  CC      fs/nsfs.o
  CC      lib/cpu_rmap.o
  CC      drivers/char/misc.o
  CC      drivers/base/firmware_loader/builtin/main.o
  CC      drivers/base/firmware_loader/main.o
  CC      drivers/gpu/drm/i915/i915_drm_client.o
  CC      fs/fs_types.o
  CC      drivers/gpu/drm/ttm/ttm_execbuf_util.o
  CC      drivers/base/power/wakeirq.o
  CC      drivers/gpu/drm/i915/i915_getparam.o
  AR      drivers/gpu/drm/omapdrm/built-in.a
  CC      drivers/iommu/dma-iommu.o
  AR      drivers/gpu/drm/tilcdc/built-in.a
  CC      drivers/iommu/iova.o
  CC      drivers/acpi/acpica/nsprepkg.o
  CC      net/ipv6/netfilter.o
  CC      drivers/gpu/drm/virtio/virtgpu_drv.o
  CC      net/ipv6/proc.o
  AR      drivers/gpu/drm/imx/built-in.a
  AR      drivers/base/firmware_loader/builtin/built-in.a
  CC      drivers/gpu/drm/ttm/ttm_range_manager.o
  CC      drivers/gpu/drm/ttm/ttm_resource.o
  CC      drivers/gpu/drm/ttm/ttm_pool.o
  CC      net/ipv6/syncookies.o
  CC      drivers/gpu/drm/ttm/ttm_device.o
  CC      drivers/acpi/acpica/nsrepair.o
  CC      drivers/gpu/drm/display/drm_hdcp_helper.o
  CC      drivers/acpi/acpica/nsrepair2.o
  CC      lib/dynamic_queue_limits.o
  CC      arch/x86/kernel/vmcore_info_32.o
  CC      drivers/gpu/drm/display/drm_hdmi_helper.o
  AR      drivers/char/agp/built-in.a
  CC      drivers/gpu/drm/display/drm_scdc_helper.o
  CC      drivers/char/virtio_console.o
  CC      net/netfilter/xt_CONNSECMARK.o
  CC      drivers/gpu/drm/ttm/ttm_sys_manager.o
  AR      drivers/gpu/drm/i2c/built-in.a
  CC      drivers/char/hpet.o
  CC      drivers/gpu/drm/ttm/ttm_agp_backend.o
  CC      drivers/acpi/fan_attr.o
  CC      drivers/acpi/acpica/nssearch.o
  CC      net/ipv6/calipso.o
  CC      drivers/base/power/main.o
  CC      drivers/gpu/drm/i915/i915_ioctl.o
  CC      fs/fs_context.o
  AR      drivers/block/built-in.a
  AR      drivers/mfd/built-in.a
  AR      drivers/nfc/built-in.a
  CC      lib/glob.o
  AR      drivers/dax/hmem/built-in.a
  AR      drivers/dax/built-in.a
  CC      drivers/dma-buf/dma-buf.o
  CC      kernel/audit_watch.o
  AR      drivers/cxl/core/built-in.a
  CC      drivers/acpi/acpica/nsutils.o
  AR      drivers/cxl/built-in.a
  CC      net/mac80211/link.o
  CC      fs/fs_parser.o
  CC      drivers/gpu/drm/i915/i915_irq.o
  CC      drivers/acpi/acpi_video.o
  CC      fs/fsopen.o
  CC      arch/x86/kernel/machine_kexec_32.o
  CC      net/ipv6/ah6.o
  AS      arch/x86/kernel/relocate_kernel_32.o
  CC      drivers/gpu/drm/virtio/virtgpu_kms.o
  CC      drivers/tty/serial/serial_port.o
  AR      drivers/base/firmware_loader/built-in.a
  CC      arch/x86/kernel/crash_dump_32.o
  CC      fs/init.o
  CC      lib/strncpy_from_user.o
  CC      net/ipv4/tcp_recovery.o
  CC      net/ipv6/esp6.o
  CC      drivers/tty/serial/earlycon.o
  CC      drivers/gpu/drm/virtio/virtgpu_gem.o
  CC      drivers/acpi/acpica/nswalk.o
  AR      drivers/tty/serial/8250/built-in.a
  CC      drivers/acpi/acpica/nsxfeval.o
  CC      kernel/audit_fsnotify.o
  CC      drivers/base/power/wakeup.o
  CC      net/ipv4/tcp_ulp.o
  CC      lib/strnlen_user.o
  CC      net/wireless/sme.o
  CC      arch/x86/kernel/crash.o
  AR      drivers/gpu/drm/ttm/built-in.a
  CC      drivers/char/nvram.o
  AR      drivers/gpu/drm/panel/built-in.a
  CC      arch/x86/kernel/module.o
  CC      net/wireless/chan.o
  AR      drivers/gpu/drm/bridge/analogix/built-in.a
  CC      drivers/gpu/drm/i915/i915_mitigations.o
  CC      arch/x86/kernel/doublefault_32.o
  AR      drivers/gpu/drm/bridge/cadence/built-in.a
  AR      drivers/gpu/drm/bridge/imx/built-in.a
  AR      drivers/gpu/drm/bridge/synopsys/built-in.a
  AR      drivers/gpu/drm/bridge/built-in.a
  CC      net/ipv4/tcp_offload.o
  CC      net/ipv4/tcp_plb.o
  CC      drivers/acpi/acpica/nsxfname.o
  CC      net/netfilter/xt_NFLOG.o
  CC      drivers/gpu/drm/i915/i915_module.o
  AR      drivers/iommu/built-in.a
  CC      net/netfilter/xt_SECMARK.o
  CC      drivers/gpu/drm/i915/i915_params.o
  CC      drivers/macintosh/mac_hid.o
  CC      drivers/dma-buf/dma-fence.o
  CC      net/ipv4/datagram.o
  CC      drivers/acpi/video_detect.o
  CC      fs/kernel_read_file.o
  CC      drivers/acpi/acpica/nsxfobj.o
  CC      drivers/acpi/processor_driver.o
  CC      drivers/acpi/processor_thermal.o
  AR      drivers/scsi/pcmcia/built-in.a
  CC      lib/net_utils.o
  CC      drivers/scsi/scsi.o
  CC      arch/x86/kernel/early_printk.o
  CC      drivers/scsi/hosts.o
  CC      lib/sg_pool.o
  CC      net/ipv6/sit.o
  CC      net/ipv4/raw.o
  CC      net/netfilter/xt_TCPMSS.o
  CC      kernel/audit_tree.o
  CC      net/ipv4/udp.o
  AR      drivers/tty/serial/built-in.a
  CC      drivers/gpu/drm/virtio/virtgpu_vram.o
  CC      drivers/tty/tty_mutex.o
  CC      kernel/kprobes.o
  CC      arch/x86/kernel/hpet.o
  CC      lib/stackdepot.o
  CC      net/netfilter/xt_conntrack.o
  AR      drivers/char/built-in.a
  CC      drivers/acpi/acpica/psargs.o
  AR      drivers/gpu/drm/hisilicon/built-in.a
  AR      drivers/nvme/common/built-in.a
  AR      drivers/nvme/host/built-in.a
  AR      drivers/nvme/target/built-in.a
  AR      drivers/nvme/built-in.a
  CC      drivers/scsi/scsi_ioctl.o
  CC      arch/x86/kernel/amd_nb.o
  AR      drivers/gpu/drm/display/built-in.a
  CC      drivers/dma-buf/dma-fence-array.o
  CC      net/wireless/ethtool.o
  AR      drivers/macintosh/built-in.a
  CC      drivers/ata/libata-core.o
  CC      arch/x86/kernel/kvm.o
  CC      arch/x86/kernel/kvmclock.o
  CC      drivers/scsi/scsicam.o
  CC      drivers/acpi/acpica/psloop.o
  CC      drivers/gpu/drm/i915/i915_pci.o
  CC      arch/x86/kernel/paravirt.o
  CC      drivers/base/power/wakeup_stats.o
  CC      drivers/acpi/acpica/psobject.o
  CC      net/wireless/mesh.o
  AR      drivers/net/pse-pd/built-in.a
  AR      drivers/net/phy/qcom/built-in.a
  CC      drivers/scsi/scsi_error.o
  CC      drivers/net/phy/mdio-boardinfo.o
  CC      drivers/net/mdio/acpi_mdio.o
  CC      fs/mnt_idmapping.o
  CC      arch/x86/kernel/pvclock.o
  AR      drivers/net/pcs/built-in.a
  AR      drivers/net/ethernet/3com/built-in.a
  AR      drivers/net/wireless/admtek/built-in.a
  CC      drivers/tty/tty_ldsem.o
  CC      drivers/net/ethernet/8390/ne2k-pci.o
  CC      net/mac80211/rate.o
  AR      drivers/net/wireless/ath/built-in.a
  CC      drivers/acpi/processor_idle.o
  AR      drivers/net/wireless/atmel/built-in.a
  CC      drivers/gpu/drm/i915/i915_scatterlist.o
  AR      drivers/net/wireless/broadcom/built-in.a
  AR      drivers/net/wireless/intel/built-in.a
  CC      drivers/gpu/drm/virtio/virtgpu_display.o
  AR      drivers/net/wireless/intersil/built-in.a
  CC      net/ipv4/udplite.o
  CC      drivers/gpu/drm/virtio/virtgpu_vq.o
  AR      drivers/net/wireless/marvell/built-in.a
  AR      drivers/net/wireless/mediatek/built-in.a
  AR      drivers/net/wireless/microchip/built-in.a
  AR      drivers/net/wireless/purelifi/built-in.a
  AR      drivers/net/wireless/quantenna/built-in.a
  CC      drivers/gpu/drm/i915/i915_suspend.o
  AR      drivers/net/wireless/ralink/built-in.a
  CC      drivers/gpu/drm/i915/i915_switcheroo.o
  AR      drivers/net/wireless/realtek/built-in.a
  CC      net/netfilter/xt_policy.o
  AR      drivers/net/wireless/rsi/built-in.a
  CC      lib/asn1_decoder.o
  CC      drivers/base/power/trace.o
  AR      drivers/net/wireless/silabs/built-in.a
  CC      drivers/acpi/acpica/psopcode.o
  AR      drivers/net/wireless/st/built-in.a
  GEN     lib/oid_registry_data.c
  CC      drivers/acpi/processor_throttling.o
  AR      drivers/net/wireless/ti/built-in.a
  CC      drivers/gpu/drm/i915/i915_sysfs.o
  AR      drivers/net/wireless/zydas/built-in.a
  CC      drivers/dma-buf/dma-fence-chain.o
  AR      drivers/net/wireless/virtual/built-in.a
  CC      drivers/gpu/drm/i915/i915_utils.o
  AR      drivers/net/wireless/built-in.a
  CC      lib/ucs2_string.o
  CC      drivers/gpu/drm/i915/intel_clock_gating.o
  CC      arch/x86/kernel/pcspeaker.o
  CC      net/mac80211/michael.o
  CC      drivers/acpi/acpica/psopinfo.o
  CC      fs/remap_range.o
  CC      kernel/seccomp.o
  CC      net/mac80211/tkip.o
  CC      drivers/firewire/init_ohci1394_dma.o
  CC      drivers/cdrom/cdrom.o
  AR      drivers/auxdisplay/built-in.a
  AR      drivers/net/ethernet/adaptec/built-in.a
  CC      arch/x86/kernel/check.o
  CC      drivers/net/phy/stubs.o
  CC      arch/x86/kernel/uprobes.o
  CC      drivers/net/phy/mdio_devres.o
  CC      drivers/acpi/acpica/psparse.o
  CC      drivers/tty/tty_baudrate.o
  AR      drivers/net/usb/built-in.a
  CC      drivers/net/mii.o
  CC      drivers/net/mdio/fwnode_mdio.o
  AR      drivers/net/ethernet/agere/built-in.a
  CC      net/netfilter/xt_state.o
  CC      lib/sbitmap.o
  CC      drivers/dma-buf/dma-fence-unwrap.o
  CC      drivers/gpu/drm/virtio/virtgpu_fence.o
  CC      drivers/dma-buf/dma-resv.o
  CC      drivers/pcmcia/cs.o
  CC      drivers/gpu/drm/i915/intel_device_info.o
  CC      drivers/gpu/drm/virtio/virtgpu_object.o
  CC      drivers/pcmcia/socket_sysfs.o
  CC      drivers/scsi/scsi_lib.o
  CC      drivers/gpu/drm/i915/intel_memory_region.o
  AR      drivers/base/power/built-in.a
  CC      drivers/pcmcia/cardbus.o
  CC      drivers/base/regmap/regmap.o
  CC      net/ipv6/addrconf_core.o
  CC      drivers/acpi/acpica/psscope.o
  CC      drivers/net/ethernet/8390/8390.o
  CC      drivers/base/regmap/regcache.o
  CC      drivers/pcmcia/ds.o
  CC      drivers/gpu/drm/virtio/virtgpu_debugfs.o
  AR      drivers/firewire/built-in.a
  CC      drivers/gpu/drm/i915/intel_pcode.o
  CC      drivers/input/serio/serio.o
  CC      drivers/usb/common/common.o
  CC      drivers/gpu/drm/i915/intel_region_ttm.o
  CC      drivers/acpi/processor_perflib.o
  CC      drivers/usb/common/debug.o
  CC      drivers/gpu/drm/virtio/virtgpu_plane.o
  CC      drivers/input/serio/i8042.o
  CC      drivers/pcmcia/pcmcia_resource.o
  CC      drivers/tty/tty_jobctrl.o
  CC      arch/x86/kernel/perf_regs.o
  CC      drivers/tty/n_null.o
  CC      drivers/tty/pty.o
  CC      drivers/net/phy/phy.o
  CC      drivers/tty/tty_audit.o
  CC      drivers/acpi/acpica/pstree.o
  CC      drivers/usb/core/usb.o
  CC      fs/pidfs.o
  CC      drivers/usb/core/hub.o
  AR      drivers/base/test/built-in.a
  CC      drivers/tty/sysrq.o
  CC      drivers/gpu/drm/virtio/virtgpu_ioctl.o
  CC      lib/group_cpus.o
  CC      lib/fw_table.o
  AR      drivers/net/mdio/built-in.a
  CC      drivers/base/component.o
  CC      drivers/acpi/acpica/psutils.o
  CC      drivers/dma-buf/sync_file.o
  CC      net/ipv6/exthdrs_core.o
  CC [M]  net/netfilter/nf_log_syslog.o
  CC      drivers/net/loopback.o
  CC      drivers/input/serio/serport.o
  CC      drivers/gpu/drm/virtio/virtgpu_prime.o
  CC      drivers/acpi/acpica/pswalk.o
  AR      drivers/usb/common/built-in.a
  CC      fs/buffer.o
  CC      drivers/gpu/drm/i915/intel_runtime_pm.o
  AR      drivers/usb/phy/built-in.a
  CC      drivers/acpi/acpica/psxface.o
  CC      drivers/usb/mon/mon_main.o
  CC      drivers/gpu/drm/virtio/virtgpu_trace_points.o
  CC      drivers/acpi/acpica/rsaddr.o
  CC      kernel/relay.o
  CC      drivers/acpi/container.o
  CC      drivers/usb/host/pci-quirks.o
  CC      arch/x86/kernel/tracepoint.o
  CC      drivers/usb/host/ehci-hcd.o
  CC      drivers/acpi/thermal_lib.o
  CC      drivers/acpi/thermal.o
  CC      net/ipv6/ip6_checksum.o
  CC      drivers/usb/class/usblp.o
  AR      lib/lib.a
  GEN     lib/crc32table.h
  CC      drivers/acpi/nhlt.o
  CC      drivers/acpi/acpi_memhotplug.o
  AR      drivers/cdrom/built-in.a
  CC      lib/oid_registry.o
  CC      drivers/net/phy/phy-c45.o
  CC      drivers/base/regmap/regcache-rbtree.o
  CC      drivers/gpu/drm/i915/intel_sbi.o
  CC      drivers/base/regmap/regcache-flat.o
  AR      drivers/net/ethernet/8390/built-in.a
  CC      drivers/base/regmap/regcache-maple.o
  CC      net/ipv4/udp_offload.o
  AR      drivers/net/ethernet/alacritech/built-in.a
  CC      fs/mpage.o
  AR      drivers/net/ethernet/alteon/built-in.a
  CC      fs/proc_namespace.o
  AR      drivers/net/ethernet/amazon/built-in.a
  AR      drivers/net/ethernet/amd/built-in.a
  AR      drivers/net/ethernet/aquantia/built-in.a
  AR      drivers/net/ethernet/arc/built-in.a
  AR      drivers/net/ethernet/asix/built-in.a
  AR      drivers/dma-buf/built-in.a
  CC      drivers/usb/mon/mon_stat.o
  AR      drivers/net/ethernet/atheros/built-in.a
  CC      drivers/acpi/acpica/rscalc.o
  CC      net/ipv6/ip6_icmp.o
  AR      drivers/net/ethernet/cadence/built-in.a
  CC      drivers/acpi/acpica/rscreate.o
  CC      drivers/pcmcia/cistpl.o
  CC      drivers/net/ethernet/broadcom/bnx2.o
  CC      drivers/acpi/acpica/rsdumpinfo.o
  CC      arch/x86/kernel/itmt.o
  CC      drivers/net/phy/phy-core.o
  CC      drivers/acpi/ioapic.o
  AR      drivers/net/ethernet/brocade/built-in.a
  CC      net/mac80211/aes_cmac.o
  CC      drivers/input/serio/libps2.o
  CC      drivers/pcmcia/pcmcia_cis.o
  AR      drivers/tty/built-in.a
  CC      net/wireless/ap.o
  CC      drivers/acpi/battery.o
  CC      lib/crc32.o
  CC      net/wireless/trace.o
  CC      drivers/input/keyboard/atkbd.o
  CC      drivers/usb/core/hcd.o
  CC      net/mac80211/aes_gmac.o
  CC      drivers/scsi/constants.o
  CC      fs/direct-io.o
  CC      drivers/rtc/lib.o
  CC      net/ipv6/output_core.o
  CC      drivers/acpi/acpica/rsinfo.o
  CC      drivers/acpi/acpica/rsio.o
  CC      drivers/i2c/algos/i2c-algo-bit.o
  CC      drivers/gpu/drm/virtio/virtgpu_submit.o
  CC      net/ipv6/protocol.o
  CC      net/ipv6/ip6_offload.o
  CC      drivers/usb/mon/mon_text.o
  AR      drivers/gpu/drm/mxsfb/built-in.a
  CC      drivers/net/netconsole.o
  AR      drivers/i3c/built-in.a
  AR      drivers/gpu/drm/tiny/built-in.a
  CC      kernel/utsname_sysctl.o
  CC      drivers/pcmcia/rsrc_mgr.o
  CC      arch/x86/kernel/umip.o
  CC      drivers/net/ethernet/broadcom/tg3.o
  CC      drivers/i2c/busses/i2c-i801.o
  AR      drivers/usb/class/built-in.a
  CC      net/ipv6/tcpv6_offload.o
  CC      net/mac80211/fils_aead.o
  CC      drivers/acpi/bgrt.o
  CC      kernel/delayacct.o
  CC      drivers/gpu/drm/i915/intel_step.o
  CC      kernel/taskstats.o
  CC      drivers/acpi/acpica/rsirq.o
  CC      net/ipv6/exthdrs_offload.o
  AR      drivers/i2c/muxes/built-in.a
  AR      lib/built-in.a
  CC      drivers/i2c/i2c-boardinfo.o
  CC      drivers/i2c/i2c-core-base.o
  AR      drivers/input/serio/built-in.a
  CC      net/mac80211/cfg.o
  CC      fs/eventpoll.o
  CC      drivers/usb/storage/scsiglue.o
  CC      drivers/rtc/class.o
  CC [M]  net/netfilter/xt_mark.o
  CC      drivers/usb/storage/protocol.o
  CC      drivers/scsi/scsi_lib_dma.o
  CC      drivers/acpi/acpica/rslist.o
  CC      drivers/base/regmap/regmap-debugfs.o
  CC      drivers/ata/libata-scsi.o
  CC      drivers/ata/libata-eh.o
  CC      drivers/pcmcia/rsrc_nonstatic.o
  AR      drivers/gpu/drm/xlnx/built-in.a
  CC      drivers/pcmcia/yenta_socket.o
  CC      drivers/net/phy/phy_device.o
  CC      net/mac80211/ethtool.o
  CC      drivers/acpi/acpica/rsmemory.o
  AR      drivers/input/keyboard/built-in.a
  CC      net/ipv4/arp.o
  CC      drivers/input/mouse/psmouse-base.o
  CC      net/ipv4/icmp.o
  CC      drivers/input/mouse/synaptics.o
  AR      drivers/gpu/drm/virtio/built-in.a
  CC      drivers/acpi/acpica/rsmisc.o
  CC      drivers/rtc/interface.o
  CC      drivers/input/mouse/focaltech.o
  CC      drivers/rtc/nvmem.o
  CC      drivers/usb/mon/mon_bin.o
  AR      drivers/i2c/algos/built-in.a
  CC      drivers/acpi/spcr.o
  CC      arch/x86/kernel/unwind_frame.o
  CC      drivers/i2c/i2c-core-smbus.o
  CC      drivers/usb/host/ehci-pci.o
  CC      drivers/net/phy/linkmode.o
  CC      drivers/net/virtio_net.o
  CC      fs/anon_inodes.o
  CC      drivers/input/mouse/alps.o
  CC      net/ipv4/devinet.o
  CC      drivers/i2c/i2c-core-acpi.o
  AR      drivers/input/joystick/built-in.a
  CC      drivers/usb/core/urb.o
  CC      drivers/gpu/drm/i915/intel_uncore.o
  CC      net/mac80211/rx.o
  CC      drivers/i2c/i2c-smbus.o
  AR      drivers/i2c/busses/built-in.a
  CC      kernel/tsacct.o
  CC      net/mac80211/spectmgmt.o
  CC      drivers/net/net_failover.o
  CC      fs/signalfd.o
  CC      drivers/scsi/scsi_scan.o
  CC      drivers/usb/storage/transport.o
  CC      drivers/acpi/acpica/rsserial.o
  CC      net/mac80211/tx.o
  CC [M]  net/netfilter/xt_nat.o
  AR      drivers/usb/misc/built-in.a
  CC      drivers/usb/early/ehci-dbgp.o
  CC      drivers/rtc/dev.o
  CC      net/ipv6/inet6_hashtables.o
  AR      drivers/base/regmap/built-in.a
  CC      drivers/base/core.o
  CC      drivers/input/mouse/byd.o
  CC      drivers/input/mouse/logips2pp.o
  CC      drivers/input/mouse/lifebook.o
  AR      arch/x86/kernel/built-in.a
  AR      arch/x86/built-in.a
  CC      drivers/gpu/drm/i915/intel_wakeref.o
  GEN     drivers/scsi/scsi_devinfo_tbl.c
  CC      drivers/acpi/acpica/rsutils.o
  CC      drivers/scsi/scsi_devinfo.o
  CC      fs/timerfd.o
  CC [M]  net/netfilter/xt_LOG.o
  CC      drivers/input/mouse/trackpoint.o
  AR      drivers/usb/mon/built-in.a
  CC      drivers/input/mouse/cypress_ps2.o
  CC      drivers/usb/host/ohci-hcd.o
  CC      kernel/tracepoint.o
  AR      drivers/pcmcia/built-in.a
  CC      drivers/usb/core/message.o
  CC      net/mac80211/key.o
  CC      net/mac80211/util.o
  CC      net/mac80211/parse.o
  CC      drivers/input/mouse/psmouse-smbus.o
  CC      fs/eventfd.o
  CC      drivers/scsi/scsi_sysctl.o
  CC      drivers/acpi/acpica/rsxface.o
  CC [M]  net/netfilter/xt_MASQUERADE.o
  CC      drivers/gpu/drm/i915/vlv_sideband.o
  CC      drivers/rtc/proc.o
  AR      drivers/gpu/drm/gud/built-in.a
  CC      net/ipv4/af_inet.o
  AR      drivers/usb/early/built-in.a
  AR      drivers/media/i2c/built-in.a
  CC      net/mac80211/wme.o
  CC      drivers/gpu/drm/i915/vlv_suspend.o
  CC      net/mac80211/chan.o
  AR      drivers/media/tuners/built-in.a
  AR      drivers/i2c/built-in.a
  AR      drivers/media/rc/keymaps/built-in.a
  AR      drivers/media/rc/built-in.a
  CC      drivers/usb/storage/usb.o
  AR      drivers/pps/clients/built-in.a
  AR      drivers/pps/generators/built-in.a
  AR      drivers/media/common/b2c2/built-in.a
  CC      drivers/pps/pps.o
  AR      drivers/media/common/saa7146/built-in.a
  AR      drivers/media/common/siano/built-in.a
  AR      drivers/media/common/v4l2-tpg/built-in.a
  AR      drivers/media/common/videobuf2/built-in.a
  AR      drivers/media/common/built-in.a
  CC      drivers/net/phy/mdio_bus.o
  CC      drivers/acpi/acpica/tbdata.o
  AR      drivers/media/platform/allegro-dvt/built-in.a
  AR      drivers/media/platform/amlogic/meson-ge2d/built-in.a
  CC      net/ipv4/igmp.o
  CC      net/mac80211/trace.o
  AR      drivers/media/platform/amlogic/built-in.a
  AR      drivers/media/platform/amphion/built-in.a
  CC      drivers/net/phy/mdio_device.o
  AR      drivers/media/platform/aspeed/built-in.a
  CC      kernel/irq_work.o
  AR      drivers/media/platform/atmel/built-in.a
  CC      drivers/gpu/drm/i915/soc/intel_dram.o
  CC      drivers/acpi/acpica/tbfadt.o
  AR      drivers/media/platform/broadcom/built-in.a
  AR      drivers/gpu/drm/solomon/built-in.a
  CC      drivers/net/phy/swphy.o
  AR      drivers/media/platform/cadence/built-in.a
  CC      net/wireless/ocb.o
  AR      drivers/media/pci/ttpci/built-in.a
  CC      net/wireless/pmsr.o
  AR      drivers/media/platform/chips-media/coda/built-in.a
  AR      drivers/media/pci/b2c2/built-in.a
  AR      drivers/media/pci/pluto2/built-in.a
  CC      drivers/gpu/drm/i915/soc/intel_gmch.o
  CC [M]  net/netfilter/xt_addrtype.o
  AR      drivers/media/platform/chips-media/wave5/built-in.a
  AR      drivers/media/pci/dm1105/built-in.a
  AR      drivers/media/usb/b2c2/built-in.a
  AR      drivers/media/platform/chips-media/built-in.a
  AR      drivers/media/pci/pt1/built-in.a
  CC      drivers/usb/core/driver.o
  AR      drivers/media/platform/intel/built-in.a
  AR      drivers/media/usb/dvb-usb/built-in.a
  AR      drivers/media/pci/pt3/built-in.a
  CC      drivers/rtc/sysfs.o
  AR      drivers/media/platform/marvell/built-in.a
  AR      drivers/media/usb/dvb-usb-v2/built-in.a
  AR      drivers/media/pci/mantis/built-in.a
  AR      drivers/media/usb/s2255/built-in.a
  AR      drivers/media/pci/ngene/built-in.a
  AR      drivers/media/platform/mediatek/jpeg/built-in.a
  AR      drivers/media/usb/siano/built-in.a
  AR      drivers/media/pci/ddbridge/built-in.a
  AR      drivers/media/platform/mediatek/mdp/built-in.a
  AR      drivers/media/usb/ttusb-budget/built-in.a
  AR      drivers/media/pci/saa7146/built-in.a
  AR      drivers/media/platform/mediatek/vcodec/common/built-in.a
  AR      drivers/media/usb/ttusb-dec/built-in.a
  AR      drivers/media/pci/smipcie/built-in.a
  AR      drivers/media/usb/built-in.a
  CC      drivers/scsi/scsi_proc.o
  AR      drivers/media/platform/mediatek/vcodec/encoder/built-in.a
  AR      drivers/media/pci/netup_unidvb/built-in.a
  AR      drivers/media/platform/mediatek/vcodec/decoder/built-in.a
  AR      drivers/media/platform/mediatek/vcodec/built-in.a
  CC      net/ipv6/mcast_snoop.o
  AR      drivers/media/platform/mediatek/vpu/built-in.a
  AR      drivers/input/mouse/built-in.a
  AR      drivers/media/pci/intel/ipu3/built-in.a
  CC      drivers/usb/core/config.o
  AR      drivers/input/tablet/built-in.a
  AR      drivers/media/pci/intel/ivsc/built-in.a
  AR      drivers/media/platform/mediatek/mdp3/built-in.a
  AR      drivers/input/touchscreen/built-in.a
  AR      drivers/media/pci/intel/built-in.a
  AR      drivers/media/platform/mediatek/built-in.a
  AR      drivers/media/pci/built-in.a
  AR      drivers/input/misc/built-in.a
  CC      drivers/input/input.o
  AR      drivers/media/platform/microchip/built-in.a
  CC      fs/aio.o
  AR      drivers/media/platform/nuvoton/built-in.a
  CC      drivers/base/bus.o
  CC      fs/locks.o
  AR      drivers/media/platform/nvidia/tegra-vde/built-in.a
  CC [M]  drivers/gpu/drm/scheduler/sched_main.o
  CC      drivers/acpi/acpica/tbfind.o
  AR      drivers/media/platform/nvidia/built-in.a
  CC      drivers/pps/kapi.o
  AR      drivers/media/platform/nxp/dw100/built-in.a
  AR      drivers/media/platform/nxp/imx-jpeg/built-in.a
  AR      drivers/media/platform/nxp/imx8-isi/built-in.a
  AR      drivers/media/platform/nxp/built-in.a
  AR      drivers/media/platform/qcom/camss/built-in.a
  AR      drivers/media/platform/qcom/venus/built-in.a
  AR      drivers/media/platform/qcom/built-in.a
  AR      drivers/media/platform/renesas/rcar-vin/built-in.a
  CC      drivers/acpi/acpica/tbinstal.o
  AR      drivers/media/platform/renesas/rzg2l-cru/built-in.a
  AR      drivers/media/platform/renesas/vsp1/built-in.a
  CC      net/mac80211/mlme.o
  CC      kernel/static_call.o
  AR      drivers/media/platform/renesas/built-in.a
  AR      drivers/media/platform/rockchip/rga/built-in.a
  AR      drivers/media/platform/samsung/exynos-gsc/built-in.a
  AR      drivers/media/platform/rockchip/rkisp1/built-in.a
  AR      drivers/media/platform/samsung/exynos4-is/built-in.a
  AR      drivers/media/platform/rockchip/built-in.a
  AR      drivers/media/platform/samsung/s3c-camif/built-in.a
  AR      drivers/media/platform/samsung/s5p-g2d/built-in.a
  AR      drivers/media/platform/st/sti/bdisp/built-in.a
  AR      drivers/media/platform/st/sti/c8sectpfe/built-in.a
  AR      drivers/media/platform/samsung/s5p-jpeg/built-in.a
  AR      drivers/media/platform/st/sti/hva/built-in.a
  AR      drivers/media/platform/st/sti/delta/built-in.a
  AR      drivers/media/platform/samsung/s5p-mfc/built-in.a
  CC      net/mac80211/tdls.o
  AR      drivers/media/platform/samsung/built-in.a
  AR      drivers/media/platform/st/stm32/built-in.a
  AR      drivers/media/platform/st/built-in.a
  CC      drivers/usb/storage/initializers.o
  CC      net/mac80211/ocb.o
  CC      drivers/base/dd.o
  CC      drivers/base/syscore.o
  CC      drivers/rtc/rtc-mc146818-lib.o
  AR      drivers/media/platform/sunxi/sun4i-csi/built-in.a
  AR      drivers/media/platform/sunxi/sun6i-csi/built-in.a
  CC      drivers/ata/libata-transport.o
  AR      drivers/media/platform/sunxi/sun6i-mipi-csi2/built-in.a
  CC      drivers/ata/libata-trace.o
  AR      drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/built-in.a
  CC      drivers/ptp/ptp_clock.o
  AR      drivers/media/platform/sunxi/sun8i-di/built-in.a
  AR      drivers/media/platform/sunxi/sun8i-rotate/built-in.a
  AR      drivers/media/platform/sunxi/built-in.a
  AR      drivers/media/platform/ti/am437x/built-in.a
  AR      drivers/media/platform/ti/cal/built-in.a
  CC      drivers/acpi/acpica/tbprint.o
  AR      drivers/media/platform/ti/vpe/built-in.a
  AR      drivers/media/platform/ti/davinci/built-in.a
  CC      drivers/ata/libata-sata.o
  CC      drivers/ptp/ptp_chardev.o
  CC      kernel/padata.o
  AR      drivers/media/platform/ti/j721e-csi2rx/built-in.a
  CC      drivers/pps/sysfs.o
  AR      drivers/media/platform/ti/omap/built-in.a
  CC      net/mac80211/airtime.o
  AR      drivers/media/platform/ti/omap3isp/built-in.a
  AR      drivers/media/platform/ti/built-in.a
  CC      drivers/scsi/scsi_debugfs.o
  CC [M]  drivers/gpu/drm/scheduler/sched_fence.o
  CC      net/mac80211/eht.o
  AR      drivers/media/platform/verisilicon/built-in.a
  CC      net/mac80211/led.o
  AR      drivers/media/platform/via/built-in.a
  AR      drivers/media/platform/xilinx/built-in.a
  AR      drivers/media/platform/built-in.a
  CC      drivers/net/phy/fixed_phy.o
  CC      drivers/gpu/drm/i915/soc/intel_pch.o
  CC      drivers/usb/host/ohci-pci.o
  CC      drivers/usb/host/uhci-hcd.o
  AR      drivers/media/mmc/siano/built-in.a
  AR      drivers/media/mmc/built-in.a
  CC      drivers/rtc/rtc-cmos.o
  AR      drivers/media/firewire/built-in.a
  AR      drivers/media/spi/built-in.a
  AR      drivers/media/test-drivers/built-in.a
  AR      drivers/media/built-in.a
  CC      drivers/acpi/acpica/tbutils.o
  CC      net/ipv4/fib_frontend.o
  CC      drivers/usb/core/file.o
  AR      net/netfilter/built-in.a
  AR      drivers/pps/built-in.a
  CC      kernel/jump_label.o
  AR      net/ipv6/built-in.a
  CC      drivers/scsi/scsi_trace.o
  CC      drivers/usb/storage/sierra_ms.o
  CC      drivers/usb/storage/option_ms.o
  CC      drivers/usb/storage/usual-tables.o
  CC      drivers/gpu/drm/i915/i915_memcpy.o
  CC      drivers/base/driver.o
  CC      drivers/ptp/ptp_sysfs.o
  CC      drivers/gpu/drm/i915/i915_mm.o
  CC [M]  drivers/gpu/drm/scheduler/sched_entity.o
  CC      drivers/input/input-compat.o
  CC      drivers/input/input-mt.o
  CC      drivers/acpi/acpica/tbxface.o
  CC      drivers/scsi/scsi_logging.o
  CC      drivers/ptp/ptp_vclock.o
  CC      drivers/ata/libata-sff.o
  CC      drivers/base/class.o
  CC      drivers/usb/host/xhci.o
  CC      drivers/ptp/ptp_kvm_x86.o
  CC      drivers/ata/libata-pmp.o
  CC      drivers/ata/libata-acpi.o
  CC      drivers/ptp/ptp_kvm_common.o
  CC      net/mac80211/pm.o
  CC      drivers/usb/core/buffer.o
  CC      fs/binfmt_misc.o
  CC      drivers/gpu/drm/i915/i915_sw_fence.o
  CC      drivers/scsi/scsi_pm.o
  CC      kernel/context_tracking.o
  CC      drivers/net/phy/realtek.o
  CC      drivers/scsi/scsi_bsg.o
  CC      drivers/acpi/acpica/tbxfload.o
  CC      drivers/ata/libata-pata-timings.o
  CC      net/ipv4/fib_semantics.o
  CC      drivers/base/platform.o
  CC      net/mac80211/rc80211_minstrel_ht.o
  AR      drivers/usb/storage/built-in.a
  CC      net/mac80211/wbrf.o
  CC      drivers/scsi/scsi_common.o
  CC      drivers/scsi/scsi_transport_spi.o
  AR      drivers/rtc/built-in.a
  CC      drivers/scsi/virtio_scsi.o
  CC      drivers/scsi/sd.o
  CC      drivers/power/supply/power_supply_core.o
  LD [M]  drivers/gpu/drm/scheduler/gpu-sched.o
  CC      kernel/iomem.o
  CC      drivers/input/input-poller.o
  CC      drivers/power/supply/power_supply_sysfs.o
  CC      fs/binfmt_script.o
  CC      fs/binfmt_elf.o
  CC      drivers/gpu/drm/i915/i915_sw_fence_work.o
  CC      drivers/acpi/acpica/tbxfroot.o
  CC      drivers/base/cpu.o
  CC      drivers/gpu/drm/i915/i915_syncmap.o
  CC      drivers/hwmon/hwmon.o
  CC      drivers/ata/ahci.o
  CC      drivers/ata/libahci.o
  AR      drivers/thermal/broadcom/built-in.a
  CC      drivers/usb/core/sysfs.o
  AR      drivers/ptp/built-in.a
  AR      drivers/thermal/samsung/built-in.a
  CC      drivers/thermal/intel/intel_tcc.o
  CC      drivers/ata/ata_piix.o
  CC      drivers/thermal/intel/therm_throt.o
  CC      drivers/usb/core/endpoint.o
  CC      drivers/scsi/sr.o
  CC      drivers/acpi/acpica/utaddress.o
  CC      drivers/gpu/drm/i915/i915_user_extensions.o
  CC      drivers/gpu/drm/i915/i915_debugfs.o
  CC      drivers/gpu/drm/i915/i915_debugfs_params.o
  CC      drivers/acpi/acpica/utalloc.o
  CC      drivers/ata/pata_amd.o
  CC      drivers/usb/core/devio.o
  CC      fs/mbcache.o
  CC      drivers/usb/core/notify.o
  CC      drivers/power/supply/power_supply_leds.o
  CC      drivers/input/ff-core.o
  CC      kernel/rseq.o
  CC      drivers/power/supply/power_supply_hwmon.o
  CC      fs/posix_acl.o
  CC      drivers/input/touchscreen.o
  CC      drivers/acpi/acpica/utascii.o
  CC [M]  drivers/thermal/intel/x86_pkg_temp_thermal.o
  CC      drivers/ata/pata_oldpiix.o
  CC      net/ipv4/fib_trie.o
  CC      drivers/base/firmware.o
  AR      drivers/net/phy/built-in.a
  CC      fs/coredump.o
  CC      drivers/gpu/drm/i915/i915_pmu.o
  CC      fs/drop_caches.o
  CC      drivers/gpu/drm/i915/gt/gen2_engine_cs.o
  CC      fs/sysctls.o
  AR      drivers/net/ethernet/cavium/common/built-in.a
  AR      drivers/net/ethernet/cavium/thunder/built-in.a
  CC      fs/fhandle.o
  AR      drivers/net/ethernet/cavium/liquidio/built-in.a
  AR      drivers/net/ethernet/cavium/octeon/built-in.a
  AR      drivers/net/ethernet/cavium/built-in.a
  CC      drivers/usb/core/generic.o
  CC      drivers/base/init.o
  CC      drivers/usb/host/xhci-mem.o
  CC      drivers/usb/core/quirks.o
  CC      drivers/acpi/acpica/utbuffer.o
  AR      drivers/net/ethernet/chelsio/built-in.a
  GEN     net/wireless/shipped-certs.c
  AR      drivers/power/supply/built-in.a
  AR      drivers/thermal/st/built-in.a
  AR      drivers/power/built-in.a
  AR      drivers/thermal/qcom/built-in.a
  CC      net/wireless/shipped-certs.o
  AR      drivers/thermal/tegra/built-in.a
  AR      drivers/net/ethernet/cisco/built-in.a
  CC      drivers/scsi/sr_ioctl.o
  CC      drivers/thermal/thermal_core.o
  CC      drivers/usb/core/devices.o
  AR      drivers/thermal/mediatek/built-in.a
  CC      drivers/thermal/thermal_sysfs.o
  CC      drivers/input/ff-memless.o
  AR      drivers/net/ethernet/cortina/built-in.a
  AR      drivers/watchdog/built-in.a
  CC      drivers/base/map.o
  CC      drivers/md/md.o
  CC      drivers/md/md-bitmap.o
  CC      drivers/scsi/sr_vendor.o
  AR      drivers/hwmon/built-in.a
  CC      drivers/md/md-autodetect.o
  HOSTCC  drivers/gpu/drm/xe/xe_gen_wa_oob
  CC      drivers/cpufreq/cpufreq.o
  AR      drivers/thermal/intel/built-in.a
  CC      drivers/scsi/sg.o
  CC      drivers/cpuidle/cpuidle.o
  CC      drivers/cpuidle/governors/menu.o
  CC      drivers/acpi/acpica/utcksum.o
  CC      drivers/cpufreq/freq_table.o
  CC      net/ipv4/fib_notifier.o
  CC      drivers/input/sparse-keymap.o
  AR      kernel/built-in.a
  CC      net/ipv4/inet_fragment.o
  CC      drivers/scsi/scsi_sysfs.o
  CC      drivers/usb/core/phy.o
  CC      drivers/gpu/drm/i915/gt/gen6_engine_cs.o
  GEN     xe_wa_oob.c xe_wa_oob.h
  CC [M]  drivers/gpu/drm/xe/xe_bb.o
  CC      drivers/acpi/acpica/utcopy.o
  CC      drivers/base/devres.o
  CC      drivers/usb/core/port.o
  CC      drivers/usb/core/hcd-pci.o
  AR      drivers/net/ethernet/dec/tulip/built-in.a
  AR      drivers/net/ethernet/dec/built-in.a
  AR      drivers/net/ethernet/dlink/built-in.a
  CC      drivers/acpi/acpica/utexcep.o
  AR      drivers/net/ethernet/emulex/built-in.a
  AR      drivers/net/ethernet/engleder/built-in.a
  CC      drivers/acpi/acpica/utdebug.o
  CC      drivers/usb/core/usb-acpi.o
  CC [M]  drivers/gpu/drm/xe/xe_bo.o
  CC [M]  drivers/gpu/drm/xe/xe_bo_evict.o
  CC      drivers/ata/pata_sch.o
  CC      drivers/cpuidle/driver.o
  CC      drivers/md/dm.o
  CC      net/ipv4/ping.o
  AR      drivers/mmc/built-in.a
  AR      drivers/ufs/built-in.a
  CC      drivers/cpuidle/governors/haltpoll.o
  AR      drivers/leds/trigger/built-in.a
  AR      drivers/leds/blink/built-in.a
  AR      drivers/firmware/arm_ffa/built-in.a
  AR      drivers/leds/simple/built-in.a
  CC      drivers/leds/led-core.o
  AR      drivers/firmware/arm_scmi/built-in.a
  CC      drivers/cpufreq/cpufreq_performance.o
  CC      drivers/cpuidle/governor.o
  AR      drivers/firmware/broadcom/built-in.a
  CC      drivers/cpufreq/cpufreq_userspace.o
  AR      drivers/firmware/cirrus/built-in.a
  CC      net/ipv4/ip_tunnel_core.o
  CC      drivers/ata/pata_mpiix.o
  CC      drivers/input/vivaldi-fmap.o
  AR      drivers/firmware/meson/built-in.a
  CC      drivers/input/input-leds.o
  CC      drivers/leds/led-class.o
  AR      drivers/firmware/microchip/built-in.a
  CC      drivers/thermal/thermal_trip.o
  CC      drivers/acpi/acpica/utdecode.o
  CC [M]  drivers/gpu/drm/xe/xe_debugfs.o
  CC      drivers/firmware/efi/efi-bgrt.o
  CC      drivers/firmware/efi/libstub/efi-stub-helper.o
  CC      drivers/cpufreq/cpufreq_ondemand.o
  AR      drivers/firmware/imx/built-in.a
  AR      drivers/firmware/psci/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_debug_metadata.o
  CC      drivers/firmware/efi/libstub/gop.o
  CC      drivers/base/attribute_container.o
  CC      drivers/firmware/efi/libstub/secureboot.o
  CC      drivers/base/transport_class.o
  CC      drivers/cpuidle/sysfs.o
  CC      drivers/thermal/thermal_helpers.o
  AR      fs/built-in.a
  CC      drivers/gpu/drm/i915/gt/gen6_ppgtt.o
  CC      drivers/cpuidle/poll_state.o
  CC      drivers/cpufreq/cpufreq_governor.o
  CC      drivers/usb/host/xhci-ext-caps.o
  CC      drivers/firmware/efi/efi.o
  CC      drivers/gpu/drm/i915/gt/gen7_renderclear.o
  CC      drivers/gpu/drm/i915/gt/gen8_engine_cs.o
  CC      drivers/acpi/acpica/utdelete.o
  CC      net/ipv4/gre_offload.o
  CC      drivers/firmware/efi/libstub/tpm.o
  CC      drivers/usb/host/xhci-ring.o
  AR      drivers/usb/core/built-in.a
  CC      drivers/usb/host/xhci-hub.o
  CC      drivers/leds/led-triggers.o
  CC      drivers/gpu/drm/i915/gt/gen8_ppgtt.o
  CC      drivers/acpi/acpica/uterror.o
  CC      drivers/gpu/drm/drm_aperture.o
  CC      drivers/base/topology.o
  CC      drivers/input/evdev.o
  AR      drivers/crypto/stm32/built-in.a
  CC      drivers/clocksource/acpi_pm.o
  AR      drivers/crypto/xilinx/built-in.a
  AR      drivers/crypto/hisilicon/built-in.a
  CC      drivers/clocksource/i8253.o
  CC      drivers/base/container.o
  AR      drivers/crypto/intel/keembay/built-in.a
  AR      drivers/crypto/intel/ixp4xx/built-in.a
  AR      drivers/crypto/intel/built-in.a
  AR      drivers/crypto/starfive/built-in.a
  CC      drivers/ata/ata_generic.o
  AR      drivers/crypto/built-in.a
  CC      drivers/thermal/thermal_hwmon.o
  CC      drivers/md/dm-table.o
  CC      drivers/firmware/efi/libstub/file.o
  CC      drivers/base/property.o
  AR      drivers/firmware/qcom/built-in.a
  AR      drivers/cpuidle/governors/built-in.a
  CC      drivers/cpufreq/cpufreq_governor_attr_set.o
  CC      drivers/cpuidle/cpuidle-haltpoll.o
  AR      drivers/scsi/built-in.a
  CC      drivers/cpufreq/acpi-cpufreq.o
  AR      drivers/firmware/smccc/built-in.a
  CC      drivers/cpufreq/amd-pstate.o
  CC      drivers/acpi/acpica/uteval.o
  CC      net/ipv4/metrics.o
  AR      drivers/firmware/tegra/built-in.a
  CC      net/ipv4/netlink.o
  CC      drivers/firmware/efi/libstub/mem.o
  CC      drivers/md/dm-target.o
  CC      net/ipv4/nexthop.o
  CC      drivers/firmware/efi/libstub/random.o
  CC      drivers/md/dm-linear.o
  CC [M]  drivers/gpu/drm/xe/xe_devcoredump.o
  AR      drivers/net/ethernet/ezchip/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_device.o
  CC      drivers/usb/host/xhci-dbg.o
  CC      drivers/firmware/efi/libstub/randomalloc.o
  CC      net/ipv4/udp_tunnel_stub.o
  CC      drivers/base/cacheinfo.o
  CC      drivers/firmware/efi/vars.o
  CC      drivers/cpufreq/amd-pstate-trace.o
  CC      drivers/base/swnode.o
  AR      drivers/leds/built-in.a
  CC      drivers/firmware/efi/reboot.o
  CC      drivers/thermal/gov_step_wise.o
  CC      drivers/thermal/gov_user_space.o
  CC      drivers/hid/usbhid/hid-core.o
  CC      drivers/acpi/acpica/utglobal.o
  AR      drivers/clocksource/built-in.a
  CC      drivers/hid/usbhid/hiddev.o
  AR      drivers/cpuidle/built-in.a
  AR      drivers/net/ethernet/fujitsu/built-in.a
  AR      drivers/net/ethernet/fungible/built-in.a
  CC      drivers/md/dm-stripe.o
  AR      drivers/net/ethernet/google/built-in.a
  AR      drivers/net/ethernet/huawei/built-in.a
  CC      drivers/hid/usbhid/hid-pidff.o
  CC      drivers/md/dm-ioctl.o
  CC      drivers/net/ethernet/intel/e1000/e1000_main.o
  CC      drivers/net/ethernet/intel/e1000/e1000_hw.o
  CC      drivers/md/dm-io.o
  CC      drivers/net/ethernet/intel/e1000/e1000_ethtool.o
  AR      drivers/net/ethernet/broadcom/built-in.a
  CC      drivers/net/ethernet/intel/e1000/e1000_param.o
  CC      drivers/md/dm-kcopyd.o
  AR      drivers/ata/built-in.a
  CC      drivers/net/ethernet/intel/e1000e/82571.o
  AR      drivers/input/built-in.a
  CC      drivers/acpi/acpica/uthex.o
  CC      drivers/firmware/efi/libstub/pci.o
  CC      drivers/firmware/efi/libstub/skip_spaces.o
  CC      drivers/firmware/efi/libstub/lib-cmdline.o
  CC      drivers/usb/host/xhci-trace.o
  CC      drivers/gpu/drm/i915/gt/intel_breadcrumbs.o
  CC      drivers/gpu/drm/i915/gt/intel_context.o
  CC      drivers/firmware/efi/libstub/lib-ctype.o
  CC      drivers/gpu/drm/i915/gt/intel_context_sseu.o
  CC      drivers/firmware/efi/libstub/alignedmem.o
  CC      drivers/hid/hid-core.o
  AR      drivers/platform/x86/amd/built-in.a
  CC      drivers/net/ethernet/intel/e1000e/ich8lan.o
  CC      drivers/firmware/efi/libstub/relocate.o
  AR      drivers/platform/x86/intel/built-in.a
  CC      drivers/mailbox/mailbox.o
  CC      drivers/platform/x86/wmi.o
  AR      drivers/thermal/built-in.a
  AR      drivers/perf/built-in.a
  CC      drivers/mailbox/pcc.o
  CC      drivers/md/dm-sysfs.o
  CC      drivers/net/ethernet/intel/e100.o
  AR      drivers/hwtracing/intel_th/built-in.a
  CC      drivers/platform/x86/wmi-bmof.o
  AR      drivers/net/ethernet/i825xx/built-in.a
  CC      drivers/platform/x86/eeepc-laptop.o
  CC      drivers/hid/hid-input.o
  CC      drivers/md/dm-stats.o
  CC      drivers/gpu/drm/i915/gt/intel_engine_cs.o
  CC      net/ipv4/ip_tunnel.o
  CC      drivers/gpu/drm/i915/gt/intel_engine_heartbeat.o
  CC      drivers/acpi/acpica/utids.o
  CC [M]  drivers/gpu/drm/xe/xe_device_sysfs.o
  CC      drivers/base/auxiliary.o
  CC      drivers/cpufreq/intel_pstate.o
  CC      drivers/base/devtmpfs.o
  CC      drivers/acpi/acpica/utinit.o
  CC      net/ipv4/sysctl_net_ipv4.o
  CC [M]  drivers/gpu/drm/xe/xe_dma_buf.o
  CC      drivers/firmware/efi/memattr.o
  CC      drivers/usb/host/xhci-debugfs.o
  AR      drivers/platform/surface/built-in.a
  CC      drivers/hid/hid-quirks.o
  AR      drivers/android/built-in.a
  CC      drivers/gpu/drm/drm_atomic.o
  CC      drivers/hid/hid-debug.o
  AR      drivers/nvmem/layouts/built-in.a
  CC      drivers/nvmem/core.o
  CC      drivers/firmware/efi/libstub/printk.o
  CC      drivers/gpu/drm/drm_atomic_uapi.o
  AR      drivers/mailbox/built-in.a
  CC      drivers/md/dm-rq.o
  CC      drivers/gpu/drm/drm_auth.o
  CC      drivers/acpi/acpica/utlock.o
  AR      net/wireless/built-in.a
  CC      drivers/net/ethernet/intel/e1000e/80003es2lan.o
  AR      drivers/firmware/xilinx/built-in.a
  CC      drivers/base/module.o
  CC      drivers/firmware/efi/libstub/vsprintf.o
  CC      drivers/hid/hidraw.o
  CC      drivers/md/dm-io-rewind.o
  AR      drivers/hid/usbhid/built-in.a
  CC      drivers/hid/hid-generic.o
  CC      drivers/platform/x86/p2sb.o
  CC [M]  drivers/gpu/drm/xe/xe_drm_client.o
  CC      drivers/firmware/efi/libstub/x86-stub.o
  CC      drivers/md/dm-builtin.o
  CC      net/ipv4/proc.o
  CC      drivers/base/devcoredump.o
  CC      drivers/acpi/acpica/utmath.o
  CC      drivers/firmware/efi/tpm.o
  CC      drivers/gpu/drm/i915/gt/intel_engine_pm.o
  CC      drivers/net/ethernet/intel/e1000e/mac.o
  CC      drivers/base/platform-msi.o
  CC      drivers/usb/host/xhci-pci.o
  STUBCPY drivers/firmware/efi/libstub/alignedmem.stub.o
  STUBCPY drivers/firmware/efi/libstub/efi-stub-helper.stub.o
  AR      net/mac80211/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_exec.o
  CC [M]  drivers/gpu/drm/xe/xe_execlist.o
  STUBCPY drivers/firmware/efi/libstub/file.stub.o
  STUBCPY drivers/firmware/efi/libstub/gop.stub.o
  CC      drivers/firmware/efi/memmap.o
  CC      drivers/base/physical_location.o
  CC      drivers/net/ethernet/intel/e1000e/manage.o
  CC      drivers/md/dm-raid1.o
  CC      drivers/firmware/efi/capsule.o
  CC      drivers/hid/hid-a4tech.o
  STUBCPY drivers/firmware/efi/libstub/lib-cmdline.stub.o
  STUBCPY drivers/firmware/efi/libstub/lib-ctype.stub.o
  STUBCPY drivers/firmware/efi/libstub/mem.stub.o
  STUBCPY drivers/firmware/efi/libstub/pci.stub.o
  STUBCPY drivers/firmware/efi/libstub/printk.stub.o
  STUBCPY drivers/firmware/efi/libstub/random.stub.o
  STUBCPY drivers/firmware/efi/libstub/randomalloc.stub.o
  STUBCPY drivers/firmware/efi/libstub/relocate.stub.o
  STUBCPY drivers/firmware/efi/libstub/secureboot.stub.o
  STUBCPY drivers/firmware/efi/libstub/skip_spaces.stub.o
  CC      drivers/gpu/drm/i915/gt/intel_engine_user.o
  CC      drivers/gpu/drm/drm_blend.o
  CC      drivers/gpu/drm/i915/gt/intel_execlists_submission.o
  CC      drivers/md/dm-log.o
  CC      drivers/acpi/acpica/utmisc.o
  AR      drivers/platform/x86/built-in.a
  CC      drivers/firmware/efi/esrt.o
  CC      drivers/hid/hid-apple.o
  AR      drivers/platform/built-in.a
  CC      drivers/hid/hid-belkin.o
  CC      drivers/hid/hid-cherry.o
  CC      drivers/hid/hid-chicony.o
  STUBCPY drivers/firmware/efi/libstub/tpm.stub.o
  CC      net/ipv4/fib_rules.o
  STUBCPY drivers/firmware/efi/libstub/vsprintf.stub.o
  CC      drivers/md/dm-region-hash.o
  CC      drivers/gpu/drm/i915/gt/intel_ggtt.o
  CC      drivers/md/dm-zero.o
  AR      drivers/nvmem/built-in.a
  CC      net/ipv4/ipmr.o
  CC      net/ipv4/ipmr_base.o
  CC      net/ipv4/syncookies.o
  CC      drivers/base/trace.o
  CC      drivers/hid/hid-cypress.o
  AR      drivers/net/ethernet/microsoft/built-in.a
  CC      drivers/hid/hid-ezkey.o
  CC      drivers/firmware/efi/runtime-wrappers.o
  CC      drivers/gpu/drm/drm_bridge.o
  AR      drivers/net/ethernet/litex/built-in.a
  CC      net/ipv4/tunnel4.o
  CC      drivers/hid/hid-gyration.o
  CC      drivers/hid/hid-ite.o
  STUBCPY drivers/firmware/efi/libstub/x86-stub.stub.o
  AR      drivers/firmware/efi/libstub/lib.a
  CC      drivers/gpu/drm/i915/gt/intel_ggtt_fencing.o
  CC      drivers/acpi/acpica/utmutex.o
  CC      drivers/net/ethernet/intel/e1000e/nvm.o
  CC      drivers/acpi/acpica/utnonansi.o
  CC      drivers/net/ethernet/intel/e1000e/phy.o
  CC      drivers/hid/hid-kensington.o
  CC      net/ipv4/ipconfig.o
  CC      drivers/firmware/efi/capsule-loader.o
  CC [M]  drivers/gpu/drm/xe/xe_exec_queue.o
  AR      drivers/net/ethernet/marvell/octeon_ep/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_force_wake.o
  AR      drivers/net/ethernet/marvell/octeon_ep_vf/built-in.a
  AR      drivers/net/ethernet/mellanox/built-in.a
  AR      drivers/net/ethernet/marvell/octeontx2/built-in.a
  CC      drivers/hid/hid-lg.o
  CC      drivers/hid/hid-lgff.o
  AR      drivers/net/ethernet/marvell/prestera/built-in.a
  CC      drivers/net/ethernet/marvell/sky2.o
  CC      drivers/net/ethernet/intel/e1000e/param.o
  CC      drivers/firmware/efi/earlycon.o
  AR      drivers/cpufreq/built-in.a
  CC      drivers/net/ethernet/intel/e1000e/ethtool.o
  CC      drivers/net/ethernet/intel/e1000e/netdev.o
  CC      drivers/hid/hid-lg4ff.o
  CC      drivers/hid/hid-lg-g15.o
  CC [M]  drivers/gpu/drm/xe/xe_ggtt.o
  CC [M]  drivers/gpu/drm/xe/xe_gpu_scheduler.o
  CC      drivers/hid/hid-microsoft.o
  CC      drivers/acpi/acpica/utobject.o
  CC      drivers/gpu/drm/drm_cache.o
  AR      drivers/net/ethernet/micrel/built-in.a
  CC      drivers/hid/hid-monterey.o
  CC      drivers/net/ethernet/intel/e1000e/ptp.o
  CC      drivers/hid/hid-ntrig.o
  CC [M]  drivers/gpu/drm/xe/xe_gsc.o
  CC      drivers/hid/hid-pl.o
  CC      drivers/gpu/drm/i915/gt/intel_gt.o
  AR      drivers/net/ethernet/microchip/built-in.a
  CC      drivers/acpi/acpica/utosi.o
  CC      drivers/gpu/drm/drm_client.o
  AR      drivers/base/built-in.a
  CC      drivers/hid/hid-petalynx.o
  AR      drivers/net/ethernet/intel/e1000/built-in.a
  CC      drivers/hid/hid-redragon.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_clock_utils.o
  CC      drivers/hid/hid-samsung.o
  CC      drivers/acpi/acpica/utownerid.o
  CC      drivers/acpi/acpica/utpredef.o
  CC [M]  drivers/gpu/drm/xe/xe_gsc_proxy.o
  CC [M]  drivers/gpu/drm/xe/xe_gsc_submit.o
  AR      drivers/md/built-in.a
  CC      drivers/gpu/drm/drm_client_modeset.o
  AR      drivers/net/ethernet/mscc/built-in.a
  AR      drivers/net/ethernet/myricom/built-in.a
  AR      drivers/net/ethernet/natsemi/built-in.a
  AR      drivers/net/ethernet/neterion/built-in.a
  CC      drivers/acpi/acpica/utresdecode.o
  AR      drivers/net/ethernet/netronome/built-in.a
  CC      drivers/acpi/acpica/utresrc.o
  CC      drivers/gpu/drm/drm_color_mgmt.o
  AR      drivers/usb/host/built-in.a
  AR      drivers/usb/built-in.a
  CC      drivers/gpu/drm/drm_connector.o
  CC      drivers/acpi/acpica/utstate.o
  CC      drivers/hid/hid-sony.o
  CC [M]  drivers/gpu/drm/xe/xe_gt.o
  CC      net/ipv4/netfilter.o
  CC      drivers/acpi/acpica/utstring.o
  CC      drivers/firmware/dmi_scan.o
  AR      drivers/firmware/efi/built-in.a
  CC      drivers/firmware/dmi-id.o
  CC      drivers/acpi/acpica/utstrsuppt.o
  AR      drivers/net/ethernet/ni/built-in.a
  CC      drivers/net/ethernet/nvidia/forcedeth.o
  AR      drivers/net/ethernet/oki-semi/built-in.a
  CC      drivers/hid/hid-sunplus.o
  AR      drivers/net/ethernet/packetengines/built-in.a
  AR      drivers/net/ethernet/qlogic/built-in.a
  CC      drivers/gpu/drm/drm_crtc.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_debugfs.o
  AR      drivers/net/ethernet/qualcomm/emac/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_gt_ccs_mode.o
  CC      drivers/hid/hid-topseed.o
  AR      drivers/net/ethernet/qualcomm/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.o
  CC      drivers/acpi/acpica/utstrtoul64.o
  CC      drivers/gpu/drm/drm_displayid.o
  CC      drivers/gpu/drm/drm_drv.o
  CC      drivers/firmware/memmap.o
  CC      net/ipv4/tcp_cubic.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_clock.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_irq.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_mcr.o
  CC      drivers/gpu/drm/drm_dumb_buffers.o
  CC      drivers/acpi/acpica/utxface.o
  CC      net/ipv4/tcp_sigpool.o
  CC      drivers/acpi/acpica/utxfinit.o
  CC      drivers/net/ethernet/realtek/8139too.o
  AR      drivers/net/ethernet/renesas/built-in.a
  CC      drivers/net/ethernet/realtek/r8169_main.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_debugfs.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_freq.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_idle.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_pm.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_pm_irq.o
  CC      net/ipv4/cipso_ipv4.o
  CC      drivers/gpu/drm/i915/gt/intel_gt_requests.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_debug.o
  CC      drivers/acpi/acpica/utxferror.o
  CC      drivers/net/ethernet/realtek/r8169_firmware.o
  CC      drivers/gpu/drm/drm_edid.o
  AR      drivers/net/ethernet/rdc/built-in.a
  CC      drivers/gpu/drm/drm_eld.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_mcr.o
  AR      drivers/net/ethernet/rocker/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_gt_pagefault.o
  AR      drivers/net/ethernet/samsung/built-in.a
  CC      net/ipv4/xfrm4_policy.o
  CC      drivers/gpu/drm/drm_encoder.o
  AR      drivers/net/ethernet/seeq/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_gt_sysfs.o
  CC      drivers/gpu/drm/drm_file.o
  AR      drivers/net/ethernet/silan/built-in.a
  AR      drivers/net/ethernet/sis/built-in.a
  AR      drivers/net/ethernet/sfc/built-in.a
  AR      drivers/net/ethernet/smsc/built-in.a
  AR      drivers/net/ethernet/socionext/built-in.a
  CC      drivers/acpi/acpica/utxfmutex.o
  AR      drivers/net/ethernet/stmicro/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.o
  CC      drivers/gpu/drm/i915/gt/intel_gtt.o
  CC      drivers/gpu/drm/i915/gt/intel_llc.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_sysfs.o
  AR      drivers/firmware/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_gt_throttle.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_tlb_invalidation.o
  CC      drivers/gpu/drm/drm_fourcc.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_topology.o
  CC      net/ipv4/xfrm4_state.o
  CC [M]  drivers/gpu/drm/xe/xe_guc.o
  CC      drivers/gpu/drm/drm_framebuffer.o
  CC      drivers/net/ethernet/realtek/r8169_phy_config.o
  CC      net/ipv4/xfrm4_input.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_ads.o
  CC      drivers/gpu/drm/i915/gt/intel_lrc.o
  AR      drivers/hid/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_migrate.o
  CC      drivers/gpu/drm/i915/gt/intel_mocs.o
  AR      drivers/net/ethernet/sun/built-in.a
  CC      net/ipv4/xfrm4_output.o
  AR      drivers/net/ethernet/tehuti/built-in.a
  CC      drivers/gpu/drm/drm_gem.o
  AR      drivers/net/ethernet/ti/built-in.a
  AR      drivers/acpi/acpica/built-in.a
  AR      drivers/net/ethernet/vertexcom/built-in.a
  CC      drivers/gpu/drm/drm_ioctl.o
  AR      drivers/net/ethernet/wangxun/built-in.a
  AR      drivers/net/ethernet/via/built-in.a
  AR      drivers/acpi/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_ppgtt.o
  CC      drivers/gpu/drm/drm_lease.o
  CC      drivers/gpu/drm/drm_managed.o
  CC      drivers/gpu/drm/i915/gt/intel_rc6.o
  CC      net/ipv4/xfrm4_protocol.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_ct.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_db_mgr.o
  CC      drivers/gpu/drm/drm_mm.o
  CC      drivers/gpu/drm/i915/gt/intel_region_lmem.o
  CC      drivers/gpu/drm/drm_mode_config.o
  CC      drivers/gpu/drm/i915/gt/intel_renderstate.o
  CC      drivers/gpu/drm/i915/gt/intel_reset.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_debugfs.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_hwconfig.o
  CC      drivers/gpu/drm/i915/gt/intel_ring.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_id_mgr.o
  CC      drivers/gpu/drm/i915/gt/intel_ring_submission.o
  CC      drivers/gpu/drm/drm_mode_object.o
  AR      drivers/net/ethernet/wiznet/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_guc_klv_helpers.o
  AR      drivers/net/ethernet/xilinx/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_rps.o
  AR      drivers/net/ethernet/xircom/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_sa_media.o
  AR      drivers/net/ethernet/synopsys/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_sseu.o
  AR      drivers/net/ethernet/pensando/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_guc_log.o
  CC      drivers/gpu/drm/drm_modes.o
  CC      drivers/gpu/drm/i915/gt/intel_sseu_debugfs.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_pc.o
  CC      drivers/gpu/drm/i915/gt/intel_timeline.o
  CC      drivers/gpu/drm/drm_modeset_lock.o
  CC      drivers/gpu/drm/drm_plane.o
  CC      drivers/gpu/drm/i915/gt/intel_tlb.o
  AR      drivers/net/ethernet/marvell/built-in.a
  CC      drivers/gpu/drm/i915/gt/intel_wopcm.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_submit.o
  CC      drivers/gpu/drm/drm_prime.o
  CC      drivers/gpu/drm/drm_print.o
  CC      drivers/gpu/drm/drm_property.o
  CC [M]  drivers/gpu/drm/xe/xe_heci_gsc.o
  CC      drivers/gpu/drm/drm_syncobj.o
  CC [M]  drivers/gpu/drm/xe/xe_hw_engine.o
  CC [M]  drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.o
  CC      drivers/gpu/drm/drm_sysfs.o
  CC [M]  drivers/gpu/drm/xe/xe_hw_fence.o
  CC [M]  drivers/gpu/drm/xe/xe_huc.o
  CC [M]  drivers/gpu/drm/xe/xe_huc_debugfs.o
  CC      drivers/gpu/drm/i915/gt/intel_workarounds.o
  CC [M]  drivers/gpu/drm/xe/xe_irq.o
  CC      drivers/gpu/drm/drm_trace_points.o
  CC [M]  drivers/gpu/drm/xe/xe_lrc.o
  CC      drivers/gpu/drm/i915/gt/shmem_utils.o
  CC      drivers/gpu/drm/i915/gt/sysfs_engines.o
  CC [M]  drivers/gpu/drm/xe/xe_migrate.o
  CC      drivers/gpu/drm/i915/gt/intel_ggtt_gmch.o
  AR      net/ipv4/built-in.a
  AR      net/built-in.a
  CC      drivers/gpu/drm/drm_vblank.o
  CC      drivers/gpu/drm/i915/gt/gen6_renderstate.o
  CC      drivers/gpu/drm/i915/gt/gen7_renderstate.o
  CC      drivers/gpu/drm/drm_vblank_work.o
  CC      drivers/gpu/drm/i915/gt/gen8_renderstate.o
  CC [M]  drivers/gpu/drm/xe/xe_mmio.o
  CC [M]  drivers/gpu/drm/xe/xe_mocs.o
  CC      drivers/gpu/drm/drm_vma_manager.o
  CC      drivers/gpu/drm/i915/gt/gen9_renderstate.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_busy.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_clflush.o
  CC      drivers/gpu/drm/drm_writeback.o
  CC      drivers/gpu/drm/drm_panel.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_context.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_create.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_dmabuf.o
  CC [M]  drivers/gpu/drm/xe/xe_module.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_domain.o
  CC [M]  drivers/gpu/drm/xe/xe_oa.o
  CC      drivers/gpu/drm/drm_pci.o
  AR      drivers/net/ethernet/nvidia/built-in.a
  CC      drivers/gpu/drm/drm_debugfs.o
  CC      drivers/gpu/drm/drm_debugfs_crc.o
  CC [M]  drivers/gpu/drm/xe/xe_observation.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_execbuffer.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_internal.o
  CC      drivers/gpu/drm/drm_panel_orientation_quirks.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_lmem.o
  CC [M]  drivers/gpu/drm/xe/xe_pat.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_mman.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_object.o
  AR      drivers/net/ethernet/realtek/built-in.a
  CC [M]  drivers/gpu/drm/xe/xe_pci.o
  CC      drivers/gpu/drm/drm_buddy.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_pages.o
  AR      drivers/net/ethernet/intel/e1000e/built-in.a
  AR      drivers/net/ethernet/intel/built-in.a
  CC      drivers/gpu/drm/drm_gem_shmem_helper.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_phys.o
  AR      drivers/net/ethernet/built-in.a
  AR      drivers/net/built-in.a
  CC      drivers/gpu/drm/drm_atomic_helper.o
  CC      drivers/gpu/drm/drm_atomic_state_helper.o
  CC      drivers/gpu/drm/drm_bridge_connector.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_pm.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_region.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_shmem.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_shrinker.o
  CC      drivers/gpu/drm/drm_crtc_helper.o
  CC [M]  drivers/gpu/drm/xe/xe_pcode.o
  CC [M]  drivers/gpu/drm/xe/xe_pm.o
  CC [M]  drivers/gpu/drm/xe/xe_preempt_fence.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_stolen.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_throttle.o
  CC [M]  drivers/gpu/drm/xe/xe_pt.o
  CC      drivers/gpu/drm/drm_damage_helper.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_tiling.o
  CC [M]  drivers/gpu/drm/xe/xe_pt_walk.o
  CC      drivers/gpu/drm/drm_encoder_slave.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_ttm.o
  CC [M]  drivers/gpu/drm/xe/xe_query.o
  CC      drivers/gpu/drm/drm_flip_work.o
  CC [M]  drivers/gpu/drm/xe/xe_range_fence.o
  CC      drivers/gpu/drm/drm_format_helper.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_ttm_move.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.o
  CC      drivers/gpu/drm/drm_gem_atomic_helper.o
  CC      drivers/gpu/drm/drm_gem_framebuffer_helper.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_userptr.o
  CC      drivers/gpu/drm/drm_kms_helper_common.o
  CC      drivers/gpu/drm/i915/gem/i915_gem_wait.o
  CC      drivers/gpu/drm/i915/gem/i915_gemfs.o
  CC [M]  drivers/gpu/drm/xe/xe_reg_sr.o
  CC [M]  drivers/gpu/drm/xe/xe_reg_whitelist.o
  CC      drivers/gpu/drm/drm_modeset_helper.o
  CC [M]  drivers/gpu/drm/xe/xe_rtp.o
  CC [M]  drivers/gpu/drm/xe/xe_ring_ops.o
  CC      drivers/gpu/drm/i915/i915_active.o
  CC      drivers/gpu/drm/drm_plane_helper.o
  CC      drivers/gpu/drm/drm_probe_helper.o
  CC      drivers/gpu/drm/i915/i915_cmd_parser.o
  CC [M]  drivers/gpu/drm/xe/xe_sa.o
  CC [M]  drivers/gpu/drm/xe/xe_sched_job.o
  CC      drivers/gpu/drm/drm_rect.o
  CC [M]  drivers/gpu/drm/xe/xe_step.o
  CC      drivers/gpu/drm/i915/i915_deps.o
  CC [M]  drivers/gpu/drm/xe/xe_sync.o
  CC      drivers/gpu/drm/i915/i915_gem.o
  CC      drivers/gpu/drm/drm_self_refresh_helper.o
  CC [M]  drivers/gpu/drm/xe/xe_tile.o
  CC      drivers/gpu/drm/i915/i915_gem_evict.o
  CC      drivers/gpu/drm/drm_simple_kms_helper.o
  CC      drivers/gpu/drm/bridge/panel.o
  CC      drivers/gpu/drm/drm_mipi_dsi.o
  CC      drivers/gpu/drm/i915/i915_gem_gtt.o
  CC [M]  drivers/gpu/drm/drm_exec.o
  CC      drivers/gpu/drm/i915/i915_gem_ww.o
  CC [M]  drivers/gpu/drm/drm_gpuvm.o
  CC      drivers/gpu/drm/i915/i915_query.o
  CC      drivers/gpu/drm/i915/i915_request.o
  CC      drivers/gpu/drm/i915/i915_scheduler.o
  CC      drivers/gpu/drm/i915/i915_trace_points.o
  CC      drivers/gpu/drm/i915/i915_ttm_buddy_manager.o
  CC      drivers/gpu/drm/i915/i915_vma.o
  CC      drivers/gpu/drm/i915/i915_vma_resource.o
  CC [M]  drivers/gpu/drm/xe/xe_tile_sysfs.o
  CC [M]  drivers/gpu/drm/drm_suballoc.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.o
  CC [M]  drivers/gpu/drm/xe/xe_trace.o
  CC [M]  drivers/gpu/drm/xe/xe_trace_bo.o
  CC [M]  drivers/gpu/drm/xe/xe_trace_guc.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.o
  CC [M]  drivers/gpu/drm/drm_gem_ttm_helper.o
  CC [M]  drivers/gpu/drm/xe/xe_ttm_sys_mgr.o
  CC [M]  drivers/gpu/drm/xe/xe_ttm_stolen_mgr.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.o
  CC [M]  drivers/gpu/drm/xe/xe_ttm_vram_mgr.o
  CC [M]  drivers/gpu/drm/xe/xe_tuning.o
  CC [M]  drivers/gpu/drm/xe/xe_uc.o
  CC [M]  drivers/gpu/drm/xe/xe_uc_debugfs.o
  CC [M]  drivers/gpu/drm/xe/xe_uc_fw.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_debugfs.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_ads.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_capture.o
  CC [M]  drivers/gpu/drm/xe/xe_vm.o
  CC [M]  drivers/gpu/drm/xe/xe_vram.o
  CC [M]  drivers/gpu/drm/xe/xe_vram_freq.o
  CC [M]  drivers/gpu/drm/xe/xe_wait_user_fence.o
  CC [M]  drivers/gpu/drm/xe/xe_wa.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_ct.o
  CC [M]  drivers/gpu/drm/xe/xe_wopcm.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_fw.o
  CC [M]  drivers/gpu/drm/xe/xe_eudebug.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_hwconfig.o
  LD [M]  drivers/gpu/drm/drm_suballoc_helper.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_log.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_log_debugfs.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_rc.o
  CC [M]  drivers/gpu/drm/xe/xe_hmm.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.o
  CC [M]  drivers/gpu/drm/xe/xe_hwmon.o
  LD [M]  drivers/gpu/drm/drm_ttm_helper.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_sriov_vf.o
  CC [M]  drivers/gpu/drm/xe/xe_gt_sriov_vf_debugfs.o
  CC [M]  drivers/gpu/drm/xe/xe_guc_relay.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_guc_submission.o
  CC [M]  drivers/gpu/drm/xe/xe_memirq.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_huc.o
  CC [M]  drivers/gpu/drm/xe/xe_sriov.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_huc_debugfs.o
  CC [M]  drivers/gpu/drm/xe/display/ext/i915_irq.o
  CC [M]  drivers/gpu/drm/xe/display/ext/i915_utils.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_huc_fw.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_uc.o
  CC [M]  drivers/gpu/drm/xe/display/intel_fb_bo.o
  CC [M]  drivers/gpu/drm/xe/display/intel_fbdev_fb.o
  CC [M]  drivers/gpu/drm/xe/display/xe_display.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.o
  CC      drivers/gpu/drm/i915/gt/uc/intel_uc_fw.o
  CC [M]  drivers/gpu/drm/xe/display/xe_display_misc.o
  CC [M]  drivers/gpu/drm/xe/display/xe_display_rps.o
  CC      drivers/gpu/drm/i915/gt/intel_gsc.o
  CC [M]  drivers/gpu/drm/xe/display/xe_display_wa.o
  CC      drivers/gpu/drm/i915/i915_hwmon.o
  CC [M]  drivers/gpu/drm/xe/display/xe_dsb_buffer.o
  CC [M]  drivers/gpu/drm/xe/display/xe_fb_pin.o
  CC [M]  drivers/gpu/drm/xe/display/xe_hdcp_gsc.o
  CC [M]  drivers/gpu/drm/xe/display/xe_plane_initial.o
  CC      drivers/gpu/drm/i915/display/hsw_ips.o
  CC [M]  drivers/gpu/drm/xe/display/xe_tdf.o
  CC      drivers/gpu/drm/i915/display/i9xx_plane.o
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘find_handle’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:674:18: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
  674 |  const u64 key = (u64)p;
      |                  ^
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘find_client’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:722:10: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  722 |   return (void *)h->key;
      |          ^
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘find_exec_queue_get’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:736:7: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  736 |   q = (struct xe_exec_queue *)h->key;
      |       ^
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘find_lrc’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:751:10: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  751 |   return (void *)h->key;
      |          ^
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘find_vm’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:762:10: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  762 |   return (void *)h->key;
      |          ^
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘find_metadata_get’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:776:7: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
  776 |   m = (struct xe_debug_metadata *)h->key;
      |       ^
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘_xe_eudebug_add_handle’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:790:18: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
  790 |  const u64 key = (u64)p;
      |                  ^
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘_xe_eudebug_remove_handle’:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:870:18: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
  870 |  const u64 key = (u64)p;
      |                  ^
  CC [M]  drivers/gpu/drm/xe/i915-soc/intel_dram.o
  CC [M]  drivers/gpu/drm/xe/i915-soc/intel_pch.o
In file included from /workspace/kernel/include/linux/device.h:15,
                 from /workspace/kernel/include/linux/pci.h:37,
                 from /workspace/kernel/drivers/gpu/drm/xe/xe_device_types.h:9,
                 from /workspace/kernel/drivers/gpu/drm/xe/xe_device.h:11,
                 from /workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:19:
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c: In function ‘__xe_eudebug_vm_access’:
/workspace/kernel/include/drm/drm_print.h:470:47: error: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 15 has type ‘size_t’ {aka ‘unsigned int’} [-Werror=format=]
  470 |  dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
      |                                               ^~~~~~~~
/workspace/kernel/include/linux/dev_printk.h:110:16: note: in definition of macro ‘dev_printk_index_wrap’
  110 |   _p_func(dev, fmt, ##__VA_ARGS__);   \
      |                ^~~
/workspace/kernel/include/linux/dev_printk.h:156:54: note: in expansion of macro ‘dev_fmt’
  156 |  dev_printk_index_wrap(_dev_warn, KERN_WARNING, dev, dev_fmt(fmt), ##__VA_ARGS__)
      |                                                      ^~~~~~~
/workspace/kernel/include/drm/drm_print.h:470:2: note: in expansion of macro ‘dev_warn’
  470 |  dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
      |  ^~~~
/workspace/kernel/include/drm/drm_print.h:480:2: note: in expansion of macro ‘__drm_printk’
  480 |  __drm_printk((drm), warn,, fmt, ##__VA_ARGS__)
      |  ^~~~~~~~~~~~
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:70:30: note: in expansion of macro ‘drm_warn’
   70 | #define eu_warn(d, fmt, ...) drm_warn(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
      |                              ^~~~~~~~
/workspace/kernel/drivers/gpu/drm/xe/xe_eudebug.c:3549:3: note: in expansion of macro ‘eu_warn’
 3549 |   eu_warn(d, "vm_access(%s): vm handle mismatch client_handle=%llu, vm_handle=%llu, flags=0x%llx, pos=%llu, count=%lu\n",
      |   ^~~~~~~
  CC [M]  drivers/gpu/drm/xe/i915-display/icl_dsi.o
  CC      drivers/gpu/drm/i915/display/i9xx_wm.o
  CC      drivers/gpu/drm/i915/display/intel_alpm.o
  CC      drivers/gpu/drm/i915/display/intel_atomic.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_alpm.o
  CC      drivers/gpu/drm/i915/display/intel_atomic_plane.o
  CC      drivers/gpu/drm/i915/display/intel_audio.o
  CC      drivers/gpu/drm/i915/display/intel_bios.o
  CC      drivers/gpu/drm/i915/display/intel_bw.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_atomic.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_atomic_plane.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_audio.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_backlight.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_bios.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_bw.o
  CC      drivers/gpu/drm/i915/display/intel_cdclk.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_cdclk.o
  CC      drivers/gpu/drm/i915/display/intel_color.o
  CC      drivers/gpu/drm/i915/display/intel_combo_phy.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_color.o
  CC      drivers/gpu/drm/i915/display/intel_connector.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_combo_phy.o
  CC      drivers/gpu/drm/i915/display/intel_crtc.o
  CC      drivers/gpu/drm/i915/display/intel_crtc_state_dump.o
  CC      drivers/gpu/drm/i915/display/intel_cursor.o
  CC      drivers/gpu/drm/i915/display/intel_display.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_connector.o
  CC      drivers/gpu/drm/i915/display/intel_display_driver.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_crtc.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_crtc_state_dump.o
  CC      drivers/gpu/drm/i915/display/intel_display_irq.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_cursor.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_cx0_phy.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_ddi.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_ddi_buf_trans.o
  CC      drivers/gpu/drm/i915/display/intel_display_params.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display.o
  CC      drivers/gpu/drm/i915/display/intel_display_power.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_device.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_driver.o
  CC      drivers/gpu/drm/i915/display/intel_display_power_map.o
  CC      drivers/gpu/drm/i915/display/intel_display_power_well.o
  CC      drivers/gpu/drm/i915/display/intel_display_reset.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_irq.o
  CC      drivers/gpu/drm/i915/display/intel_display_rps.o
  CC      drivers/gpu/drm/i915/display/intel_display_wa.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_params.o
  CC      drivers/gpu/drm/i915/display/intel_dmc.o
  CC      drivers/gpu/drm/i915/display/intel_dmc_wl.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_power.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_power_map.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_power_well.o
  CC      drivers/gpu/drm/i915/display/intel_dpio_phy.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_trace.o
  CC      drivers/gpu/drm/i915/display/intel_dpll.o
  CC      drivers/gpu/drm/i915/display/intel_dpll_mgr.o
  CC      drivers/gpu/drm/i915/display/intel_dpt.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_display_wa.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dkl_phy.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dmc.o
  CC      drivers/gpu/drm/i915/display/intel_dpt_common.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dp.o
  CC      drivers/gpu/drm/i915/display/intel_drrs.o
  CC      drivers/gpu/drm/i915/display/intel_dsb.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dp_aux.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dp_aux_backlight.o
  CC      drivers/gpu/drm/i915/display/intel_dsb_buffer.o
  CC      drivers/gpu/drm/i915/display/intel_fb.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dp_hdcp.o
  CC      drivers/gpu/drm/i915/display/intel_fb_bo.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dp_link_training.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dp_mst.o
  CC      drivers/gpu/drm/i915/display/intel_fb_pin.o
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dpll.o
  CC      drivers/gpu/drm/i915/display/intel_fbc.o
  CC      drivers/gpu/drm/i915/display/intel_fdi.o
cc1: all warnings being treated as errors
  CC [M]  drivers/gpu/drm/xe/i915-display/intel_dpll_mgr.o
make[6]: *** [/workspace/kernel/scripts/Makefile.build:244: drivers/gpu/drm/xe/xe_eudebug.o] Error 1
make[6]: *** Waiting for unfinished jobs....
  CC      drivers/gpu/drm/i915/display/intel_fifo_underrun.o
  CC      drivers/gpu/drm/i915/display/intel_frontbuffer.o
  CC      drivers/gpu/drm/i915/display/intel_global_state.o
  CC      drivers/gpu/drm/i915/display/intel_hdcp.o
  CC      drivers/gpu/drm/i915/display/intel_hdcp_gsc.o
  CC      drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.o
  CC      drivers/gpu/drm/i915/display/intel_hotplug.o
  CC      drivers/gpu/drm/i915/display/intel_hotplug_irq.o
  CC      drivers/gpu/drm/i915/display/intel_hti.o
  CC      drivers/gpu/drm/i915/display/intel_link_bw.o
  CC      drivers/gpu/drm/i915/display/intel_load_detect.o
  CC      drivers/gpu/drm/i915/display/intel_lpe_audio.o
  CC      drivers/gpu/drm/i915/display/intel_modeset_lock.o
  CC      drivers/gpu/drm/i915/display/intel_modeset_setup.o
  CC      drivers/gpu/drm/i915/display/intel_modeset_verify.o
  CC      drivers/gpu/drm/i915/display/intel_overlay.o
  CC      drivers/gpu/drm/i915/display/intel_pch_display.o
  CC      drivers/gpu/drm/i915/display/intel_pch_refclk.o
  CC      drivers/gpu/drm/i915/display/intel_plane_initial.o
  CC      drivers/gpu/drm/i915/display/intel_pmdemand.o
  CC      drivers/gpu/drm/i915/display/intel_psr.o
  CC      drivers/gpu/drm/i915/display/intel_quirks.o
  CC      drivers/gpu/drm/i915/display/intel_sprite.o
  CC      drivers/gpu/drm/i915/display/intel_sprite_uapi.o
  CC      drivers/gpu/drm/i915/display/intel_tc.o
  CC      drivers/gpu/drm/i915/display/intel_vblank.o
  CC      drivers/gpu/drm/i915/display/intel_vga.o
  CC      drivers/gpu/drm/i915/display/intel_wm.o
  CC      drivers/gpu/drm/i915/display/skl_scaler.o
  CC      drivers/gpu/drm/i915/display/skl_universal_plane.o
  CC      drivers/gpu/drm/i915/display/skl_watermark.o
  CC      drivers/gpu/drm/i915/display/intel_acpi.o
  CC      drivers/gpu/drm/i915/display/intel_opregion.o
  CC      drivers/gpu/drm/i915/display/intel_display_debugfs.o
  CC      drivers/gpu/drm/i915/display/intel_display_debugfs_params.o
  CC      drivers/gpu/drm/i915/display/intel_pipe_crc.o
  CC      drivers/gpu/drm/i915/display/dvo_ch7017.o
  CC      drivers/gpu/drm/i915/display/dvo_ch7xxx.o
  CC      drivers/gpu/drm/i915/display/dvo_ivch.o
  CC      drivers/gpu/drm/i915/display/dvo_ns2501.o
  CC      drivers/gpu/drm/i915/display/dvo_sil164.o
  CC      drivers/gpu/drm/i915/display/dvo_tfp410.o
  CC      drivers/gpu/drm/i915/display/g4x_dp.o
  CC      drivers/gpu/drm/i915/display/g4x_hdmi.o
  CC      drivers/gpu/drm/i915/display/icl_dsi.o
  CC      drivers/gpu/drm/i915/display/intel_backlight.o
  CC      drivers/gpu/drm/i915/display/intel_crt.o
  CC      drivers/gpu/drm/i915/display/intel_cx0_phy.o
  CC      drivers/gpu/drm/i915/display/intel_ddi.o
  CC      drivers/gpu/drm/i915/display/intel_ddi_buf_trans.o
  CC      drivers/gpu/drm/i915/display/intel_display_device.o
  CC      drivers/gpu/drm/i915/display/intel_display_trace.o
  CC      drivers/gpu/drm/i915/display/intel_dkl_phy.o
  CC      drivers/gpu/drm/i915/display/intel_dp.o
  CC      drivers/gpu/drm/i915/display/intel_dp_aux.o
  CC      drivers/gpu/drm/i915/display/intel_dp_aux_backlight.o
  CC      drivers/gpu/drm/i915/display/intel_dp_hdcp.o
  CC      drivers/gpu/drm/i915/display/intel_dp_link_training.o
  CC      drivers/gpu/drm/i915/display/intel_dp_mst.o
  CC      drivers/gpu/drm/i915/display/intel_dsi.o
  CC      drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.o
  CC      drivers/gpu/drm/i915/display/intel_dsi_vbt.o
  CC      drivers/gpu/drm/i915/display/intel_dvo.o
  CC      drivers/gpu/drm/i915/display/intel_encoder.o
  CC      drivers/gpu/drm/i915/display/intel_gmbus.o
  CC      drivers/gpu/drm/i915/display/intel_hdmi.o
  CC      drivers/gpu/drm/i915/display/intel_lspcon.o
  CC      drivers/gpu/drm/i915/display/intel_lvds.o
  CC      drivers/gpu/drm/i915/display/intel_panel.o
  CC      drivers/gpu/drm/i915/display/intel_pps.o
  CC      drivers/gpu/drm/i915/display/intel_qp_tables.o
  CC      drivers/gpu/drm/i915/display/intel_sdvo.o
  CC      drivers/gpu/drm/i915/display/intel_snps_phy.o
  CC      drivers/gpu/drm/i915/display/intel_tv.o
  CC      drivers/gpu/drm/i915/display/intel_vdsc.o
  CC      drivers/gpu/drm/i915/display/intel_vrr.o
  CC      drivers/gpu/drm/i915/display/vlv_dsi.o
  CC      drivers/gpu/drm/i915/display/vlv_dsi_pll.o
  CC      drivers/gpu/drm/i915/i915_perf.o
  CC      drivers/gpu/drm/i915/pxp/intel_pxp.o
  CC      drivers/gpu/drm/i915/pxp/intel_pxp_huc.o
  CC      drivers/gpu/drm/i915/pxp/intel_pxp_tee.o
  CC      drivers/gpu/drm/i915/i915_gpu_error.o
  CC      drivers/gpu/drm/i915/i915_vgpu.o
make[5]: *** [/workspace/kernel/scripts/Makefile.build:485: drivers/gpu/drm/xe] Error 2
make[5]: *** Waiting for unfinished jobs....
  AR      drivers/gpu/drm/i915/built-in.a
make[4]: *** [/workspace/kernel/scripts/Makefile.build:485: drivers/gpu/drm] Error 2
make[3]: *** [/workspace/kernel/scripts/Makefile.build:485: drivers/gpu] Error 2
make[2]: *** [/workspace/kernel/scripts/Makefile.build:485: drivers] Error 2
make[1]: *** [/workspace/kernel/Makefile:1934: .] Error 2
make: *** [/workspace/kernel/Makefile:240: __sub-make] Error 2
run-parts: /workspace/ci/hooks/11-build-32b exited with return code 2



^ permalink raw reply	[flat|nested] 78+ messages in thread

* ✓ CI.checksparse: success for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (25 preceding siblings ...)
  2024-07-26 14:48 ` ✗ CI.Hooks: failure " Patchwork
@ 2024-07-26 14:49 ` Patchwork
  2024-07-26 15:10 ` ✓ CI.BAT: " Patchwork
                   ` (2 subsequent siblings)
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-26 14:49 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
State : success

== 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 220554a8ef7ac26fbfc4f141816679d742a0d232
Sparse version: 0.6.1 (Ubuntu: 0.6.1-2build1)
Fast mode used, each commit won't be checked separately.
Okay!

+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel



^ permalink raw reply	[flat|nested] 78+ messages in thread

* ✓ CI.BAT: success for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (26 preceding siblings ...)
  2024-07-26 14:49 ` ✓ CI.checksparse: success " Patchwork
@ 2024-07-26 15:10 ` Patchwork
  2024-07-27  2:37 ` ✓ CI.FULL: " Patchwork
  2024-07-27  5:23 ` [PATCH 00/21] " Matthew Brost
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-26 15:10 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

[-- Attachment #1: Type: text/plain, Size: 2478 bytes --]

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
State : success

== Summary ==

CI Bug Log - changes from xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232_BAT -> xe-pw-136572v1_BAT
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  

Participating hosts (7 -> 7)
------------------------------

  No changes in participating hosts

Known issues
------------

  Here are the changes found in xe-pw-136572v1_BAT that come from known issues:

### IGT changes ###

#### Possible fixes ####

  * igt@xe_gt_freq@freq_basic_api:
    - bat-adlp-7:         [FAIL][1] ([Intel XE#2196]) -> [PASS][2]
   [1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/bat-adlp-7/igt@xe_gt_freq@freq_basic_api.html
   [2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/bat-adlp-7/igt@xe_gt_freq@freq_basic_api.html
    - {bat-lnl-2}:        [FAIL][3] ([Intel XE#2200]) -> [PASS][4]
   [3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/bat-lnl-2/igt@xe_gt_freq@freq_basic_api.html
   [4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/bat-lnl-2/igt@xe_gt_freq@freq_basic_api.html

  * igt@xe_gt_freq@freq_fixed_idle:
    - {bat-lnl-2}:        [FAIL][5] ([Intel XE#2262]) -> [PASS][6]
   [5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/bat-lnl-2/igt@xe_gt_freq@freq_fixed_idle.html
   [6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/bat-lnl-2/igt@xe_gt_freq@freq_fixed_idle.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [Intel XE#2196]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2196
  [Intel XE#2200]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2200
  [Intel XE#2262]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2262


Build changes
-------------

  * Linux: xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232 -> xe-pw-136572v1

  IGT_7940: 2a73158fa69a2b8e20d5a0bdf773ee194bfe13c2 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232: 220554a8ef7ac26fbfc4f141816679d742a0d232
  xe-pw-136572v1: 136572v1

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/index.html

[-- Attachment #2: Type: text/html, Size: 3088 bytes --]

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property
  2024-07-26 14:08 ` [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
@ 2024-07-26 18:35   ` Matthew Brost
  2024-07-27  0:54   ` Matthew Brost
  1 sibling, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-26 18:35 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

On Fri, Jul 26, 2024 at 05:08:06PM +0300, Mika Kuoppala wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> 
> Introduce exec queue immutable property of eudebug
> with a flags as value to enable eudebug specific feature(s).
> 
> For now engine lrc will use this flag to set up runalone
> hw feature. Runalone is used to ensure that only one hw engine
> of group [rcs0, ccs0-3] is active on a tile.
> 
> Note: unlike the i915, xe allows user to set runalone
> also on devices with single render/compute engine. It should not
> make much difference, but leave control to the user.
> 
> v2: use exec queue flags (Mika)
> v3: eudebug enable as flags (Mika)
> v4: adapt to lrc_create (Mika)
> v5: EUDEBUG property space squash (Mika)
> v6: runalone as rmw (Dominik)
> 
> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> ---
>  drivers/gpu/drm/xe/regs/xe_engine_regs.h |  1 +
>  drivers/gpu/drm/xe/xe_exec_queue.c       | 35 ++++++++++++++++++++++--
>  drivers/gpu/drm/xe/xe_exec_queue_types.h |  7 +++++
>  drivers/gpu/drm/xe/xe_hw_engine.c        |  2 +-
>  drivers/gpu/drm/xe/xe_lrc.c              | 16 +++++++++--
>  drivers/gpu/drm/xe/xe_lrc.h              |  4 ++-
>  include/uapi/drm/xe_drm.h                |  3 +-
>  7 files changed, 60 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> index fd31f3fb2b4c..764c270599d0 100644
> --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> @@ -136,6 +136,7 @@
>  #define	  CTX_CTRL_OAC_CONTEXT_ENABLE		REG_BIT(8)
>  #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
>  #define	  CTX_CTRL_INDIRECT_RING_STATE_ENABLE	REG_BIT(4)
> +#define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
>  #define	  CTX_CTRL_INHIBIT_SYN_CTX_SWITCH	REG_BIT(3)
>  #define	  CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT	REG_BIT(0)
>  
> diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
> index 26ae2fdbf682..bc2edade5e5b 100644
> --- a/drivers/gpu/drm/xe/xe_exec_queue.c
> +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
> @@ -106,10 +106,14 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
>  
>  static int __xe_exec_queue_init(struct xe_exec_queue *q)
>  {
> +	u32 flags = 0;
>  	int i, err;
>  
> +	if (q->eudebug_flags & EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)
> +		flags |= LRC_CREATE_RUNALONE;
> +
>  	for (i = 0; i < q->width; ++i) {
> -		q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K);
> +		q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K, flags);
>  		if (IS_ERR(q->lrc[i])) {
>  			err = PTR_ERR(q->lrc[i]);
>  			goto err_lrc;
> @@ -336,6 +340,31 @@ static int exec_queue_set_timeslice(struct xe_device *xe, struct xe_exec_queue *
>  	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;
> +

The EU debugger only works on LR VMs, right? i.e. We can't use
dma-fences with EU debugger enabled. If so, then I'd check the q->vm to
ensure it is in a support mode.

Matt

> +	if (XE_IOCTL_DBG(xe, (value & ~known_flags)))
> +		return -EINVAL;
> +
> +	/*
> +	 * We want to explicitly set the global feature if
> +	 * property is set.
> +	 */
> +	if (XE_IOCTL_DBG(xe,
> +			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
> +		return -EINVAL;
> +
> +	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
> +
> +	return 0;
> +}
> +
>  typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
>  					     struct xe_exec_queue *q,
>  					     u64 value);
> @@ -343,6 +372,7 @@ typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
>  static const xe_exec_queue_set_property_fn exec_queue_set_property_funcs[] = {
>  	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY] = exec_queue_set_priority,
>  	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE] = exec_queue_set_timeslice,
> +	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG] = exec_queue_set_eudebug,
>  };
>  
>  static int exec_queue_user_ext_set_property(struct xe_device *xe,
> @@ -362,7 +392,8 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe,
>  			 ARRAY_SIZE(exec_queue_set_property_funcs)) ||
>  	    XE_IOCTL_DBG(xe, ext.pad) ||
>  	    XE_IOCTL_DBG(xe, ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY &&
> -			 ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE))
> +			 ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE &&
> +			 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_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h
> index 1408b02eea53..48e1190c2b58 100644
> --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h
> +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h
> @@ -90,6 +90,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/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> index 0d8b871b47fe..74813bc20787 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> @@ -532,7 +532,7 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe,
>  		goto err_name;
>  	}
>  
> -	hwe->kernel_lrc = xe_lrc_create(hwe, NULL, SZ_16K);
> +	hwe->kernel_lrc = xe_lrc_create(hwe, NULL, SZ_16K, 0);
>  	if (IS_ERR(hwe->kernel_lrc)) {
>  		err = PTR_ERR(hwe->kernel_lrc);
>  		goto err_hwsp;
> diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
> index 94ff62e1d95e..563b57f5b9ee 100644
> --- a/drivers/gpu/drm/xe/xe_lrc.c
> +++ b/drivers/gpu/drm/xe/xe_lrc.c
> @@ -890,7 +890,7 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
>  #define PVC_CTX_ACC_CTR_THOLD	(0x2a + 1)
>  
>  static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
> -		       struct xe_vm *vm, u32 ring_size)
> +		       struct xe_vm *vm, u32 ring_size, u32 flags)
>  {
>  	struct xe_gt *gt = hwe->gt;
>  	struct xe_tile *tile = gt_to_tile(gt);
> @@ -1007,6 +1007,16 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
>  	map = __xe_lrc_start_seqno_map(lrc);
>  	xe_map_write32(lrc_to_xe(lrc), &map, lrc->fence_ctx.next_seqno - 1);
>  
> +	if (flags & LRC_CREATE_RUNALONE) {
> +		u32 ctx_control = xe_lrc_read_ctx_reg(lrc, CTX_CONTEXT_CONTROL);
> +
> +		drm_dbg(&xe->drm, "read CTX_CONTEXT_CONTROL: 0x%x\n", ctx_control);
> +		ctx_control |= _MASKED_BIT_ENABLE(CTX_CTRL_RUN_ALONE);
> +		drm_dbg(&xe->drm, "written CTX_CONTEXT_CONTROL: 0x%x\n", ctx_control);
> +
> +		xe_lrc_write_ctx_reg(lrc, CTX_CONTEXT_CONTROL, ctx_control);
> +	}
> +
>  	return 0;
>  
>  err_lrc_finish:
> @@ -1026,7 +1036,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
>   * upon failure.
>   */
>  struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
> -			     u32 ring_size)
> +			     u32 ring_size, u32 flags)
>  {
>  	struct xe_lrc *lrc;
>  	int err;
> @@ -1035,7 +1045,7 @@ struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
>  	if (!lrc)
>  		return ERR_PTR(-ENOMEM);
>  
> -	err = xe_lrc_init(lrc, hwe, vm, ring_size);
> +	err = xe_lrc_init(lrc, hwe, vm, ring_size, flags);
>  	if (err) {
>  		kfree(lrc);
>  		return ERR_PTR(err);
> diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
> index c24542e89318..d2429a26fb22 100644
> --- a/drivers/gpu/drm/xe/xe_lrc.h
> +++ b/drivers/gpu/drm/xe/xe_lrc.h
> @@ -22,8 +22,10 @@ struct xe_vm;
>  
>  #define LRC_PPHWSP_SCRATCH_ADDR (0x34 * 4)
>  
> +#define LRC_CREATE_RUNALONE     BIT(0)
> +
>  struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
> -			     u32 ring_size);
> +			     u32 ring_size, u32 flags);
>  void xe_lrc_destroy(struct kref *ref);
>  
>  /**
> diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
> index a68734ff12f4..61c4c061bd75 100644
> --- a/include/uapi/drm/xe_drm.h
> +++ b/include/uapi/drm/xe_drm.h
> @@ -1110,7 +1110,8 @@ struct drm_xe_exec_queue_create {
>  #define DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY		0
>  #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY		0
>  #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE		1
> -
> +#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG		2
> +#define     DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE		(1 << 0)
>  	/** @extensions: Pointer to the first extension struct, if any */
>  	__u64 extensions;
>  
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access
  2024-07-26 14:08 ` [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access Mika Kuoppala
@ 2024-07-26 18:46   ` Matthew Brost
  2024-07-26 18:50     ` Matthew Brost
  0 siblings, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-07-26 18:46 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Andrzej Hajda, Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:12PM +0300, Mika Kuoppala wrote:
> From: Andrzej Hajda <andrzej.hajda@intel.com>
> 
> Debugger needs to read/write program's vmas including userptr_vma.
> Since hmm_range_fault is used to pin userptr vmas, it is possible
> to map those vmas from debugger context.
> 
> v2: kmap to kmap_local (Maciej)
> 
> Signed-off-by: Andrzej Hajda <andrzej.hajda@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 | 56 ++++++++++++++++++++++++++++++++-
>  1 file changed, 55 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index aa383accc468..947331c19f43 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -33,6 +33,7 @@
>  #include "xe_mmio.h"
>  #include "xe_module.h"
>  #include "xe_pm.h"
> +#include "xe_res_cursor.h"
>  #include "xe_rtp.h"
>  #include "xe_sched_job.h"
>  #include "xe_vm.h"
> @@ -2852,6 +2853,58 @@ static void discovery_work_fn(struct work_struct *work)
>  	xe_eudebug_put(d);
>  }
>  
> +static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> +				  void *buf, u64 len, bool write)
> +{
> +	struct xe_vm *vm = xe_vma_vm(&uvma->vma);
> +	struct xe_userptr *up = &uvma->userptr;
> +	struct xe_res_cursor cur = {};
> +	int cur_len, ret = 0;
> +
> +	/* lock notifier in non-invalidation state */
> +	for (unsigned long nseq = uvma->userptr.notifier_seq; true;
> +	     nseq = mmu_interval_read_begin(&uvma->userptr.notifier)) {
> +		down_read(&vm->userptr.notifier_lock);
> +		if (!mmu_interval_read_retry(&uvma->userptr.notifier, nseq))
> +			break;
> +		up_read(&vm->userptr.notifier_lock);
> +	}
> +

I don't think this will work without lockdep blowing up.
'&vm->userptr.notifier_lock' is taken in the MMU notifier, the MMU
notifier is in the path of reclaim, thus you cannot allocate memory
under this lock, xe_vma_userptr_pin_pages allocates memory.

I think you are going to need to pin the pages first, then take the
notifier_lock, recheck the seqno, retry on a miscomapre, once the
compare passes it should be safe to write the userptr.

Matt

> +	/* re-pin if necessary */
> +	if (xe_vma_userptr_check_repin(uvma)) {
> +		spin_lock(&vm->userptr.invalidated_lock);
> +		list_del_init(&uvma->userptr.invalidate_link);
> +		spin_unlock(&vm->userptr.invalidated_lock);
> +
> +		ret = xe_vma_userptr_pin_pages(uvma);
> +		if (ret)
> +			goto out_unlock_notifier;
> +	}
> +
> +	if (!up->sg) {
> +		ret = -EINVAL;
> +		goto out_unlock_notifier;
> +	}
> +
> +	for (xe_res_first_sg(up->sg, offset, len, &cur); cur.remaining;
> +	     xe_res_next(&cur, cur_len)) {
> +		void *ptr = kmap_local_page(sg_page(cur.sgl)) + cur.start;
> +
> +		cur_len = min(cur.size, cur.remaining);
> +		if (write)
> +			memcpy(ptr, buf, cur_len);
> +		else
> +			memcpy(buf, ptr, cur_len);
> +		kunmap_local(ptr);
> +		buf += cur_len;
> +	}
> +	ret = len;
> +
> +out_unlock_notifier:
> +	up_read(&vm->userptr.notifier_lock);
> +	return ret;
> +}
> +
>  static int xe_eudebug_bovma_access(struct xe_bo *bo, u64 offset,
>  				   void *buf, u64 len, bool write)
>  {
> @@ -2895,7 +2948,8 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
>  	if (bo)
>  		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
>  
> -	return -EOPNOTSUPP;
> +	return xe_eudebug_uvma_access(to_userptr_vma(vma), offset,
> +				      buf, bytes, write);
>  }
>  
>  static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access
  2024-07-26 18:46   ` Matthew Brost
@ 2024-07-26 18:50     ` Matthew Brost
  2024-07-27  1:45       ` Matthew Brost
  0 siblings, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-07-26 18:50 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Andrzej Hajda, Maciej Patelczyk

On Fri, Jul 26, 2024 at 06:46:29PM +0000, Matthew Brost wrote:
> On Fri, Jul 26, 2024 at 05:08:12PM +0300, Mika Kuoppala wrote:
> > From: Andrzej Hajda <andrzej.hajda@intel.com>
> > 
> > Debugger needs to read/write program's vmas including userptr_vma.
> > Since hmm_range_fault is used to pin userptr vmas, it is possible
> > to map those vmas from debugger context.
> > 
> > v2: kmap to kmap_local (Maciej)
> > 
> > Signed-off-by: Andrzej Hajda <andrzej.hajda@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 | 56 ++++++++++++++++++++++++++++++++-
> >  1 file changed, 55 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> > index aa383accc468..947331c19f43 100644
> > --- a/drivers/gpu/drm/xe/xe_eudebug.c
> > +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> > @@ -33,6 +33,7 @@
> >  #include "xe_mmio.h"
> >  #include "xe_module.h"
> >  #include "xe_pm.h"
> > +#include "xe_res_cursor.h"
> >  #include "xe_rtp.h"
> >  #include "xe_sched_job.h"
> >  #include "xe_vm.h"
> > @@ -2852,6 +2853,58 @@ static void discovery_work_fn(struct work_struct *work)
> >  	xe_eudebug_put(d);
> >  }
> >  
> > +static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> > +				  void *buf, u64 len, bool write)
> > +{
> > +	struct xe_vm *vm = xe_vma_vm(&uvma->vma);
> > +	struct xe_userptr *up = &uvma->userptr;
> > +	struct xe_res_cursor cur = {};
> > +	int cur_len, ret = 0;
> > +
> > +	/* lock notifier in non-invalidation state */
> > +	for (unsigned long nseq = uvma->userptr.notifier_seq; true;
> > +	     nseq = mmu_interval_read_begin(&uvma->userptr.notifier)) {
> > +		down_read(&vm->userptr.notifier_lock);
> > +		if (!mmu_interval_read_retry(&uvma->userptr.notifier, nseq))
> > +			break;
> > +		up_read(&vm->userptr.notifier_lock);
> > +	}
> > +
> 
> I don't think this will work without lockdep blowing up.
> '&vm->userptr.notifier_lock' is taken in the MMU notifier, the MMU
> notifier is in the path of reclaim, thus you cannot allocate memory
> under this lock, xe_vma_userptr_pin_pages allocates memory.
> 
> I think you are going to need to pin the pages first, then take the
> notifier_lock, recheck the seqno, retry on a miscomapre, once the

Let me make 'n a miscompare' a bit more clear.

Drop the notifier lock and repin the pages again.

This how the VM bind flow works to avoid memory allocations under the
notifier lock.

Matt

> compare passes it should be safe to write the userptr.
> 
> Matt
> 
> > +	/* re-pin if necessary */
> > +	if (xe_vma_userptr_check_repin(uvma)) {
> > +		spin_lock(&vm->userptr.invalidated_lock);
> > +		list_del_init(&uvma->userptr.invalidate_link);
> > +		spin_unlock(&vm->userptr.invalidated_lock);
> > +
> > +		ret = xe_vma_userptr_pin_pages(uvma);
> > +		if (ret)
> > +			goto out_unlock_notifier;
> > +	}
> > +
> > +	if (!up->sg) {
> > +		ret = -EINVAL;
> > +		goto out_unlock_notifier;
> > +	}
> > +
> > +	for (xe_res_first_sg(up->sg, offset, len, &cur); cur.remaining;
> > +	     xe_res_next(&cur, cur_len)) {
> > +		void *ptr = kmap_local_page(sg_page(cur.sgl)) + cur.start;
> > +
> > +		cur_len = min(cur.size, cur.remaining);
> > +		if (write)
> > +			memcpy(ptr, buf, cur_len);
> > +		else
> > +			memcpy(buf, ptr, cur_len);
> > +		kunmap_local(ptr);
> > +		buf += cur_len;
> > +	}
> > +	ret = len;
> > +
> > +out_unlock_notifier:
> > +	up_read(&vm->userptr.notifier_lock);
> > +	return ret;
> > +}
> > +
> >  static int xe_eudebug_bovma_access(struct xe_bo *bo, u64 offset,
> >  				   void *buf, u64 len, bool write)
> >  {
> > @@ -2895,7 +2948,8 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
> >  	if (bo)
> >  		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
> >  
> > -	return -EOPNOTSUPP;
> > +	return xe_eudebug_uvma_access(to_userptr_vma(vma), offset,
> > +				      buf, bytes, write);
> >  }
> >  
> >  static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
> > -- 
> > 2.34.1
> > 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 14/21] drm/xe/eudebug: vm open/pread/pwrite
  2024-07-26 14:08 ` [PATCH 14/21] drm/xe/eudebug: vm open/pread/pwrite Mika Kuoppala
@ 2024-07-26 18:59   ` Matthew Brost
  0 siblings, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-26 18:59 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:11PM +0300, Mika Kuoppala wrote:
> Debugger needs access to the client's vm to read and write. For
> example inspecting ISA/ELF and setting up breakpoints.
> 
> Add ioctl to open target vm with debugger client and vm_handle
> and hook up pread/pwrite possibility.
> 
> Open will take 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 following patch.
> 
> v2: checkpatch (Maciej)
> 
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
> ---
>  drivers/gpu/drm/xe/regs/xe_gt_regs.h |  24 ++
>  drivers/gpu/drm/xe/xe_eudebug.c      | 470 +++++++++++++++++++++++++++
>  include/uapi/drm/xe_drm_eudebug.h    |  18 +
>  3 files changed, 512 insertions(+)
> 
> diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> index 546bb7cc2337..0d688189a2b3 100644
> --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> @@ -520,6 +520,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 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)
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 5dcb7c9464e9..aa383accc468 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -8,7 +8,10 @@
>  #include <linux/anon_inodes.h>
>  #include <linux/poll.h>
>  #include <linux/delay.h>
> +#include <linux/file.h>
> +#include <linux/vmalloc.h>
>  
> +#include <drm/drm_drv.h>
>  #include <drm/drm_managed.h>
>  
>  #include "regs/xe_engine_regs.h"
> @@ -36,6 +39,7 @@
>  #include "xe_wa.h"
>  #include "xe_force_wake.h"
>  #include "xe_sync.h"
> +#include "xe_bo.h"
>  
>  /*
>   * If there is no detected event read by userspace, during this period, assume
> @@ -747,6 +751,17 @@ static struct xe_lrc *find_lrc(struct xe_eudebug *d, const u32 id)
>  	return l;
>  }
>  
> +static struct xe_vm *find_vm(struct xe_eudebug *d, const u32 id)
> +{
> +	struct xe_eudebug_handle *h;
> +
> +	h = find_resource(d->res, XE_EUDEBUG_RES_TYPE_VM, id);
> +	if (h)
> +		return (void *)h->key;
> +
> +	return NULL;
> +}
> +
>  static int _xe_eudebug_add_handle(struct xe_eudebug *d,
>  				  int type,
>  				  void *p,
> @@ -1199,6 +1214,8 @@ static long xe_eudebug_eu_control(struct xe_eudebug *d, const u64 arg)
>  	return ret;
>  }
>  
> +static long xe_eudebug_vm_open_ioctl(struct xe_eudebug *d, unsigned long arg);
> +
>  static long xe_eudebug_ioctl(struct file *file,
>  			     unsigned int cmd,
>  			     unsigned long arg)
> @@ -1219,6 +1236,11 @@ static long xe_eudebug_ioctl(struct file *file,
>  		ret = xe_eudebug_ack_event_ioctl(d, cmd, 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;
>  	}
> @@ -2829,3 +2851,451 @@ static void discovery_work_fn(struct work_struct *work)
>  
>  	xe_eudebug_put(d);
>  }
> +
> +static int xe_eudebug_bovma_access(struct xe_bo *bo, u64 offset,
> +				   void *buf, u64 len, bool write)
> +{
> +	struct xe_device * const xe = xe_bo_device(bo);
> +	struct iosys_map src;
> +	int ret;
> +

To make this clear vm->lock is held here in write mode, add lockdep assert.

> +	dma_resv_lock(bo->ttm.base.resv, NULL);
> +
> +	ret = ttm_bo_vmap(&bo->ttm, &src);
> +	if (!ret) {
> +		if (write)
> +			xe_map_memcpy_to(xe, &src, offset, buf, len);
> +		else
> +			xe_map_memcpy_from(xe, buf, &src, offset, len);
> +
> +		ttm_bo_vunmap(&bo->ttm, &src);
> +
> +		ret = len;
> +	}
> +
> +	dma_resv_unlock(bo->ttm.base.resv);
> +
> +	return ret;
> +}
> +
> +static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
> +				 void *buf, u64 len, bool write)
> +{
> +	struct xe_bo *bo;
> +	u64 bytes;
> +

Here too.

It goes for any functions in the EU debugger which access the VM state
with this is lock held. Good practice and self documenting. Helps with
reviews too because I don't need to think about questions like 'how this
is not race with a bind, exec, rebind work, or page fault?'.

Matt

> +	if (XE_WARN_ON(offset >= xe_vma_size(vma)))
> +		return -EINVAL;
> +
> +	bytes = min_t(u64, len, xe_vma_size(vma) - offset);
> +	if (!bytes)
> +		return 0;
> +
> +	bo = xe_vma_bo(vma);
> +	if (bo)
> +		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
> +				void *buf, u64 len, bool write)
> +{
> +	struct xe_vma *vma;
> +	int ret;
> +
> +	down_write(&vm->lock);
> +
> +	vma = xe_vm_find_overlapping_vma(vm, offset, len);
> +	if (vma) {
> +#ifdef VERBOSE_VM_ACCESS
> +		drm_dbg(&xe_vma_vm(vma)->xe->drm,
> +			"eudbg: offset: 0x%llx: vma start 0x%llx, size 0x%llx, offset_in_vma 0x%llx",
> +			offset, xe_vma_start(vma), xe_vma_size(vma), offset - xe_vma_start(vma));
> +#endif
> +		/* XXX: why find overlapping returns below start? */
> +		if (offset < xe_vma_start(vma) ||
> +		    offset >= (xe_vma_start(vma) + xe_vma_size(vma))) {
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +
> +		/* Offset into vma */
> +		offset -= xe_vma_start(vma);
> +		ret = xe_eudebug_vma_access(vma, 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 client_id;
> +	u64 vm_handle;
> +	u64 timeout_ns;
> +};
> +
> +static ssize_t __vm_read_write(struct xe_vm *vm,
> +			       void *bb,
> +			       char __user *r_buffer,
> +			       const char __user *w_buffer,
> +			       unsigned long offset,
> +			       unsigned long 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 != NULL;
> +	struct xe_vm *vm;
> +	ssize_t copied = 0;
> +	ssize_t bytes_left = count;
> +	ssize_t ret;
> +	unsigned long alloc_len;
> +	loff_t pos = *__pos;
> +	void *k_buffer;
> +
> +#ifdef VERBOSE_VM_ACCESS
> +	eu_dbg(d, "vm_access(%s): client_handle=%llu, vm_handle=%llu, flags=0x%llx, pos=0x%llx, count=0x%lx",
> +	       write ? "write" : "read",
> +	       vmf->client_id, vmf->vm_handle, vmf->flags, pos, count);
> +#endif
> +	if (XE_IOCTL_DBG(xe, write && r_buffer))
> +		return -EINVAL;
> +
> +	vm = find_vm(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 client_handle=%llu, vm_handle=%llu, flags=0x%llx, pos=%llu, count=%lu\n",
> +			write ? "write" : "read",
> +			vmf->client_id, vmf->vm_handle, vmf->flags, pos, count);
> +		return -EINVAL;
> +	}
> +
> +	if (!count)
> +		return 0;
> +
> +	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))
> +		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,
> +				      pos + copied,
> +				      len,
> +				      write);
> +#ifdef VERBOSE_VM_ACCESS
> +		eu_dbg(d, "vm_access(%s): pos=0x%llx, len=0x%lx, copied=%lu bytes_left=%lu, ret=%ld",
> +		       write ? "write" : "read", pos + copied, len, copied, bytes_left, ret);
> +#endif
> +		if (ret <= 0)
> +			break;
> +
> +		bytes_left -= ret;
> +		copied += ret;
> +	} while (bytes_left > 0);
> +
> +	vfree(k_buffer);
> +
> +	if (XE_WARN_ON(copied < 0))
> +		copied = 0;
> +
> +	*__pos += copied;
> +
> +#ifdef VERBOSE_VM_ACCESS
> +	eu_dbg(d, "vm_access(%s): pos=0x%llx, count=0x%lx, copied=%lu bytes_left=%lu, ret=%ld",
> +	       write ? "write" : "read", pos, count, copied, bytes_left, copied ?: ret);
> +#endif
> +
> +	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;
> +	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;
> +
> +	ret = xe_force_wake_get(gt_to_fw(gt), hwe->domain);
> +	if (ret)
> +		return ret;
> +
> +	/* Prevent concurrent flushes */
> +	mutex_lock(&d->eu_lock);
> +	psmi_ctrl = xe_mmio_read32(gt, psmi_addr);
> +	if (!(psmi_ctrl & IDLE_MSG_DISABLE))
> +		xe_mmio_write32(gt, psmi_addr, _MASKED_BIT_ENABLE(IDLE_MSG_DISABLE));
> +
> +	ret = xe_mmio_wait32(gt, RCU_ASYNC_FLUSH,
> +			     RCU_ASYNC_FLUSH_IN_PROGRESS, 0,
> +			     timeout_us, NULL, false);
> +	if (ret)
> +		goto out;
> +
> +	xe_mmio_write32(gt, RCU_ASYNC_FLUSH, mask);
> +
> +	ret = xe_mmio_wait32(gt, RCU_ASYNC_FLUSH,
> +			     RCU_ASYNC_FLUSH_IN_PROGRESS, 0,
> +			     timeout_us, NULL, false);
> +out:
> +	if (!(psmi_ctrl & IDLE_MSG_DISABLE))
> +		xe_mmio_write32(gt, psmi_addr, _MASKED_BIT_DISABLE(IDLE_MSG_DISABLE));
> +
> +	mutex_unlock(&d->eu_lock);
> +	xe_force_wake_put(gt_to_fw(gt), hwe->domain);
> +
> +	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: client_handle=%llu, vm_handle=%llu, flags=0x%llx, start=%llu, end=%llu datasync=%d\n",
> +	       vmf->client_id, vmf->vm_handle, vmf->flags, start, end, 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? */
> +		for_each_hw_engine(hwe, gt, id) {
> +			if (hwe->class != XE_ENGINE_CLASS_RENDER &&
> +			    hwe->class != XE_ENGINE_CLASS_COMPUTE)
> +				continue;
> +
> +			ret = engine_rcu_flush(d, hwe, vmf->timeout_ns / 1000ull);
> +			if (ret)
> +				break;
> +		}
> +	}
> +
> +	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: client_handle=%llu, vm_handle=%llu, flags=0x%llx",
> +	       vmf->client_id, vmf->vm_handle, vmf->flags);
> +
> +	drm_dev_get(&d->xe->drm);
> +	xe_vm_put(vmf->vm);
> +	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,
> +};
> +
> +static 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 xe_eudebug *d_ref = NULL;
> +	struct vm_file *vmf = NULL;
> +	struct xe_file *xef;
> +	struct xe_vm *vm;
> +	struct file *file;
> +	long ret = 0;
> +	int fd;
> +
> +	if (XE_IOCTL_DBG(xe, _IOC_SIZE(DRM_XE_EUDEBUG_IOCTL_VM_OPEN) != sizeof(param)))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(DRM_XE_EUDEBUG_IOCTL_VM_OPEN) & _IOC_WRITE)))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, copy_from_user(&param, (void __user *)arg, sizeof(param))))
> +		return -EFAULT;
> +
> +	if (XE_IOCTL_DBG(xe, param.flags))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, xe_eudebug_detached(d)))
> +		return -ENOTCONN;
> +
> +	vm = NULL;
> +	mutex_lock(&d->xe->files.lock);
> +	xef = find_client(d, param.client_handle);
> +	if (XE_IOCTL_DBG(xe, !xef)) {
> +		mutex_unlock(&d->xe->files.lock);
> +		return -EINVAL;
> +	}
> +
> +	d_ref = xe_eudebug_get(xef);
> +	if (XE_IOCTL_DBG(xe, !d_ref)) {
> +		mutex_unlock(&d->xe->files.lock);
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&xef->vm.lock);
> +	vm = find_vm(d, param.vm_handle);
> +	if (vm)
> +		xe_vm_get(vm);
> +	mutex_unlock(&xef->vm.lock);
> +	mutex_unlock(&d->xe->files.lock);
> +
> +	XE_WARN_ON(d != d_ref);
> +
> +	if (XE_IOCTL_DBG(xe, !vm)) {
> +		ret = -EINVAL;
> +		goto out_eudebug_put;
> +	}
> +
> +	vmf = kmalloc(sizeof(*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;
> +	}
> +
> +	vmf->debugger = d_ref;
> +	vmf->vm = vm;
> +	vmf->flags = param.flags;
> +	vmf->client_id = param.client_handle;
> +	vmf->vm_handle = param.vm_handle;
> +	vmf->timeout_ns = param.timeout_ns;
> +
> +	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_file_put;
> +	}
> +
> +	drm_dev_get(&d->xe->drm);
> +
> +	file->f_mode |= FMODE_PREAD | FMODE_PWRITE |
> +		FMODE_READ | FMODE_WRITE | FMODE_LSEEK;
> +
> +	fd_install(fd, file);
> +
> +	eu_dbg(d, "vm_open: client_handle=%llu, handle=%llu, flags=0x%llx, fd=%d",
> +	       vmf->client_id, vmf->vm_handle, vmf->flags, fd);
> +
> +	XE_WARN_ON(ret);
> +
> +	return fd;
> +
> +out_file_put:
> +	put_unused_fd(fd);
> +out_free:
> +	kfree(vmf);
> +out_vm_put:
> +	xe_vm_put(vm);
> +out_eudebug_put:
> +	xe_eudebug_put(d_ref);
> +
> +	return ret;
> +}
> diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> index 1875192e92bd..df79eafb6136 100644
> --- a/include/uapi/drm/xe_drm_eudebug.h
> +++ b/include/uapi/drm/xe_drm_eudebug.h
> @@ -18,6 +18,7 @@ extern "C" {
>  #define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
>  #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
>  #define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
> +#define DRM_XE_EUDEBUG_IOCTL_VM_OPEN		_IOW('j', 0x1, struct drm_xe_eudebug_vm_open)
>  
>  /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
>  struct drm_xe_eudebug_event {
> @@ -171,6 +172,23 @@ struct drm_xe_eudebug_ack_event {
>  	__u64 seqno;
>  };
>  
> +struct drm_xe_eudebug_vm_open {
> +	/** @extensions: Pointer to the first extension struct, if any */
> +	__u64 extensions;
> +
> +	/** @client_handle: id of client */
> +	__u64 client_handle;
> +
> +	/** @vm_handle: id of vm */
> +	__u64 vm_handle;
> +
> +	/** @flags: flags */
> +	__u64 flags;
> +
> +	/** @timeout_ns: Timeout value in nanoseconds operations (fsync) */
> +	__u64 timeout_ns;
> +};
> +
>  #if defined(__cplusplus)
>  }
>  #endif
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-07-26 14:08 ` [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support Mika Kuoppala
@ 2024-07-26 19:20   ` Matthew Brost
  2024-07-30 14:12     ` Mika Kuoppala
  2024-08-07  9:34   ` Zbigniew Kempczyński
  2024-08-12 12:02   ` Zbigniew Kempczyński
  2 siblings, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-07-26 19:20 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
	Andi Shyti, Matt Roper, Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:00PM +0300, Mika Kuoppala wrote:
> With eudebug event interface, user space debugger process (like gdb)
> is able to keep track of resources created by another process
> (debuggee using drm/xe) and act upon these resources.
> 
> For example, debugger can find a client vm which contains isa/elf
> for a particular shader/eu-kernel and then inspect and modify it
> (for example installing a breakpoint).
> 
> Debugger first opens a connection to xe with a drm ioctl specifying
> target pid to connect. This returns an anon fd handle that can then be
> used to listen for events with dedicated ioctl.
> 
> This patch introduces eudebug connection and event queuing, adding
> client create/destroy and vm create/destroy events as a baseline.
> More events for full debugger operation are needed and
> those will be introduced in follow up patches.
> 
> The resource tracking parts are inspired by the work of
> Maciej Patelczyk on resource handling for i915. Chris Wilson
> suggested improvement of two ways mapping which makes it easy to
> use resource map as a definitive bookkeep of what resources
> are played to debugger in the discovery phase (on follow up patch).
> 

Not a full review just an idea. Do you think it would be worthwhile to
add a Kconfig option to enable EU debug support so if we don't care
about EU debug it compiles out?

The layering would have to be fixed up to make this sane (e.g. all
common Xe code calls into the EU layer so we don't have 'if
IS_ENABLED(CONFIG_EU_DEBUG)' sprinkled all over the place. Fixing up
layering probably isn't bad idea anyways and as common Xe code really
shouldn't open code EU debug specific things anyways. This would enforce
good layering too.

Matt

> v2: - event printer removed (Maarten)
>     - trim down kfifo accessors (Maarten)
>     - xa_alloc spurious locking removed (Maarten)
> v3: - use list for clients (Matt)
> v4: - avoid reporting clients too early (Maciej, VLK-56889)
> v5: - return from wait if disconnect (Mika)
> v6: - read waitqueue (Mika)
> v7: - ENOTCONN early in read_event (Mika)
> v8: - consolidate resource error handling (Mika, Maciej)
> v9: - ptrace access check (Jonathan)
> v10: - detach error handling (Dominik)
> 
> 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>
> 
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
> ---
>  drivers/gpu/drm/xe/Makefile           |    3 +-
>  drivers/gpu/drm/xe/xe_device.c        |   24 +
>  drivers/gpu/drm/xe/xe_device_types.h  |   26 +
>  drivers/gpu/drm/xe/xe_eudebug.c       | 1093 +++++++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_eudebug.h       |   27 +
>  drivers/gpu/drm/xe/xe_eudebug_types.h |  169 ++++
>  drivers/gpu/drm/xe/xe_vm.c            |    7 +-
>  include/uapi/drm/xe_drm.h             |   21 +
>  include/uapi/drm/xe_drm_eudebug.h     |   57 ++
>  9 files changed, 1425 insertions(+), 2 deletions(-)
>  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/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index 1ff9602a52f6..06badc5f99af 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -114,7 +114,8 @@ xe-y += xe_bb.o \
>  	xe_vram_freq.o \
>  	xe_wait_user_fence.o \
>  	xe_wa.o \
> -	xe_wopcm.o
> +	xe_wopcm.o \
> +	xe_eudebug.o
>  
>  xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o
>  
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 1aba6f9eaa19..6c5eceaca4ab 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -54,6 +54,7 @@
>  #include "xe_vm.h"
>  #include "xe_vram.h"
>  #include "xe_wait_user_fence.h"
> +#include "xe_eudebug.h"
>  #include "xe_wa.h"
>  
>  #include <generated/xe_wa_oob.h>
> @@ -100,6 +101,14 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
>  		put_task_struct(task);
>  	}
>  
> +	INIT_LIST_HEAD(&xef->link);
> +
> +	mutex_lock(&xe->files.lock);
> +	list_add_tail(&xef->link, &xe->files.list);
> +	mutex_unlock(&xe->files.lock);
> +
> +	xe_eudebug_file_open(xef);
> +
>  	return 0;
>  }
>  
> @@ -158,6 +167,12 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
>  
>  	xe_pm_runtime_get(xe);
>  
> +	xe_eudebug_file_close(xef);
> +
> +	mutex_lock(&xef->xe->files.lock);
> +	list_del_init(&xef->link);
> +	mutex_unlock(&xef->xe->files.lock);
> +
>  	/*
>  	 * 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
> @@ -196,6 +211,7 @@ static const struct drm_ioctl_desc xe_ioctls[] = {
>  	DRM_IOCTL_DEF_DRV(XE_WAIT_USER_FENCE, xe_wait_user_fence_ioctl,
>  			  DRM_RENDER_ALLOW),
>  	DRM_IOCTL_DEF_DRV(XE_OBSERVATION, xe_observation_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)
> @@ -285,6 +301,8 @@ static void xe_device_destroy(struct drm_device *dev, void *dummy)
>  {
>  	struct xe_device *xe = to_xe_device(dev);
>  
> +	xe_eudebug_fini(xe);
> +
>  	if (xe->preempt_fence_wq)
>  		destroy_workqueue(xe->preempt_fence_wq);
>  
> @@ -330,6 +348,9 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
>  	spin_lock_init(&xe->irq.lock);
>  	spin_lock_init(&xe->clients.lock);
>  
> +	drmm_mutex_init(&xe->drm, &xe->files.lock);
> +	INIT_LIST_HEAD(&xe->files.list);
> +
>  	init_waitqueue_head(&xe->ufence_wq);
>  
>  	err = drmm_mutex_init(&xe->drm, &xe->usm.lock);
> @@ -356,7 +377,10 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
>  	INIT_LIST_HEAD(&xe->pinned.external_vram);
>  	INIT_LIST_HEAD(&xe->pinned.evicted);
>  
> +	xe_eudebug_init(xe);
> +
>  	xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq", 0);
> +
>  	xe->ordered_wq = alloc_ordered_workqueue("xe-ordered-wq", 0);
>  	xe->unordered_wq = alloc_workqueue("xe-unordered-wq", 0, 0);
>  	if (!xe->ordered_wq || !xe->unordered_wq ||
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index 5b7292a9a66d..bef7c11bd668 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -355,6 +355,15 @@ struct xe_device {
>  		u64 count;
>  	} clients;
>  
> +	/** @files: xe_file list (opens) */
> +	struct {
> +		/** @lock: Protects xe_file list */
> +		struct mutex lock;
> +
> +		/** @list: xe file list */
> +		struct list_head list;
> +	} files;
> +
>  	/** @usm: unified memory state */
>  	struct {
>  		/** @usm.asid: convert a ASID to VM */
> @@ -492,6 +501,20 @@ struct xe_device {
>  	u8 vm_inject_error_position;
>  #endif
>  
> +	/** @debugger connection list and globals for device */
> +	struct {
> +		/** @lock: protects the list of connections */
> +		spinlock_t lock;
> +		/** @list: list of connections, aka debuggers */
> +		struct list_head list;
> +
> +		/** @session_count: session counter to track connections */
> +		u64 session_count;
> +
> +		/** @available: is the debugging functionality available */
> +		bool available;
> +	} eudebug;
> +
>  	/* private: */
>  
>  #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
> @@ -596,6 +619,9 @@ struct xe_file {
>  
>  	/** @refcount: ref count of this xe file */
>  	struct kref refcount;
> +
> +	/** @link: link into xe_device.client.list */
> +	struct list_head link;
>  };
>  
>  #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..8aab02824f8a
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -0,0 +1,1093 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#include <linux/uaccess.h>
> +
> +#include <linux/anon_inodes.h>
> +#include <linux/poll.h>
> +#include <linux/delay.h>
> +
> +#include <drm/drm_managed.h>
> +
> +#include "xe_device.h"
> +#include "xe_assert.h"
> +#include "xe_macros.h"
> +
> +#include "xe_eudebug_types.h"
> +#include "xe_eudebug.h"
> +
> +/*
> + * If there is no detected event read by userspace, during this period, assume
> + * userspace problem and disconnect debugger to allow forward progress.
> + */
> +#define XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS (25 * 1000)
> +
> +#define for_each_debugger_rcu(debugger, head) \
> +	list_for_each_entry_rcu((debugger), (head), connection_link)
> +#define for_each_debugger(debugger, head) \
> +	list_for_each_entry((debugger), (head), connection_link)
> +
> +#define cast_event(T, event) container_of((event), typeof(*(T)), base)
> +
> +#define XE_EUDEBUG_DBG_STR "eudbg: %lld:%lu:%s (%d/%d) -> (%d/%d): "
> +#define XE_EUDEBUG_DBG_ARGS(d) (d)->session, \
> +		atomic_long_read(&(d)->events.seqno), \
> +		READ_ONCE(d->connection.status) <= 0 ? "disconnected" : "", \
> +		current->pid, \
> +		task_tgid_nr(current), \
> +		(d)->target_task->pid, \
> +		task_tgid_nr((d)->target_task)
> +
> +#define eu_err(d, fmt, ...) drm_err(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
> +				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
> +#define eu_warn(d, fmt, ...) drm_warn(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
> +				      XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
> +#define eu_dbg(d, fmt, ...) drm_dbg(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
> +				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
> +
> +#define xe_eudebug_assert(d, ...) xe_assert((d)->xe, ##__VA_ARGS__)
> +
> +#define struct_member(T, member) (((T *)0)->member)
> +
> +/* Keep 1:1 parity with uapi events */
> +#define write_member(T_out, ptr, member, value) { \
> +	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
> +	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
> +		     offsetof(typeof(T_out), member)); \
> +	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
> +	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
> +	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
> +	(ptr)->member = (value); \
> +	}
> +
> +static struct xe_eudebug_event *
> +event_fifo_pending(struct xe_eudebug *d)
> +{
> +	struct xe_eudebug_event *event;
> +
> +	if (kfifo_peek(&d->events.fifo, &event))
> +		return event;
> +
> +	return NULL;
> +}
> +
> +/*
> + * 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_num_events_peek(const struct xe_eudebug * const d)
> +{
> +	return kfifo_len(&d->events.fifo);
> +}
> +
> +static bool
> +xe_eudebug_detached(struct xe_eudebug *d)
> +{
> +	int status;
> +
> +	spin_lock(&d->connection.lock);
> +	status = d->connection.status;
> +	spin_unlock(&d->connection.lock);
> +
> +	return status <= 0;
> +}
> +
> +static int
> +xe_eudebug_error(const struct xe_eudebug * const d)
> +{
> +	const int status = READ_ONCE(d->connection.status);
> +
> +	return status <= 0 ? status : 0;
> +}
> +
> +static unsigned int
> +event_fifo_has_events(struct xe_eudebug *d)
> +{
> +	if (xe_eudebug_detached(d))
> +		return 1;
> +
> +	return event_fifo_num_events_peek(d);
> +}
> +
> +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_resources * const res, const int t)
> +{
> +	return &res->rt[t];
> +}
> +
> +static struct xe_eudebug_resources *
> +xe_eudebug_resources_alloc(void)
> +{
> +	struct xe_eudebug_resources *res;
> +	int err;
> +	int i;
> +
> +	res = kzalloc(sizeof(*res), GFP_ATOMIC);
> +	if (!res)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_init(&res->lock);
> +
> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
> +		xa_init_flags(&res->rt[i].xa, XA_FLAGS_ALLOC1);
> +		err = rhashtable_init(&res->rt[i].rh, &rhash_res);
> +
> +		if (err)
> +			break;
> +	}
> +
> +	if (err) {
> +		while (i--) {
> +			xa_destroy(&res->rt[i].xa);
> +			rhashtable_destroy(&res->rt[i].rh);
> +		}
> +
> +		kfree(res);
> +		return ERR_PTR(err);
> +	}
> +
> +	return res;
> +}
> +
> +static void res_free_fn(void *ptr, void *arg)
> +{
> +	XE_WARN_ON(ptr);
> +	kfree(ptr);
> +}
> +
> +static void
> +xe_eudebug_destroy_resources(struct xe_eudebug *d)
> +{
> +	struct xe_eudebug_resources *res = d->res;
> +	struct xe_eudebug_handle *h;
> +	unsigned long j;
> +	int i;
> +	int err;
> +
> +	mutex_lock(&res->lock);
> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
> +		struct xe_eudebug_resource *r = &res->rt[i];
> +
> +		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);
> +			xe_eudebug_assert(d, t == h);
> +			kfree(t);
> +		}
> +	}
> +	mutex_unlock(&res->lock);
> +
> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
> +		struct xe_eudebug_resource *r = &res->rt[i];
> +
> +		rhashtable_free_and_destroy(&r->rh, res_free_fn, NULL);
> +		xe_eudebug_assert(d, xa_empty(&r->xa));
> +		xa_destroy(&r->xa);
> +	}
> +
> +	mutex_destroy(&res->lock);
> +
> +	kfree(res);
> +}
> +
> +static void xe_eudebug_free(struct kref *ref)
> +{
> +	struct xe_eudebug *d = container_of(ref, typeof(*d), ref);
> +	struct xe_eudebug_event *event;
> +
> +	while (kfifo_get(&d->events.fifo, &event))
> +		kfree(event);
> +
> +	xe_eudebug_destroy_resources(d);
> +	put_task_struct(d->target_task);
> +
> +	xe_eudebug_assert(d, !kfifo_len(&d->events.fifo));
> +
> +	kfree_rcu(d, rcu);
> +}
> +
> +static void xe_eudebug_put(struct xe_eudebug *d)
> +{
> +	kref_put(&d->ref, xe_eudebug_free);
> +}
> +
> +static struct task_struct *find_get_target(const pid_t nr)
> +{
> +	struct task_struct *task;
> +
> +	rcu_read_lock();
> +	task = pid_task(find_pid_ns(nr, task_active_pid_ns(current)), PIDTYPE_PID);
> +	if (task)
> +		get_task_struct(task);
> +	rcu_read_unlock();
> +
> +	return task;
> +}
> +
> +static int
> +xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
> +		  const pid_t pid_nr)
> +{
> +	struct task_struct *target;
> +	struct xe_eudebug *iter;
> +	kuid_t uid = current_uid();
> +	int ret = 0;
> +
> +	target = find_get_target(pid_nr);
> +	if (!target)
> +		return -ENOENT;
> +
> +	if (!uid_eq(uid, task_uid(target)) && !capable(CAP_SYS_ADMIN)) {
> +		put_task_struct(target);
> +		return -EACCES;
> +	}
> +
> +	XE_WARN_ON(d->connection.status != 0);
> +
> +	spin_lock(&xe->eudebug.lock);
> +	for_each_debugger(iter, &xe->eudebug.list) {
> +		if (!same_thread_group(iter->target_task, target))
> +			continue;
> +
> +		ret = -EBUSY;
> +	}
> +
> +	if (!ret && xe->eudebug.session_count + 1 == 0)
> +		ret = -ENOSPC;
> +
> +	if (!ret) {
> +		d->connection.status = XE_EUDEBUG_STATUS_CONNECTED;
> +		d->xe = xe;
> +		d->target_task = target;
> +		d->session = ++xe->eudebug.session_count;
> +		kref_get(&d->ref);
> +		list_add_tail_rcu(&d->connection_link, &xe->eudebug.list);
> +	}
> +	spin_unlock(&xe->eudebug.lock);
> +
> +	if (ret)
> +		put_task_struct(target);
> +
> +	return ret;
> +}
> +
> +static bool xe_eudebug_detach(struct xe_device *xe,
> +			      struct xe_eudebug *d,
> +			      const int err)
> +{
> +	bool detached = false;
> +
> +	XE_WARN_ON(err > 0);
> +
> +	spin_lock(&d->connection.lock);
> +	if (d->connection.status == XE_EUDEBUG_STATUS_CONNECTED) {
> +		d->connection.status = err;
> +		detached = true;
> +	}
> +	spin_unlock(&d->connection.lock);
> +
> +	if (!detached)
> +		return false;
> +
> +	spin_lock(&xe->eudebug.lock);
> +	list_del_rcu(&d->connection_link);
> +	spin_unlock(&xe->eudebug.lock);
> +
> +	eu_dbg(d, "session %lld detached with %d", d->session, err);
> +
> +	/* Our ref with the connection_link */
> +	xe_eudebug_put(d);
> +
> +	return true;
> +}
> +
> +static int _xe_eudebug_disconnect(struct xe_eudebug *d,
> +				  const int err)
> +{
> +	wake_up_all(&d->events.write_done);
> +	wake_up_all(&d->events.read_done);
> +
> +	return xe_eudebug_detach(d->xe, d, err);
> +}
> +
> +#define xe_eudebug_disconnect(_d, _err) ({ \
> +	if (_xe_eudebug_disconnect((_d), (_err))) { \
> +		if ((_err) == 0 || (_err) == -ETIMEDOUT) \
> +			eu_dbg(d, "Session closed (%d)", (_err)); \
> +		else \
> +			eu_err(d, "Session disconnected, err = %d (%s:%d)", \
> +			       (_err), __func__, __LINE__); \
> +	} \
> +})
> +
> +static int xe_eudebug_release(struct inode *inode, struct file *file)
> +{
> +	struct xe_eudebug *d = file->private_data;
> +
> +	xe_eudebug_disconnect(d, 0);
> +	xe_eudebug_put(d);
> +
> +	return 0;
> +}
> +
> +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 (xe_eudebug_error(d))
> +			ret |= EPOLLERR;
> +	}
> +
> +	if (event_fifo_num_events_peek(d))
> +		ret |= EPOLLIN;
> +
> +	return ret;
> +}
> +
> +static ssize_t xe_eudebug_read(struct file *file,
> +			       char __user *buf,
> +			       size_t count,
> +			       loff_t *ppos)
> +{
> +	return -EINVAL;
> +}
> +
> +static struct xe_eudebug *
> +xe_eudebug_for_task_get(struct xe_device *xe,
> +			struct task_struct *task)
> +{
> +	struct xe_eudebug *d, *iter;
> +
> +	d = NULL;
> +
> +	rcu_read_lock();
> +	for_each_debugger_rcu(iter, &xe->eudebug.list) {
> +		if (!same_thread_group(iter->target_task, task))
> +			continue;
> +
> +		if (kref_get_unless_zero(&iter->ref))
> +			d = iter;
> +
> +		break;
> +	}
> +	rcu_read_unlock();
> +
> +	return d;
> +}
> +
> +static struct task_struct *find_task_get(struct xe_file *xef)
> +{
> +	struct task_struct *task;
> +	struct pid *pid;
> +
> +	rcu_read_lock();
> +	pid = rcu_dereference(xef->drm->pid);
> +	task = pid_task(pid, PIDTYPE_PID);
> +	if (task)
> +		get_task_struct(task);
> +	rcu_read_unlock();
> +
> +	return task;
> +}
> +
> +static struct xe_eudebug *
> +xe_eudebug_get(struct xe_file *xef)
> +{
> +	struct task_struct *task;
> +	struct xe_eudebug *d;
> +
> +	d = NULL;
> +	task = find_task_get(xef);
> +	if (task) {
> +		d = xe_eudebug_for_task_get(to_xe_device(xef->drm->minor->dev),
> +					    task);
> +		put_task_struct(task);
> +	}
> +
> +	if (!d)
> +		return NULL;
> +
> +	if (xe_eudebug_detached(d)) {
> +		xe_eudebug_put(d);
> +		return NULL;
> +	}
> +
> +	return d;
> +}
> +
> +static int xe_eudebug_queue_event(struct xe_eudebug *d,
> +				  struct xe_eudebug_event *event)
> +{
> +	const u64 wait_jiffies = msecs_to_jiffies(1000);
> +	u64 last_read_detected_ts, last_head_seqno, start_ts;
> +
> +	xe_eudebug_assert(d, event->len > sizeof(struct xe_eudebug_event));
> +	xe_eudebug_assert(d, event->type);
> +	xe_eudebug_assert(d, event->type != DRM_XE_EUDEBUG_EVENT_READ);
> +
> +	start_ts = ktime_get();
> +	last_read_detected_ts = start_ts;
> +	last_head_seqno = 0;
> +
> +	do  {
> +		struct xe_eudebug_event *head;
> +		u64 head_seqno;
> +		bool was_queued;
> +
> +		if (xe_eudebug_detached(d))
> +			break;
> +
> +		spin_lock(&d->events.lock);
> +		head = event_fifo_pending(d);
> +		if (head)
> +			head_seqno = event->seqno;
> +		else
> +			head_seqno = 0;
> +
> +		was_queued = kfifo_in(&d->events.fifo, &event, 1);
> +		spin_unlock(&d->events.lock);
> +
> +		wake_up_all(&d->events.write_done);
> +
> +		if (was_queued) {
> +			event = NULL;
> +			break;
> +		}
> +
> +		XE_WARN_ON(!head_seqno);
> +
> +		/* If we detect progress, restart timeout */
> +		if (last_head_seqno != head_seqno)
> +			last_read_detected_ts = ktime_get();
> +
> +		last_head_seqno = head_seqno;
> +
> +		wait_event_interruptible_timeout(d->events.read_done,
> +						 !kfifo_is_full(&d->events.fifo),
> +						 wait_jiffies);
> +
> +	} while (ktime_ms_delta(ktime_get(), last_read_detected_ts) <
> +		 XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS);
> +
> +	if (event) {
> +		eu_dbg(d,
> +		       "event %llu queue failed (blocked %lld ms, avail %d)",
> +		       event ? event->seqno : 0,
> +		       ktime_ms_delta(ktime_get(), start_ts),
> +		       kfifo_avail(&d->events.fifo));
> +
> +		kfree(event);
> +
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct xe_eudebug_handle *
> +alloc_handle(const int type, const u64 key)
> +{
> +	struct xe_eudebug_handle *h;
> +
> +	h = kzalloc(sizeof(*h), GFP_ATOMIC);
> +	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 find_handle(struct xe_eudebug_resources *res,
> +		       const int type,
> +		       const void *p)
> +{
> +	const u64 key = (u64)p;
> +	struct xe_eudebug_resource *r;
> +	struct xe_eudebug_handle *h;
> +	int id;
> +
> +	if (XE_WARN_ON(!key))
> +		return -EINVAL;
> +
> +	r = resource_from_type(res, type);
> +
> +	mutex_lock(&res->lock);
> +	h = __find_handle(r, key);
> +	id = h ? h->id : -ENOENT;
> +	mutex_unlock(&res->lock);
> +
> +	return id;
> +}
> +
> +static int _xe_eudebug_add_handle(struct xe_eudebug *d,
> +				  int type,
> +				  void *p,
> +				  u64 *seqno,
> +				  int *handle)
> +{
> +	const u64 key = (u64)p;
> +	struct xe_eudebug_resource *r;
> +	struct xe_eudebug_handle *h, *o;
> +	int err;
> +
> +	if (XE_WARN_ON(p == NULL))
> +		return -EINVAL;
> +
> +	if (xe_eudebug_detached(d))
> +		return -ENOTCONN;
> +
> +	h = alloc_handle(type, key);
> +	if (!h)
> +		return -ENOMEM;
> +
> +	r = resource_from_type(d->res, type);
> +
> +	mutex_lock(&d->res->lock);
> +	o = __find_handle(r, key);
> +	if (!o) {
> +		err = xa_alloc(&r->xa, &h->id, h, xa_limit_31b, GFP_KERNEL);
> +
> +		if (h->id >= INT_MAX) {
> +			xa_erase(&r->xa, h->id);
> +			err = -ENOSPC;
> +		}
> +
> +		if (!err)
> +			err = rhashtable_insert_fast(&r->rh,
> +						     &h->rh_head,
> +						     rhash_res);
> +
> +		if (err) {
> +			xa_erase(&r->xa, h->id);
> +		} else {
> +			if (seqno)
> +				*seqno = atomic_long_inc_return(&d->events.seqno);
> +		}
> +	} else {
> +		xe_eudebug_assert(d, o->id);
> +		err = -EEXIST;
> +	}
> +	mutex_unlock(&d->res->lock);
> +
> +	if (handle)
> +		*handle = o ? o->id : h->id;
> +
> +	if (err) {
> +		kfree(h);
> +		XE_WARN_ON(err > 0);
> +		return err;
> +	}
> +
> +	xe_eudebug_assert(d, h->id);
> +
> +	return h->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, NULL);
> +	if (ret == -EEXIST || ret == -ENOTCONN) {
> +		eu_dbg(d, "%d on adding %d", ret, type);
> +		return 0;
> +	}
> +
> +	if (ret < 0)
> +		xe_eudebug_disconnect(d, ret);
> +
> +	return ret;
> +}
> +
> +static int _xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
> +				     u64 *seqno)
> +{
> +	const u64 key = (u64)p;
> +	struct xe_eudebug_resource *r;
> +	struct xe_eudebug_handle *h, *xa_h;
> +	int ret;
> +
> +	if (XE_WARN_ON(!key))
> +		return -EINVAL;
> +
> +	if (xe_eudebug_detached(d))
> +		return -ENOTCONN;
> +
> +	r = resource_from_type(d->res, type);
> +
> +	mutex_lock(&d->res->lock);
> +	h = __find_handle(r, key);
> +	if (h) {
> +		ret = rhashtable_remove_fast(&r->rh,
> +					     &h->rh_head,
> +					     rhash_res);
> +		xe_eudebug_assert(d, !ret);
> +		xa_h = xa_erase(&r->xa, h->id);
> +		xe_eudebug_assert(d, xa_h == h);
> +		if (!ret) {
> +			ret = h->id;
> +			if (seqno)
> +				*seqno = atomic_long_inc_return(&d->events.seqno);
> +		}
> +	} else {
> +		ret = -ENOENT;
> +	}
> +	mutex_unlock(&d->res->lock);
> +
> +	kfree(h);
> +
> +	xe_eudebug_assert(d, ret);
> +
> +	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);
> +	if (ret == -ENOENT || ret == -ENOTCONN) {
> +		eu_dbg(d, "%d on removing %d", ret, type);
> +		return 0;
> +	}
> +
> +	if (ret < 0)
> +		xe_eudebug_disconnect(d, ret);
> +
> +	return ret;
> +}
> +
> +static struct xe_eudebug_event *
> +__xe_eudebug_create_event(struct xe_eudebug *d,
> +			  u64 seqno, u16 type, u16 flags, u32 len, gfp_t gfp)
> +{
> +	struct xe_eudebug_event *event;
> +
> +	xe_eudebug_assert(d, len > sizeof(*event));
> +
> +	event = kzalloc(len, gfp);
> +	if (!event)
> +		return NULL;
> +
> +	event->type = type;
> +	event->flags = flags;
> +	event->len = len;
> +	event->seqno = seqno;
> +
> +	return event;
> +}
> +
> +static struct xe_eudebug_event *
> +xe_eudebug_create_event(struct xe_eudebug *d, u16 type, u64 seqno, u16 flags,
> +			u32 len, gfp_t gfp)
> +{
> +	return __xe_eudebug_create_event(d, seqno, type, flags, len, gfp);
> +}
> +
> +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 drm_xe_eudebug_event user_event;
> +	struct xe_eudebug_event *event;
> +	long ret = 0;
> +
> +	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))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, user_event.type > DRM_XE_EUDEBUG_EVENT_MAX_EVENT))
> +		return -EINVAL;
> +
> +	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.reserved))
> +		return -EINVAL;
> +
> +	/* 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;
> +	}
> +
> +	ret = 0;
> +	spin_lock(&d->events.lock);
> +	event = event_fifo_pending(d);
> +	if (event) {
> +		if (user_event.len < event->len) {
> +			ret = -EMSGSIZE;
> +		} else if (!kfifo_out(&d->events.fifo, &event, 1)) {
> +			eu_warn(d, "internal fifo corruption");
> +			ret = -ENOTCONN;
> +		}
> +	}
> +	spin_unlock(&d->events.lock);
> +
> +	wake_up_all(&d->events.read_done);
> +
> +	if (XE_IOCTL_DBG(xe, ret))
> +		return ret;
> +
> +	if (!event) {
> +		if (xe_eudebug_detached(d))
> +			return -ENOTCONN;
> +		if (!wait)
> +			return -EAGAIN;
> +
> +		return -ENOENT;
> +	}
> +
> +	if (copy_to_user(user_orig, event, event->len))
> +		ret = -EFAULT;
> +	else
> +		eu_dbg(d, "event read: type=%u, flags=0x%x, seqno=%llu", event->type,
> +		       event->flags, event->seqno);
> +
> +	kfree(event);
> +
> +	return ret;
> +}
> +
> +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,
> +	.llseek		= no_llseek,
> +	.release	= xe_eudebug_release,
> +	.poll		= xe_eudebug_poll,
> +	.read		= xe_eudebug_read,
> +	.unlocked_ioctl	= xe_eudebug_ioctl,
> +};
> +
> +static int
> +xe_eudebug_connect(struct xe_device *xe,
> +		   struct drm_xe_eudebug_connect *param)
> +{
> +	const u64 known_open_flags = 0;
> +	unsigned long f_flags = 0;
> +	struct xe_eudebug *d;
> +	int fd, err;
> +
> +	if (param->extensions)
> +		return -EINVAL;
> +
> +	if (!param->pid)
> +		return -EINVAL;
> +
> +	if (param->flags & ~known_open_flags)
> +		return -EINVAL;
> +
> +	if (param->version && param->version != DRM_XE_EUDEBUG_VERSION)
> +		return -EINVAL;
> +
> +	param->version = DRM_XE_EUDEBUG_VERSION;
> +
> +	if (!xe->eudebug.available)
> +		return -EOPNOTSUPP;
> +
> +	d = kzalloc(sizeof(*d), GFP_KERNEL);
> +	if (!d)
> +		return -ENOMEM;
> +
> +	kref_init(&d->ref);
> +	spin_lock_init(&d->connection.lock);
> +	init_waitqueue_head(&d->events.write_done);
> +	init_waitqueue_head(&d->events.read_done);
> +
> +	spin_lock_init(&d->events.lock);
> +	INIT_KFIFO(d->events.fifo);
> +
> +	d->res = xe_eudebug_resources_alloc();
> +	if (IS_ERR(d->res)) {
> +		err = PTR_ERR(d->res);
> +		goto err_free;
> +	}
> +
> +	err = xe_eudebug_attach(xe, d, param->pid);
> +	if (err)
> +		goto err_free_res;
> +
> +	fd = anon_inode_getfd("[xe_eudebug]", &fops, d, f_flags);
> +	if (fd < 0) {
> +		err = fd;
> +		goto err_detach;
> +	}
> +
> +	eu_dbg(d, "connected session %lld", d->session);
> +
> +	return fd;
> +
> +err_detach:
> +	xe_eudebug_detach(xe, d, err);
> +err_free_res:
> +	xe_eudebug_destroy_resources(d);
> +err_free:
> +	kfree(d);
> +
> +	return err;
> +}
> +
> +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;
> +	int ret = 0;
> +
> +	ret = xe_eudebug_connect(xe, param);
> +
> +	return ret;
> +}
> +
> +void xe_eudebug_init(struct xe_device *xe)
> +{
> +	spin_lock_init(&xe->eudebug.lock);
> +	INIT_LIST_HEAD(&xe->eudebug.list);
> +
> +	xe->eudebug.available = true;
> +}
> +
> +void xe_eudebug_fini(struct xe_device *xe)
> +{
> +	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
> +}
> +
> +static int send_open_event(struct xe_eudebug *d, u32 flags, const u64 handle,
> +			   const u64 seqno)
> +{
> +	struct xe_eudebug_event *event;
> +	struct xe_eudebug_event_open *eo;
> +
> +	if (!handle)
> +		return -EINVAL;
> +
> +	if (XE_WARN_ON((long)handle >= INT_MAX))
> +		return -EINVAL;
> +
> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_OPEN, seqno,
> +					flags, sizeof(*eo), GFP_KERNEL);
> +	if (!event)
> +		return -ENOMEM;
> +
> +	eo = cast_event(eo, event);
> +
> +	write_member(struct drm_xe_eudebug_event_client, eo,
> +		     client_handle, handle);
> +
> +	return xe_eudebug_queue_event(d, event);
> +}
> +
> +static int client_create_event(struct xe_eudebug *d, struct xe_file *xef)
> +{
> +	u64 seqno;
> +	int ret;
> +
> +	ret = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT, xef, &seqno);
> +	if (ret > 0)
> +		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
> +					     ret, seqno);
> +
> +	return ret;
> +}
> +
> +static int client_destroy_event(struct xe_eudebug *d, struct xe_file *xef)
> +{
> +	u64 seqno;
> +	int ret;
> +
> +	ret = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT,
> +				       xef, &seqno);
> +	if (ret > 0)
> +		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY,
> +				      ret, seqno);
> +
> +	return ret;
> +}
> +
> +#define xe_eudebug_event_put(_d, _err) ({ \
> +	if ((_err)) \
> +		xe_eudebug_disconnect((_d), (_err)); \
> +	xe_eudebug_put((_d)); \
> +	})
> +
> +void xe_eudebug_file_open(struct xe_file *xef)
> +{
> +	struct xe_eudebug *d;
> +
> +	d = xe_eudebug_get(xef);
> +	if (!d)
> +		return;
> +
> +	xe_eudebug_event_put(d, client_create_event(d, xef));
> +}
> +
> +void xe_eudebug_file_close(struct xe_file *xef)
> +{
> +	struct xe_eudebug *d;
> +
> +	d = xe_eudebug_get(xef);
> +	if (!d)
> +		return;
> +
> +	xe_eudebug_event_put(d, client_destroy_event(d, xef));
> +}
> +
> +static int send_vm_event(struct xe_eudebug *d, u32 flags,
> +			 const u64 client_handle,
> +			 const u64 vm_handle,
> +			 const u64 seqno)
> +{
> +	struct xe_eudebug_event *event;
> +	struct xe_eudebug_event_vm *e;
> +
> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM,
> +					seqno, flags, sizeof(*e), GFP_KERNEL);
> +	if (!event)
> +		return -ENOMEM;
> +
> +	e = cast_event(e, event);
> +
> +	write_member(struct drm_xe_eudebug_event_vm, e, client_handle, client_handle);
> +	write_member(struct drm_xe_eudebug_event_vm, e, vm_handle, vm_handle);
> +
> +	return xe_eudebug_queue_event(d, event);
> +}
> +
> +static int vm_create_event(struct xe_eudebug *d,
> +			   struct xe_file *xef, struct xe_vm *vm)
> +{
> +	int h_c, h_vm;
> +	u64 seqno;
> +	int ret;
> +
> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
> +	if (h_c < 0)
> +		return h_c;
> +
> +	xe_eudebug_assert(d, h_c);
> +
> +	h_vm = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
> +	if (h_vm <= 0)
> +		return h_vm;
> +
> +	ret = send_vm_event(d, DRM_XE_EUDEBUG_EVENT_CREATE, h_c, h_vm, seqno);
> +
> +	return ret;
> +}
> +
> +static int vm_destroy_event(struct xe_eudebug *d,
> +			    struct xe_file *xef, struct xe_vm *vm)
> +{
> +	int h_c, h_vm;
> +	u64 seqno;
> +
> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
> +	if (h_c < 0) {
> +		XE_WARN_ON("no client found for vm");
> +		eu_warn(d, "no client found for vm");
> +		return h_c;
> +	}
> +
> +	xe_eudebug_assert(d, h_c);
> +
> +	h_vm = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
> +	if (h_vm <= 0)
> +		return h_vm;
> +
> +	return send_vm_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY, h_c, h_vm, seqno);
> +}
> +
> +void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm)
> +{
> +	struct xe_eudebug *d;
> +
> +	d = xe_eudebug_get(xef);
> +	if (!d)
> +		return;
> +
> +	xe_eudebug_event_put(d, vm_create_event(d, xef, vm));
> +}
> +
> +void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
> +{
> +	struct xe_eudebug *d;
> +
> +	d = xe_eudebug_get(xef);
> +	if (!d)
> +		return;
> +
> +	xe_eudebug_event_put(d, vm_destroy_event(d, xef, vm));
> +}
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> new file mode 100644
> index 000000000000..df577b581364
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> @@ -0,0 +1,27 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#ifndef _XE_EUDEBUG_H_
> +
> +struct drm_device;
> +struct drm_file;
> +struct xe_device;
> +struct xe_file;
> +struct xe_vm;
> +
> +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_fini(struct xe_device *xe);
> +
> +void xe_eudebug_file_open(struct xe_file *xef);
> +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);
> +
> +#endif
> 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..093221a707df
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> @@ -0,0 +1,169 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#ifndef __XE_EUDEBUG_TYPES_H_
> +
> +#include <linux/mutex.h>
> +#include <linux/kref.h>
> +#include <linux/kfifo.h>
> +#include <linux/completion.h>
> +#include <linux/wait.h>
> +#include <linux/xarray.h>
> +#include <linux/rbtree.h>
> +#include <linux/rhashtable.h>
> +
> +#include <uapi/drm/xe_drm.h>
> +
> +struct xe_device;
> +struct task_struct;
> +struct xe_eudebug_event;
> +
> +#define CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE 64
> +
> +/**
> + * 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 {
> +	/** @xa: xarrays for <id->key> */
> +	struct xarray xa;
> +
> +	/** @rh rhashtable for <key->id> */
> +	struct rhashtable rh;
> +};
> +
> +#define XE_EUDEBUG_RES_TYPE_CLIENT	0
> +#define XE_EUDEBUG_RES_TYPE_VM		1
> +#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_VM + 1)
> +
> +/**
> + * struct xe_eudebug_resources - eudebug resources for all types
> + */
> +struct xe_eudebug_resources {
> +	/** @lock: guards access into rt */
> +	struct mutex lock;
> +
> +	/** @rt: resource maps for all types */
> +	struct xe_eudebug_resource rt[XE_EUDEBUG_RES_TYPE_COUNT];
> +};
> +
> +/**
> + * struct xe_eudebug - Top level struct for eudebug: the connection
> + */
> +struct xe_eudebug {
> +	/** @ref: kref counter for this struct */
> +	struct kref ref;
> +
> +	/** @rcu: rcu_head for rcu destruction */
> +	struct rcu_head rcu;
> +
> +	/** @connection_link: our link into the xe_device:eudebug.list */
> +	struct list_head connection_link;
> +
> +	struct {
> +		/** @status: connected = 1, disconnected = error */
> +#define XE_EUDEBUG_STATUS_CONNECTED 1
> +		int status;
> +
> +		/** @lock: guards access to status */
> +		spinlock_t lock;
> +	} connection;
> +
> +	/** @xe: the parent device we are serving */
> +	struct xe_device *xe;
> +
> +	/** @target_task: the task that we are debugging */
> +	struct task_struct *target_task;
> +
> +	/** @res: the resource maps we track for target_task */
> +	struct xe_eudebug_resources *res;
> +
> +	/** @session: session number for this connection (for logs) */
> +	u64 session;
> +
> +	/** @events: kfifo queue of to-be-delivered events */
> +	struct {
> +		/** @lock: guards access to fifo */
> +		spinlock_t lock;
> +
> +		/** @fifo: queue of events pending */
> +		DECLARE_KFIFO(fifo,
> +			      struct xe_eudebug_event *,
> +			      CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE);
> +
> +		/** @write_done: waitqueue for signalling write to fifo */
> +		wait_queue_head_t write_done;
> +
> +		/** @read_done: waitqueue for signalling read from fifo */
> +		wait_queue_head_t read_done;
> +
> +		/** @event_seqno: seqno counter to stamp events for fifo */
> +		atomic_long_t seqno;
> +	} events;
> +
> +};
> +
> +/**
> + * struct xe_eudebug_event - Internal base event struct for eudebug
> + */
> +struct xe_eudebug_event {
> +	/** @len: length of this event, including payload */
> +	u32 len;
> +
> +	/** @type: message type */
> +	u16 type;
> +
> +	/** @flags: message flags */
> +	u16 flags;
> +
> +	/** @seqno: sequence number for ordering */
> +	u64 seqno;
> +
> +	/** @reserved: reserved field MBZ */
> +	u64 reserved;
> +
> +	/** @data: payload bytes */
> +	u8 data[];
> +};
> +
> +/**
> + * struct xe_eudebug_event_open - Internal event for client open/close
> + */
> +struct xe_eudebug_event_open {
> +	/** @base: base event */
> +	struct xe_eudebug_event base;
> +
> +	/** @client_handle: opaque handle for client */
> +	u64 client_handle;
> +};
> +
> +/**
> + * struct xe_eudebug_event_vm - Internal event for vm open/close
> + */
> +struct xe_eudebug_event_vm {
> +	/** @base: base event */
> +	struct xe_eudebug_event base;
> +
> +	/** @client_handle: client containing the vm open/close */
> +	u64 client_handle;
> +
> +	/** @vm_handle: vm handle it's open/close */
> +	u64 vm_handle;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index f225107bdd65..9e101c992d9c 100644
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
> @@ -39,6 +39,7 @@
>  #include "xe_trace_bo.h"
>  #include "xe_wa.h"
>  #include "xe_hmm.h"
> +#include "xe_eudebug.h"
>  
>  static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
>  {
> @@ -1818,6 +1819,8 @@ 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
>  
> +	xe_eudebug_vm_create(xef, vm);
> +
>  	return 0;
>  
>  err_free_id:
> @@ -1853,8 +1856,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 29425d7fdc77..a68734ff12f4 100644
> --- a/include/uapi/drm/xe_drm.h
> +++ b/include/uapi/drm/xe_drm.h
> @@ -102,6 +102,7 @@ extern "C" {
>  #define DRM_XE_EXEC			0x09
>  #define DRM_XE_WAIT_USER_FENCE		0x0a
>  #define DRM_XE_OBSERVATION		0x0b
> +#define DRM_XE_EUDEBUG_CONNECT		0x0c
>  
>  /* Must be kept compact -- no holes */
>  
> @@ -117,6 +118,7 @@ extern "C" {
>  #define DRM_IOCTL_XE_EXEC			DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC, struct drm_xe_exec)
>  #define DRM_IOCTL_XE_WAIT_USER_FENCE		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence)
>  #define DRM_IOCTL_XE_OBSERVATION		DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param)
> +#define DRM_IOCTL_XE_EUDEBUG_CONNECT		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)
>  
>  /**
>   * DOC: Xe IOCTL Extensions
> @@ -1694,6 +1696,25 @@ struct drm_xe_oa_stream_info {
>  	__u64 reserved[3];
>  };
>  
> +/*
> + * Debugger ABI (ioctl and events) Version History:
> + * 0 - No debugger available
> + * 1 - Initial version
> + */
> +#define DRM_XE_EUDEBUG_VERSION 1
> +
> +struct drm_xe_eudebug_connect {
> +	/** @extensions: Pointer to the first extension struct, if any */
> +	__u64 extensions;
> +
> +	__u64 pid; /* input: Target process ID */
> +	__u32 flags; /* MBZ */
> +
> +	__u32 version; /* output: current ABI (ioctl / events) version */
> +};
> +
> +#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..a1cad9c005fc
> --- /dev/null
> +++ b/include/uapi/drm/xe_drm_eudebug.h
> @@ -0,0 +1,57 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#ifndef _UAPI_XE_DRM_EUDEBUG_H_
> +#define _UAPI_XE_DRM_EUDEBUG_H_
> +
> +#if defined(__cplusplus)
> +extern "C" {
> +#endif
> +
> +/**
> + * Do a eudebug event read for a debugger connection.
> + *
> + * This ioctl is available in debug version 1.
> + */
> +#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
> +
> +/* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
> +struct drm_xe_eudebug_event {
> +	__u32 len;
> +
> +	__u16 type;
> +#define DRM_XE_EUDEBUG_EVENT_NONE		0
> +#define DRM_XE_EUDEBUG_EVENT_READ		1
> +#define DRM_XE_EUDEBUG_EVENT_OPEN		2
> +#define DRM_XE_EUDEBUG_EVENT_VM			3
> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM
> +
> +	__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)
> +	__u64 seqno;
> +	__u64 reserved;
> +};
> +
> +struct drm_xe_eudebug_event_client {
> +	struct drm_xe_eudebug_event base;
> +
> +	__u64 client_handle; /* This is unique per debug connection */
> +};
> +
> +struct drm_xe_eudebug_event_vm {
> +	struct drm_xe_eudebug_event base;
> +
> +	__u64 client_handle;
> +	__u64 vm_handle;
> +};
> +
> +#if defined(__cplusplus)
> +}
> +#endif
> +
> +#endif
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 17/21] drm/xe: Attach debug metadata to vma
  2024-07-26 14:08 ` [PATCH 17/21] drm/xe: Attach debug metadata to vma Mika Kuoppala
@ 2024-07-26 21:25   ` Matthew Brost
  0 siblings, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-26 21:25 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek, Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:14PM +0300, Mika Kuoppala wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> 
> Introduces a vm_bind_op extension, enabling users to attach metadata objects
> to each [OP_MAP|OP_MAP_USERPTR] operation. This interface will be utilized
> by the EU debugger to relay information about the contents of specified
> VMAs from the debugee to the debugger process.
> 

Not a complete, review just more comments about layering related to this
comment [1].

[1] https://patchwork.freedesktop.org/patch/606049/?series=136572&rev=1#comment_1101330

> 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_debug_metadata.c |  13 ++
>  drivers/gpu/drm/xe/xe_debug_metadata.h |   2 +
>  drivers/gpu/drm/xe/xe_vm.c             | 198 ++++++++++++++++++++++++-
>  drivers/gpu/drm/xe/xe_vm_types.h       |  15 ++
>  include/uapi/drm/xe_drm.h              |  19 +++
>  5 files changed, 243 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.c b/drivers/gpu/drm/xe/xe_debug_metadata.c
> index 8d99170d3591..daffc13c58d6 100644
> --- a/drivers/gpu/drm/xe/xe_debug_metadata.c
> +++ b/drivers/gpu/drm/xe/xe_debug_metadata.c
> @@ -24,6 +24,19 @@ void xe_debug_metadata_put(struct xe_debug_metadata *mdata)
>  	kref_put(&mdata->refcount, xe_debug_metadata_release);
>  }
>  
> +struct xe_debug_metadata *xe_debug_metadata_get(struct xe_file *xef, u32 id)
> +{
> +	struct xe_debug_metadata *mdata;
> +
> +	mutex_lock(&xef->debug_metadata.lock);
> +	mdata = xa_load(&xef->debug_metadata.xa, id);
> +	if (mdata)
> +		kref_get(&mdata->refcount);
> +	mutex_unlock(&xef->debug_metadata.lock);
> +
> +	return mdata;
> +}
> +
>  int xe_debug_metadata_create_ioctl(struct drm_device *dev,
>  				   void *data,
>  				   struct drm_file *file)
> diff --git a/drivers/gpu/drm/xe/xe_debug_metadata.h b/drivers/gpu/drm/xe/xe_debug_metadata.h
> index abaea076c12d..deca24fa2cba 100644
> --- a/drivers/gpu/drm/xe/xe_debug_metadata.h
> +++ b/drivers/gpu/drm/xe/xe_debug_metadata.h
> @@ -10,7 +10,9 @@
>  
>  struct drm_device;
>  struct drm_file;
> +struct xe_file;
>  
> +struct xe_debug_metadata *xe_debug_metadata_get(struct xe_file *xef, u32 id);
>  void xe_debug_metadata_put(struct xe_debug_metadata *mdata);
>  
>  int xe_debug_metadata_create_ioctl(struct drm_device *dev,
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index b117a892e386..9e27ae9d64e6 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_metadata.h"
>  #include "xe_device.h"
>  #include "xe_drm_client.h"
>  #include "xe_exec_queue.h"
> @@ -940,6 +941,8 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
>  			vma->gpuva.gem.obj = &bo->ttm.base;
>  	}
>  
> +	INIT_LIST_HEAD(&vma->debug_metadata);
> +
>  	INIT_LIST_HEAD(&vma->combined_links.rebind);
>  
>  	INIT_LIST_HEAD(&vma->gpuva.gem.entry);
> @@ -1003,6 +1006,48 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
>  	return vma;
>  }
>  
> +static void vma_free_debug_metadata(struct list_head *debug_metadata)
> +{

So this should be in the eudebug layer. If you don't want to add to
xe_eudebug.c you could create a new file xe_eudebug_vm.c or something.

This comment applies to all EU debug code in Xe common code, call into a
EU debug layer.

Xe isn't the best at layering, a lot of that is my fault but when adding
new code we should ensure proper layering. SRIOV is good example of how
to do this.

> +	struct xe_vma_debug_metadata *vmad, *tmp;
> +
> +	list_for_each_entry_safe(vmad, tmp, debug_metadata, link) {
> +		list_del(&vmad->link);
> +		kfree(vmad);
> +	}
> +}
> +
> +static struct xe_vma_debug_metadata *
> +vma_new_debug_metadata(u32 metadata_id, u64 cookie)
> +{
> +	struct xe_vma_debug_metadata *vmad;
> +
> +	vmad = kzalloc(sizeof(*vmad), GFP_KERNEL);
> +	if (!vmad)
> +		return ERR_PTR(-ENOMEM);
> +
> +	INIT_LIST_HEAD(&vmad->link);
> +
> +	vmad->metadata_id = metadata_id;
> +	vmad->cookie = cookie;
> +
> +	return vmad;
> +}
> +
> +static int vma_debug_metadata_copy(struct xe_vma *from,
> +				   struct xe_vma *to)
> +{
> +	struct xe_vma_debug_metadata *vmad, *vma;
> +
> +	list_for_each_entry(vmad, &from->debug_metadata, link) {
> +		vma = vma_new_debug_metadata(vmad->metadata_id, vmad->cookie);
> +		if (IS_ERR(vma))
> +			return PTR_ERR(vma);
> +
> +		list_add_tail(&vmad->link, &to->debug_metadata);
> +	}
> +	return 0;
> +}
> +
>  static void xe_vma_destroy_late(struct xe_vma *vma)
>  {
>  	struct xe_vm *vm = xe_vma_vm(vma);
> @@ -1032,6 +1077,7 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
>  		xe_bo_put(xe_vma_bo(vma));
>  	}
>  
> +	vma_free_debug_metadata(&vma->debug_metadata);
>  	xe_vma_free(vma);
>  }
>  
> @@ -2005,6 +2051,8 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_bo *bo,
>  			op->map.is_null = flags & DRM_XE_VM_BIND_FLAG_NULL;
>  			op->map.dumpable = flags & DRM_XE_VM_BIND_FLAG_DUMPABLE;
>  			op->map.pat_index = pat_index;
> +
> +			INIT_LIST_HEAD(&op->map.debug_metadata);
>  		} else if (__op->op == DRM_GPUVA_OP_PREFETCH) {
>  			op->prefetch.region = prefetch_region;
>  		}
> @@ -2195,11 +2243,11 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
>  			flags |= op->map.dumpable ?
>  				VMA_CREATE_FLAG_DUMPABLE : 0;
>  
> -			vma = new_vma(vm, &op->base.map, op->map.pat_index,
> -				      flags);
> +			vma = new_vma(vm, &op->base.map, op->map.pat_index, flags);
>  			if (IS_ERR(vma))
>  				return PTR_ERR(vma);
>  
> +			list_splice_tail_init(&op->map.debug_metadata, &vma->debug_metadata);
>  			op->map.vma = vma;
>  			if (op->map.immediate || !xe_vm_in_fault_mode(vm))
>  				xe_vma_ops_incr_pt_update_ops(vops,
> @@ -2230,6 +2278,8 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
>  				if (IS_ERR(vma))
>  					return PTR_ERR(vma);
>  
> +				list_splice_tail_init(&old->debug_metadata, &vma->debug_metadata);
> +
>  				op->remap.prev = vma;
>  
>  				/*
> @@ -2269,6 +2319,16 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
>  				if (IS_ERR(vma))
>  					return PTR_ERR(vma);
>  
> +				if (op->base.remap.prev) {
> +					err = vma_debug_metadata_copy(op->remap.prev,
> +								      vma);
> +					if (err)
> +						return err;
> +				} else {
> +					list_splice_tail_init(&old->debug_metadata,
> +							      &vma->debug_metadata);
> +				}
> +
>  				op->remap.next = vma;
>  
>  				/*
> @@ -2319,6 +2379,7 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
>  	switch (op->base.op) {
>  	case DRM_GPUVA_OP_MAP:
>  		if (op->map.vma) {
> +			vma_free_debug_metadata(&op->map.debug_metadata);
>  			prep_vma_destroy(vm, op->map.vma, post_commit);
>  			xe_vma_destroy_unlocked(op->map.vma);
>  		}
> @@ -2557,6 +2618,120 @@ static int vm_ops_setup_tile_args(struct xe_vm *vm, struct xe_vma_ops *vops)
>  	}
>  
>  	return number_tiles;
> +};
> +
> +static int vma_new_debug_metadata_op(struct xe_vma_op *op,
> +				     u32 metadata_id, u64 cookie,
> +				     u64 flags)
> +{
> +	struct xe_vma_debug_metadata *vmad;
> +
> +	vmad = vma_new_debug_metadata(metadata_id, cookie);
> +	if (IS_ERR(vmad))
> +		return PTR_ERR(vmad);
> +
> +	list_add_tail(&vmad->link, &op->map.debug_metadata);
> +	return 0;
> +}
> +
> +typedef int (*xe_vm_bind_op_user_extension_fn)(struct xe_device *xe,
> +					       struct xe_file *xef,
> +					       struct drm_gpuva_ops *ops,
> +					       u32 operation, u64 extension);
> +
> +static int vm_bind_op_ext_attach_debug(struct xe_device *xe,
> +				       struct xe_file *xef,
> +				       struct drm_gpuva_ops *ops,
> +				       u32 operation, u64 extension)
> +{
> +	u64 __user *address = u64_to_user_ptr(extension);
> +	struct drm_xe_vm_bind_op_ext_attach_debug ext;
> +	struct xe_debug_metadata *mdata;
> +	struct drm_gpuva_op *__op;
> +	int err;
> +
> +	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_MAP_USERPTR &&
> +			 operation != DRM_XE_VM_BIND_OP_MAP))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, ext.flags))
> +		return -EINVAL;
> +

Relates to comment here [2]. Ensure VM is LR mode as I don't think we
can use dma-fences with the EU debugger.

[2] https://patchwork.freedesktop.org/patch/606059/?series=136572&rev=1#comment_1101319

> +	mdata = xe_debug_metadata_get(xef, (u32)ext.metadata_id);
> +	if (XE_IOCTL_DBG(xe, !mdata))
> +		return -ENOENT;
> +
> +	/* care about metadata existence only on the time of attach */
> +	xe_debug_metadata_put(mdata);
> +
> +	if (!ops)
> +		return 0;
> +
> +	drm_gpuva_for_each_op(__op, ops) {
> +		struct xe_vma_op *op = gpuva_op_to_vma_op(__op);
> +
> +		if (op->base.op == DRM_GPUVA_OP_MAP) {
> +			err = vma_new_debug_metadata_op(op,
> +							ext.metadata_id,
> +							ext.cookie,
> +							ext.flags);
> +			if (err)
> +				return err;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static const xe_vm_bind_op_user_extension_fn vm_bind_op_extension_funcs[] = {
> +	[XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG] = vm_bind_op_ext_attach_debug,
> +};
> +
> +#define MAX_USER_EXTENSIONS	16
> +static int vm_bind_op_user_extensions(struct xe_device *xe,
> +				      struct xe_file *xef,
> +				      struct drm_gpuva_ops *ops,
> +				      u32 operation,
> +				      u64 extensions, int ext_number)
> +{
> +	u64 __user *address = u64_to_user_ptr(extensions);
> +	struct drm_xe_user_extension ext;
> +	int err;
> +
> +	if (XE_IOCTL_DBG(xe, ext_number >= 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, ext.pad) ||
> +	    XE_IOCTL_DBG(xe, ext.name >=
> +			 ARRAY_SIZE(vm_bind_op_extension_funcs)))
> +		return -EINVAL;
> +
> +	err = vm_bind_op_extension_funcs[ext.name](xe, xef, ops,
> +						   operation, extensions);
> +	if (XE_IOCTL_DBG(xe, err))
> +		return err;
> +
> +	if (ext.next_extension)
> +		return vm_bind_op_user_extensions(xe, xef, ops,
> +						  operation, ext.next_extension,
> +						  ++ext_number);
> +
> +	return 0;
> +}
> +
> +static int vm_bind_op_user_extensions_check(struct xe_device *xe,
> +					    struct xe_file *xef,
> +					    u32 operation, u64 extensions)
> +{
> +	return vm_bind_op_user_extensions(xe, xef, NULL, operation, extensions, 0);
>  }
>  
>  static struct dma_fence *ops_execute(struct xe_vm *vm,
> @@ -2753,6 +2928,7 @@ static int vm_bind_ioctl_ops_execute(struct xe_vm *vm,
>  #define ALL_DRM_XE_SYNCS_FLAGS (DRM_XE_SYNCS_FLAG_WAIT_FOR_OP)
>  
>  static int vm_bind_ioctl_check_args(struct xe_device *xe,
> +				    struct xe_file *xef,
>  				    struct drm_xe_vm_bind *args,
>  				    struct drm_xe_vm_bind_op **bind_ops)
>  {
> @@ -2796,6 +2972,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe,
>  		u64 obj_offset = (*bind_ops)[i].obj_offset;
>  		u32 prefetch_region = (*bind_ops)[i].prefetch_mem_region_instance;
>  		bool is_null = flags & DRM_XE_VM_BIND_FLAG_NULL;
> +		u64 extensions = (*bind_ops)[i].extensions;
>  		u16 pat_index = (*bind_ops)[i].pat_index;
>  		u16 coh_mode;
>  
> @@ -2856,6 +3033,13 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe,
>  			err = -EINVAL;
>  			goto free_bind_ops;
>  		}
> +
> +		if (extensions) {
> +			err = vm_bind_op_user_extensions_check(xe, xef, op, extensions);
> +			if (err)
> +				goto free_bind_ops;
> +		}
> +
>  	}
>  
>  	return 0;
> @@ -2958,7 +3142,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>  	int err;
>  	int i;
>  
> -	err = vm_bind_ioctl_check_args(xe, args, &bind_ops);
> +	err = vm_bind_ioctl_check_args(xe, xef, args, &bind_ops);
>  	if (err)
>  		return err;
>  
> @@ -3086,11 +3270,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, bos[i], obj_offset,
>  						  addr, range, op, flags,
>  						  prefetch_region, pat_index);
> -		if (IS_ERR(ops[i])) {
> +		if (!IS_ERR(ops[i]) && extensions) {
> +			err = vm_bind_op_user_extensions(xe, xef, ops[i],
> +							 op, extensions, 0);
> +			if (err)
> +				goto unwind_ops;
> +		} else if (IS_ERR(ops[i])) {
>  			err = PTR_ERR(ops[i]);
>  			ops[i] = NULL;
>  			goto unwind_ops;
> diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
> index da9d7ef6ab8f..fe64ce6ed1d9 100644
> --- a/drivers/gpu/drm/xe/xe_vm_types.h
> +++ b/drivers/gpu/drm/xe/xe_vm_types.h
> @@ -121,6 +121,9 @@ struct xe_vma {
>  	 * Needs to be signalled before UNMAP can be processed.
>  	 */
>  	struct xe_user_fence *ufence;
> +
> +	/** @debug_metadata: List of vma debug metadata */
> +	struct list_head debug_metadata;

Make this a substruct, e.g.

struct {
	struct list_head metadata;
} eudebug;

Use the 'eudebug' sub-struct in any other common Xe structures too. This
gives us scope knowing this belonging to the eudebug layer.

With my comment about about layering, only the eudebug layer should
touch these (i.e. xe_vm.c never directly touches these fields).

Matt

>  };
>  
>  /**
> @@ -309,6 +312,8 @@ struct xe_vma_op_map {
>  	bool dumpable;
>  	/** @pat_index: The pat index to use for this operation. */
>  	u16 pat_index;
> +	/** @debug_metadata: List of attached debug metadata */
> +	struct list_head debug_metadata;
>  };
>  
>  /** struct xe_vma_op_remap - VMA remap operation */
> @@ -386,4 +391,14 @@ struct xe_vma_ops {
>  #endif
>  };
>  
> +struct xe_vma_debug_metadata {
> +	/** @debug.metadata: id of attached xe_debug_metadata */
> +	u32 metadata_id;
> +	/** @debug.cookie: user defined cookie */
> +	u64 cookie;
> +
> +	/** @link: list of metadata attached to vma */
> +	struct list_head link;
> +};
> +
>  #endif
> diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
> index cddc36c9be02..eab503754735 100644
> --- a/include/uapi/drm/xe_drm.h
> +++ b/include/uapi/drm/xe_drm.h
> @@ -886,6 +886,23 @@ struct drm_xe_vm_destroy {
>  	__u64 reserved[2];
>  };
>  
> +struct drm_xe_vm_bind_op_ext_attach_debug {
> +	/** @base: base user extension */
> +	struct drm_xe_user_extension base;
> +
> +	/** @id: Debug object id from create metadata */
> +	__u64 metadata_id;
> +
> +	/** @flags: Flags */
> +	__u64 flags;
> +
> +	/** @cookie: Cookie */
> +	__u64 cookie;
> +
> +	/** @reserved: Reserved */
> +	__u64 reserved;
> +};
> +
>  /**
>   * struct drm_xe_vm_bind_op - run bind operations
>   *
> @@ -910,7 +927,9 @@ struct drm_xe_vm_destroy {
>   *    handle MBZ, and the BO offset MBZ. This flag is intended to
>   *    implement VK sparse bindings.
>   */
> +
>  struct drm_xe_vm_bind_op {
> +#define XE_VM_BIND_OP_EXTENSIONS_ATTACH_DEBUG 0
>  	/** @extensions: Pointer to the first extension struct, if any */
>  	__u64 extensions;
>  
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks
  2024-07-26 14:08 ` [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks Mika Kuoppala
@ 2024-07-27  0:40   ` Matthew Brost
  2024-07-30 14:05     ` Mika Kuoppala
  0 siblings, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  0:40 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

On Fri, Jul 26, 2024 at 05:08:10PM +0300, Mika Kuoppala wrote:
> When vma is in place, debugger needs to intercept before
> userspace proceeds with the workload. For example to install
> a breakpoint in a eu shader.
> 
> Attach debugger in xe_user_fence, send UFENCE event
> and stall normal user fence signal path to yield if
> there is debugger attached to ufence.
> 
> When ack (ioctl) is received for the corresponding seqno,
> signal ufence.
> 
> v2: ufence worker in own workqueue
> 

Not a complete review again, just a couple of quick comments.

> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> ---
>  drivers/gpu/drm/xe/xe_eudebug.c       | 239 +++++++++++++++++++++++++-
>  drivers/gpu/drm/xe/xe_eudebug.h       |   6 +
>  drivers/gpu/drm/xe/xe_eudebug_types.h |  12 ++
>  drivers/gpu/drm/xe/xe_exec.c          |   2 +-
>  drivers/gpu/drm/xe/xe_sync.c          |  49 ++++--
>  drivers/gpu/drm/xe/xe_sync.h          |   8 +-
>  drivers/gpu/drm/xe/xe_sync_types.h    |  26 ++-
>  drivers/gpu/drm/xe/xe_vm.c            |   4 +-
>  include/uapi/drm/xe_drm_eudebug.h     |  15 +-
>  9 files changed, 333 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 8f0e6a56a65e..5dcb7c9464e9 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -35,6 +35,7 @@
>  #include "xe_vm.h"
>  #include "xe_wa.h"
>  #include "xe_force_wake.h"
> +#include "xe_sync.h"
>  
>  /*
>   * If there is no detected event read by userspace, during this period, assume
> @@ -240,11 +241,115 @@ static void xe_eudebug_free(struct kref *ref)
>  	kfree_rcu(d, rcu);
>  }
>  
> -static void xe_eudebug_put(struct xe_eudebug *d)
> +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;

Here we have a seqno but then an RB tree for search which is a bit
incongruent. Let me explain, seqno typically mean something which
signals sequentially in order. But then you have RB tree for searching,
if everything signaled in order a list would be sufficient.

So without looking too much I think we want one of two things.

1. seqno + list
2. key + rb tree

Make sense?

Kinda a nit but naming matters in this case as a name implies in-order
vs out-of-order signaling.

Matt

> +	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);
> +
> +	if (READ_ONCE(ufence->signalled))
> +		xe_sync_ufence_signal(ufence);
> +
> +	xe_sync_ufence_put(ufence);
> +}
> +
> +static void kick_ufence_worker(struct xe_user_fence *f)
> +{
> +	INIT_WORK(&f->eudebug.worker, ufence_signal_worker);
> +	queue_work(f->xe->eudebug.ordered_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;
> +	u64 signaller_ack, signalled_by;
> +
> +	signaller_ack = cmpxchg64(&f->eudebug.signalled_seqno, 0, ack->seqno);
> +	signalled_by = f->eudebug.signalled_seqno;
> +
> +	if (!signaller_ack)
> +		kick_ufence_worker(f);
> +	else
> +		xe_sync_ufence_put(f);
> +
> +	eu_dbg(d, "ACK: seqno=%llu: %ssignalled by %s (%llu) (held %lluus)",
> +	       ack->seqno, signaller_ack ? "already " : "",
> +	       on_disconnect ? "disconnect" : "debugger",
> +	       signalled_by,
> +	       ktime_us_delta(ktime_get(), ack->ts_insert));
> +
> +	kfree(ack);
> +}
> +
> +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 struct task_struct *find_get_target(const pid_t nr)
>  {
>  	struct task_struct *task;
> @@ -328,6 +433,8 @@ static bool xe_eudebug_detach(struct xe_device *xe,
>  
>  	eu_dbg(d, "session %lld detached with %d", d->session, err);
>  
> +	release_acks(d);
> +
>  	/* Our ref with the connection_link */
>  	xe_eudebug_put(d);
>  
> @@ -428,7 +535,7 @@ static struct task_struct *find_task_get(struct xe_file *xef)
>  	return task;
>  }
>  
> -static struct xe_eudebug *
> +struct xe_eudebug *
>  xe_eudebug_get(struct xe_file *xef)
>  {
>  	struct task_struct *task;
> @@ -889,6 +996,44 @@ static long xe_eudebug_read_event(struct xe_eudebug *d,
>  	return ret;
>  }
>  
> +static long
> +xe_eudebug_ack_event_ioctl(struct xe_eudebug *d,
> +			   const unsigned int cmd,
> +			   const u64 arg)
> +{
> +	struct drm_xe_eudebug_ack_event __user * const user_ptr =
> +		u64_to_user_ptr(arg);
> +	struct drm_xe_eudebug_ack_event user_arg;
> +	struct xe_eudebug_ack *ack;
> +	struct xe_device *xe = d->xe;
> +
> +	if (XE_IOCTL_DBG(xe, _IOC_SIZE(cmd) < sizeof(user_arg)))
> +		return -EINVAL;
> +
> +	/* Userland write */
> +	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(cmd) & _IOC_WRITE)))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, 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, 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;
> +}
> +
>  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)
> @@ -1070,7 +1215,10 @@ static long xe_eudebug_ioctl(struct file *file,
>  		ret = xe_eudebug_eu_control(d, arg);
>  		eu_dbg(d, "ioctl cmd=EU_CONTROL ret=%ld\n", ret);
>  		break;
> -
> +	case DRM_XE_EUDEBUG_IOCTL_ACK_EVENT:
> +		ret = xe_eudebug_ack_event_ioctl(d, cmd, arg);
> +		eu_dbg(d, "ioctl cmd=EVENT_ACK ret=%ld\n", ret);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  	}
> @@ -1759,6 +1907,9 @@ xe_eudebug_connect(struct xe_device *xe,
>  	INIT_KFIFO(d->events.fifo);
>  	INIT_WORK(&d->discovery_work, discovery_work_fn);
>  
> +	spin_lock_init(&d->acks.lock);
> +	d->acks.tree = RB_ROOT;
> +
>  	d->res = xe_eudebug_resources_alloc();
>  	if (IS_ERR(d->res)) {
>  		err = PTR_ERR(d->res);
> @@ -2337,6 +2488,70 @@ static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
>  	return 0;
>  }
>  
> +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(sizeof(*ack), GFP_KERNEL);
> +	if (!ack)
> +		return -ENOMEM;
> +
> +	ack->seqno = seqno;
> +	ack->ts_insert = ktime_get();
> +
> +	spin_lock(&d->acks.lock);
> +	old = rb_find_add(&ack->rb_node,
> +			  &d->acks.tree, ack_insert_cmp);
> +	if (!old) {
> +		kref_get(&f->refcount);
> +		ack->ufence = f;
> +	}
> +	spin_unlock(&d->acks.lock);
> +
> +	if (old) {
> +		eu_dbg(d, "ACK: seqno=%llu: already exists", seqno);
> +		kfree(ack);
> +		return -EEXIST;
> +	}
> +
> +	eu_dbg(d, "ACK: seqno=%llu: tracking started", seqno);
> +
> +	return 0;
> +}
> +
> +static int vm_bind_ufence_event(struct xe_eudebug *d,
> +				struct xe_user_fence *ufence)
> +{
> +	struct xe_eudebug_event *event;
> +	struct 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;
> +
> +	seqno = atomic_long_inc_return(&d->events.seqno);
> +
> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
> +					seqno, flags, sz, GFP_KERNEL);
> +	if (!event)
> +		return -ENOMEM;
> +
> +	e = cast_event(e, event);
> +
> +	write_member(struct drm_xe_eudebug_event_vm_bind_ufence,
> +		     e, vm_bind_ref_seqno, ufence->eudebug.bind_ref_seqno);
> +
> +	ret = xe_eudebug_track_ufence(d, ufence, seqno);
> +	if (!ret)
> +		ret = xe_eudebug_queue_event(d, event);
> +
> +	return ret;
> +}
> +
>  void xe_eudebug_vm_bind_start(struct xe_vm *vm)
>  {
>  	struct xe_eudebug *d;
> @@ -2507,6 +2722,24 @@ void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int bind_err)
>  		xe_eudebug_put(d);
>  }
>  
> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence)
> +{
> +	struct xe_eudebug *d;
> +	int err;
> +
> +	d = ufence->eudebug.debugger;
> +	if (!d || xe_eudebug_detached(d))
> +		return -ENOTCONN;
> +
> +	err = vm_bind_ufence_event(d, ufence);
> +	if (err) {
> +		eu_err(d, "error %d on %s", err, __func__);
> +		xe_eudebug_disconnect(d, err);
> +	}
> +
> +	return 0;
> +}
> +
>  static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
>  {
>  	struct xe_exec_queue *q;
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> index 2cab90773b21..3de54802a6ca 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> @@ -15,6 +15,7 @@ struct xe_vm;
>  struct xe_vma;
>  struct xe_exec_queue;
>  struct xe_hw_engine;
> +struct xe_user_fence;
>  
>  int xe_eudebug_connect_ioctl(struct drm_device *dev,
>  			     void *data,
> @@ -38,4 +39,9 @@ void xe_eudebug_vm_bind_start(struct xe_vm *vm);
>  void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range);
>  void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int err);
>  
> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence);
> +
> +struct xe_eudebug *xe_eudebug_get(struct xe_file *xef);
> +void xe_eudebug_put(struct xe_eudebug *d);
> +
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
> index 1ffe33f15409..a32c51416b5f 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> @@ -86,6 +86,7 @@ struct xe_eudebug_eu_control_ops {
>  	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
>   */
> @@ -149,6 +150,12 @@ struct xe_eudebug {
>  		atomic_long_t seqno;
>  	} events;
>  
> +	/* user fences tracked by this debugger */
> +	struct {
> +		spinlock_t lock;
> +		struct rb_root tree;
> +	} acks;
> +
>  	/** @ops operations for eu_control */
>  	struct xe_eudebug_eu_control_ops *ops;
>  };
> @@ -286,4 +293,9 @@ struct xe_eudebug_event_vm_bind_op {
>  	u64 range; /* Zero for unmap all ? */
>  };
>  
> +struct xe_eudebug_event_vm_bind_ufence {
> +	struct xe_eudebug_event base;
> +	u64 vm_bind_ref_seqno;
> +};
> +
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
> index f36980aa26e6..400cb576f3b9 100644
> --- a/drivers/gpu/drm/xe/xe_exec.c
> +++ b/drivers/gpu/drm/xe/xe_exec.c
> @@ -157,7 +157,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>  	vm = q->vm;
>  
>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
>  					  &syncs_user[num_syncs], SYNC_PARSE_FLAG_EXEC |
>  					  (xe_vm_in_lr_mode(vm) ?
>  					   SYNC_PARSE_FLAG_LR_MODE : 0));
> diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
> index 533246f42256..52d56bfdf932 100644
> --- a/drivers/gpu/drm/xe/xe_sync.c
> +++ b/drivers/gpu/drm/xe/xe_sync.c
> @@ -18,17 +18,7 @@
>  #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;
> -};
> +#include "xe_eudebug.h"
>  
>  static void user_fence_destroy(struct kref *kref)
>  {
> @@ -36,6 +26,10 @@ static void user_fence_destroy(struct kref *kref)
>  						 refcount);
>  
>  	mmdrop(ufence->mm);
> +
> +	if (ufence->eudebug.debugger)
> +		xe_eudebug_put(ufence->eudebug.debugger);
> +
>  	kfree(ufence);
>  }
>  
> @@ -49,7 +43,10 @@ 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,
> +					       struct xe_file *xef,
> +					       struct xe_vm *vm,
> +					       u64 addr,
>  					       u64 value)
>  {
>  	struct xe_user_fence *ufence;
> @@ -58,7 +55,7 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
>  	if (!access_ok(ptr, sizeof(ptr)))
>  		return ERR_PTR(-EFAULT);
>  
> -	ufence = kmalloc(sizeof(*ufence), GFP_KERNEL);
> +	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
>  	if (!ufence)
>  		return ERR_PTR(-ENOMEM);
>  
> @@ -69,12 +66,17 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
>  	ufence->mm = current->mm;
>  	mmgrab(ufence->mm);
>  
> +	if (vm->eudebug_bind.ref) {
> +		ufence->eudebug.debugger = xe_eudebug_get(xef);
> +		ufence->eudebug.bind_ref_seqno = vm->eudebug_bind.ref;
> +	}
> +
>  	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);
> +	XE_WARN_ON(!ufence->signalled);
>  
>  	if (mmget_not_zero(ufence->mm)) {
>  		kthread_use_mm(ufence->mm);
> @@ -85,7 +87,20 @@ static void user_fence_worker(struct work_struct *w)
>  	}
>  
>  	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);
> +	int ret;
> +
>  	WRITE_ONCE(ufence->signalled, 1);
> +
> +	/* Lets see if debugger wants to track this */
> +	ret = xe_eudebug_vm_bind_ufence(ufence);
> +	if (ret)
> +		xe_sync_ufence_signal(ufence);
> +
>  	user_fence_put(ufence);
>  }
>  
> @@ -104,6 +119,7 @@ static void user_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
>  }
>  
>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
> +			struct xe_vm *vm,
>  			struct xe_sync_entry *sync,
>  			struct drm_xe_sync __user *sync_user,
>  			unsigned int flags)
> @@ -185,7 +201,8 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
>  		if (exec) {
>  			sync->addr = sync_in.addr;
>  		} else {
> -			sync->ufence = user_fence_create(xe, sync_in.addr,
> +			sync->ufence = user_fence_create(xe, xef, vm,
> +							 sync_in.addr,
>  							 sync_in.timeline_value);
>  			if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence)))
>  				return PTR_ERR(sync->ufence);
> diff --git a/drivers/gpu/drm/xe/xe_sync.h b/drivers/gpu/drm/xe/xe_sync.h
> index 256ffc1e54dc..f5bec2b1b4f6 100644
> --- a/drivers/gpu/drm/xe/xe_sync.h
> +++ b/drivers/gpu/drm/xe/xe_sync.h
> @@ -9,8 +9,12 @@
>  #include "xe_sync_types.h"
>  
>  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;
>  
> @@ -19,6 +23,7 @@ struct xe_vm;
>  #define SYNC_PARSE_FLAG_DISALLOW_USER_FENCE	BIT(2)
>  
>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
> +			struct xe_vm *vm,
>  			struct xe_sync_entry *sync,
>  			struct drm_xe_sync __user *sync_user,
>  			unsigned int flags);
> @@ -40,5 +45,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 30ac3f51993b..907c601a6d8c 100644
> --- a/drivers/gpu/drm/xe/xe_sync_types.h
> +++ b/drivers/gpu/drm/xe/xe_sync_types.h
> @@ -7,12 +7,28 @@
>  #define _XE_SYNC_TYPES_H_
>  
>  #include <linux/types.h>
> +#include <linux/spinlock.h>
> +#include <linux/kref.h>
> +#include <linux/dma-fence-array.h>
>  
> -struct drm_syncobj;
> -struct dma_fence;
> -struct dma_fence_chain;
> -struct drm_xe_sync;
> -struct user_fence;
> +struct xe_eudebug;
> +
> +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;
> +	struct {
> +		struct xe_eudebug *debugger;
> +		u64 bind_ref_seqno;
> +		u64 signalled_seqno;
> +		struct work_struct worker;
> +	} eudebug;
> +};
>  
>  struct xe_sync_entry {
>  	struct drm_syncobj *syncobj;
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index 657a54b74eea..b117a892e386 100644
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
> @@ -3049,9 +3049,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>  		}
>  	}
>  
> +	xe_eudebug_vm_bind_start(vm);
> +
>  	syncs_user = u64_to_user_ptr(args->syncs);
>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
>  					  &syncs_user[num_syncs],
>  					  (xe_vm_in_lr_mode(vm) ?
>  					   SYNC_PARSE_FLAG_LR_MODE : 0) |
> diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> index 789c8aa81c09..1875192e92bd 100644
> --- a/include/uapi/drm/xe_drm_eudebug.h
> +++ b/include/uapi/drm/xe_drm_eudebug.h
> @@ -17,6 +17,7 @@ extern "C" {
>   */
>  #define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
>  #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
> +#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
>  
>  /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
>  struct drm_xe_eudebug_event {
> @@ -31,7 +32,8 @@ struct drm_xe_eudebug_event {
>  #define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND		6
>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP		7
> -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_OP
> +#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE	8
> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
>  
>  	__u16 flags;
>  #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
> @@ -158,6 +160,17 @@ struct drm_xe_eudebug_event_vm_bind_op {
>  	__u64 range; /* XXX: Zero for unmap all? */
>  };
>  
> +struct drm_xe_eudebug_event_vm_bind_ufence {
> +	struct drm_xe_eudebug_event base;
> +	__u64 vm_bind_ref_seqno; /* *_event_vm_bind.base.seqno */
> +};
> +
> +struct drm_xe_eudebug_ack_event {
> +	__u32 type;
> +	__u32 flags; /* MBZ */
> +	__u64 seqno;
> +};
> +
>  #if defined(__cplusplus)
>  }
>  #endif
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property
  2024-07-26 14:08 ` [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
  2024-07-26 18:35   ` Matthew Brost
@ 2024-07-27  0:54   ` Matthew Brost
  1 sibling, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  0:54 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

On Fri, Jul 26, 2024 at 05:08:06PM +0300, Mika Kuoppala wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> 
> Introduce exec queue immutable property of eudebug
> with a flags as value to enable eudebug specific feature(s).
> 
> For now engine lrc will use this flag to set up runalone
> hw feature. Runalone is used to ensure that only one hw engine
> of group [rcs0, ccs0-3] is active on a tile.
> 
> Note: unlike the i915, xe allows user to set runalone
> also on devices with single render/compute engine. It should not
> make much difference, but leave control to the user.
> 
> v2: use exec queue flags (Mika)
> v3: eudebug enable as flags (Mika)
> v4: adapt to lrc_create (Mika)
> v5: EUDEBUG property space squash (Mika)
> v6: runalone as rmw (Dominik)
> 
> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> ---
>  drivers/gpu/drm/xe/regs/xe_engine_regs.h |  1 +
>  drivers/gpu/drm/xe/xe_exec_queue.c       | 35 ++++++++++++++++++++++--
>  drivers/gpu/drm/xe/xe_exec_queue_types.h |  7 +++++
>  drivers/gpu/drm/xe/xe_hw_engine.c        |  2 +-
>  drivers/gpu/drm/xe/xe_lrc.c              | 16 +++++++++--
>  drivers/gpu/drm/xe/xe_lrc.h              |  4 ++-
>  include/uapi/drm/xe_drm.h                |  3 +-
>  7 files changed, 60 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> index fd31f3fb2b4c..764c270599d0 100644
> --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> @@ -136,6 +136,7 @@
>  #define	  CTX_CTRL_OAC_CONTEXT_ENABLE		REG_BIT(8)
>  #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
>  #define	  CTX_CTRL_INDIRECT_RING_STATE_ENABLE	REG_BIT(4)
> +#define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
>  #define	  CTX_CTRL_INHIBIT_SYN_CTX_SWITCH	REG_BIT(3)
>  #define	  CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT	REG_BIT(0)
>  
> diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
> index 26ae2fdbf682..bc2edade5e5b 100644
> --- a/drivers/gpu/drm/xe/xe_exec_queue.c
> +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
> @@ -106,10 +106,14 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
>  
>  static int __xe_exec_queue_init(struct xe_exec_queue *q)
>  {
> +	u32 flags = 0;
>  	int i, err;
>  
> +	if (q->eudebug_flags & EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)
> +		flags |= LRC_CREATE_RUNALONE;
> +
>  	for (i = 0; i < q->width; ++i) {
> -		q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K);
> +		q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K, flags);
>  		if (IS_ERR(q->lrc[i])) {
>  			err = PTR_ERR(q->lrc[i]);
>  			goto err_lrc;
> @@ -336,6 +340,31 @@ static int exec_queue_set_timeslice(struct xe_device *xe, struct xe_exec_queue *
>  	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;
> +

Since I've talked about layering a bit [1] [2] it worth mentioning I
think this patch fine wrt layering.

If we add a Kconfig as I suggest [1] here you'd wanna add something
like:

if (!IS_ENABLED(CONFIG_EU_DEBUG))
	return -EOPNOTSUPP;

Just make sure it is unique error code return which the UMD can
interrupt as 'kernel not compiled with EU debug support'.

Matt

[1] https://patchwork.freedesktop.org/patch/606049/?series=136572&rev=1#comment_1101330
[2] https://patchwork.freedesktop.org/patch/606056/?series=136572&rev=1#comment_1101337

> +	/*
> +	 * We want to explicitly set the global feature if
> +	 * property is set.
> +	 */
> +	if (XE_IOCTL_DBG(xe,
> +			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
> +		return -EINVAL;
> +
> +	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
> +
> +	return 0;
> +}
> +
>  typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
>  					     struct xe_exec_queue *q,
>  					     u64 value);
> @@ -343,6 +372,7 @@ typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
>  static const xe_exec_queue_set_property_fn exec_queue_set_property_funcs[] = {
>  	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY] = exec_queue_set_priority,
>  	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE] = exec_queue_set_timeslice,
> +	[DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG] = exec_queue_set_eudebug,
>  };
>  
>  static int exec_queue_user_ext_set_property(struct xe_device *xe,
> @@ -362,7 +392,8 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe,
>  			 ARRAY_SIZE(exec_queue_set_property_funcs)) ||
>  	    XE_IOCTL_DBG(xe, ext.pad) ||
>  	    XE_IOCTL_DBG(xe, ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY &&
> -			 ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE))
> +			 ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE &&
> +			 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_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h
> index 1408b02eea53..48e1190c2b58 100644
> --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h
> +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h
> @@ -90,6 +90,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/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> index 0d8b871b47fe..74813bc20787 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> @@ -532,7 +532,7 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe,
>  		goto err_name;
>  	}
>  
> -	hwe->kernel_lrc = xe_lrc_create(hwe, NULL, SZ_16K);
> +	hwe->kernel_lrc = xe_lrc_create(hwe, NULL, SZ_16K, 0);
>  	if (IS_ERR(hwe->kernel_lrc)) {
>  		err = PTR_ERR(hwe->kernel_lrc);
>  		goto err_hwsp;
> diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
> index 94ff62e1d95e..563b57f5b9ee 100644
> --- a/drivers/gpu/drm/xe/xe_lrc.c
> +++ b/drivers/gpu/drm/xe/xe_lrc.c
> @@ -890,7 +890,7 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
>  #define PVC_CTX_ACC_CTR_THOLD	(0x2a + 1)
>  
>  static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
> -		       struct xe_vm *vm, u32 ring_size)
> +		       struct xe_vm *vm, u32 ring_size, u32 flags)
>  {
>  	struct xe_gt *gt = hwe->gt;
>  	struct xe_tile *tile = gt_to_tile(gt);
> @@ -1007,6 +1007,16 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
>  	map = __xe_lrc_start_seqno_map(lrc);
>  	xe_map_write32(lrc_to_xe(lrc), &map, lrc->fence_ctx.next_seqno - 1);
>  
> +	if (flags & LRC_CREATE_RUNALONE) {
> +		u32 ctx_control = xe_lrc_read_ctx_reg(lrc, CTX_CONTEXT_CONTROL);
> +
> +		drm_dbg(&xe->drm, "read CTX_CONTEXT_CONTROL: 0x%x\n", ctx_control);
> +		ctx_control |= _MASKED_BIT_ENABLE(CTX_CTRL_RUN_ALONE);
> +		drm_dbg(&xe->drm, "written CTX_CONTEXT_CONTROL: 0x%x\n", ctx_control);
> +
> +		xe_lrc_write_ctx_reg(lrc, CTX_CONTEXT_CONTROL, ctx_control);
> +	}
> +
>  	return 0;
>  
>  err_lrc_finish:
> @@ -1026,7 +1036,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
>   * upon failure.
>   */
>  struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
> -			     u32 ring_size)
> +			     u32 ring_size, u32 flags)
>  {
>  	struct xe_lrc *lrc;
>  	int err;
> @@ -1035,7 +1045,7 @@ struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
>  	if (!lrc)
>  		return ERR_PTR(-ENOMEM);
>  
> -	err = xe_lrc_init(lrc, hwe, vm, ring_size);
> +	err = xe_lrc_init(lrc, hwe, vm, ring_size, flags);
>  	if (err) {
>  		kfree(lrc);
>  		return ERR_PTR(err);
> diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
> index c24542e89318..d2429a26fb22 100644
> --- a/drivers/gpu/drm/xe/xe_lrc.h
> +++ b/drivers/gpu/drm/xe/xe_lrc.h
> @@ -22,8 +22,10 @@ struct xe_vm;
>  
>  #define LRC_PPHWSP_SCRATCH_ADDR (0x34 * 4)
>  
> +#define LRC_CREATE_RUNALONE     BIT(0)
> +
>  struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
> -			     u32 ring_size);
> +			     u32 ring_size, u32 flags);
>  void xe_lrc_destroy(struct kref *ref);
>  
>  /**
> diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
> index a68734ff12f4..61c4c061bd75 100644
> --- a/include/uapi/drm/xe_drm.h
> +++ b/include/uapi/drm/xe_drm.h
> @@ -1110,7 +1110,8 @@ struct drm_xe_exec_queue_create {
>  #define DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY		0
>  #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY		0
>  #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE		1
> -
> +#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_EUDEBUG		2
> +#define     DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE		(1 << 0)
>  	/** @extensions: Pointer to the first extension struct, if any */
>  	__u64 extensions;
>  
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access
  2024-07-26 18:50     ` Matthew Brost
@ 2024-07-27  1:45       ` Matthew Brost
  2024-07-31 11:11         ` [PATCH] fixup! " Andrzej Hajda
  0 siblings, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  1:45 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Andrzej Hajda, Maciej Patelczyk

On Fri, Jul 26, 2024 at 06:50:24PM +0000, Matthew Brost wrote:
> On Fri, Jul 26, 2024 at 06:46:29PM +0000, Matthew Brost wrote:
> > On Fri, Jul 26, 2024 at 05:08:12PM +0300, Mika Kuoppala wrote:
> > > From: Andrzej Hajda <andrzej.hajda@intel.com>
> > > 
> > > Debugger needs to read/write program's vmas including userptr_vma.
> > > Since hmm_range_fault is used to pin userptr vmas, it is possible
> > > to map those vmas from debugger context.
> > > 
> > > v2: kmap to kmap_local (Maciej)
> > > 
> > > Signed-off-by: Andrzej Hajda <andrzej.hajda@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 | 56 ++++++++++++++++++++++++++++++++-
> > >  1 file changed, 55 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> > > index aa383accc468..947331c19f43 100644
> > > --- a/drivers/gpu/drm/xe/xe_eudebug.c
> > > +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> > > @@ -33,6 +33,7 @@
> > >  #include "xe_mmio.h"
> > >  #include "xe_module.h"
> > >  #include "xe_pm.h"
> > > +#include "xe_res_cursor.h"
> > >  #include "xe_rtp.h"
> > >  #include "xe_sched_job.h"
> > >  #include "xe_vm.h"
> > > @@ -2852,6 +2853,58 @@ static void discovery_work_fn(struct work_struct *work)
> > >  	xe_eudebug_put(d);
> > >  }
> > >  
> > > +static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> > > +				  void *buf, u64 len, bool write)
> > > +{
> > > +	struct xe_vm *vm = xe_vma_vm(&uvma->vma);
> > > +	struct xe_userptr *up = &uvma->userptr;
> > > +	struct xe_res_cursor cur = {};
> > > +	int cur_len, ret = 0;
> > > +
> > > +	/* lock notifier in non-invalidation state */
> > > +	for (unsigned long nseq = uvma->userptr.notifier_seq; true;
> > > +	     nseq = mmu_interval_read_begin(&uvma->userptr.notifier)) {
> > > +		down_read(&vm->userptr.notifier_lock);
> > > +		if (!mmu_interval_read_retry(&uvma->userptr.notifier, nseq))
> > > +			break;
> > > +		up_read(&vm->userptr.notifier_lock);
> > > +	}
> > > +
> > 
> > I don't think this will work without lockdep blowing up.
> > '&vm->userptr.notifier_lock' is taken in the MMU notifier, the MMU
> > notifier is in the path of reclaim, thus you cannot allocate memory
> > under this lock, xe_vma_userptr_pin_pages allocates memory.
> > 
> > I think you are going to need to pin the pages first, then take the
> > notifier_lock, recheck the seqno, retry on a miscomapre, once the
> 
> Let me make 'n a miscompare' a bit more clear.
> 
> Drop the notifier lock and repin the pages again.
> 
> This how the VM bind flow works to avoid memory allocations under the
> notifier lock.
> 
> Matt

Sorry triple reply... but here are two patches [1] [2] so lockdep will
complain about the why you have this immediately.

Matt

[1] https://patchwork.freedesktop.org/patch/606081/?series=136581&rev=1
[2] https://patchwork.freedesktop.org/series/136579/

> 
> > compare passes it should be safe to write the userptr.
> > 
> > Matt
> > 
> > > +	/* re-pin if necessary */
> > > +	if (xe_vma_userptr_check_repin(uvma)) {
> > > +		spin_lock(&vm->userptr.invalidated_lock);
> > > +		list_del_init(&uvma->userptr.invalidate_link);
> > > +		spin_unlock(&vm->userptr.invalidated_lock);
> > > +
> > > +		ret = xe_vma_userptr_pin_pages(uvma);
> > > +		if (ret)
> > > +			goto out_unlock_notifier;
> > > +	}
> > > +
> > > +	if (!up->sg) {
> > > +		ret = -EINVAL;
> > > +		goto out_unlock_notifier;
> > > +	}
> > > +
> > > +	for (xe_res_first_sg(up->sg, offset, len, &cur); cur.remaining;
> > > +	     xe_res_next(&cur, cur_len)) {
> > > +		void *ptr = kmap_local_page(sg_page(cur.sgl)) + cur.start;
> > > +
> > > +		cur_len = min(cur.size, cur.remaining);
> > > +		if (write)
> > > +			memcpy(ptr, buf, cur_len);
> > > +		else
> > > +			memcpy(buf, ptr, cur_len);
> > > +		kunmap_local(ptr);
> > > +		buf += cur_len;
> > > +	}
> > > +	ret = len;
> > > +
> > > +out_unlock_notifier:
> > > +	up_read(&vm->userptr.notifier_lock);
> > > +	return ret;
> > > +}
> > > +
> > >  static int xe_eudebug_bovma_access(struct xe_bo *bo, u64 offset,
> > >  				   void *buf, u64 len, bool write)
> > >  {
> > > @@ -2895,7 +2948,8 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
> > >  	if (bo)
> > >  		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
> > >  
> > > -	return -EOPNOTSUPP;
> > > +	return xe_eudebug_uvma_access(to_userptr_vma(vma), offset,
> > > +				      buf, bytes, write);
> > >  }
> > >  
> > >  static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
> > > -- 
> > > 2.34.1
> > > 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* ✓ CI.FULL: success for GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (27 preceding siblings ...)
  2024-07-26 15:10 ` ✓ CI.BAT: " Patchwork
@ 2024-07-27  2:37 ` Patchwork
  2024-07-27  5:23 ` [PATCH 00/21] " Matthew Brost
  29 siblings, 0 replies; 78+ messages in thread
From: Patchwork @ 2024-07-27  2:37 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

[-- Attachment #1: Type: text/plain, Size: 43592 bytes --]

== Series Details ==

Series: GPU debug support (eudebug)
URL   : https://patchwork.freedesktop.org/series/136572/
State : success

== Summary ==

CI Bug Log - changes from xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232_full -> xe-pw-136572v1_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  

Participating hosts (3 -> 3)
------------------------------

  No changes in participating hosts

New tests
---------

  New tests have been introduced between xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232_full and xe-pw-136572v1_full:

### New IGT tests (1) ###

  * igt@xe_mmap@small-bar:
    - Statuses : 3 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in xe-pw-136572v1_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@kms_async_flips@async-flip-with-page-flip-events@pipe-b-hdmi-a-1-y:
    - shard-adlp:         [PASS][1] -> [DMESG-WARN][2] ([Intel XE#1033]) +1 other test dmesg-warn
   [1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-1/igt@kms_async_flips@async-flip-with-page-flip-events@pipe-b-hdmi-a-1-y.html
   [2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-2/igt@kms_async_flips@async-flip-with-page-flip-events@pipe-b-hdmi-a-1-y.html

  * igt@kms_atomic_transition@plane-all-modeset-transition-internal-panels@pipe-a-edp-1:
    - shard-lnl:          [PASS][3] -> [FAIL][4] ([Intel XE#1426]) +1 other test fail
   [3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-6/igt@kms_atomic_transition@plane-all-modeset-transition-internal-panels@pipe-a-edp-1.html
   [4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-8/igt@kms_atomic_transition@plane-all-modeset-transition-internal-panels@pipe-a-edp-1.html

  * igt@kms_big_fb@4-tiled-8bpp-rotate-90:
    - shard-lnl:          NOTRUN -> [SKIP][5] ([Intel XE#1407])
   [5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_big_fb@4-tiled-8bpp-rotate-90.html

  * igt@kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0-hflip:
    - shard-lnl:          [PASS][6] -> [FAIL][7] ([Intel XE#1659])
   [6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-3/igt@kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0-hflip.html
   [7]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-5/igt@kms_big_fb@4-tiled-max-hw-stride-64bpp-rotate-0-hflip.html

  * igt@kms_big_fb@yf-tiled-32bpp-rotate-180:
    - shard-lnl:          NOTRUN -> [SKIP][8] ([Intel XE#1124]) +2 other tests skip
   [8]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-8/igt@kms_big_fb@yf-tiled-32bpp-rotate-180.html

  * igt@kms_bw@linear-tiling-2-displays-2560x1440p:
    - shard-lnl:          NOTRUN -> [SKIP][9] ([Intel XE#367])
   [9]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_bw@linear-tiling-2-displays-2560x1440p.html

  * igt@kms_ccs@ccs-on-another-bo-y-tiled-gen12-mc-ccs:
    - shard-lnl:          NOTRUN -> [SKIP][10] ([Intel XE#1399]) +4 other tests skip
   [10]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_ccs@ccs-on-another-bo-y-tiled-gen12-mc-ccs.html

  * igt@kms_chamelium_hpd@dp-hpd-for-each-pipe:
    - shard-lnl:          NOTRUN -> [SKIP][11] ([Intel XE#373])
   [11]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_chamelium_hpd@dp-hpd-for-each-pipe.html

  * igt@kms_content_protection@dp-mst-lic-type-0:
    - shard-lnl:          NOTRUN -> [SKIP][12] ([Intel XE#307])
   [12]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_content_protection@dp-mst-lic-type-0.html

  * igt@kms_cursor_crc@cursor-sliding-64x21:
    - shard-lnl:          NOTRUN -> [SKIP][13] ([Intel XE#1424]) +2 other tests skip
   [13]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-8/igt@kms_cursor_crc@cursor-sliding-64x21.html

  * igt@kms_cursor_legacy@2x-flip-vs-cursor-legacy:
    - shard-lnl:          NOTRUN -> [SKIP][14] ([Intel XE#309]) +3 other tests skip
   [14]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-8/igt@kms_cursor_legacy@2x-flip-vs-cursor-legacy.html

  * igt@kms_dirtyfb@drrs-dirtyfb-ioctl:
    - shard-lnl:          NOTRUN -> [SKIP][15] ([Intel XE#599])
   [15]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_dirtyfb@drrs-dirtyfb-ioctl.html

  * igt@kms_flip@2x-flip-vs-suspend:
    - shard-lnl:          NOTRUN -> [SKIP][16] ([Intel XE#1421]) +1 other test skip
   [16]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_flip@2x-flip-vs-suspend.html

  * igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible@b-edp1:
    - shard-lnl:          [PASS][17] -> [FAIL][18] ([Intel XE#886])
   [17]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-3/igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible@b-edp1.html
   [18]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-5/igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible@b-edp1.html

  * igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling:
    - shard-lnl:          NOTRUN -> [SKIP][19] ([Intel XE#1401] / [Intel XE#1745])
   [19]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling.html

  * igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling@pipe-a-default-mode:
    - shard-lnl:          NOTRUN -> [SKIP][20] ([Intel XE#1401])
   [20]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-32bpp-4tiledg2rcccs-upscaling@pipe-a-default-mode.html

  * igt@kms_frontbuffer_tracking@fbcdrrs-1p-rte:
    - shard-lnl:          NOTRUN -> [SKIP][21] ([Intel XE#651]) +2 other tests skip
   [21]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_frontbuffer_tracking@fbcdrrs-1p-rte.html

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-render:
    - shard-lnl:          NOTRUN -> [SKIP][22] ([Intel XE#656]) +6 other tests skip
   [22]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-cur-indfb-draw-render.html

  * igt@kms_invalid_mode@clock-too-high@pipe-a-edp-1:
    - shard-lnl:          NOTRUN -> [SKIP][23] ([Intel XE#1450]) +1 other test skip
   [23]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_invalid_mode@clock-too-high@pipe-a-edp-1.html

  * igt@kms_invalid_mode@clock-too-high@pipe-c-edp-1:
    - shard-lnl:          NOTRUN -> [SKIP][24] ([Intel XE#1450] / [Intel XE#599]) +1 other test skip
   [24]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_invalid_mode@clock-too-high@pipe-c-edp-1.html

  * igt@kms_plane@plane-position-hole:
    - shard-lnl:          [PASS][25] -> [DMESG-FAIL][26] ([Intel XE#324])
   [25]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-7/igt@kms_plane@plane-position-hole.html
   [26]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-5/igt@kms_plane@plane-position-hole.html

  * igt@kms_plane@plane-position-hole-dpms:
    - shard-lnl:          [PASS][27] -> [DMESG-WARN][28] ([Intel XE#324])
   [27]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-7/igt@kms_plane@plane-position-hole-dpms.html
   [28]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-3/igt@kms_plane@plane-position-hole-dpms.html

  * igt@kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-5@pipe-b-edp-1:
    - shard-lnl:          NOTRUN -> [SKIP][29] ([Intel XE#2318]) +3 other tests skip
   [29]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-5@pipe-b-edp-1.html

  * igt@kms_psr2_su@frontbuffer-xrgb8888:
    - shard-lnl:          NOTRUN -> [SKIP][30] ([Intel XE#1128])
   [30]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_psr2_su@frontbuffer-xrgb8888.html

  * igt@kms_rmfb@close-fd@pipe-a-edp-1:
    - shard-lnl:          NOTRUN -> [FAIL][31] ([Intel XE#294]) +1 other test fail
   [31]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_rmfb@close-fd@pipe-a-edp-1.html

  * igt@kms_rotation_crc@sprite-rotation-90-pos-100-0:
    - shard-lnl:          NOTRUN -> [SKIP][32] ([Intel XE#1437])
   [32]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@kms_rotation_crc@sprite-rotation-90-pos-100-0.html

  * igt@kms_universal_plane@cursor-fb-leak:
    - shard-adlp:         [PASS][33] -> [FAIL][34] ([Intel XE#771] / [Intel XE#899])
   [33]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-1/igt@kms_universal_plane@cursor-fb-leak.html
   [34]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-2/igt@kms_universal_plane@cursor-fb-leak.html

  * igt@kms_universal_plane@cursor-fb-leak@pipe-c-hdmi-a-1:
    - shard-adlp:         [PASS][35] -> [FAIL][36] ([Intel XE#899]) +1 other test fail
   [35]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-1/igt@kms_universal_plane@cursor-fb-leak@pipe-c-hdmi-a-1.html
   [36]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-2/igt@kms_universal_plane@cursor-fb-leak@pipe-c-hdmi-a-1.html

  * igt@xe_create@create-big-vram:
    - shard-lnl:          NOTRUN -> [SKIP][37] ([Intel XE#1062])
   [37]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@xe_create@create-big-vram.html

  * igt@xe_evict@evict-beng-mixed-threads-large:
    - shard-dg2-set2:     [PASS][38] -> [TIMEOUT][39] ([Intel XE#1473] / [Intel XE#392]) +1 other test timeout
   [38]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@xe_evict@evict-beng-mixed-threads-large.html
   [39]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@xe_evict@evict-beng-mixed-threads-large.html

  * igt@xe_evict@evict-cm-threads-small:
    - shard-lnl:          NOTRUN -> [SKIP][40] ([Intel XE#688]) +3 other tests skip
   [40]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@xe_evict@evict-cm-threads-small.html

  * igt@xe_exec_basic@multigpu-no-exec-basic:
    - shard-lnl:          NOTRUN -> [SKIP][41] ([Intel XE#1392])
   [41]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@xe_exec_basic@multigpu-no-exec-basic.html

  * igt@xe_module_load@many-reload:
    - shard-adlp:         [PASS][42] -> [TIMEOUT][43] ([Intel XE#1353] / [Intel XE#1961] / [Intel XE#2026])
   [42]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-8/igt@xe_module_load@many-reload.html
   [43]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-8/igt@xe_module_load@many-reload.html

  * igt@xe_pat@pat-index-xelpg:
    - shard-lnl:          NOTRUN -> [SKIP][44] ([Intel XE#979])
   [44]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@xe_pat@pat-index-xelpg.html

  * igt@xe_pm@s4-d3hot-basic-exec:
    - shard-lnl:          [PASS][45] -> [ABORT][46] ([Intel XE#1358] / [Intel XE#1607])
   [45]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-8/igt@xe_pm@s4-d3hot-basic-exec.html
   [46]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-2/igt@xe_pm@s4-d3hot-basic-exec.html

  * igt@xe_query@multigpu-query-topology:
    - shard-lnl:          NOTRUN -> [SKIP][47] ([Intel XE#944])
   [47]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@xe_query@multigpu-query-topology.html

  
#### Possible fixes ####

  * igt@kms_async_flips@async-flip-with-page-flip-events@pipe-c-hdmi-a-1-y:
    - shard-adlp:         [DMESG-WARN][48] ([Intel XE#1033]) -> [PASS][49]
   [48]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-1/igt@kms_async_flips@async-flip-with-page-flip-events@pipe-c-hdmi-a-1-y.html
   [49]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-2/igt@kms_async_flips@async-flip-with-page-flip-events@pipe-c-hdmi-a-1-y.html

  * igt@kms_atomic_transition@plane-all-modeset-transition@pipe-a-hdmi-a-1:
    - shard-adlp:         [FAIL][50] ([Intel XE#1426]) -> [PASS][51] +1 other test pass
   [50]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-2/igt@kms_atomic_transition@plane-all-modeset-transition@pipe-a-hdmi-a-1.html
   [51]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-6/igt@kms_atomic_transition@plane-all-modeset-transition@pipe-a-hdmi-a-1.html

  * igt@kms_atomic_transition@plane-toggle-modeset-transition:
    - shard-dg2-set2:     [FAIL][52] ([Intel XE#1426]) -> [PASS][53]
   [52]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-435/igt@kms_atomic_transition@plane-toggle-modeset-transition.html
   [53]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-433/igt@kms_atomic_transition@plane-toggle-modeset-transition.html

  * igt@kms_atomic_transition@plane-toggle-modeset-transition@pipe-a-hdmi-a-6:
    - shard-dg2-set2:     [FAIL][54] -> [PASS][55]
   [54]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-435/igt@kms_atomic_transition@plane-toggle-modeset-transition@pipe-a-hdmi-a-6.html
   [55]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-433/igt@kms_atomic_transition@plane-toggle-modeset-transition@pipe-a-hdmi-a-6.html

  * igt@kms_big_fb@linear-64bpp-rotate-0:
    - shard-dg2-set2:     [DMESG-WARN][56] -> [PASS][57]
   [56]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-436/igt@kms_big_fb@linear-64bpp-rotate-0.html
   [57]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-434/igt@kms_big_fb@linear-64bpp-rotate-0.html

  * igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible@c-edp1:
    - shard-lnl:          [FAIL][58] ([Intel XE#886]) -> [PASS][59]
   [58]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-3/igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible@c-edp1.html
   [59]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-5/igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible@c-edp1.html

  * {igt@kms_plane@plane-position-covered@pipe-a-plane-1}:
    - shard-lnl:          [DMESG-FAIL][60] ([Intel XE#324]) -> [PASS][61] +1 other test pass
   [60]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-2/igt@kms_plane@plane-position-covered@pipe-a-plane-1.html
   [61]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-2/igt@kms_plane@plane-position-covered@pipe-a-plane-1.html

  * {igt@kms_plane@plane-position-covered@pipe-b-plane-4}:
    - shard-lnl:          [DMESG-WARN][62] ([Intel XE#324]) -> [PASS][63] +2 other tests pass
   [62]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-2/igt@kms_plane@plane-position-covered@pipe-b-plane-4.html
   [63]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-2/igt@kms_plane@plane-position-covered@pipe-b-plane-4.html

  * igt@kms_plane_scaling@intel-max-src-size@pipe-a-hdmi-a-6:
    - shard-dg2-set2:     [FAIL][64] ([Intel XE#361]) -> [PASS][65]
   [64]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-463/igt@kms_plane_scaling@intel-max-src-size@pipe-a-hdmi-a-6.html
   [65]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-434/igt@kms_plane_scaling@intel-max-src-size@pipe-a-hdmi-a-6.html

  * igt@kms_pm_dc@dc6-dpms:
    - shard-lnl:          [FAIL][66] ([Intel XE#1430]) -> [PASS][67]
   [66]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-5/igt@kms_pm_dc@dc6-dpms.html
   [67]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-3/igt@kms_pm_dc@dc6-dpms.html

  * igt@kms_universal_plane@cursor-fb-leak:
    - shard-dg2-set2:     [FAIL][68] ([Intel XE#771] / [Intel XE#899]) -> [PASS][69]
   [68]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_universal_plane@cursor-fb-leak.html
   [69]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_universal_plane@cursor-fb-leak.html

  * igt@kms_universal_plane@cursor-fb-leak@pipe-c-hdmi-a-6:
    - shard-dg2-set2:     [FAIL][70] ([Intel XE#899]) -> [PASS][71]
   [70]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_universal_plane@cursor-fb-leak@pipe-c-hdmi-a-6.html
   [71]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_universal_plane@cursor-fb-leak@pipe-c-hdmi-a-6.html

  * igt@xe_evict@evict-beng-threads-large:
    - shard-dg2-set2:     [TIMEOUT][72] ([Intel XE#1473]) -> [PASS][73]
   [72]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-466/igt@xe_evict@evict-beng-threads-large.html
   [73]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-436/igt@xe_evict@evict-beng-threads-large.html

  * igt@xe_gt_freq@freq_fixed_exec:
    - shard-dg2-set2:     [FAIL][74] ([Intel XE#2262]) -> [PASS][75]
   [74]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-435/igt@xe_gt_freq@freq_fixed_exec.html
   [75]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-433/igt@xe_gt_freq@freq_fixed_exec.html
    - shard-lnl:          [FAIL][76] ([Intel XE#2262]) -> [PASS][77]
   [76]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-4/igt@xe_gt_freq@freq_fixed_exec.html
   [77]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-8/igt@xe_gt_freq@freq_fixed_exec.html

  * igt@xe_pm@s4-multiple-execs:
    - shard-lnl:          [ABORT][78] ([Intel XE#1358] / [Intel XE#1794]) -> [PASS][79]
   [78]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-2/igt@xe_pm@s4-multiple-execs.html
   [79]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-1/igt@xe_pm@s4-multiple-execs.html

  * igt@xe_vm@mixed-userptr-binds-3145728:
    - shard-lnl:          [INCOMPLETE][80] -> [PASS][81]
   [80]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-lnl-6/igt@xe_vm@mixed-userptr-binds-3145728.html
   [81]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-lnl-8/igt@xe_vm@mixed-userptr-binds-3145728.html

  
#### Warnings ####

  * igt@kms_async_flips@invalid-async-flip:
    - shard-dg2-set2:     [SKIP][82] ([Intel XE#1201] / [Intel XE#873]) -> [SKIP][83] ([Intel XE#873])
   [82]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_async_flips@invalid-async-flip.html
   [83]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_async_flips@invalid-async-flip.html

  * igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip:
    - shard-adlp:         [FAIL][84] ([Intel XE#1231]) -> [FAIL][85] ([Intel XE#1242])
   [84]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-9/igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip.html
   [85]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-9/igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip.html

  * igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip:
    - shard-adlp:         [FAIL][86] ([Intel XE#1231]) -> [DMESG-FAIL][87] ([Intel XE#324])
   [86]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-adlp-6/igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html
   [87]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-adlp-1/igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html

  * igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip:
    - shard-dg2-set2:     [SKIP][88] ([Intel XE#1124] / [Intel XE#1201]) -> [SKIP][89] ([Intel XE#1124]) +4 other tests skip
   [88]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip.html
   [89]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-0-hflip-async-flip.html

  * igt@kms_big_fb@yf-tiled-addfb:
    - shard-dg2-set2:     [SKIP][90] ([Intel XE#1201] / [Intel XE#619]) -> [SKIP][91] ([Intel XE#619])
   [90]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@kms_big_fb@yf-tiled-addfb.html
   [91]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_big_fb@yf-tiled-addfb.html

  * igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-0:
    - shard-dg2-set2:     [SKIP][92] ([Intel XE#1124]) -> [SKIP][93] ([Intel XE#1124] / [Intel XE#1201])
   [92]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-0.html
   [93]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-0.html

  * igt@kms_bw@linear-tiling-1-displays-1920x1080p:
    - shard-dg2-set2:     [SKIP][94] ([Intel XE#1201] / [Intel XE#367]) -> [SKIP][95] ([Intel XE#367]) +1 other test skip
   [94]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@kms_bw@linear-tiling-1-displays-1920x1080p.html
   [95]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_bw@linear-tiling-1-displays-1920x1080p.html

  * igt@kms_ccs@bad-aux-stride-4-tiled-mtl-mc-ccs@pipe-a-hdmi-a-6:
    - shard-dg2-set2:     [SKIP][96] ([Intel XE#1201] / [Intel XE#787]) -> [SKIP][97] ([Intel XE#787]) +41 other tests skip
   [96]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_ccs@bad-aux-stride-4-tiled-mtl-mc-ccs@pipe-a-hdmi-a-6.html
   [97]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_ccs@bad-aux-stride-4-tiled-mtl-mc-ccs@pipe-a-hdmi-a-6.html

  * igt@kms_ccs@bad-pixel-format-y-tiled-gen12-rc-ccs@pipe-d-dp-4:
    - shard-dg2-set2:     [SKIP][98] ([Intel XE#455] / [Intel XE#787]) -> [SKIP][99] ([Intel XE#1201] / [Intel XE#455] / [Intel XE#787]) +3 other tests skip
   [98]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_ccs@bad-pixel-format-y-tiled-gen12-rc-ccs@pipe-d-dp-4.html
   [99]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_ccs@bad-pixel-format-y-tiled-gen12-rc-ccs@pipe-d-dp-4.html

  * igt@kms_ccs@crc-primary-basic-4-tiled-mtl-mc-ccs@pipe-b-dp-4:
    - shard-dg2-set2:     [SKIP][100] ([Intel XE#787]) -> [SKIP][101] ([Intel XE#1201] / [Intel XE#787]) +13 other tests skip
   [100]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_ccs@crc-primary-basic-4-tiled-mtl-mc-ccs@pipe-b-dp-4.html
   [101]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_ccs@crc-primary-basic-4-tiled-mtl-mc-ccs@pipe-b-dp-4.html

  * igt@kms_ccs@random-ccs-data-4-tiled-mtl-rc-ccs-cc:
    - shard-dg2-set2:     [SKIP][102] ([Intel XE#1201] / [Intel XE#455] / [Intel XE#787]) -> [SKIP][103] ([Intel XE#455] / [Intel XE#787]) +11 other tests skip
   [102]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_ccs@random-ccs-data-4-tiled-mtl-rc-ccs-cc.html
   [103]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_ccs@random-ccs-data-4-tiled-mtl-rc-ccs-cc.html

  * igt@kms_cdclk@plane-scaling@pipe-b-dp-4:
    - shard-dg2-set2:     [SKIP][104] ([Intel XE#1152] / [Intel XE#1201]) -> [SKIP][105] ([Intel XE#1152]) +3 other tests skip
   [104]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@kms_cdclk@plane-scaling@pipe-b-dp-4.html
   [105]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_cdclk@plane-scaling@pipe-b-dp-4.html

  * igt@kms_chamelium_frames@dp-frame-dump:
    - shard-dg2-set2:     [SKIP][106] ([Intel XE#373]) -> [SKIP][107] ([Intel XE#1201] / [Intel XE#373])
   [106]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_chamelium_frames@dp-frame-dump.html
   [107]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_chamelium_frames@dp-frame-dump.html

  * igt@kms_chamelium_frames@vga-frame-dump:
    - shard-dg2-set2:     [SKIP][108] ([Intel XE#1201] / [Intel XE#373]) -> [SKIP][109] ([Intel XE#373]) +3 other tests skip
   [108]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_chamelium_frames@vga-frame-dump.html
   [109]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_chamelium_frames@vga-frame-dump.html

  * igt@kms_cursor_crc@cursor-offscreen-512x170:
    - shard-dg2-set2:     [SKIP][110] ([Intel XE#308]) -> [SKIP][111] ([Intel XE#1201] / [Intel XE#308])
   [110]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_cursor_crc@cursor-offscreen-512x170.html
   [111]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_cursor_crc@cursor-offscreen-512x170.html

  * igt@kms_display_modes@mst-extended-mode-negative:
    - shard-dg2-set2:     [SKIP][112] ([Intel XE#1201] / [Intel XE#307]) -> [SKIP][113] ([Intel XE#307]) +1 other test skip
   [112]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_display_modes@mst-extended-mode-negative.html
   [113]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_display_modes@mst-extended-mode-negative.html

  * igt@kms_feature_discovery@psr2:
    - shard-dg2-set2:     [SKIP][114] ([Intel XE#1135] / [Intel XE#1201]) -> [SKIP][115] ([Intel XE#1135])
   [114]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@kms_feature_discovery@psr2.html
   [115]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_feature_discovery@psr2.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling:
    - shard-dg2-set2:     [SKIP][116] ([Intel XE#1201] / [Intel XE#455]) -> [SKIP][117] ([Intel XE#455]) +7 other tests skip
   [116]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling.html
   [117]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling.html

  * igt@kms_frontbuffer_tracking@drrs-2p-scndscrn-indfb-msflip-blt:
    - shard-dg2-set2:     [SKIP][118] ([Intel XE#1201] / [Intel XE#651]) -> [SKIP][119] ([Intel XE#651]) +15 other tests skip
   [118]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_frontbuffer_tracking@drrs-2p-scndscrn-indfb-msflip-blt.html
   [119]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_frontbuffer_tracking@drrs-2p-scndscrn-indfb-msflip-blt.html

  * igt@kms_frontbuffer_tracking@fbcdrrs-shrfb-scaledprimary:
    - shard-dg2-set2:     [SKIP][120] ([Intel XE#651]) -> [SKIP][121] ([Intel XE#1201] / [Intel XE#651]) +4 other tests skip
   [120]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_frontbuffer_tracking@fbcdrrs-shrfb-scaledprimary.html
   [121]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_frontbuffer_tracking@fbcdrrs-shrfb-scaledprimary.html

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-mmap-wc:
    - shard-dg2-set2:     [SKIP][122] ([Intel XE#1201] / [Intel XE#653]) -> [SKIP][123] ([Intel XE#653]) +13 other tests skip
   [122]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-mmap-wc.html
   [123]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-cur-indfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-fullscreen:
    - shard-dg2-set2:     [SKIP][124] ([Intel XE#653]) -> [SKIP][125] ([Intel XE#1201] / [Intel XE#653])
   [124]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-fullscreen.html
   [125]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-fullscreen.html

  * igt@kms_getfb@getfb-reject-ccs:
    - shard-dg2-set2:     [SKIP][126] ([Intel XE#1201] / [Intel XE#605]) -> [SKIP][127] ([Intel XE#605])
   [126]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@kms_getfb@getfb-reject-ccs.html
   [127]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_getfb@getfb-reject-ccs.html

  * igt@kms_plane_scaling@planes-downscale-factor-0-25:
    - shard-dg2-set2:     [SKIP][128] ([Intel XE#1201] / [Intel XE#2318] / [Intel XE#455]) -> [SKIP][129] ([Intel XE#2318] / [Intel XE#455])
   [128]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_plane_scaling@planes-downscale-factor-0-25.html
   [129]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_plane_scaling@planes-downscale-factor-0-25.html

  * igt@kms_plane_scaling@planes-downscale-factor-0-25@pipe-b-hdmi-a-6:
    - shard-dg2-set2:     [SKIP][130] ([Intel XE#1201] / [Intel XE#2318]) -> [SKIP][131] ([Intel XE#2318]) +2 other tests skip
   [130]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_plane_scaling@planes-downscale-factor-0-25@pipe-b-hdmi-a-6.html
   [131]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_plane_scaling@planes-downscale-factor-0-25@pipe-b-hdmi-a-6.html

  * igt@kms_pm_dc@dc5-psr:
    - shard-dg2-set2:     [SKIP][132] ([Intel XE#1129] / [Intel XE#1201]) -> [SKIP][133] ([Intel XE#1129])
   [132]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_pm_dc@dc5-psr.html
   [133]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_pm_dc@dc5-psr.html

  * igt@kms_psr2_sf@overlay-plane-move-continuous-sf:
    - shard-dg2-set2:     [SKIP][134] ([Intel XE#1489]) -> [SKIP][135] ([Intel XE#1201] / [Intel XE#1489])
   [134]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_psr2_sf@overlay-plane-move-continuous-sf.html
   [135]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_psr2_sf@overlay-plane-move-continuous-sf.html

  * igt@kms_psr2_sf@primary-plane-update-sf-dmg-area-big-fb:
    - shard-dg2-set2:     [SKIP][136] ([Intel XE#1201] / [Intel XE#1489]) -> [SKIP][137] ([Intel XE#1489]) +2 other tests skip
   [136]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_psr2_sf@primary-plane-update-sf-dmg-area-big-fb.html
   [137]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_psr2_sf@primary-plane-update-sf-dmg-area-big-fb.html

  * igt@kms_psr@pr-sprite-blt:
    - shard-dg2-set2:     [SKIP][138] ([Intel XE#929]) -> [SKIP][139] ([Intel XE#1201] / [Intel XE#929]) +1 other test skip
   [138]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@kms_psr@pr-sprite-blt.html
   [139]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@kms_psr@pr-sprite-blt.html

  * igt@kms_psr@psr2-primary-render:
    - shard-dg2-set2:     [SKIP][140] ([Intel XE#1201] / [Intel XE#929]) -> [SKIP][141] ([Intel XE#929]) +5 other tests skip
   [140]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_psr@psr2-primary-render.html
   [141]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_psr@psr2-primary-render.html

  * igt@kms_rotation_crc@bad-pixel-format:
    - shard-dg2-set2:     [SKIP][142] ([Intel XE#1201] / [Intel XE#327]) -> [SKIP][143] ([Intel XE#327]) +1 other test skip
   [142]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@kms_rotation_crc@bad-pixel-format.html
   [143]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_rotation_crc@bad-pixel-format.html

  * igt@kms_writeback@writeback-check-output:
    - shard-dg2-set2:     [SKIP][144] ([Intel XE#1201] / [Intel XE#756]) -> [SKIP][145] ([Intel XE#756])
   [144]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@kms_writeback@writeback-check-output.html
   [145]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@kms_writeback@writeback-check-output.html

  * igt@xe_compute_preempt@compute-preempt:
    - shard-dg2-set2:     [SKIP][146] ([Intel XE#1201] / [Intel XE#1280] / [Intel XE#455]) -> [SKIP][147] ([Intel XE#1280] / [Intel XE#455]) +1 other test skip
   [146]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@xe_compute_preempt@compute-preempt.html
   [147]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@xe_compute_preempt@compute-preempt.html

  * igt@xe_copy_basic@mem-copy-linear-0xfffe:
    - shard-dg2-set2:     [SKIP][148] ([Intel XE#1123]) -> [SKIP][149] ([Intel XE#1123] / [Intel XE#1201])
   [148]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@xe_copy_basic@mem-copy-linear-0xfffe.html
   [149]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@xe_copy_basic@mem-copy-linear-0xfffe.html

  * igt@xe_exec_fault_mode@many-bindexecqueue-prefetch:
    - shard-dg2-set2:     [SKIP][150] ([Intel XE#288]) -> [SKIP][151] ([Intel XE#1201] / [Intel XE#288]) +3 other tests skip
   [150]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-432/igt@xe_exec_fault_mode@many-bindexecqueue-prefetch.html
   [151]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-466/igt@xe_exec_fault_mode@many-bindexecqueue-prefetch.html

  * igt@xe_exec_fault_mode@many-bindexecqueue-userptr-invalidate:
    - shard-dg2-set2:     [SKIP][152] ([Intel XE#1201] / [Intel XE#288]) -> [SKIP][153] ([Intel XE#288]) +12 other tests skip
   [152]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@xe_exec_fault_mode@many-bindexecqueue-userptr-invalidate.html
   [153]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@xe_exec_fault_mode@many-bindexecqueue-userptr-invalidate.html

  * igt@xe_module_load@load:
    - shard-dg2-set2:     [SKIP][154] ([Intel XE#1201] / [Intel XE#378]) -> [SKIP][155] ([Intel XE#378])
   [154]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@xe_module_load@load.html
   [155]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@xe_module_load@load.html

  * igt@xe_pm@vram-d3cold-threshold:
    - shard-dg2-set2:     [SKIP][156] ([Intel XE#1201] / [Intel XE#579]) -> [SKIP][157] ([Intel XE#579])
   [156]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-433/igt@xe_pm@vram-d3cold-threshold.html
   [157]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@xe_pm@vram-d3cold-threshold.html

  * igt@xe_query@multigpu-query-cs-cycles:
    - shard-dg2-set2:     [SKIP][158] ([Intel XE#1201] / [Intel XE#944]) -> [SKIP][159] ([Intel XE#944]) +1 other test skip
   [158]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232/shard-dg2-434/igt@xe_query@multigpu-query-cs-cycles.html
   [159]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/shard-dg2-432/igt@xe_query@multigpu-query-cs-cycles.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [Intel XE#1033]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1033
  [Intel XE#1062]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1062
  [Intel XE#1123]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1123
  [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#1129]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1129
  [Intel XE#1135]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1135
  [Intel XE#1152]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1152
  [Intel XE#1201]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1201
  [Intel XE#1231]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1231
  [Intel XE#1242]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1242
  [Intel XE#1280]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1280
  [Intel XE#1353]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1353
  [Intel XE#1358]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1358
  [Intel XE#1392]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1392
  [Intel XE#1399]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1399
  [Intel XE#1401]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1401
  [Intel XE#1407]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1407
  [Intel XE#1421]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1421
  [Intel XE#1424]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1424
  [Intel XE#1426]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1426
  [Intel XE#1430]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1430
  [Intel XE#1437]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1437
  [Intel XE#1450]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1450
  [Intel XE#1473]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1473
  [Intel XE#1489]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1489
  [Intel XE#1512]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1512
  [Intel XE#1607]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1607
  [Intel XE#1659]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1659
  [Intel XE#1745]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1745
  [Intel XE#1794]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1794
  [Intel XE#1961]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1961
  [Intel XE#2026]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2026
  [Intel XE#2207]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2207
  [Intel XE#2262]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2262
  [Intel XE#2318]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2318
  [Intel XE#2343]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2343
  [Intel XE#288]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/288
  [Intel XE#294]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/294
  [Intel XE#307]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/307
  [Intel XE#308]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/308
  [Intel XE#309]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/309
  [Intel XE#324]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/324
  [Intel XE#327]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/327
  [Intel XE#361]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/361
  [Intel XE#367]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/367
  [Intel XE#373]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/373
  [Intel XE#378]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/378
  [Intel XE#392]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/392
  [Intel XE#455]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/455
  [Intel XE#579]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/579
  [Intel XE#599]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/599
  [Intel XE#605]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/605
  [Intel XE#619]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/619
  [Intel XE#651]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/651
  [Intel XE#653]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/653
  [Intel XE#656]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/656
  [Intel XE#688]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/688
  [Intel XE#756]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/756
  [Intel XE#771]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/771
  [Intel XE#787]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/787
  [Intel XE#873]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/873
  [Intel XE#886]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/886
  [Intel XE#899]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/899
  [Intel XE#929]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/929
  [Intel XE#944]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/944
  [Intel XE#979]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/979


Build changes
-------------

  * Linux: xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232 -> xe-pw-136572v1

  IGT_7940: 2a73158fa69a2b8e20d5a0bdf773ee194bfe13c2 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  xe-1672-220554a8ef7ac26fbfc4f141816679d742a0d232: 220554a8ef7ac26fbfc4f141816679d742a0d232
  xe-pw-136572v1: 136572v1

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-136572v1/index.html

[-- Attachment #2: Type: text/html, Size: 54107 bytes --]

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 19/21] drm/xe/eudebug: Implement vm_bind_op discovery
  2024-07-26 14:08 ` [PATCH 19/21] drm/xe/eudebug: Implement vm_bind_op discovery Mika Kuoppala
@ 2024-07-27  4:39   ` Matthew Brost
  0 siblings, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  4:39 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

On Fri, Jul 26, 2024 at 05:08:16PM +0300, Mika Kuoppala wrote:
> Follow the vm bind, vm_bind op sequence for
> discovery process of a vm with the vmas it has.
> Send events for ops and attach metadata if available.
> 
> v2: Fix bad op ref seqno (Christoph)
> 
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> ---
>  drivers/gpu/drm/xe/xe_eudebug.c | 40 +++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index f0bec8c8bba1..a80ffb64df15 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -3070,6 +3070,42 @@ void xe_eudebug_debug_metadata_destroy(struct xe_file *xef, struct xe_debug_meta
>  	xe_eudebug_event_put(d, debug_metadata_destroy_event(d, xef, m));
>  }
>  
> +static int vm_discover_binds(struct xe_eudebug *d, struct xe_vm *vm)
> +{
> +	struct drm_gpuva *va;
> +	unsigned int num_ops = 0, send_ops = 0;
> +	u64 ref_seqno = 0;
> +	int err;
> +
> +	/* Currently only vm_bind_ioctl inserts vma's */
> +	drm_gpuvm_for_each_va(va, &vm->gpuvm)

This is not safe without at least vm->lock in read mode.

This function is called with xef->vm.lock & xe->files.lock and we likely
don't want to create locking dependency chain between these locks and
vm->lock either.

Hmm... How about when discovery_work_fn is called wait for executing
IOCTLs to complete and pause new IOCTLs until it is done. We should be
able to hook in xe_drm_ioctl to do this. Then we wouldn't need
xef->vm.lock & xe->files.lock locks either.

Also to be clear xef->exec_queue.lock & xef->vm.lock are not designed to
be held and do anything underneath expect to lookup something in the
xarray + take a ref to the object. Any other use is abusing these locks
and asking for trouble.

e.g. we do things like this.

241         mutex_lock(&xef->exec_queue.lock);
242         q = xa_load(&xef->exec_queue.xa, id);
243         if (q)
244                 xe_exec_queue_get(q);
245         mutex_unlock(&xef->exec_queue.lock);

If you need use xa_for_each I'd expect to look like this:

mutex_lock(&xef->exec_queue.lock);
xa_for_each(&xef->exec_queue.xa, i, q) {
	xe_exec_queue_get(q);
	mutex_unlock(&xef->exec_queue.lock);

	/* Do something with exec queue */

	xe_exec_queue_put(q);
	mutex_lock(&xef->exec_queue.lock);
}
mutex_unlock(&xef->exec_queue.lock);

It is prefectly fine in the above loop for exec queue to be removed from
the xa, xa_for_each is safe for that. The lock protects the lookup and
reference, nothing more.

Does this make sense? Feel free to ping me directly to discuss further.

Matt

> +		num_ops++;
> +
> +	if (!num_ops)
> +		return 0;
> +
> +	err = vm_bind_event(d, vm, num_ops, &ref_seqno);
> +	if (err)
> +		return err;
> +
> +	drm_gpuvm_for_each_va(va, &vm->gpuvm) {
> +		struct xe_vma *vma = container_of(va, struct xe_vma, gpuva);
> +
> +		if (send_ops >= num_ops)
> +			break;
> +
> +		err = vm_bind_op(d, vm, DRM_XE_EUDEBUG_EVENT_CREATE, ref_seqno,
> +				 xe_vma_start(vma), xe_vma_size(vma),
> +				 &vma->debug_metadata);
> +		if (err)
> +			return err;
> +
> +		send_ops++;
> +	}
> +
> +	return num_ops == send_ops ? 0 : -EINVAL;
> +}
> +
>  static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
>  {
>  	struct xe_debug_metadata *m;
> @@ -3095,6 +3131,10 @@ static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
>  		err = vm_create_event(d, xef, vm);
>  		if (err)
>  			break;
> +
> +		err = vm_discover_binds(d, vm);
> +		if (err)
> +			break;
>  	}
>  	mutex_unlock(&xef->vm.lock);
>  
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker
  2024-07-26 14:08 ` [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
@ 2024-07-27  5:08   ` Matthew Brost
  2024-07-29 10:10     ` Grzegorzek, Dominik
  2024-07-27  5:39   ` Matthew Brost
  1 sibling, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  5:08 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Dominik Grzegorzek, Christoph Manszewski,
	Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:07PM +0300, Mika Kuoppala wrote:
> 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 10 times slower when there is no debugger
> connection open. Send attention event whenever we see attention with
> debugger presence. If there is no debugger connection active - reset.
> 
> Based on work by authors and other folks who were part of attentions in
> i915.
> 
> - v2 Do not validate potentially active hwe against engine->hwe.
>   Whenever the engine has width > 1, this field contains only the first
>   hwe of the class.
> - squash dss walking and semaphore to mutex
> - v3 error path fix in xe_send_gt_attention (Christoph)
> - v4 runalone active fix (Mika)
> - v5 q->lrc changes (Mika)
> - v6 Use C99 flexible arrays (Maciej, checkpatch)
>      function with 'for_each' in name (Maciej, checkpatch)
> - v7 long running active fix (Dominik)
> - v8 resource handling errors rebase (Mika)
> - v9 find out lrc handles first before sending event (Mika)
> - v10 adjust runalone shift according to hw
> 
> 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>
> ---
>  drivers/gpu/drm/xe/Makefile              |   1 +
>  drivers/gpu/drm/xe/regs/xe_engine_regs.h |   3 +
>  drivers/gpu/drm/xe/regs/xe_gt_regs.h     |   7 +
>  drivers/gpu/drm/xe/xe_device.c           |   2 +
>  drivers/gpu/drm/xe/xe_device_types.h     |   3 +
>  drivers/gpu/drm/xe/xe_eudebug.c          | 389 ++++++++++++++++++++++-
>  drivers/gpu/drm/xe/xe_eudebug.h          |   1 +
>  drivers/gpu/drm/xe/xe_eudebug_types.h    |  32 ++
>  drivers/gpu/drm/xe/xe_gt_debug.c         | 152 +++++++++
>  drivers/gpu/drm/xe/xe_gt_debug.h         |  21 ++
>  include/uapi/drm/xe_drm_eudebug.h        |  15 +-
>  11 files changed, 624 insertions(+), 2 deletions(-)
>  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 06badc5f99af..b7b6b047c02c 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -49,6 +49,7 @@ xe-y += xe_bb.o \
>  	xe_gt_debugfs.o \
>  	xe_gt_freq.o \
>  	xe_gt_idle.o \
> +	xe_gt_debug.o \
>  	xe_gt_mcr.o \
>  	xe_gt_pagefault.o \
>  	xe_gt_sysfs.o \
> diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> index 764c270599d0..b9d713a2061d 100644
> --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> @@ -132,6 +132,9 @@
>  #define RING_EXECLIST_STATUS_LO(base)		XE_REG((base) + 0x234)
>  #define RING_EXECLIST_STATUS_HI(base)		XE_REG((base) + 0x234 + 4)
>  
> +#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_OAC_CONTEXT_ENABLE		REG_BIT(8)
>  #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
> diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> index 96a59a96dd4c..03e83ce3e35d 100644
> --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> @@ -437,6 +437,8 @@
>  #define   DISABLE_ECC				REG_BIT(5)
>  #define   ENABLE_PREFETCH_INTO_IC		REG_BIT(3)
>  
> +#define TD_ATT(x)				XE_REG_MCR(0xe470 + (x) * 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)
> @@ -516,6 +518,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 FORCEWAKE_ACK_GT			XE_REG(0x130044)
>  
>  /* Applicable for all FORCEWAKE_DOMAIN and FORCEWAKE_ACK_DOMAIN regs */
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 90bb0a8b1881..ba1c80089906 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -768,6 +768,8 @@ int xe_device_probe(struct xe_device *xe)
>  
>  	xe_debugfs_register(xe);
>  
> +	xe_eudebug_init_late(xe);
> +
>  	xe_hwmon_register(xe);
>  
>  	for_each_gt(gt, xe, id)
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index 4dcfd39cb909..3b33add576be 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -516,6 +516,9 @@ struct xe_device {
>  
>  		/** @ordered_wq: used to discovery */
>  		struct workqueue_struct *ordered_wq;
> +
> +		/** @attention_scan: attention scan worker */
> +		struct delayed_work attention_scan;
>  	} eudebug;
>  
>  	/* private: */
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 9611acedeee9..c2de001cc33a 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -11,19 +11,29 @@
>  
>  #include <drm/drm_managed.h>
>  
> -#include "regs/xe_gt_regs.h"
>  #include "regs/xe_engine_regs.h"
> +#include "regs/xe_gt_regs.h"
>  #include "xe_device.h"
>  #include "xe_assert.h"
>  #include "xe_macros.h"
>  #include "xe_gt.h"
> +#include "xe_gt_debug.h"
> +#include "xe_lrc.h"
> +#include "xe_hw_engine.h"
> +#include "xe_exec_queue.h"
>  #include "xe_eudebug_types.h"
>  #include "xe_eudebug.h"
>  #include "xe_exec_queue_types.h"
> +#include "xe_guc_exec_queue_types.h"
> +#include "xe_execlist_types.h"
> +#include "xe_mmio.h"
>  #include "xe_module.h"
> +#include "xe_pm.h"
>  #include "xe_rtp.h"
> +#include "xe_sched_job.h"
>  #include "xe_vm.h"
>  #include "xe_wa.h"
> +#include "xe_force_wake.h"
>  
>  /*
>   * If there is no detected event read by userspace, during this period, assume
> @@ -843,6 +853,371 @@ static const struct file_operations fops = {
>  	.unlocked_ioctl	= xe_eudebug_ioctl,
>  };
>  
> +static bool queue_has_active_job(struct xe_exec_queue *q)

This should probably be a generic function in xe_exec_queue.c. We seemly
already have one - xe_exec_queue_is_idle.

> +{
> +
> +	struct drm_gpu_scheduler *sched;
> +	struct drm_sched_job *drm_job;
> +
> +	if (xe_device_uc_enabled(gt_to_xe(q->gt)))

General comment, we likely don't want to the EU debugger enabled unless
GuC submission is enabled as the execlist backend really doesn't work. 

> +		sched = &q->guc->sched.base;
> +	else
> +		sched = &q->execlist->sched;
> +
> +	drm_job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list);

Random musing that don't apply as we have xe_exec_queue_is_idle but...

You need a scheduler lock here which is missing. If you wanted to see
the scheduler pending list was not empty, we'd call into the drm
scheduler layer.

That being said, I think the EU debugger only support LR VMs? If so,
then this always going to be empty.

> +
> +	if (drm_job) {
> +		struct xe_sched_job *job = to_xe_sched_job(drm_job);
> +
> +		return xe_sched_job_started(job) && !xe_sched_job_completed(job);
> +	} else if (xe_exec_queue_is_lr(q) &&
> +		   (xe_lrc_ring_head(q->lrc[0]) != xe_lrc_ring_tail(q->lrc[0]))) {
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +static int current_lrc(struct xe_hw_engine *hwe, u32 *lrc_hw)
> +{
> +	u32 lrc_reg;
> +	int err;
> +
> +	err = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
> +	if (err)
> +		return err;
> +
> +	lrc_reg = hw_engine_mmio_read32(hwe, RING_CURRENT_LRCA(0));
> +
> +	xe_force_wake_put(gt_to_fw(hwe->gt), hwe->domain);
> +
> +	if (!(lrc_reg & CURRENT_LRCA_VALID))
> +		return -ENOENT;
> +
> +	*lrc_hw = lrc_reg & GENMASK(31, 12);
> +
> +	return 0;
> +}
> +
> +static int match_engine_lrc(struct xe_exec_queue *q, u32 lrc_hw)
> +{
> +	int i;
> +	u32 lrc_ggtt;
> +
> +	for (i = 0; i < q->width; i++) {
> +		lrc_ggtt = lower_32_bits(xe_lrc_descriptor(q->lrc[i]));
> +		lrc_ggtt &= GENMASK(31, 12);
> +		if (lrc_ggtt == lrc_hw)
> +			return i;
> +	}
> +
> +	return -1;
> +}
> +
> +static u32 engine_status(const struct xe_hw_engine * const hwe,
> +			 u32 rcu_debug1)
> +{
> +	const bool xe1 = GRAPHICS_VER(gt_to_xe(hwe->gt)) < 20;
> +	unsigned int shift;
> +
> +	if (hwe->class == XE_ENGINE_CLASS_RENDER) {
> +		shift = 7;
> +		XE_WARN_ON(hwe->instance != 0);
> +	} else if (hwe->class == XE_ENGINE_CLASS_COMPUTE) {
> +		XE_WARN_ON(hwe->instance > 3);
> +
> +		if (xe1)
> +			shift = 10 + (hwe->instance * 3);
> +		else
> +			shift = 11 + (hwe->instance * 4);
> +	} else {
> +		XE_WARN_ON(hwe->class);
> +		return 0;
> +	}
> +
> +	return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
> +}
> +
> +static bool engine_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_context_set(const struct xe_hw_engine * const hwe,
> +			       u32 rcu_debug1)
> +{
> +	return engine_status(hwe, rcu_debug1) & RCU_DEBUG_1_CONTEXT_ACTIVE;
> +}
> +
> +static bool engine_has_runalone(const struct xe_hw_engine * const hwe)
> +{
> +	return hwe->class == XE_ENGINE_CLASS_RENDER ||
> +		hwe->class == XE_ENGINE_CLASS_COMPUTE;
> +}
> +
> +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;
> +	u32 val;
> +
> +	if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GT)) {
> +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone failed to get force wake\n");
> +		return NULL;
> +	}
> +
> +	val = xe_mmio_read32(gt, RCU_DEBUG_1);
> +	xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
> +
> +	drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone RCU_DEBUG_1 = 0x%08x\n", val);
> +
> +	num_active = 0;
> +	for_each_hw_engine(hwe, gt, id) {
> +		bool runalone, ctx;
> +
> +		if (!engine_has_runalone(hwe))
> +			continue;
> +
> +		runalone = engine_runalone_set(hwe, val);
> +		ctx = engine_context_set(hwe, val);
> +
> +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: engine %s: runalone=%s, context=%s",
> +			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(&gt_to_xe(gt)->drm, "eudbg: runalone engine %s %s",
> +				hwe->name, first ? "selected" : "found");
> +			if (!first)
> +				first = hwe;
> +		}
> +	}
> +
> +	if (num_active > 1)
> +		drm_err(&gt_to_xe(gt)->drm, "eudbg: %d runalone engines active!",
> +			num_active);
> +
> +	return first;
> +}
> +
> +static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
> +{
> +	struct xe_device *xe = gt_to_xe(gt);
> +	struct xe_exec_queue *q, *found = NULL;
> +	struct xe_hw_engine *active;
> +	struct xe_file *xef, *tmp;
> +	unsigned long i;
> +	int idx, err;
> +	u32 lrc_hw;
> +
> +	active = get_runalone_active_hw_engine(gt);
> +	if (!active) {
> +		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
> +		return ERR_PTR(-ENOENT);
> +	}
> +
> +	err = current_lrc(active, &lrc_hw);
> +	if (err)
> +		return ERR_PTR(err);
> +
> +	mutex_lock(&xe->files.lock);
> +	list_for_each_entry_safe(xef, tmp, &xe->files.list, link) {
> +		mutex_lock(&xef->exec_queue.lock);
> +		xa_for_each(&xef->exec_queue.xa, i, q) {

Same comment here as [1]. Don't hold xe->files.lock or
xef->exec_queue.lock for anything but the lookup. Holding locks longer
than needed creates unwanted lock dep chains which creates all sorts of
problems. The only time chains should exist is when we have well defined
locking chain like we have for a VM (vm->lock -> dma-resv -> notifier
lock).

So this should look something like this:

mutex_lock(&xe->files.lock);
xa_for_each(.., xef) {
	xe_file_get(xef);
	mutex_unlock(&xe->files.lock);

	mutex_lock(&xef->exec_queue.lock);
	xa_for_each(&xef->exec_queue.xa, i, q) {
		xe_exec_queue_get(q);
		mutex_unlock(&xef->exec_queue.lock);

		/* Do something */
	
		xe_exec_queue_put(q);
		mutex_lock(&xef->exec_queue.lock);
	}
	mutex_unlock(&xef->exec_queue.lock);
	
	xe_file_put(xef);
	mutex_lock(&xe->files.lock);
}
mutex_unlock(&xe->files.lock);

Note you will need to change xe->files.list to an xarray to make this
safe too.

Matt

[1] https://patchwork.freedesktop.org/patch/606052/?series=136572&rev=1

> +			if (q->gt != gt)
> +				continue;
> +
> +			if (q->class != active->class)
> +				continue;
> +
> +			if (!queue_has_active_job(q))
> +				continue;
> +
> +			idx = match_engine_lrc(q, lrc_hw);
> +			if (idx < 0)
> +				continue;
> +
> +			xe_exec_queue_get(q);
> +			found = q;
> +
> +			if (lrc_idx)
> +				*lrc_idx = idx;
> +
> +			break;
> +		}
> +		mutex_unlock(&xef->exec_queue.lock);
> +
> +		if (found)
> +			break;
> +	}
> +	mutex_unlock(&xe->files.lock);
> +
> +	if (!found)
> +		return ERR_PTR(-ENOENT);
> +
> +	if (XE_WARN_ON(current_lrc(active, &lrc_hw)) &&
> +	    XE_WARN_ON(match_engine_lrc(found, lrc_hw) < 0)) {
> +		xe_exec_queue_put(found);
> +		return ERR_PTR(-ENOENT);
> +	}
> +
> +	return found;
> +}
> +
> +static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, int lrc_idx)
> +{
> +	struct xe_eudebug_event_eu_attention *ea;
> +	struct xe_eudebug_event *event;
> +	int h_c, h_queue, h_lrc;
> +	u32 size = xe_gt_eu_attention_bitmap_size(q->gt);
> +	u32 sz = struct_size(ea, bitmask, size);
> +	int ret;
> +
> +	XE_WARN_ON(lrc_idx < 0 || lrc_idx >= q->width);
> +
> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, q->vm->xef);
> +	if (h_c < 0)
> +		return h_c;
> +
> +	h_queue = find_handle(d->res, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q);
> +	if (h_queue < 0)
> +		return h_queue;
> +
> +	h_lrc = find_handle(d->res, XE_EUDEBUG_RES_TYPE_LRC, q->lrc[lrc_idx]);
> +	if (h_lrc < 0)
> +		return h_lrc;
> +
> +	event = __xe_eudebug_create_event(d, 0, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
> +					  DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, sz, GFP_KERNEL);
> +
> +	if (!event)
> +		return -ENOSPC;
> +
> +	ea = cast_event(ea, event);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, client_handle, (u64)h_c);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, exec_queue_handle, (u64)h_queue);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, lrc_handle, (u64)h_lrc);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, bitmask_size, size);
> +
> +	mutex_lock(&d->eu_lock);
> +	event->seqno = atomic_long_inc_return(&d->events.seqno);
> +	ret = xe_gt_eu_attention_bitmap(q->gt, &ea->bitmask[0], ea->bitmask_size);
> +	mutex_unlock(&d->eu_lock);
> +
> +	if (ret)
> +		return ret;
> +
> +	return xe_eudebug_queue_event(d, event);
> +}
> +
> +
> +static int xe_send_gt_attention(struct xe_gt *gt)
> +{
> +	struct xe_eudebug *d;
> +	struct xe_exec_queue *q;
> +	int ret, lrc_idx;
> +
> +	if (list_empty_careful(&gt_to_xe(gt)->eudebug.list))
> +		return -ENOTCONN;
> +
> +	q = runalone_active_queue_get(gt, &lrc_idx);
> +	if (IS_ERR(q))
> +		return PTR_ERR(q);
> +
> +	d = xe_eudebug_get(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);
> +	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)
> +{
> +	int ret;
> +
> +	ret = xe_gt_eu_threads_needing_attention(gt);
> +	if (ret <= 0)
> +		return ret;
> +
> +	ret = xe_send_gt_attention(gt);
> +
> +	/* Discovery in progress, fake it */
> +	if (ret == -EBUSY)
> +		return 0;
> +
> +	return ret;
> +}
> +
> +#define XE_EUDEBUG_ATTENTION_INTERVAL 100
> +static void attention_scan_fn(struct work_struct *work)
> +{
> +	struct xe_device *xe = container_of(work, typeof(*xe), eudebug.attention_scan.work);
> +	long delay = msecs_to_jiffies(XE_EUDEBUG_ATTENTION_INTERVAL);
> +	struct xe_gt *gt;
> +	u8 gt_id;
> +
> +	if (list_empty_careful(&xe->eudebug.list))
> +		delay *= 10;
> +
> +	if (delay >= HZ)
> +		delay = round_jiffies_up_relative(delay);
> +
> +	if (pm_runtime_active(xe->drm.dev)) {
> +		for_each_gt(gt, xe, gt_id) {
> +			int ret;
> +
> +			ret = xe_eudebug_handle_gt_attention(gt);
> +			if (ret) {
> +				// TODO: error capture
> +				drm_info(&gt_to_xe(gt)->drm,
> +					 "gt:%d unable to handle eu attention ret=%d\n",
> +					 gt_id, ret);
> +
> +				xe_gt_reset_async(gt);
> +			}
> +		}
> +	}
> +
> +	schedule_delayed_work(&xe->eudebug.attention_scan, delay);
> +}
> +
> +static void attention_scan_cancel(struct xe_device *xe)
> +{
> +	cancel_delayed_work_sync(&xe->eudebug.attention_scan);
> +}
> +
> +static void attention_scan_flush(struct xe_device *xe)
> +{
> +	mod_delayed_work(system_wq, &xe->eudebug.attention_scan, 0);
> +}
> +
>  static void discovery_work_fn(struct work_struct *work);
>  
>  static int
> @@ -877,6 +1252,7 @@ xe_eudebug_connect(struct xe_device *xe,
>  
>  	kref_init(&d->ref);
>  	spin_lock_init(&d->connection.lock);
> +	mutex_init(&d->eu_lock);
>  	init_waitqueue_head(&d->events.write_done);
>  	init_waitqueue_head(&d->events.read_done);
>  	init_completion(&d->discovery);
> @@ -903,6 +1279,7 @@ xe_eudebug_connect(struct xe_device *xe,
>  
>  	kref_get(&d->ref);
>  	queue_work(xe->eudebug.ordered_wq, &d->discovery_work);
> +	attention_scan_flush(xe);
>  
>  	eu_dbg(d, "connected session %lld", d->session);
>  
> @@ -979,12 +1356,22 @@ void xe_eudebug_init(struct xe_device *xe)
>  {
>  	spin_lock_init(&xe->eudebug.lock);
>  	INIT_LIST_HEAD(&xe->eudebug.list);
> +	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
>  
>  	xe->eudebug.available = true;
>  }
>  
> +void xe_eudebug_init_late(struct xe_device *xe)
> +{
> +	if (!xe->eudebug.available)
> +		return;
> +
> +	attention_scan_flush(xe);
> +}
> +
>  void xe_eudebug_fini(struct xe_device *xe)
>  {
> +	attention_scan_cancel(xe);
>  	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
>  }
>  
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> index ac89a3d1ee1d..1e233c4683d6 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> @@ -18,6 +18,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>  			     struct drm_file *file);
>  
>  void xe_eudebug_init(struct xe_device *xe);
> +void xe_eudebug_init_late(struct xe_device *xe);
>  void xe_eudebug_fini(struct xe_device *xe);
>  void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
>  
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
> index 6e3c23023933..16667b4dfe45 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> @@ -105,6 +105,9 @@ struct xe_eudebug {
>  	/** @discovery_work: worker to discover resources for target_task */
>  	struct work_struct discovery_work;
>  
> +	/** eu_lock: guards operations on eus (eu thread control and attention) */
> +	struct mutex eu_lock;
> +
>  	/** @events: kfifo queue of to-be-delivered events */
>  	struct {
>  		/** @lock: guards access to fifo */
> @@ -202,4 +205,33 @@ struct xe_eudebug_event_exec_queue {
>  	u64 lrc_handle[];
>  };
>  
> +/**
> + * struct xe_eudebug_event_eu_attention - Internal event for EU attention
> + */
> +struct xe_eudebug_event_eu_attention {
> +	/** @base: base event */
> +	struct xe_eudebug_event base;
> +
> +	/** @client_handle: client for the attention */
> +	u64 client_handle;
> +
> +	/** @exec_queue_handle: handle of exec_queue which raised attention */
> +	u64 exec_queue_handle;
> +
> +	/** @lrc_handle: lrc handle of the workload which raised attention */
> +	u64 lrc_handle;
> +
> +	/** @flags: eu attention event flags, currently MBZ */
> +	u32 flags;
> +
> +	/** @bitmask_size: size of the bitmask, specific to device */
> +	u32 bitmask_size;
> +
> +	/**
> +	 * @bitmask: reflects threads currently signalling attention,
> +	 * starting from natural hardware order of DSS=0, eu=0
> +	 */
> +	u8 bitmask[];
> +};
> +
>  #endif
> 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..04d2d43ce249
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_gt_debug.c
> @@ -0,0 +1,152 @@
> +// 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"
> +
> +static int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
> +					    int (*fn)(struct xe_gt *gt,
> +						      void *data,
> +						      u16 group,
> +						      u16 instance),
> +					    void *data)
> +{
> +	const enum xe_force_wake_domains fw_domains = XE_FW_GT | XE_FW_RENDER;
> +	unsigned int dss;
> +	u16 group, instance;
> +	int ret;
> +
> +	xe_pm_runtime_get(gt_to_xe(gt));
> +	ret = xe_force_wake_get(gt_to_fw(gt), fw_domains);
> +	if (ret)
> +		goto pm_runtime_put;
> +
> +	for_each_dss_steering(dss, gt, group, instance) {
> +		ret = fn(gt, data, group, instance);
> +		if (ret)
> +			break;
> +	}
> +
> +	xe_force_wake_put(gt_to_fw(gt), fw_domains);
> +pm_runtime_put:
> +	xe_pm_runtime_put(gt_to_xe(gt));
> +
> +	return ret;
> +}
> +
> +static int read_first_attention_mcr(struct xe_gt *gt, void *data,
> +				    u16 group, u16 instance)
> +{
> +	unsigned int row;
> +
> +	for (row = 0; row < 2; row++) {
> +		u32 val;
> +
> +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(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);
> +
> +	return  bitmap_weight(dss_mask, XE_MAX_DSS_FUSE_BITS) *
> +		TD_EU_ATTENTION_MAX_ROWS * 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)
> +{
> +	struct attn_read_iter * const iter = data;
> +	unsigned int row;
> +
> +	for (row = 0; row < TD_EU_ATTENTION_MAX_ROWS; row++) {
> +		u32 val;
> +
> +		if (iter->i >= iter->size)
> +			return 0;
> +
> +		XE_WARN_ON(iter->i + sizeof(val) > xe_gt_eu_attention_bitmap_size(gt));
> +
> +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(row), group, instance);
> +
> +
> +		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
> +	};
> +
> +	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..3f13dbb17a5f
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_gt_debug.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#ifndef __XE_GT_DEBUG_
> +#define __XE_GT_DEBUG_
> +
> +#define TD_EU_ATTENTION_MAX_ROWS 2u
> +
> +#include "xe_gt_types.h"
> +
> +#define XE_GT_ATTENTION_TIMEOUT_MS 100
> +
> +int xe_gt_eu_threads_needing_attention(struct xe_gt *gt);
> +
> +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/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> index 25dddb8b22f4..453269ac8307 100644
> --- a/include/uapi/drm/xe_drm_eudebug.h
> +++ b/include/uapi/drm/xe_drm_eudebug.h
> @@ -27,13 +27,15 @@ struct drm_xe_eudebug_event {
>  #define DRM_XE_EUDEBUG_EVENT_OPEN		2
>  #define DRM_XE_EUDEBUG_EVENT_VM			3
>  #define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE		4
> -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
> +#define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
>  
>  	__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)
> +
>  	__u64 seqno;
>  	__u64 reserved;
>  };
> @@ -62,6 +64,17 @@ struct drm_xe_eudebug_event_exec_queue {
>  	__u64 lrc_handle[];
>  };
>  
> +struct drm_xe_eudebug_event_eu_attention {
> +	struct drm_xe_eudebug_event base;
> +
> +	__u64 client_handle;
> +	__u64 exec_queue_handle;
> +	__u64 lrc_handle;
> +	__u32 flags;
> +	__u32 bitmask_size;
> +	__u8 bitmask[];
> +};
> +
>  #if defined(__cplusplus)
>  }
>  #endif
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 00/21] GPU debug support (eudebug)
  2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
                   ` (28 preceding siblings ...)
  2024-07-27  2:37 ` ✓ CI.FULL: " Patchwork
@ 2024-07-27  5:23 ` Matthew Brost
  2024-07-29  8:27   ` Gwan-gyeong Mun
  29 siblings, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  5:23 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

On Fri, Jul 26, 2024 at 05:07:57PM +0300, Mika Kuoppala wrote:
> Hi,
> 
> We (Intel eudebug kernel team) would like to submit this
> patchset to enable debug support for Intel GPU devices.
> 
> The aim is to allow Level-Zero + GDB (or some other tool)
> to attach to xe driver in order to receive information
> about relevant driver resources, hardware events and to allow debug
> related hardware control. End goal is full debug capability
> of supported Intel hardware, see [4].
> 
> Debugger first opens a connection to a device through
> drm ioctl with debug target process as a pid. This will
> return a dedicated file descriptor used for debugging
> for further events and control.
> 
> Xe internal resources that are considered essential
> to debugger functionality are relayed as events to the
> debugger. On debugger connection, all existing resources
> are relayed to debugger (discovery) and from that
> point onwards, as they are created/destroyed.
> 
> uapi is extended to allow an application/lib to provide
> debug metadata information. These are relayed as events
> to the debugger so it can decode the program state.
> 
> Along with the resource and metadata events, an event for
> hardware exceptions, called EU attention, is provided.
> The debugger, with the assistance of an exception handling
> program called System Routine (short: SIP) provided
> with the pipeline setup, can determine which specific
> EU/thread and instruction encountered the breakpoint
> or other exceptions.
> 
> EU controlling ioctl interface is also introduced where
> debugger can manipulate individual threads of the currently
> active workload. This interface enables the debugger to
> interrupt all threads on demand, check their current state
> and resume them individually.
> 
> The intent is to provide a similar but not API compatible
> functionality as in out-of-tree i915 debugger support:
> https://dgpu-docs.intel.com/driver/gpu-debugging.html
> 
> For xe the aim is to have all support merged in upstream,
> starting with this series. With Lunarlake being first targetted
> hardware.
> 
> I have split the events into xe_drm_eudebug.h instead
> pushing everything into xe_drm.h, in order to help
> distinguish what is controlled by which descriptor.
> If it's through the original xe fd, it is in xe_drm.h and
> if it's through the opened debugger connection fd, it
> is in xe_drm_eudebug.h.
> 

Looking through the series, I do have question wrt to GPU fault and
eudebug. I don't see any interaction there. Without knowing eudebug
works, it seems like setting a break point on a GPU access to virtual
address is something a debugger would want. On a faulting device, this
is something we should be able to support. This really comes into play
once we have SVM as the UMD won't be issuing binds either. Curious about
your thoughts here.

If this something that required, in particular with SVM, this something
the SVM and eudebug teams need to collaborate on early to make sure both
designs work with each other.

Matt

> Latest code can be found in:
> [1] https://gitlab.freedesktop.org/miku/kernel/-/tree/eudebug-dev
> 
> With the associated IGT tests:
> [2] https://gitlab.freedesktop.org/cmanszew/igt-gpu-tools/-/tree/eudebug-dev
> 
> The user for this uapi:
> [3] https://github.com/intel/compute-runtime
> Event loop and thread control interaction can be found at:
> https://github.com/intel/compute-runtime/tree/master/level_zero/tools/source/debug/linux/xe
> And the wrappers in:
> https://github.com/intel/compute-runtime/tree/master/shared/source/os_interface/linux/xe
> https://github.com/intel/compute-runtime/blob/master/shared/source/os_interface/linux/xe/ioctl_helper_xe_debugger.cpp
> Note that the XE support is disabled by default and you will need
> NEO_ENABLE_XE_EU_DEBUG_SUPPORT enabled in order to test.
> 
> GDB support:
> [4]: https://sourceware.org/pipermail/gdb-patches/2024-July/210264.html
> 
> Thank you in advance for any comments and insight.
> 
> 
> Andrzej Hajda (1):
>   drm/xe/eudebug: implement userptr_vma access
> 
> Christoph Manszewski (3):
>   drm/xe/eudebug: Add vm bind and vm bind ops
>   drm/xe/eudebug: Dynamically toggle debugger functionality
>   drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test
> 
> Dominik Grzegorzek (10):
>   drm/xe: Export xe_hw_engine's mmio accessors
>   drm/xe: Move and export xe_hw_engine lookup.
>   drm/xe/eudebug: Introduce exec_queue events
>   drm/xe/eudebug: hw enablement for eudebug
>   drm/xe: Add EUDEBUG_ENABLE exec queue property
>   drm/xe/eudebug: Introduce per device attention scan worker
>   drm/xe/eudebug: Introduce EU control interface
>   drm/xe: Debug metadata create/destroy ioctls
>   drm/xe: Attach debug metadata to vma
>   drm/xe/eudebug: Add debug metadata support for xe_eudebug
> 
> Jonathan Cavitt (1):
>   drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach
> 
> Mika Kuoppala (6):
>   drm/xe/eudebug: Introduce eudebug support
>   kernel: export ptrace_may_access
>   drm/xe/eudebug: Introduce discovery for resources
>   drm/xe/eudebug: Add UFENCE events with acks
>   drm/xe/eudebug: vm open/pread/pwrite
>   drm/xe/eudebug: Implement vm_bind_op discovery
> 
>  drivers/gpu/drm/xe/Makefile                  |    5 +-
>  drivers/gpu/drm/xe/regs/xe_engine_regs.h     |    8 +
>  drivers/gpu/drm/xe/regs/xe_gt_regs.h         |   43 +
>  drivers/gpu/drm/xe/tests/xe_eudebug.c        |  170 +
>  drivers/gpu/drm/xe/tests/xe_live_test_mod.c  |    2 +
>  drivers/gpu/drm/xe/xe_debug_metadata.c       |  125 +
>  drivers/gpu/drm/xe/xe_debug_metadata.h       |   25 +
>  drivers/gpu/drm/xe/xe_debug_metadata_types.h |   28 +
>  drivers/gpu/drm/xe/xe_device.c               |   47 +-
>  drivers/gpu/drm/xe/xe_device_types.h         |   45 +
>  drivers/gpu/drm/xe/xe_eudebug.c              | 3841 ++++++++++++++++++
>  drivers/gpu/drm/xe/xe_eudebug.h              |   51 +
>  drivers/gpu/drm/xe/xe_eudebug_types.h        |  326 ++
>  drivers/gpu/drm/xe/xe_exec.c                 |    2 +-
>  drivers/gpu/drm/xe/xe_exec_queue.c           |   80 +-
>  drivers/gpu/drm/xe/xe_exec_queue_types.h     |    7 +
>  drivers/gpu/drm/xe/xe_gt_debug.c             |  152 +
>  drivers/gpu/drm/xe/xe_gt_debug.h             |   27 +
>  drivers/gpu/drm/xe/xe_hw_engine.c            |   39 +-
>  drivers/gpu/drm/xe/xe_hw_engine.h            |   11 +
>  drivers/gpu/drm/xe/xe_lrc.c                  |   16 +-
>  drivers/gpu/drm/xe/xe_lrc.h                  |    4 +-
>  drivers/gpu/drm/xe/xe_reg_sr.c               |   21 +-
>  drivers/gpu/drm/xe/xe_reg_sr.h               |    4 +-
>  drivers/gpu/drm/xe/xe_rtp.c                  |    2 +-
>  drivers/gpu/drm/xe/xe_rtp_types.h            |    1 +
>  drivers/gpu/drm/xe/xe_sync.c                 |   49 +-
>  drivers/gpu/drm/xe/xe_sync.h                 |    8 +-
>  drivers/gpu/drm/xe/xe_sync_types.h           |   26 +-
>  drivers/gpu/drm/xe/xe_vm.c                   |  227 +-
>  drivers/gpu/drm/xe/xe_vm_types.h             |   26 +
>  include/uapi/drm/xe_drm.h                    |   96 +-
>  include/uapi/drm/xe_drm_eudebug.h            |  226 ++
>  kernel/ptrace.c                              |    1 +
>  34 files changed, 5655 insertions(+), 86 deletions(-)
>  create mode 100644 drivers/gpu/drm/xe/tests/xe_eudebug.c
>  create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.c
>  create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.h
>  create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata_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_types.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 include/uapi/drm/xe_drm_eudebug.h
> 
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker
  2024-07-26 14:08 ` [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
  2024-07-27  5:08   ` Matthew Brost
@ 2024-07-27  5:39   ` Matthew Brost
  1 sibling, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  5:39 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Dominik Grzegorzek, Christoph Manszewski,
	Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:07PM +0300, Mika Kuoppala wrote:
> 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 10 times slower when there is no debugger
> connection open. Send attention event whenever we see attention with
> debugger presence. If there is no debugger connection active - reset.
> 
> Based on work by authors and other folks who were part of attentions in
> i915.
> 
> - v2 Do not validate potentially active hwe against engine->hwe.
>   Whenever the engine has width > 1, this field contains only the first
>   hwe of the class.
> - squash dss walking and semaphore to mutex
> - v3 error path fix in xe_send_gt_attention (Christoph)
> - v4 runalone active fix (Mika)
> - v5 q->lrc changes (Mika)
> - v6 Use C99 flexible arrays (Maciej, checkpatch)
>      function with 'for_each' in name (Maciej, checkpatch)
> - v7 long running active fix (Dominik)
> - v8 resource handling errors rebase (Mika)
> - v9 find out lrc handles first before sending event (Mika)
> - v10 adjust runalone shift according to hw
> 
> 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>
> ---
>  drivers/gpu/drm/xe/Makefile              |   1 +
>  drivers/gpu/drm/xe/regs/xe_engine_regs.h |   3 +
>  drivers/gpu/drm/xe/regs/xe_gt_regs.h     |   7 +
>  drivers/gpu/drm/xe/xe_device.c           |   2 +
>  drivers/gpu/drm/xe/xe_device_types.h     |   3 +
>  drivers/gpu/drm/xe/xe_eudebug.c          | 389 ++++++++++++++++++++++-
>  drivers/gpu/drm/xe/xe_eudebug.h          |   1 +
>  drivers/gpu/drm/xe/xe_eudebug_types.h    |  32 ++
>  drivers/gpu/drm/xe/xe_gt_debug.c         | 152 +++++++++
>  drivers/gpu/drm/xe/xe_gt_debug.h         |  21 ++
>  include/uapi/drm/xe_drm_eudebug.h        |  15 +-
>  11 files changed, 624 insertions(+), 2 deletions(-)
>  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 06badc5f99af..b7b6b047c02c 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -49,6 +49,7 @@ xe-y += xe_bb.o \
>  	xe_gt_debugfs.o \
>  	xe_gt_freq.o \
>  	xe_gt_idle.o \
> +	xe_gt_debug.o \
>  	xe_gt_mcr.o \
>  	xe_gt_pagefault.o \
>  	xe_gt_sysfs.o \
> diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> index 764c270599d0..b9d713a2061d 100644
> --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> @@ -132,6 +132,9 @@
>  #define RING_EXECLIST_STATUS_LO(base)		XE_REG((base) + 0x234)
>  #define RING_EXECLIST_STATUS_HI(base)		XE_REG((base) + 0x234 + 4)
>  
> +#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_OAC_CONTEXT_ENABLE		REG_BIT(8)
>  #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
> diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> index 96a59a96dd4c..03e83ce3e35d 100644
> --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> @@ -437,6 +437,8 @@
>  #define   DISABLE_ECC				REG_BIT(5)
>  #define   ENABLE_PREFETCH_INTO_IC		REG_BIT(3)
>  
> +#define TD_ATT(x)				XE_REG_MCR(0xe470 + (x) * 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)
> @@ -516,6 +518,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 FORCEWAKE_ACK_GT			XE_REG(0x130044)
>  
>  /* Applicable for all FORCEWAKE_DOMAIN and FORCEWAKE_ACK_DOMAIN regs */
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 90bb0a8b1881..ba1c80089906 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -768,6 +768,8 @@ int xe_device_probe(struct xe_device *xe)
>  
>  	xe_debugfs_register(xe);
>  
> +	xe_eudebug_init_late(xe);
> +
>  	xe_hwmon_register(xe);
>  
>  	for_each_gt(gt, xe, id)
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index 4dcfd39cb909..3b33add576be 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -516,6 +516,9 @@ struct xe_device {
>  
>  		/** @ordered_wq: used to discovery */
>  		struct workqueue_struct *ordered_wq;
> +
> +		/** @attention_scan: attention scan worker */
> +		struct delayed_work attention_scan;
>  	} eudebug;
>  
>  	/* private: */
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 9611acedeee9..c2de001cc33a 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -11,19 +11,29 @@
>  
>  #include <drm/drm_managed.h>
>  
> -#include "regs/xe_gt_regs.h"
>  #include "regs/xe_engine_regs.h"
> +#include "regs/xe_gt_regs.h"
>  #include "xe_device.h"
>  #include "xe_assert.h"
>  #include "xe_macros.h"
>  #include "xe_gt.h"
> +#include "xe_gt_debug.h"
> +#include "xe_lrc.h"
> +#include "xe_hw_engine.h"
> +#include "xe_exec_queue.h"
>  #include "xe_eudebug_types.h"
>  #include "xe_eudebug.h"
>  #include "xe_exec_queue_types.h"
> +#include "xe_guc_exec_queue_types.h"
> +#include "xe_execlist_types.h"
> +#include "xe_mmio.h"
>  #include "xe_module.h"
> +#include "xe_pm.h"
>  #include "xe_rtp.h"
> +#include "xe_sched_job.h"
>  #include "xe_vm.h"
>  #include "xe_wa.h"
> +#include "xe_force_wake.h"
>  
>  /*
>   * If there is no detected event read by userspace, during this period, assume
> @@ -843,6 +853,371 @@ static const struct file_operations fops = {
>  	.unlocked_ioctl	= xe_eudebug_ioctl,
>  };
>  
> +static bool queue_has_active_job(struct xe_exec_queue *q)
> +{
> +
> +	struct drm_gpu_scheduler *sched;
> +	struct drm_sched_job *drm_job;
> +
> +	if (xe_device_uc_enabled(gt_to_xe(q->gt)))
> +		sched = &q->guc->sched.base;
> +	else
> +		sched = &q->execlist->sched;
> +
> +	drm_job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list);
> +
> +	if (drm_job) {
> +		struct xe_sched_job *job = to_xe_sched_job(drm_job);
> +
> +		return xe_sched_job_started(job) && !xe_sched_job_completed(job);
> +	} else if (xe_exec_queue_is_lr(q) &&
> +		   (xe_lrc_ring_head(q->lrc[0]) != xe_lrc_ring_tail(q->lrc[0]))) {
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +static int current_lrc(struct xe_hw_engine *hwe, u32 *lrc_hw)
> +{
> +	u32 lrc_reg;
> +	int err;
> +
> +	err = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
> +	if (err)
> +		return err;
> +
> +	lrc_reg = hw_engine_mmio_read32(hwe, RING_CURRENT_LRCA(0));
> +
> +	xe_force_wake_put(gt_to_fw(hwe->gt), hwe->domain);
> +
> +	if (!(lrc_reg & CURRENT_LRCA_VALID))
> +		return -ENOENT;
> +
> +	*lrc_hw = lrc_reg & GENMASK(31, 12);
> +
> +	return 0;
> +}
> +
> +static int match_engine_lrc(struct xe_exec_queue *q, u32 lrc_hw)
> +{
> +	int i;
> +	u32 lrc_ggtt;
> +
> +	for (i = 0; i < q->width; i++) {
> +		lrc_ggtt = lower_32_bits(xe_lrc_descriptor(q->lrc[i]));
> +		lrc_ggtt &= GENMASK(31, 12);
> +		if (lrc_ggtt == lrc_hw)
> +			return i;
> +	}
> +
> +	return -1;
> +}
> +
> +static u32 engine_status(const struct xe_hw_engine * const hwe,
> +			 u32 rcu_debug1)
> +{
> +	const bool xe1 = GRAPHICS_VER(gt_to_xe(hwe->gt)) < 20;
> +	unsigned int shift;
> +
> +	if (hwe->class == XE_ENGINE_CLASS_RENDER) {
> +		shift = 7;
> +		XE_WARN_ON(hwe->instance != 0);
> +	} else if (hwe->class == XE_ENGINE_CLASS_COMPUTE) {
> +		XE_WARN_ON(hwe->instance > 3);
> +
> +		if (xe1)
> +			shift = 10 + (hwe->instance * 3);
> +		else
> +			shift = 11 + (hwe->instance * 4);
> +	} else {
> +		XE_WARN_ON(hwe->class);
> +		return 0;
> +	}
> +
> +	return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
> +}
> +
> +static bool engine_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_context_set(const struct xe_hw_engine * const hwe,
> +			       u32 rcu_debug1)
> +{
> +	return engine_status(hwe, rcu_debug1) & RCU_DEBUG_1_CONTEXT_ACTIVE;
> +}
> +
> +static bool engine_has_runalone(const struct xe_hw_engine * const hwe)
> +{
> +	return hwe->class == XE_ENGINE_CLASS_RENDER ||
> +		hwe->class == XE_ENGINE_CLASS_COMPUTE;
> +}
> +
> +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;
> +	u32 val;
> +
> +	if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GT)) {
> +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone failed to get force wake\n");
> +		return NULL;
> +	}
> +
> +	val = xe_mmio_read32(gt, RCU_DEBUG_1);
> +	xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
> +
> +	drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone RCU_DEBUG_1 = 0x%08x\n", val);
> +
> +	num_active = 0;
> +	for_each_hw_engine(hwe, gt, id) {
> +		bool runalone, ctx;
> +
> +		if (!engine_has_runalone(hwe))
> +			continue;
> +
> +		runalone = engine_runalone_set(hwe, val);
> +		ctx = engine_context_set(hwe, val);
> +
> +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: engine %s: runalone=%s, context=%s",
> +			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(&gt_to_xe(gt)->drm, "eudbg: runalone engine %s %s",
> +				hwe->name, first ? "selected" : "found");
> +			if (!first)
> +				first = hwe;
> +		}
> +	}
> +
> +	if (num_active > 1)
> +		drm_err(&gt_to_xe(gt)->drm, "eudbg: %d runalone engines active!",
> +			num_active);
> +
> +	return first;
> +}
> +
> +static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
> +{
> +	struct xe_device *xe = gt_to_xe(gt);
> +	struct xe_exec_queue *q, *found = NULL;
> +	struct xe_hw_engine *active;
> +	struct xe_file *xef, *tmp;
> +	unsigned long i;
> +	int idx, err;
> +	u32 lrc_hw;
> +
> +	active = get_runalone_active_hw_engine(gt);
> +	if (!active) {
> +		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
> +		return ERR_PTR(-ENOENT);
> +	}
> +
> +	err = current_lrc(active, &lrc_hw);
> +	if (err)
> +		return ERR_PTR(err);
> +
> +	mutex_lock(&xe->files.lock);
> +	list_for_each_entry_safe(xef, tmp, &xe->files.list, link) {
> +		mutex_lock(&xef->exec_queue.lock);
> +		xa_for_each(&xef->exec_queue.xa, i, q) {
> +			if (q->gt != gt)
> +				continue;
> +
> +			if (q->class != active->class)
> +				continue;
> +
> +			if (!queue_has_active_job(q))
> +				continue;
> +
> +			idx = match_engine_lrc(q, lrc_hw);
> +			if (idx < 0)
> +				continue;
> +
> +			xe_exec_queue_get(q);
> +			found = q;
> +
> +			if (lrc_idx)
> +				*lrc_idx = idx;
> +
> +			break;
> +		}
> +		mutex_unlock(&xef->exec_queue.lock);
> +
> +		if (found)
> +			break;
> +	}
> +	mutex_unlock(&xe->files.lock);
> +
> +	if (!found)
> +		return ERR_PTR(-ENOENT);
> +
> +	if (XE_WARN_ON(current_lrc(active, &lrc_hw)) &&
> +	    XE_WARN_ON(match_engine_lrc(found, lrc_hw) < 0)) {
> +		xe_exec_queue_put(found);
> +		return ERR_PTR(-ENOENT);
> +	}
> +
> +	return found;
> +}
> +
> +static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, int lrc_idx)
> +{
> +	struct xe_eudebug_event_eu_attention *ea;
> +	struct xe_eudebug_event *event;
> +	int h_c, h_queue, h_lrc;
> +	u32 size = xe_gt_eu_attention_bitmap_size(q->gt);
> +	u32 sz = struct_size(ea, bitmask, size);
> +	int ret;
> +
> +	XE_WARN_ON(lrc_idx < 0 || lrc_idx >= q->width);
> +
> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, q->vm->xef);
> +	if (h_c < 0)
> +		return h_c;
> +
> +	h_queue = find_handle(d->res, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q);
> +	if (h_queue < 0)
> +		return h_queue;
> +
> +	h_lrc = find_handle(d->res, XE_EUDEBUG_RES_TYPE_LRC, q->lrc[lrc_idx]);
> +	if (h_lrc < 0)
> +		return h_lrc;
> +
> +	event = __xe_eudebug_create_event(d, 0, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
> +					  DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, sz, GFP_KERNEL);
> +
> +	if (!event)
> +		return -ENOSPC;
> +
> +	ea = cast_event(ea, event);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, client_handle, (u64)h_c);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, exec_queue_handle, (u64)h_queue);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, lrc_handle, (u64)h_lrc);
> +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, bitmask_size, size);
> +
> +	mutex_lock(&d->eu_lock);
> +	event->seqno = atomic_long_inc_return(&d->events.seqno);
> +	ret = xe_gt_eu_attention_bitmap(q->gt, &ea->bitmask[0], ea->bitmask_size);
> +	mutex_unlock(&d->eu_lock);
> +
> +	if (ret)
> +		return ret;
> +
> +	return xe_eudebug_queue_event(d, event);
> +}
> +
> +
> +static int xe_send_gt_attention(struct xe_gt *gt)
> +{
> +	struct xe_eudebug *d;
> +	struct xe_exec_queue *q;
> +	int ret, lrc_idx;
> +
> +	if (list_empty_careful(&gt_to_xe(gt)->eudebug.list))
> +		return -ENOTCONN;
> +
> +	q = runalone_active_queue_get(gt, &lrc_idx);
> +	if (IS_ERR(q))
> +		return PTR_ERR(q);
> +
> +	d = xe_eudebug_get(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);
> +	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)
> +{
> +	int ret;
> +
> +	ret = xe_gt_eu_threads_needing_attention(gt);
> +	if (ret <= 0)
> +		return ret;
> +
> +	ret = xe_send_gt_attention(gt);
> +
> +	/* Discovery in progress, fake it */
> +	if (ret == -EBUSY)
> +		return 0;
> +
> +	return ret;
> +}
> +
> +#define XE_EUDEBUG_ATTENTION_INTERVAL 100
> +static void attention_scan_fn(struct work_struct *work)
> +{
> +	struct xe_device *xe = container_of(work, typeof(*xe), eudebug.attention_scan.work);
> +	long delay = msecs_to_jiffies(XE_EUDEBUG_ATTENTION_INTERVAL);
> +	struct xe_gt *gt;
> +	u8 gt_id;
> +
> +	if (list_empty_careful(&xe->eudebug.list))
> +		delay *= 10;
> +
> +	if (delay >= HZ)
> +		delay = round_jiffies_up_relative(delay);
> +
> +	if (pm_runtime_active(xe->drm.dev)) {
> +		for_each_gt(gt, xe, gt_id) {
> +			int ret;
> +
> +			ret = xe_eudebug_handle_gt_attention(gt);
> +			if (ret) {
> +				// TODO: error capture
> +				drm_info(&gt_to_xe(gt)->drm,
> +					 "gt:%d unable to handle eu attention ret=%d\n",
> +					 gt_id, ret);
> +
> +				xe_gt_reset_async(gt);
> +			}
> +		}
> +	}
> +
> +	schedule_delayed_work(&xe->eudebug.attention_scan, delay);
> +}
> +
> +static void attention_scan_cancel(struct xe_device *xe)
> +{
> +	cancel_delayed_work_sync(&xe->eudebug.attention_scan);
> +}
> +
> +static void attention_scan_flush(struct xe_device *xe)
> +{
> +	mod_delayed_work(system_wq, &xe->eudebug.attention_scan, 0);
> +}
> +
>  static void discovery_work_fn(struct work_struct *work);
>  
>  static int
> @@ -877,6 +1252,7 @@ xe_eudebug_connect(struct xe_device *xe,
>  
>  	kref_init(&d->ref);
>  	spin_lock_init(&d->connection.lock);
> +	mutex_init(&d->eu_lock);
>  	init_waitqueue_head(&d->events.write_done);
>  	init_waitqueue_head(&d->events.read_done);
>  	init_completion(&d->discovery);
> @@ -903,6 +1279,7 @@ xe_eudebug_connect(struct xe_device *xe,
>  
>  	kref_get(&d->ref);
>  	queue_work(xe->eudebug.ordered_wq, &d->discovery_work);
> +	attention_scan_flush(xe);
>  
>  	eu_dbg(d, "connected session %lld", d->session);
>  
> @@ -979,12 +1356,22 @@ void xe_eudebug_init(struct xe_device *xe)
>  {
>  	spin_lock_init(&xe->eudebug.lock);
>  	INIT_LIST_HEAD(&xe->eudebug.list);
> +	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
>  
>  	xe->eudebug.available = true;
>  }
>  
> +void xe_eudebug_init_late(struct xe_device *xe)
> +{
> +	if (!xe->eudebug.available)
> +		return;
> +
> +	attention_scan_flush(xe);
> +}
> +
>  void xe_eudebug_fini(struct xe_device *xe)
>  {
> +	attention_scan_cancel(xe);
>  	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
>  }
>  
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> index ac89a3d1ee1d..1e233c4683d6 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> @@ -18,6 +18,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>  			     struct drm_file *file);
>  
>  void xe_eudebug_init(struct xe_device *xe);
> +void xe_eudebug_init_late(struct xe_device *xe);
>  void xe_eudebug_fini(struct xe_device *xe);
>  void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
>  
> diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
> index 6e3c23023933..16667b4dfe45 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> @@ -105,6 +105,9 @@ struct xe_eudebug {
>  	/** @discovery_work: worker to discover resources for target_task */
>  	struct work_struct discovery_work;
>  
> +	/** eu_lock: guards operations on eus (eu thread control and attention) */
> +	struct mutex eu_lock;
> +
>  	/** @events: kfifo queue of to-be-delivered events */
>  	struct {
>  		/** @lock: guards access to fifo */
> @@ -202,4 +205,33 @@ struct xe_eudebug_event_exec_queue {
>  	u64 lrc_handle[];
>  };
>  
> +/**
> + * struct xe_eudebug_event_eu_attention - Internal event for EU attention
> + */
> +struct xe_eudebug_event_eu_attention {
> +	/** @base: base event */
> +	struct xe_eudebug_event base;
> +
> +	/** @client_handle: client for the attention */
> +	u64 client_handle;
> +
> +	/** @exec_queue_handle: handle of exec_queue which raised attention */
> +	u64 exec_queue_handle;
> +
> +	/** @lrc_handle: lrc handle of the workload which raised attention */
> +	u64 lrc_handle;
> +
> +	/** @flags: eu attention event flags, currently MBZ */
> +	u32 flags;
> +
> +	/** @bitmask_size: size of the bitmask, specific to device */
> +	u32 bitmask_size;
> +
> +	/**
> +	 * @bitmask: reflects threads currently signalling attention,
> +	 * starting from natural hardware order of DSS=0, eu=0
> +	 */
> +	u8 bitmask[];
> +};
> +
>  #endif
> 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..04d2d43ce249
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_gt_debug.c
> @@ -0,0 +1,152 @@
> +// 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"
> +
> +static int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
> +					    int (*fn)(struct xe_gt *gt,
> +						      void *data,
> +						      u16 group,
> +						      u16 instance),
> +					    void *data)
> +{
> +	const enum xe_force_wake_domains fw_domains = XE_FW_GT | XE_FW_RENDER;
> +	unsigned int dss;
> +	u16 group, instance;
> +	int ret;
> +
> +	xe_pm_runtime_get(gt_to_xe(gt));

Missed this in my previous reply...

This looks pretty dangerous. The 'xe_pm_runtime_get' is designed to
called on the outer most layers. This is an inner layer.

i.e. Calling xe_pm_runtime_get with any locks held is not allowed as it
can wake the device and waking a device takes numerous locks which then
deadlock. What makes this really scary is most times xe_pm_runtime_get
doesn't wake the device, it just increments a counter so we have silent
bug until xe_pm_runtime_get actually wakes the device.

A quick audit shows this is called with d->eu_lock, probably actually
safe in case this but still not a good idea.

I suggest just protecting all of the EU debug code with
xe_pm_runtime_get / xe_pm_runtime_put at the outer most layers (e.g.
workers, IOCTLs already have this built in see xe_drm_ioctl).

Matt

> +	ret = xe_force_wake_get(gt_to_fw(gt), fw_domains);
> +	if (ret)
> +		goto pm_runtime_put;
> +
> +	for_each_dss_steering(dss, gt, group, instance) {
> +		ret = fn(gt, data, group, instance);
> +		if (ret)
> +			break;
> +	}
> +
> +	xe_force_wake_put(gt_to_fw(gt), fw_domains);
> +pm_runtime_put:
> +	xe_pm_runtime_put(gt_to_xe(gt));
> +
> +	return ret;
> +}
> +
> +static int read_first_attention_mcr(struct xe_gt *gt, void *data,
> +				    u16 group, u16 instance)
> +{
> +	unsigned int row;
> +
> +	for (row = 0; row < 2; row++) {
> +		u32 val;
> +
> +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(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);
> +
> +	return  bitmap_weight(dss_mask, XE_MAX_DSS_FUSE_BITS) *
> +		TD_EU_ATTENTION_MAX_ROWS * 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)
> +{
> +	struct attn_read_iter * const iter = data;
> +	unsigned int row;
> +
> +	for (row = 0; row < TD_EU_ATTENTION_MAX_ROWS; row++) {
> +		u32 val;
> +
> +		if (iter->i >= iter->size)
> +			return 0;
> +
> +		XE_WARN_ON(iter->i + sizeof(val) > xe_gt_eu_attention_bitmap_size(gt));
> +
> +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(row), group, instance);
> +
> +
> +		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
> +	};
> +
> +	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..3f13dbb17a5f
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_gt_debug.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#ifndef __XE_GT_DEBUG_
> +#define __XE_GT_DEBUG_
> +
> +#define TD_EU_ATTENTION_MAX_ROWS 2u
> +
> +#include "xe_gt_types.h"
> +
> +#define XE_GT_ATTENTION_TIMEOUT_MS 100
> +
> +int xe_gt_eu_threads_needing_attention(struct xe_gt *gt);
> +
> +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/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> index 25dddb8b22f4..453269ac8307 100644
> --- a/include/uapi/drm/xe_drm_eudebug.h
> +++ b/include/uapi/drm/xe_drm_eudebug.h
> @@ -27,13 +27,15 @@ struct drm_xe_eudebug_event {
>  #define DRM_XE_EUDEBUG_EVENT_OPEN		2
>  #define DRM_XE_EUDEBUG_EVENT_VM			3
>  #define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE		4
> -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
> +#define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
>  
>  	__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)
> +
>  	__u64 seqno;
>  	__u64 reserved;
>  };
> @@ -62,6 +64,17 @@ struct drm_xe_eudebug_event_exec_queue {
>  	__u64 lrc_handle[];
>  };
>  
> +struct drm_xe_eudebug_event_eu_attention {
> +	struct drm_xe_eudebug_event base;
> +
> +	__u64 client_handle;
> +	__u64 exec_queue_handle;
> +	__u64 lrc_handle;
> +	__u32 flags;
> +	__u32 bitmask_size;
> +	__u8 bitmask[];
> +};
> +
>  #if defined(__cplusplus)
>  }
>  #endif
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors
  2024-07-26 14:07 ` [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors Mika Kuoppala
@ 2024-07-27  5:45   ` Matthew Brost
  2024-08-08 11:04   ` Andi Shyti
  1 sibling, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  5:45 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

On Fri, Jul 26, 2024 at 05:07:58PM +0300, Mika Kuoppala wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> 
> Declare hw engine's mmio accessors in header file.
> This is in preparation to use these from eudebug code.
> 
> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> ---
>  drivers/gpu/drm/xe/xe_hw_engine.c | 5 ++---
>  drivers/gpu/drm/xe/xe_hw_engine.h | 5 +++++
>  2 files changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> index 07ed9fd28f19..b8c0cfbf8b49 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> @@ -274,8 +274,7 @@ static void hw_engine_fini(struct drm_device *drm, void *arg)
>  	hwe->gt = NULL;
>  }
>  
> -static void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg,
> -				   u32 val)
> +void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg, u32 val)

Rename this xe_hw_engine_mmio_write32.

>  {
>  	xe_gt_assert(hwe->gt, !(reg.addr & hwe->mmio_base));
>  	xe_force_wake_assert_held(gt_to_fw(hwe->gt), hwe->domain);
> @@ -285,7 +284,7 @@ static void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg,
>  	xe_mmio_write32(hwe->gt, reg, val);
>  }
>  
> -static u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg)
> +u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg)

Rename this xe_hw_engine_mmio_read32.

Matt

>  {
>  	xe_gt_assert(hwe->gt, !(reg.addr & hwe->mmio_base));
>  	xe_force_wake_assert_held(gt_to_fw(hwe->gt), hwe->domain);
> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.h b/drivers/gpu/drm/xe/xe_hw_engine.h
> index 900c8c991430..08c3a9df7154 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.h
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.h
> @@ -62,6 +62,11 @@ void xe_hw_engine_print(struct xe_hw_engine *hwe, struct drm_printer *p);
>  void xe_hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe);
>  
>  bool xe_hw_engine_is_reserved(struct xe_hw_engine *hwe);
> +
> +void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg, u32 val);
> +
> +u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg);
> +
>  static inline bool xe_hw_engine_is_valid(struct xe_hw_engine *hwe)
>  {
>  	return hwe->name;
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup.
  2024-07-26 14:07 ` [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup Mika Kuoppala
@ 2024-07-27  5:49   ` Matthew Brost
  2024-08-08 11:08   ` Andi Shyti
  1 sibling, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-27  5:49 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

On Fri, Jul 26, 2024 at 05:07:59PM +0300, Mika Kuoppala wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> 
> Move and export xe_hw_engine lookup. This is in preparation
> to use this in eudebug code where we want to find active
> engine.
> 
> v2: s/tile/gt due to uapi changes (Mika)
> 
> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>

Feel free to send this independently, immediately with:
Reviewed-by: Matthew Brost <matthew.brost@intel.com>

> ---
>  drivers/gpu/drm/xe/xe_exec_queue.c | 37 ++++--------------------------
>  drivers/gpu/drm/xe/xe_hw_engine.c  | 31 +++++++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_hw_engine.h  |  6 +++++
>  3 files changed, 41 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
> index 69867a7b7c77..956dc15b432a 100644
> --- a/drivers/gpu/drm/xe/xe_exec_queue.c
> +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
> @@ -413,34 +413,6 @@ static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue
>  	return 0;
>  }
>  
> -static const enum xe_engine_class user_to_xe_engine_class[] = {
> -	[DRM_XE_ENGINE_CLASS_RENDER] = XE_ENGINE_CLASS_RENDER,
> -	[DRM_XE_ENGINE_CLASS_COPY] = XE_ENGINE_CLASS_COPY,
> -	[DRM_XE_ENGINE_CLASS_VIDEO_DECODE] = XE_ENGINE_CLASS_VIDEO_DECODE,
> -	[DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE] = XE_ENGINE_CLASS_VIDEO_ENHANCE,
> -	[DRM_XE_ENGINE_CLASS_COMPUTE] = XE_ENGINE_CLASS_COMPUTE,
> -};
> -
> -static struct xe_hw_engine *
> -find_hw_engine(struct xe_device *xe,
> -	       struct drm_xe_engine_class_instance eci)
> -{
> -	u32 idx;
> -
> -	if (eci.engine_class >= ARRAY_SIZE(user_to_xe_engine_class))
> -		return NULL;
> -
> -	if (eci.gt_id >= xe->info.gt_count)
> -		return NULL;
> -
> -	idx = array_index_nospec(eci.engine_class,
> -				 ARRAY_SIZE(user_to_xe_engine_class));
> -
> -	return xe_gt_hw_engine(xe_device_get_gt(xe, eci.gt_id),
> -			       user_to_xe_engine_class[idx],
> -			       eci.engine_instance, true);
> -}
> -
>  static u32 bind_exec_queue_logical_mask(struct xe_device *xe, struct xe_gt *gt,
>  					struct drm_xe_engine_class_instance *eci,
>  					u16 width, u16 num_placements)
> @@ -462,8 +434,7 @@ static u32 bind_exec_queue_logical_mask(struct xe_device *xe, struct xe_gt *gt,
>  		if (xe_hw_engine_is_reserved(hwe))
>  			continue;
>  
> -		if (hwe->class ==
> -		    user_to_xe_engine_class[DRM_XE_ENGINE_CLASS_COPY])
> +		if (hwe->class == XE_ENGINE_CLASS_COPY)
>  			logical_mask |= BIT(hwe->logical_instance);
>  	}
>  
> @@ -492,7 +463,7 @@ static u32 calc_validate_logical_mask(struct xe_device *xe, struct xe_gt *gt,
>  
>  			n = j * width + i;
>  
> -			hwe = find_hw_engine(xe, eci[n]);
> +			hwe = xe_hw_engine_lookup(xe, eci[n]);
>  			if (XE_IOCTL_DBG(xe, !hwe))
>  				return 0;
>  
> @@ -571,7 +542,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
>  			if (XE_IOCTL_DBG(xe, !logical_mask))
>  				return -EINVAL;
>  
> -			hwe = find_hw_engine(xe, eci[0]);
> +			hwe = xe_hw_engine_lookup(xe, eci[0]);
>  			if (XE_IOCTL_DBG(xe, !hwe))
>  				return -EINVAL;
>  
> @@ -608,7 +579,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
>  		if (XE_IOCTL_DBG(xe, !logical_mask))
>  			return -EINVAL;
>  
> -		hwe = find_hw_engine(xe, eci[0]);
> +		hwe = xe_hw_engine_lookup(xe, eci[0]);
>  		if (XE_IOCTL_DBG(xe, !hwe))
>  			return -EINVAL;
>  
> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> index b8c0cfbf8b49..20c4fdf40790 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> @@ -5,7 +5,10 @@
>  
>  #include "xe_hw_engine.h"
>  
> +#include <linux/nospec.h>
> +
>  #include <drm/drm_managed.h>
> +#include <drm/xe_drm.h>
>  
>  #include "regs/xe_engine_regs.h"
>  #include "regs/xe_gt_regs.h"
> @@ -1134,3 +1137,31 @@ enum xe_force_wake_domains xe_hw_engine_to_fw_domain(struct xe_hw_engine *hwe)
>  {
>  	return engine_infos[hwe->engine_id].domain;
>  }
> +
> +static const enum xe_engine_class user_to_xe_engine_class[] = {
> +	[DRM_XE_ENGINE_CLASS_RENDER] = XE_ENGINE_CLASS_RENDER,
> +	[DRM_XE_ENGINE_CLASS_COPY] = XE_ENGINE_CLASS_COPY,
> +	[DRM_XE_ENGINE_CLASS_VIDEO_DECODE] = XE_ENGINE_CLASS_VIDEO_DECODE,
> +	[DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE] = XE_ENGINE_CLASS_VIDEO_ENHANCE,
> +	[DRM_XE_ENGINE_CLASS_COMPUTE] = XE_ENGINE_CLASS_COMPUTE,
> +};
> +
> +struct xe_hw_engine *
> +xe_hw_engine_lookup(struct xe_device *xe,
> +		    struct drm_xe_engine_class_instance eci)
> +{
> +	unsigned int idx;
> +
> +	if (eci.engine_class > ARRAY_SIZE(user_to_xe_engine_class))
> +		return NULL;
> +
> +	if (eci.gt_id >= xe->info.gt_count)
> +		return NULL;
> +
> +	idx = array_index_nospec(eci.engine_class,
> +				 ARRAY_SIZE(user_to_xe_engine_class));
> +
> +	return xe_gt_hw_engine(xe_device_get_gt(xe, eci.gt_id),
> +			       user_to_xe_engine_class[idx],
> +			       eci.engine_instance, true);
> +}
> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.h b/drivers/gpu/drm/xe/xe_hw_engine.h
> index 08c3a9df7154..0383aa7d8e89 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.h
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.h
> @@ -9,6 +9,8 @@
>  #include "xe_hw_engine_types.h"
>  
>  struct drm_printer;
> +struct drm_xe_engine_class_instance;
> +struct xe_device;
>  
>  #ifdef CONFIG_DRM_XE_JOB_TIMEOUT_MIN
>  #define XE_HW_ENGINE_JOB_TIMEOUT_MIN CONFIG_DRM_XE_JOB_TIMEOUT_MIN
> @@ -67,6 +69,10 @@ void hw_engine_mmio_write32(struct xe_hw_engine *hwe, struct xe_reg reg, u32 val
>  
>  u32 hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg);
>  
> +struct xe_hw_engine *
> +xe_hw_engine_lookup(struct xe_device *xe,
> +		    struct drm_xe_engine_class_instance eci);
> +
>  static inline bool xe_hw_engine_is_valid(struct xe_hw_engine *hwe)
>  {
>  	return hwe->name;
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality
  2024-07-26 14:08 ` [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality Mika Kuoppala
@ 2024-07-28  4:50   ` Matthew Brost
  2024-07-30 15:01     ` Manszewski, Christoph
  2024-08-07 10:09     ` Manszewski, Christoph
  0 siblings, 2 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-28  4:50 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Christoph Manszewski, Dominik Grzegorzek,
	Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:17PM +0300, Mika Kuoppala wrote:
> From: Christoph Manszewski <christoph.manszewski@intel.com>
> 
> Make it possible to dynamically enable/disable debugger funtionality,
> including the setting and unsetting of required hw register values via a
> sysfs entry located at '/sys/class/drm/card<X>/device/enable_eudebug'.
> 
> This entry uses 'kstrtobool' and as such it accepts inputs as documented
> by this function, in particular '0' and '1'.
> 
> 1) Adjust to xe_rtp graphics ranges changes.
> 2) Fix pile placement. Wa 14019869343 (aka. 16021232320) was
> added later in the pile, move disablement to appropriate commit.
> 3) flush reset (Christoph)
> 4) dont allow exec queue enable if feature is disabled (Dominik)
> 5) bind to drm sysfs functions (Maciej)
> 
> Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
> 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/xe_device.c       |   2 -
>  drivers/gpu/drm/xe/xe_device_types.h |   5 +
>  drivers/gpu/drm/xe/xe_eudebug.c      | 174 +++++++++++++++++++++++----
>  drivers/gpu/drm/xe/xe_eudebug.h      |   2 -
>  drivers/gpu/drm/xe/xe_exec_queue.c   |   3 +
>  drivers/gpu/drm/xe/xe_hw_engine.c    |   1 -
>  drivers/gpu/drm/xe/xe_reg_sr.c       |  21 +++-
>  drivers/gpu/drm/xe/xe_reg_sr.h       |   4 +-
>  drivers/gpu/drm/xe/xe_rtp.c          |   2 +-
>  drivers/gpu/drm/xe/xe_rtp_types.h    |   1 +
>  10 files changed, 178 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 268faa1800c4..30a2bf2a7e00 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -785,8 +785,6 @@ int xe_device_probe(struct xe_device *xe)
>  
>  	xe_debugfs_register(xe);
>  
> -	xe_eudebug_init_late(xe);
> -
>  	xe_hwmon_register(xe);
>  
>  	for_each_gt(gt, xe, id)
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index beb1f3c8dc63..17aedbba3130 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -517,6 +517,11 @@ struct xe_device {
>  		/** @ordered_wq: used to discovery */
>  		struct workqueue_struct *ordered_wq;
>  
> +		/** @enable_lock: protects the enable toggle */
> +		struct mutex enable_lock;
> +		/** @enable: is the debugging functionality enabled */
> +		bool enable;
> +
>  		/** @attention_scan: attention scan worker */
>  		struct delayed_work attention_scan;
>  	} eudebug;
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index a80ffb64df15..80066f787ec2 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -2000,9 +2000,6 @@ xe_eudebug_connect(struct xe_device *xe,
>  
>  	param->version = DRM_XE_EUDEBUG_VERSION;
>  
> -	if (!xe->eudebug.available)
> -		return -EOPNOTSUPP;
> -
>  	d = kzalloc(sizeof(*d), GFP_KERNEL);
>  	if (!d)
>  		return -ENOMEM;
> @@ -2064,70 +2061,199 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>  	struct drm_xe_eudebug_connect * const param = data;
>  	int ret = 0;
>  
> +	mutex_lock(&xe->eudebug.enable_lock);
> +
> +	if (!xe->eudebug.enable) {
> +		mutex_unlock(&xe->eudebug.enable_lock);
> +		return -ENODEV;
> +	}
> +
>  	ret = xe_eudebug_connect(xe, param);
>  
> +	mutex_unlock(&xe->eudebug.enable_lock);
> +
>  	return ret;
>  }
>  
>  #undef XE_REG_MCR
>  #define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
>  
> -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
> +static void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
>  {
>  	const struct xe_rtp_entry_sr eudebug_was[] = {
> -		{ XE_RTP_NAME("GlobalDebugEnable"),
> -		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
> -			       ENGINE_CLASS(RENDER)),
> -		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
> -				     GLOBAL_DEBUG_ENABLE))
> -		},
>  		{ XE_RTP_NAME("TdCtlDebugEnable"),
>  		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
>  			       FUNC(xe_rtp_match_first_render_or_compute)),
>  		  XE_RTP_ACTIONS(SET(TD_CTL,
>  				     TD_CTL_BREAKPOINT_ENABLE |
>  				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
> -				     TD_CTL_FEH_AND_FEE_ENABLE))
> +				     TD_CTL_FEH_AND_FEE_ENABLE,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>  		},
>  		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
>  		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
>  			       FUNC(xe_rtp_match_first_render_or_compute)),
> -		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
> +		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>  		},
>  		{ XE_RTP_NAME("18022722726"),
>  		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
>  			       FUNC(xe_rtp_match_first_render_or_compute)),
> -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
> +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>  		},
>  		{ XE_RTP_NAME("14015527279"),
>  		  XE_RTP_RULES(PLATFORM(PVC),
>  			       FUNC(xe_rtp_match_first_render_or_compute)),
> -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
> +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>  		},
>  		{}
>  	};
>  	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
> -	struct xe_device *xe = gt_to_xe(hwe->gt);
>  
> -	if (xe->eudebug.available)
> -		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
> +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
> +}
> +
> +static void xe_eudebug_fini_hw_engine(struct xe_hw_engine *hwe)
> +{
> +	const struct xe_rtp_entry_sr eudebug_was[] = {
> +		{ XE_RTP_NAME("TdCtlDebugEnable"),
> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
> +			       FUNC(xe_rtp_match_first_render_or_compute)),
> +		  XE_RTP_ACTIONS(CLR(TD_CTL,
> +				     TD_CTL_BREAKPOINT_ENABLE |
> +				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
> +				     TD_CTL_FEH_AND_FEE_ENABLE,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> +		},
> +		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
> +			       FUNC(xe_rtp_match_first_render_or_compute)),
> +		  XE_RTP_ACTIONS(CLR(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> +		},
> +		{ XE_RTP_NAME("18022722726"),
> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
> +			       FUNC(xe_rtp_match_first_render_or_compute)),
> +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> +		},
> +		{ XE_RTP_NAME("14015527279"),
> +		  XE_RTP_RULES(PLATFORM(PVC),
> +			       FUNC(xe_rtp_match_first_render_or_compute)),
> +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> +		},
> +		{}
> +	};
> +	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
> +
> +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
> +}
> +
> +static int xe_eudebug_enable(struct xe_device *xe, bool enable)
> +{
> +	struct xe_gt *gt;
> +	int i;
> +	u8 id;
> +
> +	if (!xe->eudebug.available)
> +		return -EOPNOTSUPP;
> +
> +	/* XXX: TODO hold list lock? */
> +	mutex_lock(&xe->eudebug.enable_lock);
> +
> +	if (!enable && !list_empty(&xe->eudebug.list)) {
> +		mutex_unlock(&xe->eudebug.enable_lock);
> +		return -EBUSY;
> +	}
> +
> +	if (enable == xe->eudebug.enable) {
> +		mutex_unlock(&xe->eudebug.enable_lock);
> +		return 0;
> +	}
> +
> +	for_each_gt(gt, xe, id) {
> +		for (i = 0; i < ARRAY_SIZE(gt->hw_engines); i++) {
> +			if (!(gt->info.engine_mask & BIT(i)))
> +				continue;
> +
> +			if (enable)
> +				xe_eudebug_init_hw_engine(&gt->hw_engines[i]);
> +			else
> +				xe_eudebug_fini_hw_engine(&gt->hw_engines[i]);
> +		}
> +
> +		xe_gt_reset_async(gt);

What are you trying to accomplish with the reset? Reinit of some HW
settings? Doing GT reset does have a side affect of killing exec queues
with jobs active on the GPU which is not ideal. Please explain exactly
what needs to be done, and maybe we can brainstorm something that won't
kill things.

Also exposing a GT reset via sysfs might be potential security issue
too.

> +		flush_work(&gt->reset.worker);

Flushing the reset worker here creates a lock dependency chain with
xe->eudebug.enable_lock and all locks taken during a GT reset which is
not ideal either. If we need to do a GT reset (or something else with a
worker that takes locks) it probably best to flush the worker after
dropping xe->eudebug.enable_lock. This relates to my other comments on
locking, we shouldn't create lock depeendecy chains unless we have to
and the chains are well defined.

Matt

> +	}
> +
> +	if (enable)
> +		attention_scan_flush(xe);
> +	else
> +		attention_scan_cancel(xe);
> +
> +	xe->eudebug.enable = enable;
> +	mutex_unlock(&xe->eudebug.enable_lock);
> +
> +	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.enable);
> +}
> +
> +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;
> +
> +	sysfs_remove_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
>  }
>  
>  void xe_eudebug_init(struct xe_device *xe)
>  {
> +	struct device *dev = xe->drm.dev;
> +	int ret;
> +
>  	spin_lock_init(&xe->eudebug.lock);
>  	INIT_LIST_HEAD(&xe->eudebug.list);
>  	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
>  
> -	xe->eudebug.available = true;
> -}
> +	drmm_mutex_init(&xe->drm, &xe->eudebug.enable_lock);
> +	xe->eudebug.enable = false;
>  
> -void xe_eudebug_init_late(struct xe_device *xe)
> -{
> -	if (!xe->eudebug.available)
> -		return;
>  
> -	attention_scan_flush(xe);
> +	ret = sysfs_create_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
> +	if (ret)
> +		drm_warn(&xe->drm, "eudebug sysfs init failed: %d, debugger unavailable\n", ret);
> +	else
> +		devm_add_action_or_reset(dev, xe_eudebug_sysfs_fini, xe);
> +
> +	xe->eudebug.available = ret == 0;
>  }
>  
>  void xe_eudebug_fini(struct xe_device *xe)
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> index 02c9ba56e752..2f66aa87a0f6 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.h
> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> @@ -24,9 +24,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>  			     struct drm_file *file);
>  
>  void xe_eudebug_init(struct xe_device *xe);
> -void xe_eudebug_init_late(struct xe_device *xe);
>  void xe_eudebug_fini(struct xe_device *xe);
> -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
>  
>  void xe_eudebug_file_open(struct xe_file *xef);
>  void xe_eudebug_file_close(struct xe_file *xef);
> diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
> index bc2edade5e5b..b6fc65ab8aa9 100644
> --- a/drivers/gpu/drm/xe/xe_exec_queue.c
> +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
> @@ -360,6 +360,9 @@ static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
>  			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
>  		return -EINVAL;
>  
> +	if (XE_IOCTL_DBG(xe, !xe->eudebug.enable))
> +		return -EPERM;
> +
>  	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
>  
>  	return 0;
> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> index 74813bc20787..0f90416be0ba 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> @@ -504,7 +504,6 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
>  	xe_tuning_process_engine(hwe);
>  	xe_wa_process_engine(hwe);
>  	hw_engine_setup_default_state(hwe);
> -	xe_eudebug_init_hw_engine(hwe);
>  
>  	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
>  	xe_reg_whitelist_process_engine(hwe);
> diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
> index 440ac572f6e5..a7671722a84e 100644
> --- a/drivers/gpu/drm/xe/xe_reg_sr.c
> +++ b/drivers/gpu/drm/xe/xe_reg_sr.c
> @@ -92,22 +92,31 @@ static void reg_sr_inc_error(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);
>  	int ret;
>  
>  	if (pentry) {
> -		if (!compatible_entries(pentry, e)) {
> +		if (overwrite && e->set_bits) {
> +			pentry->clr_bits |= e->clr_bits;
> +			pentry->set_bits |= e->set_bits;
> +			pentry->read_mask |= e->read_mask;
> +		} else if (overwrite && !e->set_bits) {
> +			pentry->clr_bits |= e->clr_bits;
> +			pentry->set_bits &= ~e->clr_bits;
> +			pentry->read_mask |= e->read_mask;
> +		} else if (!compatible_entries(pentry, e)) {
>  			ret = -EINVAL;
>  			goto fail;
> +		} else {
> +			pentry->clr_bits |= e->clr_bits;
> +			pentry->set_bits |= e->set_bits;
> +			pentry->read_mask |= e->read_mask;
>  		}
>  
> -		pentry->clr_bits |= e->clr_bits;
> -		pentry->set_bits |= e->set_bits;
> -		pentry->read_mask |= e->read_mask;
> -
>  		return 0;
>  	}
>  
> diff --git a/drivers/gpu/drm/xe/xe_reg_sr.h b/drivers/gpu/drm/xe/xe_reg_sr.h
> index 51fbba423e27..d67fafdcd847 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_
>  #define _XE_REG_SR_
>  
> +#include <linux/types.h>
> +
>  /*
>   * Reg save/restore bookkeeping
>   */
> @@ -21,7 +23,7 @@ int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe)
>  void xe_reg_sr_dump(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_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
> index 02e28274282f..5643bcde52bd 100644
> --- a/drivers/gpu/drm/xe/xe_rtp.c
> +++ b/drivers/gpu/drm/xe/xe_rtp.c
> @@ -153,7 +153,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, action->flags & XE_RTP_ACTION_FLAG_OVERWRITE);
>  }
>  
>  static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry,
> diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h
> index 1b76b947c706..20d228067da3 100644
> --- a/drivers/gpu/drm/xe/xe_rtp_types.h
> +++ b/drivers/gpu/drm/xe/xe_rtp_types.h
> @@ -33,6 +33,7 @@ struct xe_rtp_action {
>  	/** @read_mask: mask for bits to consider when reading value back */
>  	u32			read_mask;
>  #define XE_RTP_ACTION_FLAG_ENGINE_BASE		BIT(0)
> +#define XE_RTP_ACTION_FLAG_OVERWRITE		BIT(1)
>  	/** @flags: flags to apply on rule evaluation or action */
>  	u8			flags;
>  };
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 00/21] GPU debug support (eudebug)
  2024-07-27  5:23 ` [PATCH 00/21] " Matthew Brost
@ 2024-07-29  8:27   ` Gwan-gyeong Mun
  0 siblings, 0 replies; 78+ messages in thread
From: Gwan-gyeong Mun @ 2024-07-29  8:27 UTC (permalink / raw)
  To: Matthew Brost, Mika Kuoppala, jonathan.cavitt, Joonas Lahtinen,
	Grzegorzek, Dominik
  Cc: intel-xe



On 7/27/24 8:23 AM, Matthew Brost wrote:
> On Fri, Jul 26, 2024 at 05:07:57PM +0300, Mika Kuoppala wrote:
>> Hi,
>>
>> We (Intel eudebug kernel team) would like to submit this
>> patchset to enable debug support for Intel GPU devices.
>>
>> The aim is to allow Level-Zero + GDB (or some other tool)
>> to attach to xe driver in order to receive information
>> about relevant driver resources, hardware events and to allow debug
>> related hardware control. End goal is full debug capability
>> of supported Intel hardware, see [4].
>>
>> Debugger first opens a connection to a device through
>> drm ioctl with debug target process as a pid. This will
>> return a dedicated file descriptor used for debugging
>> for further events and control.
>>
>> Xe internal resources that are considered essential
>> to debugger functionality are relayed as events to the
>> debugger. On debugger connection, all existing resources
>> are relayed to debugger (discovery) and from that
>> point onwards, as they are created/destroyed.
>>
>> uapi is extended to allow an application/lib to provide
>> debug metadata information. These are relayed as events
>> to the debugger so it can decode the program state.
>>
>> Along with the resource and metadata events, an event for
>> hardware exceptions, called EU attention, is provided.
>> The debugger, with the assistance of an exception handling
>> program called System Routine (short: SIP) provided
>> with the pipeline setup, can determine which specific
>> EU/thread and instruction encountered the breakpoint
>> or other exceptions.
>>
>> EU controlling ioctl interface is also introduced where
>> debugger can manipulate individual threads of the currently
>> active workload. This interface enables the debugger to
>> interrupt all threads on demand, check their current state
>> and resume them individually.
>>
>> The intent is to provide a similar but not API compatible
>> functionality as in out-of-tree i915 debugger support:
>> https://dgpu-docs.intel.com/driver/gpu-debugging.html
>>
>> For xe the aim is to have all support merged in upstream,
>> starting with this series. With Lunarlake being first targetted
>> hardware.
>>
>> I have split the events into xe_drm_eudebug.h instead
>> pushing everything into xe_drm.h, in order to help
>> distinguish what is controlled by which descriptor.
>> If it's through the original xe fd, it is in xe_drm.h and
>> if it's through the opened debugger connection fd, it
>> is in xe_drm_eudebug.h.
>>
> 
> Looking through the series, I do have question wrt to GPU fault and
> eudebug. I don't see any interaction there. Without knowing eudebug
> works, it seems like setting a break point on a GPU access to virtual
> address is something a debugger would want. On a faulting device, this
> is something we should be able to support. This really comes into play
> once we have SVM as the UMD won't be issuing binds either. Curious about
> your thoughts here.
> 
> If this something that required, in particular with SVM, this something
> the SVM and eudebug teams need to collaborate on early to make sure both
> designs work with each other.
> 
Hi Matt,

Here's a quick scenario of what I understand to happen when a breakpoint 
is set on an EU thread.

The breakpoint behavior of eudebug is that if the breakpoint bit is on 
for an EU instruction, the EU thread will jump from AIP to SIP mode with 
a breakpoint exception before that instruction is executed.
The SIP shader can load/store the ARF (and GRF) registers of the EU 
thread, including the AIP of the EU thread, in memory that communicates 
with the debugger.
And when the SIP shader of the EU thread executes the sync.host 
instruction, it sets the bit of the corresponding thread in the TD_ATT 
(MMIOed) register and the eu thread stops.
The KMD periodically checks the TD_ATT register and notifies the debug UMD.
To resume the EU thread, simply unset the set bit of TD_ATT.
When debug UMD sends the eu thread resume event to the KMD, the KMD 
unsets the TD_ATT register.

It is my understanding that this EU thread breakpoint scenario does not 
conflict with the recoverable pagefault behavior scenario used by (HMM 
based)SVM, and that they can work together without any additional design 
changes.

Apart from this, the unrecoverable pagefault that occurs when an EU 
thread accesses an unallocated PPGTT virtual address requires additional 
implementation.

Mika, Joonas, Dominik, Jonathan, if I misunderstand/missed something or 
have any additional thoughts, could you please share your thought?

Br,

G.G.
> Matt
> 
>> Latest code can be found in:
>> [1] https://gitlab.freedesktop.org/miku/kernel/-/tree/eudebug-dev
>>
>> With the associated IGT tests:
>> [2] https://gitlab.freedesktop.org/cmanszew/igt-gpu-tools/-/tree/eudebug-dev
>>
>> The user for this uapi:
>> [3] https://github.com/intel/compute-runtime
>> Event loop and thread control interaction can be found at:
>> https://github.com/intel/compute-runtime/tree/master/level_zero/tools/source/debug/linux/xe
>> And the wrappers in:
>> https://github.com/intel/compute-runtime/tree/master/shared/source/os_interface/linux/xe
>> https://github.com/intel/compute-runtime/blob/master/shared/source/os_interface/linux/xe/ioctl_helper_xe_debugger.cpp
>> Note that the XE support is disabled by default and you will need
>> NEO_ENABLE_XE_EU_DEBUG_SUPPORT enabled in order to test.
>>
>> GDB support:
>> [4]: https://sourceware.org/pipermail/gdb-patches/2024-July/210264.html
>>
>> Thank you in advance for any comments and insight.
>>
>>
>> Andrzej Hajda (1):
>>    drm/xe/eudebug: implement userptr_vma access
>>
>> Christoph Manszewski (3):
>>    drm/xe/eudebug: Add vm bind and vm bind ops
>>    drm/xe/eudebug: Dynamically toggle debugger functionality
>>    drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test
>>
>> Dominik Grzegorzek (10):
>>    drm/xe: Export xe_hw_engine's mmio accessors
>>    drm/xe: Move and export xe_hw_engine lookup.
>>    drm/xe/eudebug: Introduce exec_queue events
>>    drm/xe/eudebug: hw enablement for eudebug
>>    drm/xe: Add EUDEBUG_ENABLE exec queue property
>>    drm/xe/eudebug: Introduce per device attention scan worker
>>    drm/xe/eudebug: Introduce EU control interface
>>    drm/xe: Debug metadata create/destroy ioctls
>>    drm/xe: Attach debug metadata to vma
>>    drm/xe/eudebug: Add debug metadata support for xe_eudebug
>>
>> Jonathan Cavitt (1):
>>    drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach
>>
>> Mika Kuoppala (6):
>>    drm/xe/eudebug: Introduce eudebug support
>>    kernel: export ptrace_may_access
>>    drm/xe/eudebug: Introduce discovery for resources
>>    drm/xe/eudebug: Add UFENCE events with acks
>>    drm/xe/eudebug: vm open/pread/pwrite
>>    drm/xe/eudebug: Implement vm_bind_op discovery
>>
>>   drivers/gpu/drm/xe/Makefile                  |    5 +-
>>   drivers/gpu/drm/xe/regs/xe_engine_regs.h     |    8 +
>>   drivers/gpu/drm/xe/regs/xe_gt_regs.h         |   43 +
>>   drivers/gpu/drm/xe/tests/xe_eudebug.c        |  170 +
>>   drivers/gpu/drm/xe/tests/xe_live_test_mod.c  |    2 +
>>   drivers/gpu/drm/xe/xe_debug_metadata.c       |  125 +
>>   drivers/gpu/drm/xe/xe_debug_metadata.h       |   25 +
>>   drivers/gpu/drm/xe/xe_debug_metadata_types.h |   28 +
>>   drivers/gpu/drm/xe/xe_device.c               |   47 +-
>>   drivers/gpu/drm/xe/xe_device_types.h         |   45 +
>>   drivers/gpu/drm/xe/xe_eudebug.c              | 3841 ++++++++++++++++++
>>   drivers/gpu/drm/xe/xe_eudebug.h              |   51 +
>>   drivers/gpu/drm/xe/xe_eudebug_types.h        |  326 ++
>>   drivers/gpu/drm/xe/xe_exec.c                 |    2 +-
>>   drivers/gpu/drm/xe/xe_exec_queue.c           |   80 +-
>>   drivers/gpu/drm/xe/xe_exec_queue_types.h     |    7 +
>>   drivers/gpu/drm/xe/xe_gt_debug.c             |  152 +
>>   drivers/gpu/drm/xe/xe_gt_debug.h             |   27 +
>>   drivers/gpu/drm/xe/xe_hw_engine.c            |   39 +-
>>   drivers/gpu/drm/xe/xe_hw_engine.h            |   11 +
>>   drivers/gpu/drm/xe/xe_lrc.c                  |   16 +-
>>   drivers/gpu/drm/xe/xe_lrc.h                  |    4 +-
>>   drivers/gpu/drm/xe/xe_reg_sr.c               |   21 +-
>>   drivers/gpu/drm/xe/xe_reg_sr.h               |    4 +-
>>   drivers/gpu/drm/xe/xe_rtp.c                  |    2 +-
>>   drivers/gpu/drm/xe/xe_rtp_types.h            |    1 +
>>   drivers/gpu/drm/xe/xe_sync.c                 |   49 +-
>>   drivers/gpu/drm/xe/xe_sync.h                 |    8 +-
>>   drivers/gpu/drm/xe/xe_sync_types.h           |   26 +-
>>   drivers/gpu/drm/xe/xe_vm.c                   |  227 +-
>>   drivers/gpu/drm/xe/xe_vm_types.h             |   26 +
>>   include/uapi/drm/xe_drm.h                    |   96 +-
>>   include/uapi/drm/xe_drm_eudebug.h            |  226 ++
>>   kernel/ptrace.c                              |    1 +
>>   34 files changed, 5655 insertions(+), 86 deletions(-)
>>   create mode 100644 drivers/gpu/drm/xe/tests/xe_eudebug.c
>>   create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.c
>>   create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata.h
>>   create mode 100644 drivers/gpu/drm/xe/xe_debug_metadata_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_types.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 include/uapi/drm/xe_drm_eudebug.h
>>
>> -- 
>> 2.34.1
>>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker
  2024-07-27  5:08   ` Matthew Brost
@ 2024-07-29 10:10     ` Grzegorzek, Dominik
  2024-07-31  1:25       ` Matthew Brost
  0 siblings, 1 reply; 78+ messages in thread
From: Grzegorzek, Dominik @ 2024-07-29 10:10 UTC (permalink / raw)
  To: mika.kuoppala@linux.intel.com, Brost, Matthew
  Cc: intel-xe@lists.freedesktop.org, Patelczyk, Maciej,
	Manszewski, Christoph

/On Sat, 2024-07-27 at 05:08 +0000, Matthew Brost wrote:
> On Fri, Jul 26, 2024 at 05:08:07PM +0300, Mika Kuoppala wrote:
> > 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 10 times slower when there is no debugger
> > connection open. Send attention event whenever we see attention with
> > debugger presence. If there is no debugger connection active - reset.
> > 
> > Based on work by authors and other folks who were part of attentions in
> > i915.
> > 
> > - v2 Do not validate potentially active hwe against engine->hwe.
> >   Whenever the engine has width > 1, this field contains only the first
> >   hwe of the class.
> > - squash dss walking and semaphore to mutex
> > - v3 error path fix in xe_send_gt_attention (Christoph)
> > - v4 runalone active fix (Mika)
> > - v5 q->lrc changes (Mika)
> > - v6 Use C99 flexible arrays (Maciej, checkpatch)
> >      function with 'for_each' in name (Maciej, checkpatch)
> > - v7 long running active fix (Dominik)
> > - v8 resource handling errors rebase (Mika)
> > - v9 find out lrc handles first before sending event (Mika)
> > - v10 adjust runalone shift according to hw
> > 
> > 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>
> > ---
> >  drivers/gpu/drm/xe/Makefile              |   1 +
> >  drivers/gpu/drm/xe/regs/xe_engine_regs.h |   3 +
> >  drivers/gpu/drm/xe/regs/xe_gt_regs.h     |   7 +
> >  drivers/gpu/drm/xe/xe_device.c           |   2 +
> >  drivers/gpu/drm/xe/xe_device_types.h     |   3 +
> >  drivers/gpu/drm/xe/xe_eudebug.c          | 389 ++++++++++++++++++++++-
> >  drivers/gpu/drm/xe/xe_eudebug.h          |   1 +
> >  drivers/gpu/drm/xe/xe_eudebug_types.h    |  32 ++
> >  drivers/gpu/drm/xe/xe_gt_debug.c         | 152 +++++++++
> >  drivers/gpu/drm/xe/xe_gt_debug.h         |  21 ++
> >  include/uapi/drm/xe_drm_eudebug.h        |  15 +-
> >  11 files changed, 624 insertions(+), 2 deletions(-)
> >  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 06badc5f99af..b7b6b047c02c 100644
> > --- a/drivers/gpu/drm/xe/Makefile
> > +++ b/drivers/gpu/drm/xe/Makefile
> > @@ -49,6 +49,7 @@ xe-y += xe_bb.o \
> >  	xe_gt_debugfs.o \
> >  	xe_gt_freq.o \
> >  	xe_gt_idle.o \
> > +	xe_gt_debug.o \
> >  	xe_gt_mcr.o \
> >  	xe_gt_pagefault.o \
> >  	xe_gt_sysfs.o \
> > diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > index 764c270599d0..b9d713a2061d 100644
> > --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > @@ -132,6 +132,9 @@
> >  #define RING_EXECLIST_STATUS_LO(base)		XE_REG((base) + 0x234)
> >  #define RING_EXECLIST_STATUS_HI(base)		XE_REG((base) + 0x234 + 4)
> >  
> > +#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_OAC_CONTEXT_ENABLE		REG_BIT(8)
> >  #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
> > diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > index 96a59a96dd4c..03e83ce3e35d 100644
> > --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > @@ -437,6 +437,8 @@
> >  #define   DISABLE_ECC				REG_BIT(5)
> >  #define   ENABLE_PREFETCH_INTO_IC		REG_BIT(3)
> >  
> > +#define TD_ATT(x)				XE_REG_MCR(0xe470 + (x) * 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)
> > @@ -516,6 +518,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 FORCEWAKE_ACK_GT			XE_REG(0x130044)
> >  
> >  /* Applicable for all FORCEWAKE_DOMAIN and FORCEWAKE_ACK_DOMAIN regs */
> > diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> > index 90bb0a8b1881..ba1c80089906 100644
> > --- a/drivers/gpu/drm/xe/xe_device.c
> > +++ b/drivers/gpu/drm/xe/xe_device.c
> > @@ -768,6 +768,8 @@ int xe_device_probe(struct xe_device *xe)
> >  
> >  	xe_debugfs_register(xe);
> >  
> > +	xe_eudebug_init_late(xe);
> > +
> >  	xe_hwmon_register(xe);
> >  
> >  	for_each_gt(gt, xe, id)
> > diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> > index 4dcfd39cb909..3b33add576be 100644
> > --- a/drivers/gpu/drm/xe/xe_device_types.h
> > +++ b/drivers/gpu/drm/xe/xe_device_types.h
> > @@ -516,6 +516,9 @@ struct xe_device {
> >  
> >  		/** @ordered_wq: used to discovery */
> >  		struct workqueue_struct *ordered_wq;
> > +
> > +		/** @attention_scan: attention scan worker */
> > +		struct delayed_work attention_scan;
> >  	} eudebug;
> >  
> >  	/* private: */
> > diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> > index 9611acedeee9..c2de001cc33a 100644
> > --- a/drivers/gpu/drm/xe/xe_eudebug.c
> > +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> > @@ -11,19 +11,29 @@
> >  
> >  #include <drm/drm_managed.h>
> >  
> > -#include "regs/xe_gt_regs.h"
> >  #include "regs/xe_engine_regs.h"
> > +#include "regs/xe_gt_regs.h"
> >  #include "xe_device.h"
> >  #include "xe_assert.h"
> >  #include "xe_macros.h"
> >  #include "xe_gt.h"
> > +#include "xe_gt_debug.h"
> > +#include "xe_lrc.h"
> > +#include "xe_hw_engine.h"
> > +#include "xe_exec_queue.h"
> >  #include "xe_eudebug_types.h"
> >  #include "xe_eudebug.h"
> >  #include "xe_exec_queue_types.h"
> > +#include "xe_guc_exec_queue_types.h"
> > +#include "xe_execlist_types.h"
> > +#include "xe_mmio.h"
> >  #include "xe_module.h"
> > +#include "xe_pm.h"
> >  #include "xe_rtp.h"
> > +#include "xe_sched_job.h"
> >  #include "xe_vm.h"
> >  #include "xe_wa.h"
> > +#include "xe_force_wake.h"
> >  
> >  /*
> >   * If there is no detected event read by userspace, during this period, assume
> > @@ -843,6 +853,371 @@ static const struct file_operations fops = {
> >  	.unlocked_ioctl	= xe_eudebug_ioctl,
> >  };
> >  
> > +static bool queue_has_active_job(struct xe_exec_queue *q)
> 
> This should probably be a generic function in xe_exec_queue.c. We seemly
> already have one - xe_exec_queue_is_idle.
> 
> > +{
> > +
> > +	struct drm_gpu_scheduler *sched;
> > +	struct drm_sched_job *drm_job;
> > +
> > +	if (xe_device_uc_enabled(gt_to_xe(q->gt)))
> 
> General comment, we likely don't want to the EU debugger enabled unless
> GuC submission is enabled as the execlist backend really doesn't work. 
> 
> > +		sched = &q->guc->sched.base;
> > +	else
> > +		sched = &q->execlist->sched;
> > +
> > +	drm_job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list);
> 
> Random musing that don't apply as we have xe_exec_queue_is_idle but...
> 
> You need a scheduler lock here which is missing. If you wanted to see
> the scheduler pending list was not empty, we'd call into the drm
> scheduler layer.
> 
> That being said, I think the EU debugger only support LR VMs? If so,
> then this always going to be empty.
Up until now, we were not requiring a VM to be in lr mode, thus I wanted to support both paths.
However, we do depend on LR mode, as job timeouts would make debugging effectively ineffective.
Therefore, we should add this constraint.

Thanks for your comments! I will reuse xe_exec_queue_is_idle here as proposed, and I will try to
follow your hints with respect to locking and forcewake.

Regards,
Dominik
> 
> > +
> > +	if (drm_job) {
> > +		struct xe_sched_job *job = to_xe_sched_job(drm_job);
> > +
> > +		return xe_sched_job_started(job) && !xe_sched_job_completed(job);
> > +	} else if (xe_exec_queue_is_lr(q) &&
> > +		   (xe_lrc_ring_head(q->lrc[0]) != xe_lrc_ring_tail(q->lrc[0]))) {
> > +		return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +static int current_lrc(struct xe_hw_engine *hwe, u32 *lrc_hw)
> > +{
> > +	u32 lrc_reg;
> > +	int err;
> > +
> > +	err = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
> > +	if (err)
> > +		return err;
> > +
> > +	lrc_reg = hw_engine_mmio_read32(hwe, RING_CURRENT_LRCA(0));
> > +
> > +	xe_force_wake_put(gt_to_fw(hwe->gt), hwe->domain);
> > +
> > +	if (!(lrc_reg & CURRENT_LRCA_VALID))
> > +		return -ENOENT;
> > +
> > +	*lrc_hw = lrc_reg & GENMASK(31, 12);
> > +
> > +	return 0;
> > +}
> > +
> > +static int match_engine_lrc(struct xe_exec_queue *q, u32 lrc_hw)
> > +{
> > +	int i;
> > +	u32 lrc_ggtt;
> > +
> > +	for (i = 0; i < q->width; i++) {
> > +		lrc_ggtt = lower_32_bits(xe_lrc_descriptor(q->lrc[i]));
> > +		lrc_ggtt &= GENMASK(31, 12);
> > +		if (lrc_ggtt == lrc_hw)
> > +			return i;
> > +	}
> > +
> > +	return -1;
> > +}
> > +
> > +static u32 engine_status(const struct xe_hw_engine * const hwe,
> > +			 u32 rcu_debug1)
> > +{
> > +	const bool xe1 = GRAPHICS_VER(gt_to_xe(hwe->gt)) < 20;
> > +	unsigned int shift;
> > +
> > +	if (hwe->class == XE_ENGINE_CLASS_RENDER) {
> > +		shift = 7;
> > +		XE_WARN_ON(hwe->instance != 0);
> > +	} else if (hwe->class == XE_ENGINE_CLASS_COMPUTE) {
> > +		XE_WARN_ON(hwe->instance > 3);
> > +
> > +		if (xe1)
> > +			shift = 10 + (hwe->instance * 3);
> > +		else
> > +			shift = 11 + (hwe->instance * 4);
> > +	} else {
> > +		XE_WARN_ON(hwe->class);
> > +		return 0;
> > +	}
> > +
> > +	return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
> > +}
> > +
> > +static bool engine_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_context_set(const struct xe_hw_engine * const hwe,
> > +			       u32 rcu_debug1)
> > +{
> > +	return engine_status(hwe, rcu_debug1) & RCU_DEBUG_1_CONTEXT_ACTIVE;
> > +}
> > +
> > +static bool engine_has_runalone(const struct xe_hw_engine * const hwe)
> > +{
> > +	return hwe->class == XE_ENGINE_CLASS_RENDER ||
> > +		hwe->class == XE_ENGINE_CLASS_COMPUTE;
> > +}
> > +
> > +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;
> > +	u32 val;
> > +
> > +	if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GT)) {
> > +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone failed to get force wake\n");
> > +		return NULL;
> > +	}
> > +
> > +	val = xe_mmio_read32(gt, RCU_DEBUG_1);
> > +	xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
> > +
> > +	drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone RCU_DEBUG_1 = 0x%08x\n", val);
> > +
> > +	num_active = 0;
> > +	for_each_hw_engine(hwe, gt, id) {
> > +		bool runalone, ctx;
> > +
> > +		if (!engine_has_runalone(hwe))
> > +			continue;
> > +
> > +		runalone = engine_runalone_set(hwe, val);
> > +		ctx = engine_context_set(hwe, val);
> > +
> > +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: engine %s: runalone=%s, context=%s",
> > +			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(&gt_to_xe(gt)->drm, "eudbg: runalone engine %s %s",
> > +				hwe->name, first ? "selected" : "found");
> > +			if (!first)
> > +				first = hwe;
> > +		}
> > +	}
> > +
> > +	if (num_active > 1)
> > +		drm_err(&gt_to_xe(gt)->drm, "eudbg: %d runalone engines active!",
> > +			num_active);
> > +
> > +	return first;
> > +}
> > +
> > +static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
> > +{
> > +	struct xe_device *xe = gt_to_xe(gt);
> > +	struct xe_exec_queue *q, *found = NULL;
> > +	struct xe_hw_engine *active;
> > +	struct xe_file *xef, *tmp;
> > +	unsigned long i;
> > +	int idx, err;
> > +	u32 lrc_hw;
> > +
> > +	active = get_runalone_active_hw_engine(gt);
> > +	if (!active) {
> > +		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
> > +		return ERR_PTR(-ENOENT);
> > +	}
> > +
> > +	err = current_lrc(active, &lrc_hw);
> > +	if (err)
> > +		return ERR_PTR(err);
> > +
> > +	mutex_lock(&xe->files.lock);
> > +	list_for_each_entry_safe(xef, tmp, &xe->files.list, link) {
> > +		mutex_lock(&xef->exec_queue.lock);
> > +		xa_for_each(&xef->exec_queue.xa, i, q) {
> 
> Same comment here as [1]. Don't hold xe->files.lock or
> xef->exec_queue.lock for anything but the lookup. Holding locks longer
> than needed creates unwanted lock dep chains which creates all sorts of
> problems. The only time chains should exist is when we have well defined
> locking chain like we have for a VM (vm->lock -> dma-resv -> notifier
> lock).
> 
> So this should look something like this:
> 
> mutex_lock(&xe->files.lock);
> xa_for_each(.., xef) {
> 	xe_file_get(xef);
> 	mutex_unlock(&xe->files.lock);
> 
> 	mutex_lock(&xef->exec_queue.lock);
> 	xa_for_each(&xef->exec_queue.xa, i, q) {
> 		xe_exec_queue_get(q);
> 		mutex_unlock(&xef->exec_queue.lock);
> 
> 		/* Do something */
> 	
> 		xe_exec_queue_put(q);
> 		mutex_lock(&xef->exec_queue.lock);
> 	}
> 	mutex_unlock(&xef->exec_queue.lock);
> 	
> 	xe_file_put(xef);
> 	mutex_lock(&xe->files.lock);
> }
> mutex_unlock(&xe->files.lock);
> 
> Note you will need to change xe->files.list to an xarray to make this
> safe too.
> 
> Matt
> 
> [1] https://patchwork.freedesktop.org/patch/606052/?series=136572&rev=1
> 
> > +			if (q->gt != gt)
> > +				continue;
> > +
> > +			if (q->class != active->class)
> > +				continue;
> > +
> > +			if (!queue_has_active_job(q))
> > +				continue;
> > +
> > +			idx = match_engine_lrc(q, lrc_hw);
> > +			if (idx < 0)
> > +				continue;
> > +
> > +			xe_exec_queue_get(q);
> > +			found = q;
> > +
> > +			if (lrc_idx)
> > +				*lrc_idx = idx;
> > +
> > +			break;
> > +		}
> > +		mutex_unlock(&xef->exec_queue.lock);
> > +
> > +		if (found)
> > +			break;
> > +	}
> > +	mutex_unlock(&xe->files.lock);
> > +
> > +	if (!found)
> > +		return ERR_PTR(-ENOENT);
> > +
> > +	if (XE_WARN_ON(current_lrc(active, &lrc_hw)) &&
> > +	    XE_WARN_ON(match_engine_lrc(found, lrc_hw) < 0)) {
> > +		xe_exec_queue_put(found);
> > +		return ERR_PTR(-ENOENT);
> > +	}
> > +
> > +	return found;
> > +}
> > +
> > +static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, int lrc_idx)
> > +{
> > +	struct xe_eudebug_event_eu_attention *ea;
> > +	struct xe_eudebug_event *event;
> > +	int h_c, h_queue, h_lrc;
> > +	u32 size = xe_gt_eu_attention_bitmap_size(q->gt);
> > +	u32 sz = struct_size(ea, bitmask, size);
> > +	int ret;
> > +
> > +	XE_WARN_ON(lrc_idx < 0 || lrc_idx >= q->width);
> > +
> > +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, q->vm->xef);
> > +	if (h_c < 0)
> > +		return h_c;
> > +
> > +	h_queue = find_handle(d->res, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q);
> > +	if (h_queue < 0)
> > +		return h_queue;
> > +
> > +	h_lrc = find_handle(d->res, XE_EUDEBUG_RES_TYPE_LRC, q->lrc[lrc_idx]);
> > +	if (h_lrc < 0)
> > +		return h_lrc;
> > +
> > +	event = __xe_eudebug_create_event(d, 0, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
> > +					  DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, sz, GFP_KERNEL);
> > +
> > +	if (!event)
> > +		return -ENOSPC;
> > +
> > +	ea = cast_event(ea, event);
> > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, client_handle, (u64)h_c);
> > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, exec_queue_handle, (u64)h_queue);
> > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, lrc_handle, (u64)h_lrc);
> > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, bitmask_size, size);
> > +
> > +	mutex_lock(&d->eu_lock);
> > +	event->seqno = atomic_long_inc_return(&d->events.seqno);
> > +	ret = xe_gt_eu_attention_bitmap(q->gt, &ea->bitmask[0], ea->bitmask_size);
> > +	mutex_unlock(&d->eu_lock);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return xe_eudebug_queue_event(d, event);
> > +}
> > +
> > +
> > +static int xe_send_gt_attention(struct xe_gt *gt)
> > +{
> > +	struct xe_eudebug *d;
> > +	struct xe_exec_queue *q;
> > +	int ret, lrc_idx;
> > +
> > +	if (list_empty_careful(&gt_to_xe(gt)->eudebug.list))
> > +		return -ENOTCONN;
> > +
> > +	q = runalone_active_queue_get(gt, &lrc_idx);
> > +	if (IS_ERR(q))
> > +		return PTR_ERR(q);
> > +
> > +	d = xe_eudebug_get(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);
> > +	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)
> > +{
> > +	int ret;
> > +
> > +	ret = xe_gt_eu_threads_needing_attention(gt);
> > +	if (ret <= 0)
> > +		return ret;
> > +
> > +	ret = xe_send_gt_attention(gt);
> > +
> > +	/* Discovery in progress, fake it */
> > +	if (ret == -EBUSY)
> > +		return 0;
> > +
> > +	return ret;
> > +}
> > +
> > +#define XE_EUDEBUG_ATTENTION_INTERVAL 100
> > +static void attention_scan_fn(struct work_struct *work)
> > +{
> > +	struct xe_device *xe = container_of(work, typeof(*xe), eudebug.attention_scan.work);
> > +	long delay = msecs_to_jiffies(XE_EUDEBUG_ATTENTION_INTERVAL);
> > +	struct xe_gt *gt;
> > +	u8 gt_id;
> > +
> > +	if (list_empty_careful(&xe->eudebug.list))
> > +		delay *= 10;
> > +
> > +	if (delay >= HZ)
> > +		delay = round_jiffies_up_relative(delay);
> > +
> > +	if (pm_runtime_active(xe->drm.dev)) {
> > +		for_each_gt(gt, xe, gt_id) {
> > +			int ret;
> > +
> > +			ret = xe_eudebug_handle_gt_attention(gt);
> > +			if (ret) {
> > +				// TODO: error capture
> > +				drm_info(&gt_to_xe(gt)->drm,
> > +					 "gt:%d unable to handle eu attention ret=%d\n",
> > +					 gt_id, ret);
> > +
> > +				xe_gt_reset_async(gt);
> > +			}
> > +		}
> > +	}
> > +
> > +	schedule_delayed_work(&xe->eudebug.attention_scan, delay);
> > +}
> > +
> > +static void attention_scan_cancel(struct xe_device *xe)
> > +{
> > +	cancel_delayed_work_sync(&xe->eudebug.attention_scan);
> > +}
> > +
> > +static void attention_scan_flush(struct xe_device *xe)
> > +{
> > +	mod_delayed_work(system_wq, &xe->eudebug.attention_scan, 0);
> > +}
> > +
> >  static void discovery_work_fn(struct work_struct *work);
> >  
> >  static int
> > @@ -877,6 +1252,7 @@ xe_eudebug_connect(struct xe_device *xe,
> >  
> >  	kref_init(&d->ref);
> >  	spin_lock_init(&d->connection.lock);
> > +	mutex_init(&d->eu_lock);
> >  	init_waitqueue_head(&d->events.write_done);
> >  	init_waitqueue_head(&d->events.read_done);
> >  	init_completion(&d->discovery);
> > @@ -903,6 +1279,7 @@ xe_eudebug_connect(struct xe_device *xe,
> >  
> >  	kref_get(&d->ref);
> >  	queue_work(xe->eudebug.ordered_wq, &d->discovery_work);
> > +	attention_scan_flush(xe);
> >  
> >  	eu_dbg(d, "connected session %lld", d->session);
> >  
> > @@ -979,12 +1356,22 @@ void xe_eudebug_init(struct xe_device *xe)
> >  {
> >  	spin_lock_init(&xe->eudebug.lock);
> >  	INIT_LIST_HEAD(&xe->eudebug.list);
> > +	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
> >  
> >  	xe->eudebug.available = true;
> >  }
> >  
> > +void xe_eudebug_init_late(struct xe_device *xe)
> > +{
> > +	if (!xe->eudebug.available)
> > +		return;
> > +
> > +	attention_scan_flush(xe);
> > +}
> > +
> >  void xe_eudebug_fini(struct xe_device *xe)
> >  {
> > +	attention_scan_cancel(xe);
> >  	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
> >  }
> >  
> > diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> > index ac89a3d1ee1d..1e233c4683d6 100644
> > --- a/drivers/gpu/drm/xe/xe_eudebug.h
> > +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> > @@ -18,6 +18,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
> >  			     struct drm_file *file);
> >  
> >  void xe_eudebug_init(struct xe_device *xe);
> > +void xe_eudebug_init_late(struct xe_device *xe);
> >  void xe_eudebug_fini(struct xe_device *xe);
> >  void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
> >  
> > diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
> > index 6e3c23023933..16667b4dfe45 100644
> > --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
> > +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> > @@ -105,6 +105,9 @@ struct xe_eudebug {
> >  	/** @discovery_work: worker to discover resources for target_task */
> >  	struct work_struct discovery_work;
> >  
> > +	/** eu_lock: guards operations on eus (eu thread control and attention) */
> > +	struct mutex eu_lock;
> > +
> >  	/** @events: kfifo queue of to-be-delivered events */
> >  	struct {
> >  		/** @lock: guards access to fifo */
> > @@ -202,4 +205,33 @@ struct xe_eudebug_event_exec_queue {
> >  	u64 lrc_handle[];
> >  };
> >  
> > +/**
> > + * struct xe_eudebug_event_eu_attention - Internal event for EU attention
> > + */
> > +struct xe_eudebug_event_eu_attention {
> > +	/** @base: base event */
> > +	struct xe_eudebug_event base;
> > +
> > +	/** @client_handle: client for the attention */
> > +	u64 client_handle;
> > +
> > +	/** @exec_queue_handle: handle of exec_queue which raised attention */
> > +	u64 exec_queue_handle;
> > +
> > +	/** @lrc_handle: lrc handle of the workload which raised attention */
> > +	u64 lrc_handle;
> > +
> > +	/** @flags: eu attention event flags, currently MBZ */
> > +	u32 flags;
> > +
> > +	/** @bitmask_size: size of the bitmask, specific to device */
> > +	u32 bitmask_size;
> > +
> > +	/**
> > +	 * @bitmask: reflects threads currently signalling attention,
> > +	 * starting from natural hardware order of DSS=0, eu=0
> > +	 */
> > +	u8 bitmask[];
> > +};
> > +
> >  #endif
> > 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..04d2d43ce249
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_gt_debug.c
> > @@ -0,0 +1,152 @@
> > +// 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"
> > +
> > +static int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
> > +					    int (*fn)(struct xe_gt *gt,
> > +						      void *data,
> > +						      u16 group,
> > +						      u16 instance),
> > +					    void *data)
> > +{
> > +	const enum xe_force_wake_domains fw_domains = XE_FW_GT | XE_FW_RENDER;
> > +	unsigned int dss;
> > +	u16 group, instance;
> > +	int ret;
> > +
> > +	xe_pm_runtime_get(gt_to_xe(gt));
> > +	ret = xe_force_wake_get(gt_to_fw(gt), fw_domains);
> > +	if (ret)
> > +		goto pm_runtime_put;
> > +
> > +	for_each_dss_steering(dss, gt, group, instance) {
> > +		ret = fn(gt, data, group, instance);
> > +		if (ret)
> > +			break;
> > +	}
> > +
> > +	xe_force_wake_put(gt_to_fw(gt), fw_domains);
> > +pm_runtime_put:
> > +	xe_pm_runtime_put(gt_to_xe(gt));
> > +
> > +	return ret;
> > +}
> > +
> > +static int read_first_attention_mcr(struct xe_gt *gt, void *data,
> > +				    u16 group, u16 instance)
> > +{
> > +	unsigned int row;
> > +
> > +	for (row = 0; row < 2; row++) {
> > +		u32 val;
> > +
> > +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(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);
> > +
> > +	return  bitmap_weight(dss_mask, XE_MAX_DSS_FUSE_BITS) *
> > +		TD_EU_ATTENTION_MAX_ROWS * 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)
> > +{
> > +	struct attn_read_iter * const iter = data;
> > +	unsigned int row;
> > +
> > +	for (row = 0; row < TD_EU_ATTENTION_MAX_ROWS; row++) {
> > +		u32 val;
> > +
> > +		if (iter->i >= iter->size)
> > +			return 0;
> > +
> > +		XE_WARN_ON(iter->i + sizeof(val) > xe_gt_eu_attention_bitmap_size(gt));
> > +
> > +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(row), group, instance);
> > +
> > +
> > +		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
> > +	};
> > +
> > +	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..3f13dbb17a5f
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_gt_debug.h
> > @@ -0,0 +1,21 @@
> > +/* SPDX-License-Identifier: MIT */
> > +/*
> > + * Copyright © 2023 Intel Corporation
> > + */
> > +
> > +#ifndef __XE_GT_DEBUG_
> > +#define __XE_GT_DEBUG_
> > +
> > +#define TD_EU_ATTENTION_MAX_ROWS 2u
> > +
> > +#include "xe_gt_types.h"
> > +
> > +#define XE_GT_ATTENTION_TIMEOUT_MS 100
> > +
> > +int xe_gt_eu_threads_needing_attention(struct xe_gt *gt);
> > +
> > +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/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> > index 25dddb8b22f4..453269ac8307 100644
> > --- a/include/uapi/drm/xe_drm_eudebug.h
> > +++ b/include/uapi/drm/xe_drm_eudebug.h
> > @@ -27,13 +27,15 @@ struct drm_xe_eudebug_event {
> >  #define DRM_XE_EUDEBUG_EVENT_OPEN		2
> >  #define DRM_XE_EUDEBUG_EVENT_VM			3
> >  #define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE		4
> > -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
> > +#define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
> > +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
> >  
> >  	__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)
> > +
> >  	__u64 seqno;
> >  	__u64 reserved;
> >  };
> > @@ -62,6 +64,17 @@ struct drm_xe_eudebug_event_exec_queue {
> >  	__u64 lrc_handle[];
> >  };
> >  
> > +struct drm_xe_eudebug_event_eu_attention {
> > +	struct drm_xe_eudebug_event base;
> > +
> > +	__u64 client_handle;
> > +	__u64 exec_queue_handle;
> > +	__u64 lrc_handle;
> > +	__u32 flags;
> > +	__u32 bitmask_size;
> > +	__u8 bitmask[];
> > +};
> > +
> >  #if defined(__cplusplus)
> >  }
> >  #endif
> > -- 
> > 2.34.1
> > 


^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 04/21] kernel: export ptrace_may_access
  2024-07-26 14:08 ` [PATCH 04/21] kernel: export ptrace_may_access Mika Kuoppala
@ 2024-07-29 18:56   ` Lucas De Marchi
  2024-08-08 11:18   ` Andi Shyti
  1 sibling, 0 replies; 78+ messages in thread
From: Lucas De Marchi @ 2024-07-29 18:56 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Andi Shyti, Maciej Patelczyk, Jonathan Cavitt

On Fri, Jul 26, 2024 at 05:08:01PM GMT, Mika Kuoppala wrote:
>We need to export ptrace_may_access to be able to
>allow debugger connection to check for debuggee access and
>at the same time allow xe.ko module build.

I don't follow this explanation, particularly this last line.
Based on other patches you want to export the function because it would
cause the calling process to manipulate another process. Like described
in Documentation/process/adding-syscalls.rst.

The reason to export this function is that this comes as an ioctl to the
xe driver, which may be built as a module.

>
>CC: Lucas De Marchi <lucas.demarchi@intel.com>
>Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>CC: Andi Shyti <andi.shyti@intel.com>
>CC: Maciej Patelczyk <maciej.patelczyk@linux.intel.com>
>Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>

$ ./scripts/get_maintainer.pl  kernel/ptrace.c
Oleg Nesterov <oleg@redhat.com> (maintainer:PTRACE SUPPORT)
linux-kernel@vger.kernel.org (open list)

and I don't see these Cc'ed. Also the commit title should likely start
with "ptrace:" rather than "kernel:"

Lucas De Marchi

>---
> kernel/ptrace.c | 1 +
> 1 file changed, 1 insertion(+)
>
>diff --git a/kernel/ptrace.c b/kernel/ptrace.c
>index d5f89f9ef29f..86be1805ebd8 100644
>--- a/kernel/ptrace.c
>+++ b/kernel/ptrace.c
>@@ -354,6 +354,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
> 	task_unlock(task);
> 	return !err;
> }
>+EXPORT_SYMBOL_GPL(ptrace_may_access);
>
> static int check_ptrace_options(unsigned long data)
> {
>-- 
>2.34.1
>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 05/21] drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach
  2024-07-26 14:08 ` [PATCH 05/21] drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach Mika Kuoppala
@ 2024-07-29 19:00   ` Lucas De Marchi
  0 siblings, 0 replies; 78+ messages in thread
From: Lucas De Marchi @ 2024-07-29 19:00 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Jonathan Cavitt

On Fri, Jul 26, 2024 at 05:08:02PM GMT, Mika Kuoppala wrote:
>From: Jonathan Cavitt <jonathan.cavitt@intel.com>
>
>xe_eudebug_attach wants to use ptrace_may_access for determining when
>the user has the right to attach a debugger to a given process.  With
>ptrace_may_access now exported, this has become possible.
>
>Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
>Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>


this patch shouldn't exist. The patch exporting ptrace_may_access()
should be moved before xe_eudebug_attach() is added, so it's already
added with the right perm check.

If exporting that is not acceptable (which needs to be discussed with
proper maintainers / mainling-list) then this could remain as a
CAP_SYS_ADMIN.

Lucas De Marchi

>---
> drivers/gpu/drm/xe/xe_eudebug.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
>diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
>index 8aab02824f8a..c4bc66660218 100644
>--- a/drivers/gpu/drm/xe/xe_eudebug.c
>+++ b/drivers/gpu/drm/xe/xe_eudebug.c
>@@ -246,14 +246,13 @@ xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
> {
> 	struct task_struct *target;
> 	struct xe_eudebug *iter;
>-	kuid_t uid = current_uid();
> 	int ret = 0;
>
> 	target = find_get_target(pid_nr);
> 	if (!target)
> 		return -ENOENT;
>
>-	if (!uid_eq(uid, task_uid(target)) && !capable(CAP_SYS_ADMIN)) {
>+	if (!ptrace_may_access(target, PTRACE_MODE_READ_REALCREDS)) {
> 		put_task_struct(target);
> 		return -EACCES;
> 	}
>-- 
>2.34.1
>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug
  2024-07-26 14:08 ` [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug Mika Kuoppala
@ 2024-07-29 19:05   ` Lucas De Marchi
  2024-07-29 19:16     ` Lucas De Marchi
  2024-07-30  9:01     ` Grzegorzek, Dominik
  0 siblings, 2 replies; 78+ messages in thread
From: Lucas De Marchi @ 2024-07-29 19:05 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

On Fri, Jul 26, 2024 at 05:08:05PM GMT, Mika Kuoppala wrote:
>From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>
>In order to turn on debug capabilities, (i.e. breakpoints), TD_CTL
>and some other registers needs to be programmed. Implement eudebug
>mode enabling including eudebug related workarounds.

nack for the workadound part. See below.

>
>1) Enable exceptions only on platforms that does not have per context
>   debugging functionality
>
>2) Fixup 22015693276:
>   Use lineage HSD instead of per platform specific, be precise defining
>   graphics range.
>
>Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>---
> drivers/gpu/drm/xe/regs/xe_engine_regs.h |  4 ++
> drivers/gpu/drm/xe/regs/xe_gt_regs.h     | 10 +++++
> drivers/gpu/drm/xe/xe_eudebug.c          | 50 ++++++++++++++++++++++++
> drivers/gpu/drm/xe/xe_eudebug.h          |  2 +
> drivers/gpu/drm/xe/xe_hw_engine.c        |  2 +
> 5 files changed, 68 insertions(+)
>
>diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
>index c38db2a74614..fd31f3fb2b4c 100644
>--- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
>+++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
>@@ -114,6 +114,10 @@
>
> #define INDIRECT_RING_STATE(base)		XE_REG((base) + 0x108)
>
>+#define CS_DEBUG_MODE2(base)			XE_REG((base) + 0xd8, XE_REG_OPTION_MASKED)
>+#define   INST_STATE_CACHE_INVALIDATE		REG_BIT(6)
>+#define   GLOBAL_DEBUG_ENABLE			REG_BIT(5)
>+
> #define RING_BBADDR(base)			XE_REG((base) + 0x140)
> #define RING_BBADDR_UDW(base)			XE_REG((base) + 0x168)
>
>diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
>index 8a94a94d2267..96a59a96dd4c 100644
>--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
>+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
>@@ -425,6 +425,14 @@
> #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)
>@@ -450,11 +458,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)
>diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
>index db55e449049a..9611acedeee9 100644
>--- a/drivers/gpu/drm/xe/xe_eudebug.c
>+++ b/drivers/gpu/drm/xe/xe_eudebug.c
>@@ -11,13 +11,19 @@
>
> #include <drm/drm_managed.h>
>
>+#include "regs/xe_gt_regs.h"
>+#include "regs/xe_engine_regs.h"
> #include "xe_device.h"
> #include "xe_assert.h"
> #include "xe_macros.h"
>+#include "xe_gt.h"
> #include "xe_eudebug_types.h"
> #include "xe_eudebug.h"
> #include "xe_exec_queue_types.h"
>+#include "xe_module.h"
>+#include "xe_rtp.h"
> #include "xe_vm.h"
>+#include "xe_wa.h"
>
> /*
>  * If there is no detected event read by userspace, during this period, assume
>@@ -925,6 +931,50 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
> 	return ret;
> }
>
>+#undef XE_REG_MCR
>+#define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
>+
>+void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
>+{
>+	const struct xe_rtp_entry_sr eudebug_was[] = {
>+		{ XE_RTP_NAME("GlobalDebugEnable"),
>+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
>+			       ENGINE_CLASS(RENDER)),
>+		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
>+				     GLOBAL_DEBUG_ENABLE))
>+		},
>+		{ XE_RTP_NAME("TdCtlDebugEnable"),
>+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
>+			       FUNC(xe_rtp_match_first_render_or_compute)),
>+		  XE_RTP_ACTIONS(SET(TD_CTL,
>+				     TD_CTL_BREAKPOINT_ENABLE |
>+				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
>+				     TD_CTL_FEH_AND_FEE_ENABLE))
>+		},
>+		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
>+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
>+			       FUNC(xe_rtp_match_first_render_or_compute)),
>+		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
>+		},
>+		{ XE_RTP_NAME("18022722726"),
>+		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
>+			       FUNC(xe_rtp_match_first_render_or_compute)),
>+		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
>+		},
>+		{ XE_RTP_NAME("14015527279"),
>+		  XE_RTP_RULES(PLATFORM(PVC),
>+			       FUNC(xe_rtp_match_first_render_or_compute)),
>+		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
>+		},

workarounds don't belong here. All workarounds should be moved to
xe_wa.c, which also has tracking for active workarounds and make them
show up in debugfs.

tuning and other non-wa stuff may be added separately, like we have in
xe_tuning.c, xe_hw_engine.c etc.

Lucas De Marchi

>+		{}
>+	};
>+	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
>+	struct xe_device *xe = gt_to_xe(hwe->gt);
>+
>+	if (xe->eudebug.available)
>+		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>+}
>+
> void xe_eudebug_init(struct xe_device *xe)
> {
> 	spin_lock_init(&xe->eudebug.lock);
>diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
>index 44b20549eb6d..ac89a3d1ee1d 100644
>--- a/drivers/gpu/drm/xe/xe_eudebug.h
>+++ b/drivers/gpu/drm/xe/xe_eudebug.h
>@@ -11,6 +11,7 @@ struct xe_device;
> struct xe_file;
> struct xe_vm;
> struct xe_exec_queue;
>+struct xe_hw_engine;
>
> int xe_eudebug_connect_ioctl(struct drm_device *dev,
> 			     void *data,
>@@ -18,6 +19,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>
> void xe_eudebug_init(struct xe_device *xe);
> void xe_eudebug_fini(struct xe_device *xe);
>+void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
>
> void xe_eudebug_file_open(struct xe_file *xef);
> void xe_eudebug_file_close(struct xe_file *xef);
>diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
>index 20c4fdf40790..0d8b871b47fe 100644
>--- a/drivers/gpu/drm/xe/xe_hw_engine.c
>+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
>@@ -15,6 +15,7 @@
> #include "xe_assert.h"
> #include "xe_bo.h"
> #include "xe_device.h"
>+#include "xe_eudebug.h"
> #include "xe_execlist.h"
> #include "xe_force_wake.h"
> #include "xe_gsc.h"
>@@ -503,6 +504,7 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
> 	xe_tuning_process_engine(hwe);
> 	xe_wa_process_engine(hwe);
> 	hw_engine_setup_default_state(hwe);
>+	xe_eudebug_init_hw_engine(hwe);
>
> 	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
> 	xe_reg_whitelist_process_engine(hwe);
>-- 
>2.34.1
>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug
  2024-07-29 19:05   ` Lucas De Marchi
@ 2024-07-29 19:16     ` Lucas De Marchi
  2024-07-30  9:01     ` Grzegorzek, Dominik
  1 sibling, 0 replies; 78+ messages in thread
From: Lucas De Marchi @ 2024-07-29 19:16 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

On Mon, Jul 29, 2024 at 02:05:25PM GMT, Lucas De Marchi wrote:
>On Fri, Jul 26, 2024 at 05:08:05PM GMT, Mika Kuoppala wrote:
>>From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>>
>>In order to turn on debug capabilities, (i.e. breakpoints), TD_CTL
>>and some other registers needs to be programmed. Implement eudebug
>>mode enabling including eudebug related workarounds.
>
>nack for the workadound part. See below.
>
>>
>>1) Enable exceptions only on platforms that does not have per context
>>  debugging functionality
>>
>>2) Fixup 22015693276:
>>  Use lineage HSD instead of per platform specific, be precise defining
>>  graphics range.


also no idea what "1)" and "2)" are here.

Lucas De Marchi

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug
  2024-07-29 19:05   ` Lucas De Marchi
  2024-07-29 19:16     ` Lucas De Marchi
@ 2024-07-30  9:01     ` Grzegorzek, Dominik
  2024-07-30 13:56       ` Lucas De Marchi
  1 sibling, 1 reply; 78+ messages in thread
From: Grzegorzek, Dominik @ 2024-07-30  9:01 UTC (permalink / raw)
  To: mika.kuoppala@linux.intel.com, De Marchi, Lucas
  Cc: intel-xe@lists.freedesktop.org

On Mon, 2024-07-29 at 14:05 -0500, Lucas De Marchi wrote:
> On Fri, Jul 26, 2024 at 05:08:05PM GMT, Mika Kuoppala wrote:
> > From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> > 
> > In order to turn on debug capabilities, (i.e. breakpoints), TD_CTL
> > and some other registers needs to be programmed. Implement eudebug
> > mode enabling including eudebug related workarounds.
> 
> nack for the workadound part. See below.
> 
> > 
> > 1) Enable exceptions only on platforms that does not have per context
> >   debugging functionality
> > 
> > 2) Fixup 22015693276:
> >   Use lineage HSD instead of per platform specific, be precise defining
> >   graphics range.
> > 
> > Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> > Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> > ---
> > drivers/gpu/drm/xe/regs/xe_engine_regs.h |  4 ++
> > drivers/gpu/drm/xe/regs/xe_gt_regs.h     | 10 +++++
> > drivers/gpu/drm/xe/xe_eudebug.c          | 50 ++++++++++++++++++++++++
> > drivers/gpu/drm/xe/xe_eudebug.h          |  2 +
> > drivers/gpu/drm/xe/xe_hw_engine.c        |  2 +
> > 5 files changed, 68 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > index c38db2a74614..fd31f3fb2b4c 100644
> > --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > @@ -114,6 +114,10 @@
> > 
> > #define INDIRECT_RING_STATE(base)		XE_REG((base) + 0x108)
> > 
> > +#define CS_DEBUG_MODE2(base)			XE_REG((base) + 0xd8, XE_REG_OPTION_MASKED)
> > +#define   INST_STATE_CACHE_INVALIDATE		REG_BIT(6)
> > +#define   GLOBAL_DEBUG_ENABLE			REG_BIT(5)
> > +
> > #define RING_BBADDR(base)			XE_REG((base) + 0x140)
> > #define RING_BBADDR_UDW(base)			XE_REG((base) + 0x168)
> > 
> > diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > index 8a94a94d2267..96a59a96dd4c 100644
> > --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > @@ -425,6 +425,14 @@
> > #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)
> > @@ -450,11 +458,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)
> > diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> > index db55e449049a..9611acedeee9 100644
> > --- a/drivers/gpu/drm/xe/xe_eudebug.c
> > +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> > @@ -11,13 +11,19 @@
> > 
> > #include <drm/drm_managed.h>
> > 
> > +#include "regs/xe_gt_regs.h"
> > +#include "regs/xe_engine_regs.h"
> > #include "xe_device.h"
> > #include "xe_assert.h"
> > #include "xe_macros.h"
> > +#include "xe_gt.h"
> > #include "xe_eudebug_types.h"
> > #include "xe_eudebug.h"
> > #include "xe_exec_queue_types.h"
> > +#include "xe_module.h"
> > +#include "xe_rtp.h"
> > #include "xe_vm.h"
> > +#include "xe_wa.h"
> > 
> > /*
> >  * If there is no detected event read by userspace, during this period, assume
> > @@ -925,6 +931,50 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
> > 	return ret;
> > }
> > 
> > +#undef XE_REG_MCR
> > +#define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
> > +
> > +void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
> > +{
> > +	const struct xe_rtp_entry_sr eudebug_was[] = {
> > +		{ XE_RTP_NAME("GlobalDebugEnable"),
> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
> > +			       ENGINE_CLASS(RENDER)),
> > +		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
> > +				     GLOBAL_DEBUG_ENABLE))
> > +		},
> > +		{ XE_RTP_NAME("TdCtlDebugEnable"),
> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > +		  XE_RTP_ACTIONS(SET(TD_CTL,
> > +				     TD_CTL_BREAKPOINT_ENABLE |
> > +				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
> > +				     TD_CTL_FEH_AND_FEE_ENABLE))
> > +		},
> > +		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > +		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
> > +		},
> > +		{ XE_RTP_NAME("18022722726"),
> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
> > +		},
> > +		{ XE_RTP_NAME("14015527279"),
> > +		  XE_RTP_RULES(PLATFORM(PVC),
> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
> > +		},
> 
> workarounds don't belong here. All workarounds should be moved to
> xe_wa.c, which also has tracking for active workarounds and make them
> show up in debugfs.
> 
> tuning and other non-wa stuff may be added separately, like we have in
> xe_tuning.c, xe_hw_engine.c etc.
> 
> Lucas De Marchi

The thing is that these workarounds are purely specific to EU debug. For
instance, the description in 18022722726 states, "When enabling the 
Debug feature, [...]" I assumed that there is no need to enable them when 
the debugger is not active to limit any negative interference, and we 
address this later in the series. Please take a look on "[PATCH 20/21] 
drm/xe/eudebug: Dynamically toggle debugger functionality." Could you 
also share your thoughts on that?

xe_rtp isn't really designed for dynamic changes and we may be bending it
a bit there. If so, we would appreciate any ideas on how to dynamically feed
GuC restore list in a proper way. 

Regards, 
Dominik
> 
> > +		{}
> > +	};
> > +	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
> > +	struct xe_device *xe = gt_to_xe(hwe->gt);
> > +
> > +	if (xe->eudebug.available)
> > +		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
> > +}
> > +
> > void xe_eudebug_init(struct xe_device *xe)
> > {
> > 	spin_lock_init(&xe->eudebug.lock);
> > diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> > index 44b20549eb6d..ac89a3d1ee1d 100644
> > --- a/drivers/gpu/drm/xe/xe_eudebug.h
> > +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> > @@ -11,6 +11,7 @@ struct xe_device;
> > struct xe_file;
> > struct xe_vm;
> > struct xe_exec_queue;
> > +struct xe_hw_engine;
> > 
> > int xe_eudebug_connect_ioctl(struct drm_device *dev,
> > 			     void *data,
> > @@ -18,6 +19,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
> > 
> > void xe_eudebug_init(struct xe_device *xe);
> > void xe_eudebug_fini(struct xe_device *xe);
> > +void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
> > 
> > void xe_eudebug_file_open(struct xe_file *xef);
> > void xe_eudebug_file_close(struct xe_file *xef);
> > diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> > index 20c4fdf40790..0d8b871b47fe 100644
> > --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> > +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> > @@ -15,6 +15,7 @@
> > #include "xe_assert.h"
> > #include "xe_bo.h"
> > #include "xe_device.h"
> > +#include "xe_eudebug.h"
> > #include "xe_execlist.h"
> > #include "xe_force_wake.h"
> > #include "xe_gsc.h"
> > @@ -503,6 +504,7 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
> > 	xe_tuning_process_engine(hwe);
> > 	xe_wa_process_engine(hwe);
> > 	hw_engine_setup_default_state(hwe);
> > +	xe_eudebug_init_hw_engine(hwe);
> > 
> > 	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
> > 	xe_reg_whitelist_process_engine(hwe);
> > -- 
> > 2.34.1
> > 


^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug
  2024-07-30  9:01     ` Grzegorzek, Dominik
@ 2024-07-30 13:56       ` Lucas De Marchi
  0 siblings, 0 replies; 78+ messages in thread
From: Lucas De Marchi @ 2024-07-30 13:56 UTC (permalink / raw)
  To: Grzegorzek, Dominik
  Cc: mika.kuoppala@linux.intel.com, intel-xe@lists.freedesktop.org,
	Matt Roper

On Tue, Jul 30, 2024 at 09:01:50AM GMT, Grzegorzek, Dominik wrote:
>On Mon, 2024-07-29 at 14:05 -0500, Lucas De Marchi wrote:
>> On Fri, Jul 26, 2024 at 05:08:05PM GMT, Mika Kuoppala wrote:
>> > From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>> >
>> > In order to turn on debug capabilities, (i.e. breakpoints), TD_CTL
>> > and some other registers needs to be programmed. Implement eudebug
>> > mode enabling including eudebug related workarounds.
>>
>> nack for the workadound part. See below.
>>
>> >
>> > 1) Enable exceptions only on platforms that does not have per context
>> >   debugging functionality
>> >
>> > 2) Fixup 22015693276:
>> >   Use lineage HSD instead of per platform specific, be precise defining
>> >   graphics range.
>> >
>> > Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
>> > Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>> > ---
>> > drivers/gpu/drm/xe/regs/xe_engine_regs.h |  4 ++
>> > drivers/gpu/drm/xe/regs/xe_gt_regs.h     | 10 +++++
>> > drivers/gpu/drm/xe/xe_eudebug.c          | 50 ++++++++++++++++++++++++
>> > drivers/gpu/drm/xe/xe_eudebug.h          |  2 +
>> > drivers/gpu/drm/xe/xe_hw_engine.c        |  2 +
>> > 5 files changed, 68 insertions(+)
>> >
>> > diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
>> > index c38db2a74614..fd31f3fb2b4c 100644
>> > --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
>> > +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
>> > @@ -114,6 +114,10 @@
>> >
>> > #define INDIRECT_RING_STATE(base)		XE_REG((base) + 0x108)
>> >
>> > +#define CS_DEBUG_MODE2(base)			XE_REG((base) + 0xd8, XE_REG_OPTION_MASKED)
>> > +#define   INST_STATE_CACHE_INVALIDATE		REG_BIT(6)
>> > +#define   GLOBAL_DEBUG_ENABLE			REG_BIT(5)
>> > +
>> > #define RING_BBADDR(base)			XE_REG((base) + 0x140)
>> > #define RING_BBADDR_UDW(base)			XE_REG((base) + 0x168)
>> >
>> > diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
>> > index 8a94a94d2267..96a59a96dd4c 100644
>> > --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
>> > +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
>> > @@ -425,6 +425,14 @@
>> > #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)
>> > @@ -450,11 +458,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)
>> > diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
>> > index db55e449049a..9611acedeee9 100644
>> > --- a/drivers/gpu/drm/xe/xe_eudebug.c
>> > +++ b/drivers/gpu/drm/xe/xe_eudebug.c
>> > @@ -11,13 +11,19 @@
>> >
>> > #include <drm/drm_managed.h>
>> >
>> > +#include "regs/xe_gt_regs.h"
>> > +#include "regs/xe_engine_regs.h"
>> > #include "xe_device.h"
>> > #include "xe_assert.h"
>> > #include "xe_macros.h"
>> > +#include "xe_gt.h"
>> > #include "xe_eudebug_types.h"
>> > #include "xe_eudebug.h"
>> > #include "xe_exec_queue_types.h"
>> > +#include "xe_module.h"
>> > +#include "xe_rtp.h"
>> > #include "xe_vm.h"
>> > +#include "xe_wa.h"
>> >
>> > /*
>> >  * If there is no detected event read by userspace, during this period, assume
>> > @@ -925,6 +931,50 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>> > 	return ret;
>> > }
>> >
>> > +#undef XE_REG_MCR
>> > +#define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
>> > +
>> > +void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
>> > +{
>> > +	const struct xe_rtp_entry_sr eudebug_was[] = {
>> > +		{ XE_RTP_NAME("GlobalDebugEnable"),
>> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
>> > +			       ENGINE_CLASS(RENDER)),
>> > +		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
>> > +				     GLOBAL_DEBUG_ENABLE))
>> > +		},
>> > +		{ XE_RTP_NAME("TdCtlDebugEnable"),
>> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
>> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> > +		  XE_RTP_ACTIONS(SET(TD_CTL,
>> > +				     TD_CTL_BREAKPOINT_ENABLE |
>> > +				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
>> > +				     TD_CTL_FEH_AND_FEE_ENABLE))
>> > +		},
>> > +		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
>> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
>> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> > +		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
>> > +		},
>> > +		{ XE_RTP_NAME("18022722726"),
>> > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
>> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> > +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
>> > +		},
>> > +		{ XE_RTP_NAME("14015527279"),
>> > +		  XE_RTP_RULES(PLATFORM(PVC),
>> > +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> > +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
>> > +		},
>>
>> workarounds don't belong here. All workarounds should be moved to
>> xe_wa.c, which also has tracking for active workarounds and make them
>> show up in debugfs.
>>
>> tuning and other non-wa stuff may be added separately, like we have in
>> xe_tuning.c, xe_hw_engine.c etc.
>>
>> Lucas De Marchi
>
>The thing is that these workarounds are purely specific to EU debug. For
>instance, the description in 18022722726 states, "When enabling the
>Debug feature, [...]" I assumed that there is no need to enable them when

ok, we may have to do something else for that then:

1) if there's no side-effect of setting it, enable it unconditionally
2) set it as an OOB WA - this will enable the WA tracking and allow us
    to check the WAs implemented for each platform

(1) is the simplest one

For (2), then if you are using an RTP table for enabling/disabling you
basically check if that OOB WA is enabled as the rule.  Currently you
will need to split some rules as the OOB WAs are gt-centric (so the
engine check part would still be in outside OOB).  +Matt Roper if he
has other ideas.

>the debugger is not active to limit any negative interference, and we
>address this later in the series. Please take a look on "[PATCH 20/21]
>drm/xe/eudebug: Dynamically toggle debugger functionality." Could you
>also share your thoughts on that?
>
>xe_rtp isn't really designed for dynamic changes and we may be bending it

that part is beyond rtp. RTP is mainly about getting a bunch of entries
on a table. Applying the outcome of that table to the hw is left to
xe_sr and guc-ads

>a bit there. If so, we would appreciate any ideas on how to dynamically feed
>GuC restore list in a proper way.

will try to take a look later today, but I believe you will need tweak
the ADS and reset GuC.

Lucas De Marchi

>
>Regards,
>Dominik
>>
>> > +		{}
>> > +	};
>> > +	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
>> > +	struct xe_device *xe = gt_to_xe(hwe->gt);
>> > +
>> > +	if (xe->eudebug.available)
>> > +		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>> > +}
>> > +
>> > void xe_eudebug_init(struct xe_device *xe)
>> > {
>> > 	spin_lock_init(&xe->eudebug.lock);
>> > diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
>> > index 44b20549eb6d..ac89a3d1ee1d 100644
>> > --- a/drivers/gpu/drm/xe/xe_eudebug.h
>> > +++ b/drivers/gpu/drm/xe/xe_eudebug.h
>> > @@ -11,6 +11,7 @@ struct xe_device;
>> > struct xe_file;
>> > struct xe_vm;
>> > struct xe_exec_queue;
>> > +struct xe_hw_engine;
>> >
>> > int xe_eudebug_connect_ioctl(struct drm_device *dev,
>> > 			     void *data,
>> > @@ -18,6 +19,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>> >
>> > void xe_eudebug_init(struct xe_device *xe);
>> > void xe_eudebug_fini(struct xe_device *xe);
>> > +void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
>> >
>> > void xe_eudebug_file_open(struct xe_file *xef);
>> > void xe_eudebug_file_close(struct xe_file *xef);
>> > diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
>> > index 20c4fdf40790..0d8b871b47fe 100644
>> > --- a/drivers/gpu/drm/xe/xe_hw_engine.c
>> > +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
>> > @@ -15,6 +15,7 @@
>> > #include "xe_assert.h"
>> > #include "xe_bo.h"
>> > #include "xe_device.h"
>> > +#include "xe_eudebug.h"
>> > #include "xe_execlist.h"
>> > #include "xe_force_wake.h"
>> > #include "xe_gsc.h"
>> > @@ -503,6 +504,7 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
>> > 	xe_tuning_process_engine(hwe);
>> > 	xe_wa_process_engine(hwe);
>> > 	hw_engine_setup_default_state(hwe);
>> > +	xe_eudebug_init_hw_engine(hwe);
>> >
>> > 	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
>> > 	xe_reg_whitelist_process_engine(hwe);
>> > --
>> > 2.34.1
>> >
>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks
  2024-07-27  0:40   ` Matthew Brost
@ 2024-07-30 14:05     ` Mika Kuoppala
  2024-07-31  1:33       ` Matthew Brost
  0 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-30 14:05 UTC (permalink / raw)
  To: Matthew Brost; +Cc: intel-xe

Matthew Brost <matthew.brost@intel.com> writes:

> On Fri, Jul 26, 2024 at 05:08:10PM +0300, Mika Kuoppala wrote:
>> When vma is in place, debugger needs to intercept before
>> userspace proceeds with the workload. For example to install
>> a breakpoint in a eu shader.
>> 
>> Attach debugger in xe_user_fence, send UFENCE event
>> and stall normal user fence signal path to yield if
>> there is debugger attached to ufence.
>> 
>> When ack (ioctl) is received for the corresponding seqno,
>> signal ufence.
>> 
>> v2: ufence worker in own workqueue
>> 
>
> Not a complete review again, just a couple of quick comments.
>
>> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>> ---
>>  drivers/gpu/drm/xe/xe_eudebug.c       | 239 +++++++++++++++++++++++++-
>>  drivers/gpu/drm/xe/xe_eudebug.h       |   6 +
>>  drivers/gpu/drm/xe/xe_eudebug_types.h |  12 ++
>>  drivers/gpu/drm/xe/xe_exec.c          |   2 +-
>>  drivers/gpu/drm/xe/xe_sync.c          |  49 ++++--
>>  drivers/gpu/drm/xe/xe_sync.h          |   8 +-
>>  drivers/gpu/drm/xe/xe_sync_types.h    |  26 ++-
>>  drivers/gpu/drm/xe/xe_vm.c            |   4 +-
>>  include/uapi/drm/xe_drm_eudebug.h     |  15 +-
>>  9 files changed, 333 insertions(+), 28 deletions(-)
>> 
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
>> index 8f0e6a56a65e..5dcb7c9464e9 100644
>> --- a/drivers/gpu/drm/xe/xe_eudebug.c
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
>> @@ -35,6 +35,7 @@
>>  #include "xe_vm.h"
>>  #include "xe_wa.h"
>>  #include "xe_force_wake.h"
>> +#include "xe_sync.h"
>>  
>>  /*
>>   * If there is no detected event read by userspace, during this period, assume
>> @@ -240,11 +241,115 @@ static void xe_eudebug_free(struct kref *ref)
>>  	kfree_rcu(d, rcu);
>>  }
>>  
>> -static void xe_eudebug_put(struct xe_eudebug *d)
>> +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;
>
> Here we have a seqno but then an RB tree for search which is a bit
> incongruent. Let me explain, seqno typically mean something which
> signals sequentially in order. But then you have RB tree for searching,
> if everything signaled in order a list would be sufficient.
>
> So without looking too much I think we want one of two things.
>
> 1. seqno + list
> 2. key + rb tree
>
> Make sense?
>
> Kinda a nit but naming matters in this case as a name implies in-order
> vs out-of-order signaling.

This is the seqno of event that was associated with ufence. If userspace
does multiple binds with ufences, it can then pinpoint, with ack ioctl,
the particular bind it wants to be released, with this seqno.

And userspace can ack out of sequence. As it can potentially
receive events out of sequence.

Would it help if it would be event_seqno instead of just seqno?

-Mika

>
> Matt
>
>> +	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);
>> +
>> +	if (READ_ONCE(ufence->signalled))
>> +		xe_sync_ufence_signal(ufence);
>> +
>> +	xe_sync_ufence_put(ufence);
>> +}
>> +
>> +static void kick_ufence_worker(struct xe_user_fence *f)
>> +{
>> +	INIT_WORK(&f->eudebug.worker, ufence_signal_worker);
>> +	queue_work(f->xe->eudebug.ordered_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;
>> +	u64 signaller_ack, signalled_by;
>> +
>> +	signaller_ack = cmpxchg64(&f->eudebug.signalled_seqno, 0, ack->seqno);
>> +	signalled_by = f->eudebug.signalled_seqno;
>> +
>> +	if (!signaller_ack)
>> +		kick_ufence_worker(f);
>> +	else
>> +		xe_sync_ufence_put(f);
>> +
>> +	eu_dbg(d, "ACK: seqno=%llu: %ssignalled by %s (%llu) (held %lluus)",
>> +	       ack->seqno, signaller_ack ? "already " : "",
>> +	       on_disconnect ? "disconnect" : "debugger",
>> +	       signalled_by,
>> +	       ktime_us_delta(ktime_get(), ack->ts_insert));
>> +
>> +	kfree(ack);
>> +}
>> +
>> +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 struct task_struct *find_get_target(const pid_t nr)
>>  {
>>  	struct task_struct *task;
>> @@ -328,6 +433,8 @@ static bool xe_eudebug_detach(struct xe_device *xe,
>>  
>>  	eu_dbg(d, "session %lld detached with %d", d->session, err);
>>  
>> +	release_acks(d);
>> +
>>  	/* Our ref with the connection_link */
>>  	xe_eudebug_put(d);
>>  
>> @@ -428,7 +535,7 @@ static struct task_struct *find_task_get(struct xe_file *xef)
>>  	return task;
>>  }
>>  
>> -static struct xe_eudebug *
>> +struct xe_eudebug *
>>  xe_eudebug_get(struct xe_file *xef)
>>  {
>>  	struct task_struct *task;
>> @@ -889,6 +996,44 @@ static long xe_eudebug_read_event(struct xe_eudebug *d,
>>  	return ret;
>>  }
>>  
>> +static long
>> +xe_eudebug_ack_event_ioctl(struct xe_eudebug *d,
>> +			   const unsigned int cmd,
>> +			   const u64 arg)
>> +{
>> +	struct drm_xe_eudebug_ack_event __user * const user_ptr =
>> +		u64_to_user_ptr(arg);
>> +	struct drm_xe_eudebug_ack_event user_arg;
>> +	struct xe_eudebug_ack *ack;
>> +	struct xe_device *xe = d->xe;
>> +
>> +	if (XE_IOCTL_DBG(xe, _IOC_SIZE(cmd) < sizeof(user_arg)))
>> +		return -EINVAL;
>> +
>> +	/* Userland write */
>> +	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(cmd) & _IOC_WRITE)))
>> +		return -EINVAL;
>> +
>> +	if (XE_IOCTL_DBG(xe, 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, 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;
>> +}
>> +
>>  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)
>> @@ -1070,7 +1215,10 @@ static long xe_eudebug_ioctl(struct file *file,
>>  		ret = xe_eudebug_eu_control(d, arg);
>>  		eu_dbg(d, "ioctl cmd=EU_CONTROL ret=%ld\n", ret);
>>  		break;
>> -
>> +	case DRM_XE_EUDEBUG_IOCTL_ACK_EVENT:
>> +		ret = xe_eudebug_ack_event_ioctl(d, cmd, arg);
>> +		eu_dbg(d, "ioctl cmd=EVENT_ACK ret=%ld\n", ret);
>> +		break;
>>  	default:
>>  		ret = -EINVAL;
>>  	}
>> @@ -1759,6 +1907,9 @@ xe_eudebug_connect(struct xe_device *xe,
>>  	INIT_KFIFO(d->events.fifo);
>>  	INIT_WORK(&d->discovery_work, discovery_work_fn);
>>  
>> +	spin_lock_init(&d->acks.lock);
>> +	d->acks.tree = RB_ROOT;
>> +
>>  	d->res = xe_eudebug_resources_alloc();
>>  	if (IS_ERR(d->res)) {
>>  		err = PTR_ERR(d->res);
>> @@ -2337,6 +2488,70 @@ static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
>>  	return 0;
>>  }
>>  
>> +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(sizeof(*ack), GFP_KERNEL);
>> +	if (!ack)
>> +		return -ENOMEM;
>> +
>> +	ack->seqno = seqno;
>> +	ack->ts_insert = ktime_get();
>> +
>> +	spin_lock(&d->acks.lock);
>> +	old = rb_find_add(&ack->rb_node,
>> +			  &d->acks.tree, ack_insert_cmp);
>> +	if (!old) {
>> +		kref_get(&f->refcount);
>> +		ack->ufence = f;
>> +	}
>> +	spin_unlock(&d->acks.lock);
>> +
>> +	if (old) {
>> +		eu_dbg(d, "ACK: seqno=%llu: already exists", seqno);
>> +		kfree(ack);
>> +		return -EEXIST;
>> +	}
>> +
>> +	eu_dbg(d, "ACK: seqno=%llu: tracking started", seqno);
>> +
>> +	return 0;
>> +}
>> +
>> +static int vm_bind_ufence_event(struct xe_eudebug *d,
>> +				struct xe_user_fence *ufence)
>> +{
>> +	struct xe_eudebug_event *event;
>> +	struct 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;
>> +
>> +	seqno = atomic_long_inc_return(&d->events.seqno);
>> +
>> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
>> +					seqno, flags, sz, GFP_KERNEL);
>> +	if (!event)
>> +		return -ENOMEM;
>> +
>> +	e = cast_event(e, event);
>> +
>> +	write_member(struct drm_xe_eudebug_event_vm_bind_ufence,
>> +		     e, vm_bind_ref_seqno, ufence->eudebug.bind_ref_seqno);
>> +
>> +	ret = xe_eudebug_track_ufence(d, ufence, seqno);
>> +	if (!ret)
>> +		ret = xe_eudebug_queue_event(d, event);
>> +
>> +	return ret;
>> +}
>> +
>>  void xe_eudebug_vm_bind_start(struct xe_vm *vm)
>>  {
>>  	struct xe_eudebug *d;
>> @@ -2507,6 +2722,24 @@ void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int bind_err)
>>  		xe_eudebug_put(d);
>>  }
>>  
>> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence)
>> +{
>> +	struct xe_eudebug *d;
>> +	int err;
>> +
>> +	d = ufence->eudebug.debugger;
>> +	if (!d || xe_eudebug_detached(d))
>> +		return -ENOTCONN;
>> +
>> +	err = vm_bind_ufence_event(d, ufence);
>> +	if (err) {
>> +		eu_err(d, "error %d on %s", err, __func__);
>> +		xe_eudebug_disconnect(d, err);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>  static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
>>  {
>>  	struct xe_exec_queue *q;
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
>> index 2cab90773b21..3de54802a6ca 100644
>> --- a/drivers/gpu/drm/xe/xe_eudebug.h
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
>> @@ -15,6 +15,7 @@ struct xe_vm;
>>  struct xe_vma;
>>  struct xe_exec_queue;
>>  struct xe_hw_engine;
>> +struct xe_user_fence;
>>  
>>  int xe_eudebug_connect_ioctl(struct drm_device *dev,
>>  			     void *data,
>> @@ -38,4 +39,9 @@ void xe_eudebug_vm_bind_start(struct xe_vm *vm);
>>  void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range);
>>  void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int err);
>>  
>> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence);
>> +
>> +struct xe_eudebug *xe_eudebug_get(struct xe_file *xef);
>> +void xe_eudebug_put(struct xe_eudebug *d);
>> +
>>  #endif
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
>> index 1ffe33f15409..a32c51416b5f 100644
>> --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
>> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
>> @@ -86,6 +86,7 @@ struct xe_eudebug_eu_control_ops {
>>  	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
>>   */
>> @@ -149,6 +150,12 @@ struct xe_eudebug {
>>  		atomic_long_t seqno;
>>  	} events;
>>  
>> +	/* user fences tracked by this debugger */
>> +	struct {
>> +		spinlock_t lock;
>> +		struct rb_root tree;
>> +	} acks;
>> +
>>  	/** @ops operations for eu_control */
>>  	struct xe_eudebug_eu_control_ops *ops;
>>  };
>> @@ -286,4 +293,9 @@ struct xe_eudebug_event_vm_bind_op {
>>  	u64 range; /* Zero for unmap all ? */
>>  };
>>  
>> +struct xe_eudebug_event_vm_bind_ufence {
>> +	struct xe_eudebug_event base;
>> +	u64 vm_bind_ref_seqno;
>> +};
>> +
>>  #endif
>> diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
>> index f36980aa26e6..400cb576f3b9 100644
>> --- a/drivers/gpu/drm/xe/xe_exec.c
>> +++ b/drivers/gpu/drm/xe/xe_exec.c
>> @@ -157,7 +157,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>>  	vm = q->vm;
>>  
>>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
>> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
>> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
>>  					  &syncs_user[num_syncs], SYNC_PARSE_FLAG_EXEC |
>>  					  (xe_vm_in_lr_mode(vm) ?
>>  					   SYNC_PARSE_FLAG_LR_MODE : 0));
>> diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
>> index 533246f42256..52d56bfdf932 100644
>> --- a/drivers/gpu/drm/xe/xe_sync.c
>> +++ b/drivers/gpu/drm/xe/xe_sync.c
>> @@ -18,17 +18,7 @@
>>  #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;
>> -};
>> +#include "xe_eudebug.h"
>>  
>>  static void user_fence_destroy(struct kref *kref)
>>  {
>> @@ -36,6 +26,10 @@ static void user_fence_destroy(struct kref *kref)
>>  						 refcount);
>>  
>>  	mmdrop(ufence->mm);
>> +
>> +	if (ufence->eudebug.debugger)
>> +		xe_eudebug_put(ufence->eudebug.debugger);
>> +
>>  	kfree(ufence);
>>  }
>>  
>> @@ -49,7 +43,10 @@ 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,
>> +					       struct xe_file *xef,
>> +					       struct xe_vm *vm,
>> +					       u64 addr,
>>  					       u64 value)
>>  {
>>  	struct xe_user_fence *ufence;
>> @@ -58,7 +55,7 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
>>  	if (!access_ok(ptr, sizeof(ptr)))
>>  		return ERR_PTR(-EFAULT);
>>  
>> -	ufence = kmalloc(sizeof(*ufence), GFP_KERNEL);
>> +	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
>>  	if (!ufence)
>>  		return ERR_PTR(-ENOMEM);
>>  
>> @@ -69,12 +66,17 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
>>  	ufence->mm = current->mm;
>>  	mmgrab(ufence->mm);
>>  
>> +	if (vm->eudebug_bind.ref) {
>> +		ufence->eudebug.debugger = xe_eudebug_get(xef);
>> +		ufence->eudebug.bind_ref_seqno = vm->eudebug_bind.ref;
>> +	}
>> +
>>  	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);
>> +	XE_WARN_ON(!ufence->signalled);
>>  
>>  	if (mmget_not_zero(ufence->mm)) {
>>  		kthread_use_mm(ufence->mm);
>> @@ -85,7 +87,20 @@ static void user_fence_worker(struct work_struct *w)
>>  	}
>>  
>>  	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);
>> +	int ret;
>> +
>>  	WRITE_ONCE(ufence->signalled, 1);
>> +
>> +	/* Lets see if debugger wants to track this */
>> +	ret = xe_eudebug_vm_bind_ufence(ufence);
>> +	if (ret)
>> +		xe_sync_ufence_signal(ufence);
>> +
>>  	user_fence_put(ufence);
>>  }
>>  
>> @@ -104,6 +119,7 @@ static void user_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
>>  }
>>  
>>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
>> +			struct xe_vm *vm,
>>  			struct xe_sync_entry *sync,
>>  			struct drm_xe_sync __user *sync_user,
>>  			unsigned int flags)
>> @@ -185,7 +201,8 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
>>  		if (exec) {
>>  			sync->addr = sync_in.addr;
>>  		} else {
>> -			sync->ufence = user_fence_create(xe, sync_in.addr,
>> +			sync->ufence = user_fence_create(xe, xef, vm,
>> +							 sync_in.addr,
>>  							 sync_in.timeline_value);
>>  			if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence)))
>>  				return PTR_ERR(sync->ufence);
>> diff --git a/drivers/gpu/drm/xe/xe_sync.h b/drivers/gpu/drm/xe/xe_sync.h
>> index 256ffc1e54dc..f5bec2b1b4f6 100644
>> --- a/drivers/gpu/drm/xe/xe_sync.h
>> +++ b/drivers/gpu/drm/xe/xe_sync.h
>> @@ -9,8 +9,12 @@
>>  #include "xe_sync_types.h"
>>  
>>  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;
>>  
>> @@ -19,6 +23,7 @@ struct xe_vm;
>>  #define SYNC_PARSE_FLAG_DISALLOW_USER_FENCE	BIT(2)
>>  
>>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
>> +			struct xe_vm *vm,
>>  			struct xe_sync_entry *sync,
>>  			struct drm_xe_sync __user *sync_user,
>>  			unsigned int flags);
>> @@ -40,5 +45,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 30ac3f51993b..907c601a6d8c 100644
>> --- a/drivers/gpu/drm/xe/xe_sync_types.h
>> +++ b/drivers/gpu/drm/xe/xe_sync_types.h
>> @@ -7,12 +7,28 @@
>>  #define _XE_SYNC_TYPES_H_
>>  
>>  #include <linux/types.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/kref.h>
>> +#include <linux/dma-fence-array.h>
>>  
>> -struct drm_syncobj;
>> -struct dma_fence;
>> -struct dma_fence_chain;
>> -struct drm_xe_sync;
>> -struct user_fence;
>> +struct xe_eudebug;
>> +
>> +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;
>> +	struct {
>> +		struct xe_eudebug *debugger;
>> +		u64 bind_ref_seqno;
>> +		u64 signalled_seqno;
>> +		struct work_struct worker;
>> +	} eudebug;
>> +};
>>  
>>  struct xe_sync_entry {
>>  	struct drm_syncobj *syncobj;
>> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
>> index 657a54b74eea..b117a892e386 100644
>> --- a/drivers/gpu/drm/xe/xe_vm.c
>> +++ b/drivers/gpu/drm/xe/xe_vm.c
>> @@ -3049,9 +3049,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>>  		}
>>  	}
>>  
>> +	xe_eudebug_vm_bind_start(vm);
>> +
>>  	syncs_user = u64_to_user_ptr(args->syncs);
>>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
>> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
>> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
>>  					  &syncs_user[num_syncs],
>>  					  (xe_vm_in_lr_mode(vm) ?
>>  					   SYNC_PARSE_FLAG_LR_MODE : 0) |
>> diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
>> index 789c8aa81c09..1875192e92bd 100644
>> --- a/include/uapi/drm/xe_drm_eudebug.h
>> +++ b/include/uapi/drm/xe_drm_eudebug.h
>> @@ -17,6 +17,7 @@ extern "C" {
>>   */
>>  #define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
>>  #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
>> +#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
>>  
>>  /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
>>  struct drm_xe_eudebug_event {
>> @@ -31,7 +32,8 @@ struct drm_xe_eudebug_event {
>>  #define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
>>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND		6
>>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP		7
>> -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_OP
>> +#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE	8
>> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
>>  
>>  	__u16 flags;
>>  #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
>> @@ -158,6 +160,17 @@ struct drm_xe_eudebug_event_vm_bind_op {
>>  	__u64 range; /* XXX: Zero for unmap all? */
>>  };
>>  
>> +struct drm_xe_eudebug_event_vm_bind_ufence {
>> +	struct drm_xe_eudebug_event base;
>> +	__u64 vm_bind_ref_seqno; /* *_event_vm_bind.base.seqno */
>> +};
>> +
>> +struct drm_xe_eudebug_ack_event {
>> +	__u32 type;
>> +	__u32 flags; /* MBZ */
>> +	__u64 seqno;
>> +};
>> +
>>  #if defined(__cplusplus)
>>  }
>>  #endif
>> -- 
>> 2.34.1
>> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-07-26 19:20   ` Matthew Brost
@ 2024-07-30 14:12     ` Mika Kuoppala
  2024-07-31  1:18       ` Matthew Brost
  0 siblings, 1 reply; 78+ messages in thread
From: Mika Kuoppala @ 2024-07-30 14:12 UTC (permalink / raw)
  To: Matthew Brost
  Cc: intel-xe, Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
	Andi Shyti, Matt Roper, Maciej Patelczyk

Matthew Brost <matthew.brost@intel.com> writes:

> On Fri, Jul 26, 2024 at 05:08:00PM +0300, Mika Kuoppala wrote:
>> With eudebug event interface, user space debugger process (like gdb)
>> is able to keep track of resources created by another process
>> (debuggee using drm/xe) and act upon these resources.
>> 
>> For example, debugger can find a client vm which contains isa/elf
>> for a particular shader/eu-kernel and then inspect and modify it
>> (for example installing a breakpoint).
>> 
>> Debugger first opens a connection to xe with a drm ioctl specifying
>> target pid to connect. This returns an anon fd handle that can then be
>> used to listen for events with dedicated ioctl.
>> 
>> This patch introduces eudebug connection and event queuing, adding
>> client create/destroy and vm create/destroy events as a baseline.
>> More events for full debugger operation are needed and
>> those will be introduced in follow up patches.
>> 
>> The resource tracking parts are inspired by the work of
>> Maciej Patelczyk on resource handling for i915. Chris Wilson
>> suggested improvement of two ways mapping which makes it easy to
>> use resource map as a definitive bookkeep of what resources
>> are played to debugger in the discovery phase (on follow up patch).
>> 
>
> Not a full review just an idea. Do you think it would be worthwhile to
> add a Kconfig option to enable EU debug support so if we don't care
> about EU debug it compiles out?
>

It is possible and it was done like this in i915. Test triage space will
grow. On the other hand, we can isolate on hunting issues.

> The layering would have to be fixed up to make this sane (e.g. all
> common Xe code calls into the EU layer so we don't have 'if
> IS_ENABLED(CONFIG_EU_DEBUG)' sprinkled all over the place. Fixing up
> layering probably isn't bad idea anyways and as common Xe code really
> shouldn't open code EU debug specific things anyways. This would enforce
> good layering too.

Agreed that it would enforce better layering. Naturally we cant reach
100% here as there are some ioctl argument and null checks sprinkled.
But perfect is enemy is good. We will push more into the xe_eudebug_*
files and lets see how it look. Kconfig is trivial and icing on the
cake after this.

-Mika

> Matt
>
>> v2: - event printer removed (Maarten)
>>     - trim down kfifo accessors (Maarten)
>>     - xa_alloc spurious locking removed (Maarten)
>> v3: - use list for clients (Matt)
>> v4: - avoid reporting clients too early (Maciej, VLK-56889)
>> v5: - return from wait if disconnect (Mika)
>> v6: - read waitqueue (Mika)
>> v7: - ENOTCONN early in read_event (Mika)
>> v8: - consolidate resource error handling (Mika, Maciej)
>> v9: - ptrace access check (Jonathan)
>> v10: - detach error handling (Dominik)
>> 
>> 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>
>> 
>> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>> Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
>> ---
>>  drivers/gpu/drm/xe/Makefile           |    3 +-
>>  drivers/gpu/drm/xe/xe_device.c        |   24 +
>>  drivers/gpu/drm/xe/xe_device_types.h  |   26 +
>>  drivers/gpu/drm/xe/xe_eudebug.c       | 1093 +++++++++++++++++++++++++
>>  drivers/gpu/drm/xe/xe_eudebug.h       |   27 +
>>  drivers/gpu/drm/xe/xe_eudebug_types.h |  169 ++++
>>  drivers/gpu/drm/xe/xe_vm.c            |    7 +-
>>  include/uapi/drm/xe_drm.h             |   21 +
>>  include/uapi/drm/xe_drm_eudebug.h     |   57 ++
>>  9 files changed, 1425 insertions(+), 2 deletions(-)
>>  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/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
>> index 1ff9602a52f6..06badc5f99af 100644
>> --- a/drivers/gpu/drm/xe/Makefile
>> +++ b/drivers/gpu/drm/xe/Makefile
>> @@ -114,7 +114,8 @@ xe-y += xe_bb.o \
>>  	xe_vram_freq.o \
>>  	xe_wait_user_fence.o \
>>  	xe_wa.o \
>> -	xe_wopcm.o
>> +	xe_wopcm.o \
>> +	xe_eudebug.o
>>  
>>  xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o
>>  
>> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
>> index 1aba6f9eaa19..6c5eceaca4ab 100644
>> --- a/drivers/gpu/drm/xe/xe_device.c
>> +++ b/drivers/gpu/drm/xe/xe_device.c
>> @@ -54,6 +54,7 @@
>>  #include "xe_vm.h"
>>  #include "xe_vram.h"
>>  #include "xe_wait_user_fence.h"
>> +#include "xe_eudebug.h"
>>  #include "xe_wa.h"
>>  
>>  #include <generated/xe_wa_oob.h>
>> @@ -100,6 +101,14 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
>>  		put_task_struct(task);
>>  	}
>>  
>> +	INIT_LIST_HEAD(&xef->link);
>> +
>> +	mutex_lock(&xe->files.lock);
>> +	list_add_tail(&xef->link, &xe->files.list);
>> +	mutex_unlock(&xe->files.lock);
>> +
>> +	xe_eudebug_file_open(xef);
>> +
>>  	return 0;
>>  }
>>  
>> @@ -158,6 +167,12 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
>>  
>>  	xe_pm_runtime_get(xe);
>>  
>> +	xe_eudebug_file_close(xef);
>> +
>> +	mutex_lock(&xef->xe->files.lock);
>> +	list_del_init(&xef->link);
>> +	mutex_unlock(&xef->xe->files.lock);
>> +
>>  	/*
>>  	 * 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
>> @@ -196,6 +211,7 @@ static const struct drm_ioctl_desc xe_ioctls[] = {
>>  	DRM_IOCTL_DEF_DRV(XE_WAIT_USER_FENCE, xe_wait_user_fence_ioctl,
>>  			  DRM_RENDER_ALLOW),
>>  	DRM_IOCTL_DEF_DRV(XE_OBSERVATION, xe_observation_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)
>> @@ -285,6 +301,8 @@ static void xe_device_destroy(struct drm_device *dev, void *dummy)
>>  {
>>  	struct xe_device *xe = to_xe_device(dev);
>>  
>> +	xe_eudebug_fini(xe);
>> +
>>  	if (xe->preempt_fence_wq)
>>  		destroy_workqueue(xe->preempt_fence_wq);
>>  
>> @@ -330,6 +348,9 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
>>  	spin_lock_init(&xe->irq.lock);
>>  	spin_lock_init(&xe->clients.lock);
>>  
>> +	drmm_mutex_init(&xe->drm, &xe->files.lock);
>> +	INIT_LIST_HEAD(&xe->files.list);
>> +
>>  	init_waitqueue_head(&xe->ufence_wq);
>>  
>>  	err = drmm_mutex_init(&xe->drm, &xe->usm.lock);
>> @@ -356,7 +377,10 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
>>  	INIT_LIST_HEAD(&xe->pinned.external_vram);
>>  	INIT_LIST_HEAD(&xe->pinned.evicted);
>>  
>> +	xe_eudebug_init(xe);
>> +
>>  	xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq", 0);
>> +
>>  	xe->ordered_wq = alloc_ordered_workqueue("xe-ordered-wq", 0);
>>  	xe->unordered_wq = alloc_workqueue("xe-unordered-wq", 0, 0);
>>  	if (!xe->ordered_wq || !xe->unordered_wq ||
>> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
>> index 5b7292a9a66d..bef7c11bd668 100644
>> --- a/drivers/gpu/drm/xe/xe_device_types.h
>> +++ b/drivers/gpu/drm/xe/xe_device_types.h
>> @@ -355,6 +355,15 @@ struct xe_device {
>>  		u64 count;
>>  	} clients;
>>  
>> +	/** @files: xe_file list (opens) */
>> +	struct {
>> +		/** @lock: Protects xe_file list */
>> +		struct mutex lock;
>> +
>> +		/** @list: xe file list */
>> +		struct list_head list;
>> +	} files;
>> +
>>  	/** @usm: unified memory state */
>>  	struct {
>>  		/** @usm.asid: convert a ASID to VM */
>> @@ -492,6 +501,20 @@ struct xe_device {
>>  	u8 vm_inject_error_position;
>>  #endif
>>  
>> +	/** @debugger connection list and globals for device */
>> +	struct {
>> +		/** @lock: protects the list of connections */
>> +		spinlock_t lock;
>> +		/** @list: list of connections, aka debuggers */
>> +		struct list_head list;
>> +
>> +		/** @session_count: session counter to track connections */
>> +		u64 session_count;
>> +
>> +		/** @available: is the debugging functionality available */
>> +		bool available;
>> +	} eudebug;
>> +
>>  	/* private: */
>>  
>>  #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
>> @@ -596,6 +619,9 @@ struct xe_file {
>>  
>>  	/** @refcount: ref count of this xe file */
>>  	struct kref refcount;
>> +
>> +	/** @link: link into xe_device.client.list */
>> +	struct list_head link;
>>  };
>>  
>>  #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..8aab02824f8a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
>> @@ -0,0 +1,1093 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright © 2023 Intel Corporation
>> + */
>> +
>> +#include <linux/uaccess.h>
>> +
>> +#include <linux/anon_inodes.h>
>> +#include <linux/poll.h>
>> +#include <linux/delay.h>
>> +
>> +#include <drm/drm_managed.h>
>> +
>> +#include "xe_device.h"
>> +#include "xe_assert.h"
>> +#include "xe_macros.h"
>> +
>> +#include "xe_eudebug_types.h"
>> +#include "xe_eudebug.h"
>> +
>> +/*
>> + * If there is no detected event read by userspace, during this period, assume
>> + * userspace problem and disconnect debugger to allow forward progress.
>> + */
>> +#define XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS (25 * 1000)
>> +
>> +#define for_each_debugger_rcu(debugger, head) \
>> +	list_for_each_entry_rcu((debugger), (head), connection_link)
>> +#define for_each_debugger(debugger, head) \
>> +	list_for_each_entry((debugger), (head), connection_link)
>> +
>> +#define cast_event(T, event) container_of((event), typeof(*(T)), base)
>> +
>> +#define XE_EUDEBUG_DBG_STR "eudbg: %lld:%lu:%s (%d/%d) -> (%d/%d): "
>> +#define XE_EUDEBUG_DBG_ARGS(d) (d)->session, \
>> +		atomic_long_read(&(d)->events.seqno), \
>> +		READ_ONCE(d->connection.status) <= 0 ? "disconnected" : "", \
>> +		current->pid, \
>> +		task_tgid_nr(current), \
>> +		(d)->target_task->pid, \
>> +		task_tgid_nr((d)->target_task)
>> +
>> +#define eu_err(d, fmt, ...) drm_err(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
>> +				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
>> +#define eu_warn(d, fmt, ...) drm_warn(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
>> +				      XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
>> +#define eu_dbg(d, fmt, ...) drm_dbg(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
>> +				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
>> +
>> +#define xe_eudebug_assert(d, ...) xe_assert((d)->xe, ##__VA_ARGS__)
>> +
>> +#define struct_member(T, member) (((T *)0)->member)
>> +
>> +/* Keep 1:1 parity with uapi events */
>> +#define write_member(T_out, ptr, member, value) { \
>> +	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
>> +	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
>> +		     offsetof(typeof(T_out), member)); \
>> +	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
>> +	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
>> +	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
>> +	(ptr)->member = (value); \
>> +	}
>> +
>> +static struct xe_eudebug_event *
>> +event_fifo_pending(struct xe_eudebug *d)
>> +{
>> +	struct xe_eudebug_event *event;
>> +
>> +	if (kfifo_peek(&d->events.fifo, &event))
>> +		return event;
>> +
>> +	return NULL;
>> +}
>> +
>> +/*
>> + * 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_num_events_peek(const struct xe_eudebug * const d)
>> +{
>> +	return kfifo_len(&d->events.fifo);
>> +}
>> +
>> +static bool
>> +xe_eudebug_detached(struct xe_eudebug *d)
>> +{
>> +	int status;
>> +
>> +	spin_lock(&d->connection.lock);
>> +	status = d->connection.status;
>> +	spin_unlock(&d->connection.lock);
>> +
>> +	return status <= 0;
>> +}
>> +
>> +static int
>> +xe_eudebug_error(const struct xe_eudebug * const d)
>> +{
>> +	const int status = READ_ONCE(d->connection.status);
>> +
>> +	return status <= 0 ? status : 0;
>> +}
>> +
>> +static unsigned int
>> +event_fifo_has_events(struct xe_eudebug *d)
>> +{
>> +	if (xe_eudebug_detached(d))
>> +		return 1;
>> +
>> +	return event_fifo_num_events_peek(d);
>> +}
>> +
>> +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_resources * const res, const int t)
>> +{
>> +	return &res->rt[t];
>> +}
>> +
>> +static struct xe_eudebug_resources *
>> +xe_eudebug_resources_alloc(void)
>> +{
>> +	struct xe_eudebug_resources *res;
>> +	int err;
>> +	int i;
>> +
>> +	res = kzalloc(sizeof(*res), GFP_ATOMIC);
>> +	if (!res)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	mutex_init(&res->lock);
>> +
>> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
>> +		xa_init_flags(&res->rt[i].xa, XA_FLAGS_ALLOC1);
>> +		err = rhashtable_init(&res->rt[i].rh, &rhash_res);
>> +
>> +		if (err)
>> +			break;
>> +	}
>> +
>> +	if (err) {
>> +		while (i--) {
>> +			xa_destroy(&res->rt[i].xa);
>> +			rhashtable_destroy(&res->rt[i].rh);
>> +		}
>> +
>> +		kfree(res);
>> +		return ERR_PTR(err);
>> +	}
>> +
>> +	return res;
>> +}
>> +
>> +static void res_free_fn(void *ptr, void *arg)
>> +{
>> +	XE_WARN_ON(ptr);
>> +	kfree(ptr);
>> +}
>> +
>> +static void
>> +xe_eudebug_destroy_resources(struct xe_eudebug *d)
>> +{
>> +	struct xe_eudebug_resources *res = d->res;
>> +	struct xe_eudebug_handle *h;
>> +	unsigned long j;
>> +	int i;
>> +	int err;
>> +
>> +	mutex_lock(&res->lock);
>> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
>> +		struct xe_eudebug_resource *r = &res->rt[i];
>> +
>> +		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);
>> +			xe_eudebug_assert(d, t == h);
>> +			kfree(t);
>> +		}
>> +	}
>> +	mutex_unlock(&res->lock);
>> +
>> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
>> +		struct xe_eudebug_resource *r = &res->rt[i];
>> +
>> +		rhashtable_free_and_destroy(&r->rh, res_free_fn, NULL);
>> +		xe_eudebug_assert(d, xa_empty(&r->xa));
>> +		xa_destroy(&r->xa);
>> +	}
>> +
>> +	mutex_destroy(&res->lock);
>> +
>> +	kfree(res);
>> +}
>> +
>> +static void xe_eudebug_free(struct kref *ref)
>> +{
>> +	struct xe_eudebug *d = container_of(ref, typeof(*d), ref);
>> +	struct xe_eudebug_event *event;
>> +
>> +	while (kfifo_get(&d->events.fifo, &event))
>> +		kfree(event);
>> +
>> +	xe_eudebug_destroy_resources(d);
>> +	put_task_struct(d->target_task);
>> +
>> +	xe_eudebug_assert(d, !kfifo_len(&d->events.fifo));
>> +
>> +	kfree_rcu(d, rcu);
>> +}
>> +
>> +static void xe_eudebug_put(struct xe_eudebug *d)
>> +{
>> +	kref_put(&d->ref, xe_eudebug_free);
>> +}
>> +
>> +static struct task_struct *find_get_target(const pid_t nr)
>> +{
>> +	struct task_struct *task;
>> +
>> +	rcu_read_lock();
>> +	task = pid_task(find_pid_ns(nr, task_active_pid_ns(current)), PIDTYPE_PID);
>> +	if (task)
>> +		get_task_struct(task);
>> +	rcu_read_unlock();
>> +
>> +	return task;
>> +}
>> +
>> +static int
>> +xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
>> +		  const pid_t pid_nr)
>> +{
>> +	struct task_struct *target;
>> +	struct xe_eudebug *iter;
>> +	kuid_t uid = current_uid();
>> +	int ret = 0;
>> +
>> +	target = find_get_target(pid_nr);
>> +	if (!target)
>> +		return -ENOENT;
>> +
>> +	if (!uid_eq(uid, task_uid(target)) && !capable(CAP_SYS_ADMIN)) {
>> +		put_task_struct(target);
>> +		return -EACCES;
>> +	}
>> +
>> +	XE_WARN_ON(d->connection.status != 0);
>> +
>> +	spin_lock(&xe->eudebug.lock);
>> +	for_each_debugger(iter, &xe->eudebug.list) {
>> +		if (!same_thread_group(iter->target_task, target))
>> +			continue;
>> +
>> +		ret = -EBUSY;
>> +	}
>> +
>> +	if (!ret && xe->eudebug.session_count + 1 == 0)
>> +		ret = -ENOSPC;
>> +
>> +	if (!ret) {
>> +		d->connection.status = XE_EUDEBUG_STATUS_CONNECTED;
>> +		d->xe = xe;
>> +		d->target_task = target;
>> +		d->session = ++xe->eudebug.session_count;
>> +		kref_get(&d->ref);
>> +		list_add_tail_rcu(&d->connection_link, &xe->eudebug.list);
>> +	}
>> +	spin_unlock(&xe->eudebug.lock);
>> +
>> +	if (ret)
>> +		put_task_struct(target);
>> +
>> +	return ret;
>> +}
>> +
>> +static bool xe_eudebug_detach(struct xe_device *xe,
>> +			      struct xe_eudebug *d,
>> +			      const int err)
>> +{
>> +	bool detached = false;
>> +
>> +	XE_WARN_ON(err > 0);
>> +
>> +	spin_lock(&d->connection.lock);
>> +	if (d->connection.status == XE_EUDEBUG_STATUS_CONNECTED) {
>> +		d->connection.status = err;
>> +		detached = true;
>> +	}
>> +	spin_unlock(&d->connection.lock);
>> +
>> +	if (!detached)
>> +		return false;
>> +
>> +	spin_lock(&xe->eudebug.lock);
>> +	list_del_rcu(&d->connection_link);
>> +	spin_unlock(&xe->eudebug.lock);
>> +
>> +	eu_dbg(d, "session %lld detached with %d", d->session, err);
>> +
>> +	/* Our ref with the connection_link */
>> +	xe_eudebug_put(d);
>> +
>> +	return true;
>> +}
>> +
>> +static int _xe_eudebug_disconnect(struct xe_eudebug *d,
>> +				  const int err)
>> +{
>> +	wake_up_all(&d->events.write_done);
>> +	wake_up_all(&d->events.read_done);
>> +
>> +	return xe_eudebug_detach(d->xe, d, err);
>> +}
>> +
>> +#define xe_eudebug_disconnect(_d, _err) ({ \
>> +	if (_xe_eudebug_disconnect((_d), (_err))) { \
>> +		if ((_err) == 0 || (_err) == -ETIMEDOUT) \
>> +			eu_dbg(d, "Session closed (%d)", (_err)); \
>> +		else \
>> +			eu_err(d, "Session disconnected, err = %d (%s:%d)", \
>> +			       (_err), __func__, __LINE__); \
>> +	} \
>> +})
>> +
>> +static int xe_eudebug_release(struct inode *inode, struct file *file)
>> +{
>> +	struct xe_eudebug *d = file->private_data;
>> +
>> +	xe_eudebug_disconnect(d, 0);
>> +	xe_eudebug_put(d);
>> +
>> +	return 0;
>> +}
>> +
>> +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 (xe_eudebug_error(d))
>> +			ret |= EPOLLERR;
>> +	}
>> +
>> +	if (event_fifo_num_events_peek(d))
>> +		ret |= EPOLLIN;
>> +
>> +	return ret;
>> +}
>> +
>> +static ssize_t xe_eudebug_read(struct file *file,
>> +			       char __user *buf,
>> +			       size_t count,
>> +			       loff_t *ppos)
>> +{
>> +	return -EINVAL;
>> +}
>> +
>> +static struct xe_eudebug *
>> +xe_eudebug_for_task_get(struct xe_device *xe,
>> +			struct task_struct *task)
>> +{
>> +	struct xe_eudebug *d, *iter;
>> +
>> +	d = NULL;
>> +
>> +	rcu_read_lock();
>> +	for_each_debugger_rcu(iter, &xe->eudebug.list) {
>> +		if (!same_thread_group(iter->target_task, task))
>> +			continue;
>> +
>> +		if (kref_get_unless_zero(&iter->ref))
>> +			d = iter;
>> +
>> +		break;
>> +	}
>> +	rcu_read_unlock();
>> +
>> +	return d;
>> +}
>> +
>> +static struct task_struct *find_task_get(struct xe_file *xef)
>> +{
>> +	struct task_struct *task;
>> +	struct pid *pid;
>> +
>> +	rcu_read_lock();
>> +	pid = rcu_dereference(xef->drm->pid);
>> +	task = pid_task(pid, PIDTYPE_PID);
>> +	if (task)
>> +		get_task_struct(task);
>> +	rcu_read_unlock();
>> +
>> +	return task;
>> +}
>> +
>> +static struct xe_eudebug *
>> +xe_eudebug_get(struct xe_file *xef)
>> +{
>> +	struct task_struct *task;
>> +	struct xe_eudebug *d;
>> +
>> +	d = NULL;
>> +	task = find_task_get(xef);
>> +	if (task) {
>> +		d = xe_eudebug_for_task_get(to_xe_device(xef->drm->minor->dev),
>> +					    task);
>> +		put_task_struct(task);
>> +	}
>> +
>> +	if (!d)
>> +		return NULL;
>> +
>> +	if (xe_eudebug_detached(d)) {
>> +		xe_eudebug_put(d);
>> +		return NULL;
>> +	}
>> +
>> +	return d;
>> +}
>> +
>> +static int xe_eudebug_queue_event(struct xe_eudebug *d,
>> +				  struct xe_eudebug_event *event)
>> +{
>> +	const u64 wait_jiffies = msecs_to_jiffies(1000);
>> +	u64 last_read_detected_ts, last_head_seqno, start_ts;
>> +
>> +	xe_eudebug_assert(d, event->len > sizeof(struct xe_eudebug_event));
>> +	xe_eudebug_assert(d, event->type);
>> +	xe_eudebug_assert(d, event->type != DRM_XE_EUDEBUG_EVENT_READ);
>> +
>> +	start_ts = ktime_get();
>> +	last_read_detected_ts = start_ts;
>> +	last_head_seqno = 0;
>> +
>> +	do  {
>> +		struct xe_eudebug_event *head;
>> +		u64 head_seqno;
>> +		bool was_queued;
>> +
>> +		if (xe_eudebug_detached(d))
>> +			break;
>> +
>> +		spin_lock(&d->events.lock);
>> +		head = event_fifo_pending(d);
>> +		if (head)
>> +			head_seqno = event->seqno;
>> +		else
>> +			head_seqno = 0;
>> +
>> +		was_queued = kfifo_in(&d->events.fifo, &event, 1);
>> +		spin_unlock(&d->events.lock);
>> +
>> +		wake_up_all(&d->events.write_done);
>> +
>> +		if (was_queued) {
>> +			event = NULL;
>> +			break;
>> +		}
>> +
>> +		XE_WARN_ON(!head_seqno);
>> +
>> +		/* If we detect progress, restart timeout */
>> +		if (last_head_seqno != head_seqno)
>> +			last_read_detected_ts = ktime_get();
>> +
>> +		last_head_seqno = head_seqno;
>> +
>> +		wait_event_interruptible_timeout(d->events.read_done,
>> +						 !kfifo_is_full(&d->events.fifo),
>> +						 wait_jiffies);
>> +
>> +	} while (ktime_ms_delta(ktime_get(), last_read_detected_ts) <
>> +		 XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS);
>> +
>> +	if (event) {
>> +		eu_dbg(d,
>> +		       "event %llu queue failed (blocked %lld ms, avail %d)",
>> +		       event ? event->seqno : 0,
>> +		       ktime_ms_delta(ktime_get(), start_ts),
>> +		       kfifo_avail(&d->events.fifo));
>> +
>> +		kfree(event);
>> +
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static struct xe_eudebug_handle *
>> +alloc_handle(const int type, const u64 key)
>> +{
>> +	struct xe_eudebug_handle *h;
>> +
>> +	h = kzalloc(sizeof(*h), GFP_ATOMIC);
>> +	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 find_handle(struct xe_eudebug_resources *res,
>> +		       const int type,
>> +		       const void *p)
>> +{
>> +	const u64 key = (u64)p;
>> +	struct xe_eudebug_resource *r;
>> +	struct xe_eudebug_handle *h;
>> +	int id;
>> +
>> +	if (XE_WARN_ON(!key))
>> +		return -EINVAL;
>> +
>> +	r = resource_from_type(res, type);
>> +
>> +	mutex_lock(&res->lock);
>> +	h = __find_handle(r, key);
>> +	id = h ? h->id : -ENOENT;
>> +	mutex_unlock(&res->lock);
>> +
>> +	return id;
>> +}
>> +
>> +static int _xe_eudebug_add_handle(struct xe_eudebug *d,
>> +				  int type,
>> +				  void *p,
>> +				  u64 *seqno,
>> +				  int *handle)
>> +{
>> +	const u64 key = (u64)p;
>> +	struct xe_eudebug_resource *r;
>> +	struct xe_eudebug_handle *h, *o;
>> +	int err;
>> +
>> +	if (XE_WARN_ON(p == NULL))
>> +		return -EINVAL;
>> +
>> +	if (xe_eudebug_detached(d))
>> +		return -ENOTCONN;
>> +
>> +	h = alloc_handle(type, key);
>> +	if (!h)
>> +		return -ENOMEM;
>> +
>> +	r = resource_from_type(d->res, type);
>> +
>> +	mutex_lock(&d->res->lock);
>> +	o = __find_handle(r, key);
>> +	if (!o) {
>> +		err = xa_alloc(&r->xa, &h->id, h, xa_limit_31b, GFP_KERNEL);
>> +
>> +		if (h->id >= INT_MAX) {
>> +			xa_erase(&r->xa, h->id);
>> +			err = -ENOSPC;
>> +		}
>> +
>> +		if (!err)
>> +			err = rhashtable_insert_fast(&r->rh,
>> +						     &h->rh_head,
>> +						     rhash_res);
>> +
>> +		if (err) {
>> +			xa_erase(&r->xa, h->id);
>> +		} else {
>> +			if (seqno)
>> +				*seqno = atomic_long_inc_return(&d->events.seqno);
>> +		}
>> +	} else {
>> +		xe_eudebug_assert(d, o->id);
>> +		err = -EEXIST;
>> +	}
>> +	mutex_unlock(&d->res->lock);
>> +
>> +	if (handle)
>> +		*handle = o ? o->id : h->id;
>> +
>> +	if (err) {
>> +		kfree(h);
>> +		XE_WARN_ON(err > 0);
>> +		return err;
>> +	}
>> +
>> +	xe_eudebug_assert(d, h->id);
>> +
>> +	return h->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, NULL);
>> +	if (ret == -EEXIST || ret == -ENOTCONN) {
>> +		eu_dbg(d, "%d on adding %d", ret, type);
>> +		return 0;
>> +	}
>> +
>> +	if (ret < 0)
>> +		xe_eudebug_disconnect(d, ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static int _xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
>> +				     u64 *seqno)
>> +{
>> +	const u64 key = (u64)p;
>> +	struct xe_eudebug_resource *r;
>> +	struct xe_eudebug_handle *h, *xa_h;
>> +	int ret;
>> +
>> +	if (XE_WARN_ON(!key))
>> +		return -EINVAL;
>> +
>> +	if (xe_eudebug_detached(d))
>> +		return -ENOTCONN;
>> +
>> +	r = resource_from_type(d->res, type);
>> +
>> +	mutex_lock(&d->res->lock);
>> +	h = __find_handle(r, key);
>> +	if (h) {
>> +		ret = rhashtable_remove_fast(&r->rh,
>> +					     &h->rh_head,
>> +					     rhash_res);
>> +		xe_eudebug_assert(d, !ret);
>> +		xa_h = xa_erase(&r->xa, h->id);
>> +		xe_eudebug_assert(d, xa_h == h);
>> +		if (!ret) {
>> +			ret = h->id;
>> +			if (seqno)
>> +				*seqno = atomic_long_inc_return(&d->events.seqno);
>> +		}
>> +	} else {
>> +		ret = -ENOENT;
>> +	}
>> +	mutex_unlock(&d->res->lock);
>> +
>> +	kfree(h);
>> +
>> +	xe_eudebug_assert(d, ret);
>> +
>> +	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);
>> +	if (ret == -ENOENT || ret == -ENOTCONN) {
>> +		eu_dbg(d, "%d on removing %d", ret, type);
>> +		return 0;
>> +	}
>> +
>> +	if (ret < 0)
>> +		xe_eudebug_disconnect(d, ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static struct xe_eudebug_event *
>> +__xe_eudebug_create_event(struct xe_eudebug *d,
>> +			  u64 seqno, u16 type, u16 flags, u32 len, gfp_t gfp)
>> +{
>> +	struct xe_eudebug_event *event;
>> +
>> +	xe_eudebug_assert(d, len > sizeof(*event));
>> +
>> +	event = kzalloc(len, gfp);
>> +	if (!event)
>> +		return NULL;
>> +
>> +	event->type = type;
>> +	event->flags = flags;
>> +	event->len = len;
>> +	event->seqno = seqno;
>> +
>> +	return event;
>> +}
>> +
>> +static struct xe_eudebug_event *
>> +xe_eudebug_create_event(struct xe_eudebug *d, u16 type, u64 seqno, u16 flags,
>> +			u32 len, gfp_t gfp)
>> +{
>> +	return __xe_eudebug_create_event(d, seqno, type, flags, len, gfp);
>> +}
>> +
>> +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 drm_xe_eudebug_event user_event;
>> +	struct xe_eudebug_event *event;
>> +	long ret = 0;
>> +
>> +	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))
>> +		return -EINVAL;
>> +
>> +	if (XE_IOCTL_DBG(xe, user_event.type > DRM_XE_EUDEBUG_EVENT_MAX_EVENT))
>> +		return -EINVAL;
>> +
>> +	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.reserved))
>> +		return -EINVAL;
>> +
>> +	/* 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;
>> +	}
>> +
>> +	ret = 0;
>> +	spin_lock(&d->events.lock);
>> +	event = event_fifo_pending(d);
>> +	if (event) {
>> +		if (user_event.len < event->len) {
>> +			ret = -EMSGSIZE;
>> +		} else if (!kfifo_out(&d->events.fifo, &event, 1)) {
>> +			eu_warn(d, "internal fifo corruption");
>> +			ret = -ENOTCONN;
>> +		}
>> +	}
>> +	spin_unlock(&d->events.lock);
>> +
>> +	wake_up_all(&d->events.read_done);
>> +
>> +	if (XE_IOCTL_DBG(xe, ret))
>> +		return ret;
>> +
>> +	if (!event) {
>> +		if (xe_eudebug_detached(d))
>> +			return -ENOTCONN;
>> +		if (!wait)
>> +			return -EAGAIN;
>> +
>> +		return -ENOENT;
>> +	}
>> +
>> +	if (copy_to_user(user_orig, event, event->len))
>> +		ret = -EFAULT;
>> +	else
>> +		eu_dbg(d, "event read: type=%u, flags=0x%x, seqno=%llu", event->type,
>> +		       event->flags, event->seqno);
>> +
>> +	kfree(event);
>> +
>> +	return ret;
>> +}
>> +
>> +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,
>> +	.llseek		= no_llseek,
>> +	.release	= xe_eudebug_release,
>> +	.poll		= xe_eudebug_poll,
>> +	.read		= xe_eudebug_read,
>> +	.unlocked_ioctl	= xe_eudebug_ioctl,
>> +};
>> +
>> +static int
>> +xe_eudebug_connect(struct xe_device *xe,
>> +		   struct drm_xe_eudebug_connect *param)
>> +{
>> +	const u64 known_open_flags = 0;
>> +	unsigned long f_flags = 0;
>> +	struct xe_eudebug *d;
>> +	int fd, err;
>> +
>> +	if (param->extensions)
>> +		return -EINVAL;
>> +
>> +	if (!param->pid)
>> +		return -EINVAL;
>> +
>> +	if (param->flags & ~known_open_flags)
>> +		return -EINVAL;
>> +
>> +	if (param->version && param->version != DRM_XE_EUDEBUG_VERSION)
>> +		return -EINVAL;
>> +
>> +	param->version = DRM_XE_EUDEBUG_VERSION;
>> +
>> +	if (!xe->eudebug.available)
>> +		return -EOPNOTSUPP;
>> +
>> +	d = kzalloc(sizeof(*d), GFP_KERNEL);
>> +	if (!d)
>> +		return -ENOMEM;
>> +
>> +	kref_init(&d->ref);
>> +	spin_lock_init(&d->connection.lock);
>> +	init_waitqueue_head(&d->events.write_done);
>> +	init_waitqueue_head(&d->events.read_done);
>> +
>> +	spin_lock_init(&d->events.lock);
>> +	INIT_KFIFO(d->events.fifo);
>> +
>> +	d->res = xe_eudebug_resources_alloc();
>> +	if (IS_ERR(d->res)) {
>> +		err = PTR_ERR(d->res);
>> +		goto err_free;
>> +	}
>> +
>> +	err = xe_eudebug_attach(xe, d, param->pid);
>> +	if (err)
>> +		goto err_free_res;
>> +
>> +	fd = anon_inode_getfd("[xe_eudebug]", &fops, d, f_flags);
>> +	if (fd < 0) {
>> +		err = fd;
>> +		goto err_detach;
>> +	}
>> +
>> +	eu_dbg(d, "connected session %lld", d->session);
>> +
>> +	return fd;
>> +
>> +err_detach:
>> +	xe_eudebug_detach(xe, d, err);
>> +err_free_res:
>> +	xe_eudebug_destroy_resources(d);
>> +err_free:
>> +	kfree(d);
>> +
>> +	return err;
>> +}
>> +
>> +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;
>> +	int ret = 0;
>> +
>> +	ret = xe_eudebug_connect(xe, param);
>> +
>> +	return ret;
>> +}
>> +
>> +void xe_eudebug_init(struct xe_device *xe)
>> +{
>> +	spin_lock_init(&xe->eudebug.lock);
>> +	INIT_LIST_HEAD(&xe->eudebug.list);
>> +
>> +	xe->eudebug.available = true;
>> +}
>> +
>> +void xe_eudebug_fini(struct xe_device *xe)
>> +{
>> +	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
>> +}
>> +
>> +static int send_open_event(struct xe_eudebug *d, u32 flags, const u64 handle,
>> +			   const u64 seqno)
>> +{
>> +	struct xe_eudebug_event *event;
>> +	struct xe_eudebug_event_open *eo;
>> +
>> +	if (!handle)
>> +		return -EINVAL;
>> +
>> +	if (XE_WARN_ON((long)handle >= INT_MAX))
>> +		return -EINVAL;
>> +
>> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_OPEN, seqno,
>> +					flags, sizeof(*eo), GFP_KERNEL);
>> +	if (!event)
>> +		return -ENOMEM;
>> +
>> +	eo = cast_event(eo, event);
>> +
>> +	write_member(struct drm_xe_eudebug_event_client, eo,
>> +		     client_handle, handle);
>> +
>> +	return xe_eudebug_queue_event(d, event);
>> +}
>> +
>> +static int client_create_event(struct xe_eudebug *d, struct xe_file *xef)
>> +{
>> +	u64 seqno;
>> +	int ret;
>> +
>> +	ret = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT, xef, &seqno);
>> +	if (ret > 0)
>> +		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
>> +					     ret, seqno);
>> +
>> +	return ret;
>> +}
>> +
>> +static int client_destroy_event(struct xe_eudebug *d, struct xe_file *xef)
>> +{
>> +	u64 seqno;
>> +	int ret;
>> +
>> +	ret = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT,
>> +				       xef, &seqno);
>> +	if (ret > 0)
>> +		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY,
>> +				      ret, seqno);
>> +
>> +	return ret;
>> +}
>> +
>> +#define xe_eudebug_event_put(_d, _err) ({ \
>> +	if ((_err)) \
>> +		xe_eudebug_disconnect((_d), (_err)); \
>> +	xe_eudebug_put((_d)); \
>> +	})
>> +
>> +void xe_eudebug_file_open(struct xe_file *xef)
>> +{
>> +	struct xe_eudebug *d;
>> +
>> +	d = xe_eudebug_get(xef);
>> +	if (!d)
>> +		return;
>> +
>> +	xe_eudebug_event_put(d, client_create_event(d, xef));
>> +}
>> +
>> +void xe_eudebug_file_close(struct xe_file *xef)
>> +{
>> +	struct xe_eudebug *d;
>> +
>> +	d = xe_eudebug_get(xef);
>> +	if (!d)
>> +		return;
>> +
>> +	xe_eudebug_event_put(d, client_destroy_event(d, xef));
>> +}
>> +
>> +static int send_vm_event(struct xe_eudebug *d, u32 flags,
>> +			 const u64 client_handle,
>> +			 const u64 vm_handle,
>> +			 const u64 seqno)
>> +{
>> +	struct xe_eudebug_event *event;
>> +	struct xe_eudebug_event_vm *e;
>> +
>> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM,
>> +					seqno, flags, sizeof(*e), GFP_KERNEL);
>> +	if (!event)
>> +		return -ENOMEM;
>> +
>> +	e = cast_event(e, event);
>> +
>> +	write_member(struct drm_xe_eudebug_event_vm, e, client_handle, client_handle);
>> +	write_member(struct drm_xe_eudebug_event_vm, e, vm_handle, vm_handle);
>> +
>> +	return xe_eudebug_queue_event(d, event);
>> +}
>> +
>> +static int vm_create_event(struct xe_eudebug *d,
>> +			   struct xe_file *xef, struct xe_vm *vm)
>> +{
>> +	int h_c, h_vm;
>> +	u64 seqno;
>> +	int ret;
>> +
>> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
>> +	if (h_c < 0)
>> +		return h_c;
>> +
>> +	xe_eudebug_assert(d, h_c);
>> +
>> +	h_vm = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
>> +	if (h_vm <= 0)
>> +		return h_vm;
>> +
>> +	ret = send_vm_event(d, DRM_XE_EUDEBUG_EVENT_CREATE, h_c, h_vm, seqno);
>> +
>> +	return ret;
>> +}
>> +
>> +static int vm_destroy_event(struct xe_eudebug *d,
>> +			    struct xe_file *xef, struct xe_vm *vm)
>> +{
>> +	int h_c, h_vm;
>> +	u64 seqno;
>> +
>> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
>> +	if (h_c < 0) {
>> +		XE_WARN_ON("no client found for vm");
>> +		eu_warn(d, "no client found for vm");
>> +		return h_c;
>> +	}
>> +
>> +	xe_eudebug_assert(d, h_c);
>> +
>> +	h_vm = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
>> +	if (h_vm <= 0)
>> +		return h_vm;
>> +
>> +	return send_vm_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY, h_c, h_vm, seqno);
>> +}
>> +
>> +void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm)
>> +{
>> +	struct xe_eudebug *d;
>> +
>> +	d = xe_eudebug_get(xef);
>> +	if (!d)
>> +		return;
>> +
>> +	xe_eudebug_event_put(d, vm_create_event(d, xef, vm));
>> +}
>> +
>> +void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
>> +{
>> +	struct xe_eudebug *d;
>> +
>> +	d = xe_eudebug_get(xef);
>> +	if (!d)
>> +		return;
>> +
>> +	xe_eudebug_event_put(d, vm_destroy_event(d, xef, vm));
>> +}
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
>> new file mode 100644
>> index 000000000000..df577b581364
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
>> @@ -0,0 +1,27 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright © 2023 Intel Corporation
>> + */
>> +
>> +#ifndef _XE_EUDEBUG_H_
>> +
>> +struct drm_device;
>> +struct drm_file;
>> +struct xe_device;
>> +struct xe_file;
>> +struct xe_vm;
>> +
>> +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_fini(struct xe_device *xe);
>> +
>> +void xe_eudebug_file_open(struct xe_file *xef);
>> +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);
>> +
>> +#endif
>> 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..093221a707df
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
>> @@ -0,0 +1,169 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright © 2023 Intel Corporation
>> + */
>> +
>> +#ifndef __XE_EUDEBUG_TYPES_H_
>> +
>> +#include <linux/mutex.h>
>> +#include <linux/kref.h>
>> +#include <linux/kfifo.h>
>> +#include <linux/completion.h>
>> +#include <linux/wait.h>
>> +#include <linux/xarray.h>
>> +#include <linux/rbtree.h>
>> +#include <linux/rhashtable.h>
>> +
>> +#include <uapi/drm/xe_drm.h>
>> +
>> +struct xe_device;
>> +struct task_struct;
>> +struct xe_eudebug_event;
>> +
>> +#define CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE 64
>> +
>> +/**
>> + * 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 {
>> +	/** @xa: xarrays for <id->key> */
>> +	struct xarray xa;
>> +
>> +	/** @rh rhashtable for <key->id> */
>> +	struct rhashtable rh;
>> +};
>> +
>> +#define XE_EUDEBUG_RES_TYPE_CLIENT	0
>> +#define XE_EUDEBUG_RES_TYPE_VM		1
>> +#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_VM + 1)
>> +
>> +/**
>> + * struct xe_eudebug_resources - eudebug resources for all types
>> + */
>> +struct xe_eudebug_resources {
>> +	/** @lock: guards access into rt */
>> +	struct mutex lock;
>> +
>> +	/** @rt: resource maps for all types */
>> +	struct xe_eudebug_resource rt[XE_EUDEBUG_RES_TYPE_COUNT];
>> +};
>> +
>> +/**
>> + * struct xe_eudebug - Top level struct for eudebug: the connection
>> + */
>> +struct xe_eudebug {
>> +	/** @ref: kref counter for this struct */
>> +	struct kref ref;
>> +
>> +	/** @rcu: rcu_head for rcu destruction */
>> +	struct rcu_head rcu;
>> +
>> +	/** @connection_link: our link into the xe_device:eudebug.list */
>> +	struct list_head connection_link;
>> +
>> +	struct {
>> +		/** @status: connected = 1, disconnected = error */
>> +#define XE_EUDEBUG_STATUS_CONNECTED 1
>> +		int status;
>> +
>> +		/** @lock: guards access to status */
>> +		spinlock_t lock;
>> +	} connection;
>> +
>> +	/** @xe: the parent device we are serving */
>> +	struct xe_device *xe;
>> +
>> +	/** @target_task: the task that we are debugging */
>> +	struct task_struct *target_task;
>> +
>> +	/** @res: the resource maps we track for target_task */
>> +	struct xe_eudebug_resources *res;
>> +
>> +	/** @session: session number for this connection (for logs) */
>> +	u64 session;
>> +
>> +	/** @events: kfifo queue of to-be-delivered events */
>> +	struct {
>> +		/** @lock: guards access to fifo */
>> +		spinlock_t lock;
>> +
>> +		/** @fifo: queue of events pending */
>> +		DECLARE_KFIFO(fifo,
>> +			      struct xe_eudebug_event *,
>> +			      CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE);
>> +
>> +		/** @write_done: waitqueue for signalling write to fifo */
>> +		wait_queue_head_t write_done;
>> +
>> +		/** @read_done: waitqueue for signalling read from fifo */
>> +		wait_queue_head_t read_done;
>> +
>> +		/** @event_seqno: seqno counter to stamp events for fifo */
>> +		atomic_long_t seqno;
>> +	} events;
>> +
>> +};
>> +
>> +/**
>> + * struct xe_eudebug_event - Internal base event struct for eudebug
>> + */
>> +struct xe_eudebug_event {
>> +	/** @len: length of this event, including payload */
>> +	u32 len;
>> +
>> +	/** @type: message type */
>> +	u16 type;
>> +
>> +	/** @flags: message flags */
>> +	u16 flags;
>> +
>> +	/** @seqno: sequence number for ordering */
>> +	u64 seqno;
>> +
>> +	/** @reserved: reserved field MBZ */
>> +	u64 reserved;
>> +
>> +	/** @data: payload bytes */
>> +	u8 data[];
>> +};
>> +
>> +/**
>> + * struct xe_eudebug_event_open - Internal event for client open/close
>> + */
>> +struct xe_eudebug_event_open {
>> +	/** @base: base event */
>> +	struct xe_eudebug_event base;
>> +
>> +	/** @client_handle: opaque handle for client */
>> +	u64 client_handle;
>> +};
>> +
>> +/**
>> + * struct xe_eudebug_event_vm - Internal event for vm open/close
>> + */
>> +struct xe_eudebug_event_vm {
>> +	/** @base: base event */
>> +	struct xe_eudebug_event base;
>> +
>> +	/** @client_handle: client containing the vm open/close */
>> +	u64 client_handle;
>> +
>> +	/** @vm_handle: vm handle it's open/close */
>> +	u64 vm_handle;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
>> index f225107bdd65..9e101c992d9c 100644
>> --- a/drivers/gpu/drm/xe/xe_vm.c
>> +++ b/drivers/gpu/drm/xe/xe_vm.c
>> @@ -39,6 +39,7 @@
>>  #include "xe_trace_bo.h"
>>  #include "xe_wa.h"
>>  #include "xe_hmm.h"
>> +#include "xe_eudebug.h"
>>  
>>  static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
>>  {
>> @@ -1818,6 +1819,8 @@ 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
>>  
>> +	xe_eudebug_vm_create(xef, vm);
>> +
>>  	return 0;
>>  
>>  err_free_id:
>> @@ -1853,8 +1856,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 29425d7fdc77..a68734ff12f4 100644
>> --- a/include/uapi/drm/xe_drm.h
>> +++ b/include/uapi/drm/xe_drm.h
>> @@ -102,6 +102,7 @@ extern "C" {
>>  #define DRM_XE_EXEC			0x09
>>  #define DRM_XE_WAIT_USER_FENCE		0x0a
>>  #define DRM_XE_OBSERVATION		0x0b
>> +#define DRM_XE_EUDEBUG_CONNECT		0x0c
>>  
>>  /* Must be kept compact -- no holes */
>>  
>> @@ -117,6 +118,7 @@ extern "C" {
>>  #define DRM_IOCTL_XE_EXEC			DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC, struct drm_xe_exec)
>>  #define DRM_IOCTL_XE_WAIT_USER_FENCE		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence)
>>  #define DRM_IOCTL_XE_OBSERVATION		DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param)
>> +#define DRM_IOCTL_XE_EUDEBUG_CONNECT		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)
>>  
>>  /**
>>   * DOC: Xe IOCTL Extensions
>> @@ -1694,6 +1696,25 @@ struct drm_xe_oa_stream_info {
>>  	__u64 reserved[3];
>>  };
>>  
>> +/*
>> + * Debugger ABI (ioctl and events) Version History:
>> + * 0 - No debugger available
>> + * 1 - Initial version
>> + */
>> +#define DRM_XE_EUDEBUG_VERSION 1
>> +
>> +struct drm_xe_eudebug_connect {
>> +	/** @extensions: Pointer to the first extension struct, if any */
>> +	__u64 extensions;
>> +
>> +	__u64 pid; /* input: Target process ID */
>> +	__u32 flags; /* MBZ */
>> +
>> +	__u32 version; /* output: current ABI (ioctl / events) version */
>> +};
>> +
>> +#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..a1cad9c005fc
>> --- /dev/null
>> +++ b/include/uapi/drm/xe_drm_eudebug.h
>> @@ -0,0 +1,57 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright © 2023 Intel Corporation
>> + */
>> +
>> +#ifndef _UAPI_XE_DRM_EUDEBUG_H_
>> +#define _UAPI_XE_DRM_EUDEBUG_H_
>> +
>> +#if defined(__cplusplus)
>> +extern "C" {
>> +#endif
>> +
>> +/**
>> + * Do a eudebug event read for a debugger connection.
>> + *
>> + * This ioctl is available in debug version 1.
>> + */
>> +#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
>> +
>> +/* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
>> +struct drm_xe_eudebug_event {
>> +	__u32 len;
>> +
>> +	__u16 type;
>> +#define DRM_XE_EUDEBUG_EVENT_NONE		0
>> +#define DRM_XE_EUDEBUG_EVENT_READ		1
>> +#define DRM_XE_EUDEBUG_EVENT_OPEN		2
>> +#define DRM_XE_EUDEBUG_EVENT_VM			3
>> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM
>> +
>> +	__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)
>> +	__u64 seqno;
>> +	__u64 reserved;
>> +};
>> +
>> +struct drm_xe_eudebug_event_client {
>> +	struct drm_xe_eudebug_event base;
>> +
>> +	__u64 client_handle; /* This is unique per debug connection */
>> +};
>> +
>> +struct drm_xe_eudebug_event_vm {
>> +	struct drm_xe_eudebug_event base;
>> +
>> +	__u64 client_handle;
>> +	__u64 vm_handle;
>> +};
>> +
>> +#if defined(__cplusplus)
>> +}
>> +#endif
>> +
>> +#endif
>> -- 
>> 2.34.1
>> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality
  2024-07-28  4:50   ` Matthew Brost
@ 2024-07-30 15:01     ` Manszewski, Christoph
  2024-07-31 18:03       ` Matthew Brost
  2024-08-07 10:09     ` Manszewski, Christoph
  1 sibling, 1 reply; 78+ messages in thread
From: Manszewski, Christoph @ 2024-07-30 15:01 UTC (permalink / raw)
  To: Matthew Brost, Mika Kuoppala
  Cc: intel-xe, Dominik Grzegorzek, Maciej Patelczyk, Joonas Lahtinen

Hi Matt,

On 28.07.2024 06:50, Matthew Brost wrote:
> On Fri, Jul 26, 2024 at 05:08:17PM +0300, Mika Kuoppala wrote:
>> From: Christoph Manszewski <christoph.manszewski@intel.com>
>>
>> Make it possible to dynamically enable/disable debugger funtionality,
>> including the setting and unsetting of required hw register values via a
>> sysfs entry located at '/sys/class/drm/card<X>/device/enable_eudebug'.
>>
>> This entry uses 'kstrtobool' and as such it accepts inputs as documented
>> by this function, in particular '0' and '1'.
>>
>> 1) Adjust to xe_rtp graphics ranges changes.
>> 2) Fix pile placement. Wa 14019869343 (aka. 16021232320) was
>> added later in the pile, move disablement to appropriate commit.
>> 3) flush reset (Christoph)
>> 4) dont allow exec queue enable if feature is disabled (Dominik)
>> 5) bind to drm sysfs functions (Maciej)
>>
>> Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
>> 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/xe_device.c       |   2 -
>>   drivers/gpu/drm/xe/xe_device_types.h |   5 +
>>   drivers/gpu/drm/xe/xe_eudebug.c      | 174 +++++++++++++++++++++++----
>>   drivers/gpu/drm/xe/xe_eudebug.h      |   2 -
>>   drivers/gpu/drm/xe/xe_exec_queue.c   |   3 +
>>   drivers/gpu/drm/xe/xe_hw_engine.c    |   1 -
>>   drivers/gpu/drm/xe/xe_reg_sr.c       |  21 +++-
>>   drivers/gpu/drm/xe/xe_reg_sr.h       |   4 +-
>>   drivers/gpu/drm/xe/xe_rtp.c          |   2 +-
>>   drivers/gpu/drm/xe/xe_rtp_types.h    |   1 +
>>   10 files changed, 178 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
>> index 268faa1800c4..30a2bf2a7e00 100644
>> --- a/drivers/gpu/drm/xe/xe_device.c
>> +++ b/drivers/gpu/drm/xe/xe_device.c
>> @@ -785,8 +785,6 @@ int xe_device_probe(struct xe_device *xe)
>>   
>>   	xe_debugfs_register(xe);
>>   
>> -	xe_eudebug_init_late(xe);
>> -
>>   	xe_hwmon_register(xe);
>>   
>>   	for_each_gt(gt, xe, id)
>> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
>> index beb1f3c8dc63..17aedbba3130 100644
>> --- a/drivers/gpu/drm/xe/xe_device_types.h
>> +++ b/drivers/gpu/drm/xe/xe_device_types.h
>> @@ -517,6 +517,11 @@ struct xe_device {
>>   		/** @ordered_wq: used to discovery */
>>   		struct workqueue_struct *ordered_wq;
>>   
>> +		/** @enable_lock: protects the enable toggle */
>> +		struct mutex enable_lock;
>> +		/** @enable: is the debugging functionality enabled */
>> +		bool enable;
>> +
>>   		/** @attention_scan: attention scan worker */
>>   		struct delayed_work attention_scan;
>>   	} eudebug;
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
>> index a80ffb64df15..80066f787ec2 100644
>> --- a/drivers/gpu/drm/xe/xe_eudebug.c
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
>> @@ -2000,9 +2000,6 @@ xe_eudebug_connect(struct xe_device *xe,
>>   
>>   	param->version = DRM_XE_EUDEBUG_VERSION;
>>   
>> -	if (!xe->eudebug.available)
>> -		return -EOPNOTSUPP;
>> -
>>   	d = kzalloc(sizeof(*d), GFP_KERNEL);
>>   	if (!d)
>>   		return -ENOMEM;
>> @@ -2064,70 +2061,199 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>>   	struct drm_xe_eudebug_connect * const param = data;
>>   	int ret = 0;
>>   
>> +	mutex_lock(&xe->eudebug.enable_lock);
>> +
>> +	if (!xe->eudebug.enable) {
>> +		mutex_unlock(&xe->eudebug.enable_lock);
>> +		return -ENODEV;
>> +	}
>> +
>>   	ret = xe_eudebug_connect(xe, param);
>>   
>> +	mutex_unlock(&xe->eudebug.enable_lock);
>> +
>>   	return ret;
>>   }
>>   
>>   #undef XE_REG_MCR
>>   #define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
>>   
>> -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
>> +static void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
>>   {
>>   	const struct xe_rtp_entry_sr eudebug_was[] = {
>> -		{ XE_RTP_NAME("GlobalDebugEnable"),
>> -		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
>> -			       ENGINE_CLASS(RENDER)),
>> -		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
>> -				     GLOBAL_DEBUG_ENABLE))
>> -		},
>>   		{ XE_RTP_NAME("TdCtlDebugEnable"),
>>   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>>   		  XE_RTP_ACTIONS(SET(TD_CTL,
>>   				     TD_CTL_BREAKPOINT_ENABLE |
>>   				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
>> -				     TD_CTL_FEH_AND_FEE_ENABLE))
>> +				     TD_CTL_FEH_AND_FEE_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
>>   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>> -		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
>> +		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{ XE_RTP_NAME("18022722726"),
>>   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>> -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
>> +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{ XE_RTP_NAME("14015527279"),
>>   		  XE_RTP_RULES(PLATFORM(PVC),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>> -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
>> +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{}
>>   	};
>>   	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
>> -	struct xe_device *xe = gt_to_xe(hwe->gt);
>>   
>> -	if (xe->eudebug.available)
>> -		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>> +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>> +}
>> +
>> +static void xe_eudebug_fini_hw_engine(struct xe_hw_engine *hwe)
>> +{
>> +	const struct xe_rtp_entry_sr eudebug_was[] = {
>> +		{ XE_RTP_NAME("TdCtlDebugEnable"),
>> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(TD_CTL,
>> +				     TD_CTL_BREAKPOINT_ENABLE |
>> +				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
>> +				     TD_CTL_FEH_AND_FEE_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
>> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{ XE_RTP_NAME("18022722726"),
>> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{ XE_RTP_NAME("14015527279"),
>> +		  XE_RTP_RULES(PLATFORM(PVC),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{}
>> +	};
>> +	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
>> +
>> +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>> +}
>> +
>> +static int xe_eudebug_enable(struct xe_device *xe, bool enable)
>> +{
>> +	struct xe_gt *gt;
>> +	int i;
>> +	u8 id;
>> +
>> +	if (!xe->eudebug.available)
>> +		return -EOPNOTSUPP;
>> +
>> +	/* XXX: TODO hold list lock? */
>> +	mutex_lock(&xe->eudebug.enable_lock);
>> +
>> +	if (!enable && !list_empty(&xe->eudebug.list)) {
>> +		mutex_unlock(&xe->eudebug.enable_lock);
>> +		return -EBUSY;
>> +	}
>> +
>> +	if (enable == xe->eudebug.enable) {
>> +		mutex_unlock(&xe->eudebug.enable_lock);
>> +		return 0;
>> +	}
>> +
>> +	for_each_gt(gt, xe, id) {
>> +		for (i = 0; i < ARRAY_SIZE(gt->hw_engines); i++) {
>> +			if (!(gt->info.engine_mask & BIT(i)))
>> +				continue;
>> +
>> +			if (enable)
>> +				xe_eudebug_init_hw_engine(&gt->hw_engines[i]);
>> +			else
>> +				xe_eudebug_fini_hw_engine(&gt->hw_engines[i]);
>> +		}
>> +
>> +		xe_gt_reset_async(gt);
> 
> What are you trying to accomplish with the reset? Reinit of some HW
> settings? Doing GT reset does have a side affect of killing exec queues
> with jobs active on the GPU which is not ideal. Please explain exactly
> what needs to be done, and maybe we can brainstorm something that won't
> kill things.

Yes, the intention is to set the required registers using the modified 
reg_sr entries. The reason for performing a reset here, instead of 
directly writing the mmio registers, is that to my best knowledge the 
register values are fetched on thread dispatch. Thus, modifying them 
directly would result in having inconsistent TD_CTL values across 
threads, which would break debugging. Resetting is a harsh way of 
ensuring consistency.

Of course, I am more than happy to discuss a better approach.

> 
> Also exposing a GT reset via sysfs might be potential security issue
> too.

I assumed that since it is only available for privileged users, security 
should not be a concern here.

> 
>> +		flush_work(&gt->reset.worker);
> 
> Flushing the reset worker here creates a lock dependency chain with
> xe->eudebug.enable_lock and all locks taken during a GT reset which is
> not ideal either. If we need to do a GT reset (or something else with a
> worker that takes locks) it probably best to flush the worker after
> dropping xe->eudebug.enable_lock. This relates to my other comments on
> locking, we shouldn't create lock depeendecy chains unless we have to
> and the chains are well defined.

Got it.

Thanks for your feeback,
Christoph

> 
> Matt
> 
>> +	}
>> +
>> +	if (enable)
>> +		attention_scan_flush(xe);
>> +	else
>> +		attention_scan_cancel(xe);
>> +
>> +	xe->eudebug.enable = enable;
>> +	mutex_unlock(&xe->eudebug.enable_lock);
>> +
>> +	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.enable);
>> +}
>> +
>> +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;
>> +
>> +	sysfs_remove_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
>>   }
>>   
>>   void xe_eudebug_init(struct xe_device *xe)
>>   {
>> +	struct device *dev = xe->drm.dev;
>> +	int ret;
>> +
>>   	spin_lock_init(&xe->eudebug.lock);
>>   	INIT_LIST_HEAD(&xe->eudebug.list);
>>   	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
>>   
>> -	xe->eudebug.available = true;
>> -}
>> +	drmm_mutex_init(&xe->drm, &xe->eudebug.enable_lock);
>> +	xe->eudebug.enable = false;
>>   
>> -void xe_eudebug_init_late(struct xe_device *xe)
>> -{
>> -	if (!xe->eudebug.available)
>> -		return;
>>   
>> -	attention_scan_flush(xe);
>> +	ret = sysfs_create_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
>> +	if (ret)
>> +		drm_warn(&xe->drm, "eudebug sysfs init failed: %d, debugger unavailable\n", ret);
>> +	else
>> +		devm_add_action_or_reset(dev, xe_eudebug_sysfs_fini, xe);
>> +
>> +	xe->eudebug.available = ret == 0;
>>   }
>>   
>>   void xe_eudebug_fini(struct xe_device *xe)
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
>> index 02c9ba56e752..2f66aa87a0f6 100644
>> --- a/drivers/gpu/drm/xe/xe_eudebug.h
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
>> @@ -24,9 +24,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>>   			     struct drm_file *file);
>>   
>>   void xe_eudebug_init(struct xe_device *xe);
>> -void xe_eudebug_init_late(struct xe_device *xe);
>>   void xe_eudebug_fini(struct xe_device *xe);
>> -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
>>   
>>   void xe_eudebug_file_open(struct xe_file *xef);
>>   void xe_eudebug_file_close(struct xe_file *xef);
>> diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
>> index bc2edade5e5b..b6fc65ab8aa9 100644
>> --- a/drivers/gpu/drm/xe/xe_exec_queue.c
>> +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
>> @@ -360,6 +360,9 @@ static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
>>   			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
>>   		return -EINVAL;
>>   
>> +	if (XE_IOCTL_DBG(xe, !xe->eudebug.enable))
>> +		return -EPERM;
>> +
>>   	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
>>   
>>   	return 0;
>> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
>> index 74813bc20787..0f90416be0ba 100644
>> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
>> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
>> @@ -504,7 +504,6 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
>>   	xe_tuning_process_engine(hwe);
>>   	xe_wa_process_engine(hwe);
>>   	hw_engine_setup_default_state(hwe);
>> -	xe_eudebug_init_hw_engine(hwe);
>>   
>>   	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
>>   	xe_reg_whitelist_process_engine(hwe);
>> diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
>> index 440ac572f6e5..a7671722a84e 100644
>> --- a/drivers/gpu/drm/xe/xe_reg_sr.c
>> +++ b/drivers/gpu/drm/xe/xe_reg_sr.c
>> @@ -92,22 +92,31 @@ static void reg_sr_inc_error(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);
>>   	int ret;
>>   
>>   	if (pentry) {
>> -		if (!compatible_entries(pentry, e)) {
>> +		if (overwrite && e->set_bits) {
>> +			pentry->clr_bits |= e->clr_bits;
>> +			pentry->set_bits |= e->set_bits;
>> +			pentry->read_mask |= e->read_mask;
>> +		} else if (overwrite && !e->set_bits) {
>> +			pentry->clr_bits |= e->clr_bits;
>> +			pentry->set_bits &= ~e->clr_bits;
>> +			pentry->read_mask |= e->read_mask;
>> +		} else if (!compatible_entries(pentry, e)) {
>>   			ret = -EINVAL;
>>   			goto fail;
>> +		} else {
>> +			pentry->clr_bits |= e->clr_bits;
>> +			pentry->set_bits |= e->set_bits;
>> +			pentry->read_mask |= e->read_mask;
>>   		}
>>   
>> -		pentry->clr_bits |= e->clr_bits;
>> -		pentry->set_bits |= e->set_bits;
>> -		pentry->read_mask |= e->read_mask;
>> -
>>   		return 0;
>>   	}
>>   
>> diff --git a/drivers/gpu/drm/xe/xe_reg_sr.h b/drivers/gpu/drm/xe/xe_reg_sr.h
>> index 51fbba423e27..d67fafdcd847 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_
>>   #define _XE_REG_SR_
>>   
>> +#include <linux/types.h>
>> +
>>   /*
>>    * Reg save/restore bookkeeping
>>    */
>> @@ -21,7 +23,7 @@ int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe)
>>   void xe_reg_sr_dump(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_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
>> index 02e28274282f..5643bcde52bd 100644
>> --- a/drivers/gpu/drm/xe/xe_rtp.c
>> +++ b/drivers/gpu/drm/xe/xe_rtp.c
>> @@ -153,7 +153,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, action->flags & XE_RTP_ACTION_FLAG_OVERWRITE);
>>   }
>>   
>>   static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry,
>> diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h
>> index 1b76b947c706..20d228067da3 100644
>> --- a/drivers/gpu/drm/xe/xe_rtp_types.h
>> +++ b/drivers/gpu/drm/xe/xe_rtp_types.h
>> @@ -33,6 +33,7 @@ struct xe_rtp_action {
>>   	/** @read_mask: mask for bits to consider when reading value back */
>>   	u32			read_mask;
>>   #define XE_RTP_ACTION_FLAG_ENGINE_BASE		BIT(0)
>> +#define XE_RTP_ACTION_FLAG_OVERWRITE		BIT(1)
>>   	/** @flags: flags to apply on rule evaluation or action */
>>   	u8			flags;
>>   };
>> -- 
>> 2.34.1
>>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-07-30 14:12     ` Mika Kuoppala
@ 2024-07-31  1:18       ` Matthew Brost
  0 siblings, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-31  1:18 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
	Andi Shyti, Matt Roper, Maciej Patelczyk

On Tue, Jul 30, 2024 at 05:12:42PM +0300, Mika Kuoppala wrote:
> Matthew Brost <matthew.brost@intel.com> writes:
> 
> > On Fri, Jul 26, 2024 at 05:08:00PM +0300, Mika Kuoppala wrote:
> >> With eudebug event interface, user space debugger process (like gdb)
> >> is able to keep track of resources created by another process
> >> (debuggee using drm/xe) and act upon these resources.
> >> 
> >> For example, debugger can find a client vm which contains isa/elf
> >> for a particular shader/eu-kernel and then inspect and modify it
> >> (for example installing a breakpoint).
> >> 
> >> Debugger first opens a connection to xe with a drm ioctl specifying
> >> target pid to connect. This returns an anon fd handle that can then be
> >> used to listen for events with dedicated ioctl.
> >> 
> >> This patch introduces eudebug connection and event queuing, adding
> >> client create/destroy and vm create/destroy events as a baseline.
> >> More events for full debugger operation are needed and
> >> those will be introduced in follow up patches.
> >> 
> >> The resource tracking parts are inspired by the work of
> >> Maciej Patelczyk on resource handling for i915. Chris Wilson
> >> suggested improvement of two ways mapping which makes it easy to
> >> use resource map as a definitive bookkeep of what resources
> >> are played to debugger in the discovery phase (on follow up patch).
> >> 
> >
> > Not a full review just an idea. Do you think it would be worthwhile to
> > add a Kconfig option to enable EU debug support so if we don't care
> > about EU debug it compiles out?
> >
> 
> It is possible and it was done like this in i915. Test triage space will
> grow. On the other hand, we can isolate on hunting issues.
> 

Yes, too many Kconfig options is always a concern wrt to testing.

> > The layering would have to be fixed up to make this sane (e.g. all
> > common Xe code calls into the EU layer so we don't have 'if
> > IS_ENABLED(CONFIG_EU_DEBUG)' sprinkled all over the place. Fixing up
> > layering probably isn't bad idea anyways and as common Xe code really
> > shouldn't open code EU debug specific things anyways. This would enforce
> > good layering too.
> 
> Agreed that it would enforce better layering. Naturally we cant reach
> 100% here as there are some ioctl argument and null checks sprinkled.
> But perfect is enemy is good. We will push more into the xe_eudebug_*
> files and lets see how it look. Kconfig is trivial and icing on the
> cake after this.
> 

Sounds good.

Matt

> -Mika
> 
> > Matt
> >
> >> v2: - event printer removed (Maarten)
> >>     - trim down kfifo accessors (Maarten)
> >>     - xa_alloc spurious locking removed (Maarten)
> >> v3: - use list for clients (Matt)
> >> v4: - avoid reporting clients too early (Maciej, VLK-56889)
> >> v5: - return from wait if disconnect (Mika)
> >> v6: - read waitqueue (Mika)
> >> v7: - ENOTCONN early in read_event (Mika)
> >> v8: - consolidate resource error handling (Mika, Maciej)
> >> v9: - ptrace access check (Jonathan)
> >> v10: - detach error handling (Dominik)
> >> 
> >> 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>
> >> 
> >> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> >> Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
> >> ---
> >>  drivers/gpu/drm/xe/Makefile           |    3 +-
> >>  drivers/gpu/drm/xe/xe_device.c        |   24 +
> >>  drivers/gpu/drm/xe/xe_device_types.h  |   26 +
> >>  drivers/gpu/drm/xe/xe_eudebug.c       | 1093 +++++++++++++++++++++++++
> >>  drivers/gpu/drm/xe/xe_eudebug.h       |   27 +
> >>  drivers/gpu/drm/xe/xe_eudebug_types.h |  169 ++++
> >>  drivers/gpu/drm/xe/xe_vm.c            |    7 +-
> >>  include/uapi/drm/xe_drm.h             |   21 +
> >>  include/uapi/drm/xe_drm_eudebug.h     |   57 ++
> >>  9 files changed, 1425 insertions(+), 2 deletions(-)
> >>  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/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> >> index 1ff9602a52f6..06badc5f99af 100644
> >> --- a/drivers/gpu/drm/xe/Makefile
> >> +++ b/drivers/gpu/drm/xe/Makefile
> >> @@ -114,7 +114,8 @@ xe-y += xe_bb.o \
> >>  	xe_vram_freq.o \
> >>  	xe_wait_user_fence.o \
> >>  	xe_wa.o \
> >> -	xe_wopcm.o
> >> +	xe_wopcm.o \
> >> +	xe_eudebug.o
> >>  
> >>  xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o
> >>  
> >> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> >> index 1aba6f9eaa19..6c5eceaca4ab 100644
> >> --- a/drivers/gpu/drm/xe/xe_device.c
> >> +++ b/drivers/gpu/drm/xe/xe_device.c
> >> @@ -54,6 +54,7 @@
> >>  #include "xe_vm.h"
> >>  #include "xe_vram.h"
> >>  #include "xe_wait_user_fence.h"
> >> +#include "xe_eudebug.h"
> >>  #include "xe_wa.h"
> >>  
> >>  #include <generated/xe_wa_oob.h>
> >> @@ -100,6 +101,14 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
> >>  		put_task_struct(task);
> >>  	}
> >>  
> >> +	INIT_LIST_HEAD(&xef->link);
> >> +
> >> +	mutex_lock(&xe->files.lock);
> >> +	list_add_tail(&xef->link, &xe->files.list);
> >> +	mutex_unlock(&xe->files.lock);
> >> +
> >> +	xe_eudebug_file_open(xef);
> >> +
> >>  	return 0;
> >>  }
> >>  
> >> @@ -158,6 +167,12 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
> >>  
> >>  	xe_pm_runtime_get(xe);
> >>  
> >> +	xe_eudebug_file_close(xef);
> >> +
> >> +	mutex_lock(&xef->xe->files.lock);
> >> +	list_del_init(&xef->link);
> >> +	mutex_unlock(&xef->xe->files.lock);
> >> +
> >>  	/*
> >>  	 * 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
> >> @@ -196,6 +211,7 @@ static const struct drm_ioctl_desc xe_ioctls[] = {
> >>  	DRM_IOCTL_DEF_DRV(XE_WAIT_USER_FENCE, xe_wait_user_fence_ioctl,
> >>  			  DRM_RENDER_ALLOW),
> >>  	DRM_IOCTL_DEF_DRV(XE_OBSERVATION, xe_observation_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)
> >> @@ -285,6 +301,8 @@ static void xe_device_destroy(struct drm_device *dev, void *dummy)
> >>  {
> >>  	struct xe_device *xe = to_xe_device(dev);
> >>  
> >> +	xe_eudebug_fini(xe);
> >> +
> >>  	if (xe->preempt_fence_wq)
> >>  		destroy_workqueue(xe->preempt_fence_wq);
> >>  
> >> @@ -330,6 +348,9 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
> >>  	spin_lock_init(&xe->irq.lock);
> >>  	spin_lock_init(&xe->clients.lock);
> >>  
> >> +	drmm_mutex_init(&xe->drm, &xe->files.lock);
> >> +	INIT_LIST_HEAD(&xe->files.list);
> >> +
> >>  	init_waitqueue_head(&xe->ufence_wq);
> >>  
> >>  	err = drmm_mutex_init(&xe->drm, &xe->usm.lock);
> >> @@ -356,7 +377,10 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
> >>  	INIT_LIST_HEAD(&xe->pinned.external_vram);
> >>  	INIT_LIST_HEAD(&xe->pinned.evicted);
> >>  
> >> +	xe_eudebug_init(xe);
> >> +
> >>  	xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq", 0);
> >> +
> >>  	xe->ordered_wq = alloc_ordered_workqueue("xe-ordered-wq", 0);
> >>  	xe->unordered_wq = alloc_workqueue("xe-unordered-wq", 0, 0);
> >>  	if (!xe->ordered_wq || !xe->unordered_wq ||
> >> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> >> index 5b7292a9a66d..bef7c11bd668 100644
> >> --- a/drivers/gpu/drm/xe/xe_device_types.h
> >> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> >> @@ -355,6 +355,15 @@ struct xe_device {
> >>  		u64 count;
> >>  	} clients;
> >>  
> >> +	/** @files: xe_file list (opens) */
> >> +	struct {
> >> +		/** @lock: Protects xe_file list */
> >> +		struct mutex lock;
> >> +
> >> +		/** @list: xe file list */
> >> +		struct list_head list;
> >> +	} files;
> >> +
> >>  	/** @usm: unified memory state */
> >>  	struct {
> >>  		/** @usm.asid: convert a ASID to VM */
> >> @@ -492,6 +501,20 @@ struct xe_device {
> >>  	u8 vm_inject_error_position;
> >>  #endif
> >>  
> >> +	/** @debugger connection list and globals for device */
> >> +	struct {
> >> +		/** @lock: protects the list of connections */
> >> +		spinlock_t lock;
> >> +		/** @list: list of connections, aka debuggers */
> >> +		struct list_head list;
> >> +
> >> +		/** @session_count: session counter to track connections */
> >> +		u64 session_count;
> >> +
> >> +		/** @available: is the debugging functionality available */
> >> +		bool available;
> >> +	} eudebug;
> >> +
> >>  	/* private: */
> >>  
> >>  #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
> >> @@ -596,6 +619,9 @@ struct xe_file {
> >>  
> >>  	/** @refcount: ref count of this xe file */
> >>  	struct kref refcount;
> >> +
> >> +	/** @link: link into xe_device.client.list */
> >> +	struct list_head link;
> >>  };
> >>  
> >>  #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..8aab02824f8a
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> >> @@ -0,0 +1,1093 @@
> >> +// SPDX-License-Identifier: MIT
> >> +/*
> >> + * Copyright © 2023 Intel Corporation
> >> + */
> >> +
> >> +#include <linux/uaccess.h>
> >> +
> >> +#include <linux/anon_inodes.h>
> >> +#include <linux/poll.h>
> >> +#include <linux/delay.h>
> >> +
> >> +#include <drm/drm_managed.h>
> >> +
> >> +#include "xe_device.h"
> >> +#include "xe_assert.h"
> >> +#include "xe_macros.h"
> >> +
> >> +#include "xe_eudebug_types.h"
> >> +#include "xe_eudebug.h"
> >> +
> >> +/*
> >> + * If there is no detected event read by userspace, during this period, assume
> >> + * userspace problem and disconnect debugger to allow forward progress.
> >> + */
> >> +#define XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS (25 * 1000)
> >> +
> >> +#define for_each_debugger_rcu(debugger, head) \
> >> +	list_for_each_entry_rcu((debugger), (head), connection_link)
> >> +#define for_each_debugger(debugger, head) \
> >> +	list_for_each_entry((debugger), (head), connection_link)
> >> +
> >> +#define cast_event(T, event) container_of((event), typeof(*(T)), base)
> >> +
> >> +#define XE_EUDEBUG_DBG_STR "eudbg: %lld:%lu:%s (%d/%d) -> (%d/%d): "
> >> +#define XE_EUDEBUG_DBG_ARGS(d) (d)->session, \
> >> +		atomic_long_read(&(d)->events.seqno), \
> >> +		READ_ONCE(d->connection.status) <= 0 ? "disconnected" : "", \
> >> +		current->pid, \
> >> +		task_tgid_nr(current), \
> >> +		(d)->target_task->pid, \
> >> +		task_tgid_nr((d)->target_task)
> >> +
> >> +#define eu_err(d, fmt, ...) drm_err(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
> >> +				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
> >> +#define eu_warn(d, fmt, ...) drm_warn(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
> >> +				      XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
> >> +#define eu_dbg(d, fmt, ...) drm_dbg(&(d)->xe->drm, XE_EUDEBUG_DBG_STR # fmt, \
> >> +				    XE_EUDEBUG_DBG_ARGS(d), ##__VA_ARGS__)
> >> +
> >> +#define xe_eudebug_assert(d, ...) xe_assert((d)->xe, ##__VA_ARGS__)
> >> +
> >> +#define struct_member(T, member) (((T *)0)->member)
> >> +
> >> +/* Keep 1:1 parity with uapi events */
> >> +#define write_member(T_out, ptr, member, value) { \
> >> +	BUILD_BUG_ON(sizeof(*ptr) != sizeof(T_out)); \
> >> +	BUILD_BUG_ON(offsetof(typeof(*ptr), member) != \
> >> +		     offsetof(typeof(T_out), member)); \
> >> +	BUILD_BUG_ON(sizeof(ptr->member) != sizeof(value)); \
> >> +	BUILD_BUG_ON(sizeof(struct_member(T_out, member)) != sizeof(value)); \
> >> +	BUILD_BUG_ON(!typecheck(typeof((ptr)->member), value));	\
> >> +	(ptr)->member = (value); \
> >> +	}
> >> +
> >> +static struct xe_eudebug_event *
> >> +event_fifo_pending(struct xe_eudebug *d)
> >> +{
> >> +	struct xe_eudebug_event *event;
> >> +
> >> +	if (kfifo_peek(&d->events.fifo, &event))
> >> +		return event;
> >> +
> >> +	return NULL;
> >> +}
> >> +
> >> +/*
> >> + * 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_num_events_peek(const struct xe_eudebug * const d)
> >> +{
> >> +	return kfifo_len(&d->events.fifo);
> >> +}
> >> +
> >> +static bool
> >> +xe_eudebug_detached(struct xe_eudebug *d)
> >> +{
> >> +	int status;
> >> +
> >> +	spin_lock(&d->connection.lock);
> >> +	status = d->connection.status;
> >> +	spin_unlock(&d->connection.lock);
> >> +
> >> +	return status <= 0;
> >> +}
> >> +
> >> +static int
> >> +xe_eudebug_error(const struct xe_eudebug * const d)
> >> +{
> >> +	const int status = READ_ONCE(d->connection.status);
> >> +
> >> +	return status <= 0 ? status : 0;
> >> +}
> >> +
> >> +static unsigned int
> >> +event_fifo_has_events(struct xe_eudebug *d)
> >> +{
> >> +	if (xe_eudebug_detached(d))
> >> +		return 1;
> >> +
> >> +	return event_fifo_num_events_peek(d);
> >> +}
> >> +
> >> +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_resources * const res, const int t)
> >> +{
> >> +	return &res->rt[t];
> >> +}
> >> +
> >> +static struct xe_eudebug_resources *
> >> +xe_eudebug_resources_alloc(void)
> >> +{
> >> +	struct xe_eudebug_resources *res;
> >> +	int err;
> >> +	int i;
> >> +
> >> +	res = kzalloc(sizeof(*res), GFP_ATOMIC);
> >> +	if (!res)
> >> +		return ERR_PTR(-ENOMEM);
> >> +
> >> +	mutex_init(&res->lock);
> >> +
> >> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
> >> +		xa_init_flags(&res->rt[i].xa, XA_FLAGS_ALLOC1);
> >> +		err = rhashtable_init(&res->rt[i].rh, &rhash_res);
> >> +
> >> +		if (err)
> >> +			break;
> >> +	}
> >> +
> >> +	if (err) {
> >> +		while (i--) {
> >> +			xa_destroy(&res->rt[i].xa);
> >> +			rhashtable_destroy(&res->rt[i].rh);
> >> +		}
> >> +
> >> +		kfree(res);
> >> +		return ERR_PTR(err);
> >> +	}
> >> +
> >> +	return res;
> >> +}
> >> +
> >> +static void res_free_fn(void *ptr, void *arg)
> >> +{
> >> +	XE_WARN_ON(ptr);
> >> +	kfree(ptr);
> >> +}
> >> +
> >> +static void
> >> +xe_eudebug_destroy_resources(struct xe_eudebug *d)
> >> +{
> >> +	struct xe_eudebug_resources *res = d->res;
> >> +	struct xe_eudebug_handle *h;
> >> +	unsigned long j;
> >> +	int i;
> >> +	int err;
> >> +
> >> +	mutex_lock(&res->lock);
> >> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
> >> +		struct xe_eudebug_resource *r = &res->rt[i];
> >> +
> >> +		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);
> >> +			xe_eudebug_assert(d, t == h);
> >> +			kfree(t);
> >> +		}
> >> +	}
> >> +	mutex_unlock(&res->lock);
> >> +
> >> +	for (i = 0; i < XE_EUDEBUG_RES_TYPE_COUNT; i++) {
> >> +		struct xe_eudebug_resource *r = &res->rt[i];
> >> +
> >> +		rhashtable_free_and_destroy(&r->rh, res_free_fn, NULL);
> >> +		xe_eudebug_assert(d, xa_empty(&r->xa));
> >> +		xa_destroy(&r->xa);
> >> +	}
> >> +
> >> +	mutex_destroy(&res->lock);
> >> +
> >> +	kfree(res);
> >> +}
> >> +
> >> +static void xe_eudebug_free(struct kref *ref)
> >> +{
> >> +	struct xe_eudebug *d = container_of(ref, typeof(*d), ref);
> >> +	struct xe_eudebug_event *event;
> >> +
> >> +	while (kfifo_get(&d->events.fifo, &event))
> >> +		kfree(event);
> >> +
> >> +	xe_eudebug_destroy_resources(d);
> >> +	put_task_struct(d->target_task);
> >> +
> >> +	xe_eudebug_assert(d, !kfifo_len(&d->events.fifo));
> >> +
> >> +	kfree_rcu(d, rcu);
> >> +}
> >> +
> >> +static void xe_eudebug_put(struct xe_eudebug *d)
> >> +{
> >> +	kref_put(&d->ref, xe_eudebug_free);
> >> +}
> >> +
> >> +static struct task_struct *find_get_target(const pid_t nr)
> >> +{
> >> +	struct task_struct *task;
> >> +
> >> +	rcu_read_lock();
> >> +	task = pid_task(find_pid_ns(nr, task_active_pid_ns(current)), PIDTYPE_PID);
> >> +	if (task)
> >> +		get_task_struct(task);
> >> +	rcu_read_unlock();
> >> +
> >> +	return task;
> >> +}
> >> +
> >> +static int
> >> +xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
> >> +		  const pid_t pid_nr)
> >> +{
> >> +	struct task_struct *target;
> >> +	struct xe_eudebug *iter;
> >> +	kuid_t uid = current_uid();
> >> +	int ret = 0;
> >> +
> >> +	target = find_get_target(pid_nr);
> >> +	if (!target)
> >> +		return -ENOENT;
> >> +
> >> +	if (!uid_eq(uid, task_uid(target)) && !capable(CAP_SYS_ADMIN)) {
> >> +		put_task_struct(target);
> >> +		return -EACCES;
> >> +	}
> >> +
> >> +	XE_WARN_ON(d->connection.status != 0);
> >> +
> >> +	spin_lock(&xe->eudebug.lock);
> >> +	for_each_debugger(iter, &xe->eudebug.list) {
> >> +		if (!same_thread_group(iter->target_task, target))
> >> +			continue;
> >> +
> >> +		ret = -EBUSY;
> >> +	}
> >> +
> >> +	if (!ret && xe->eudebug.session_count + 1 == 0)
> >> +		ret = -ENOSPC;
> >> +
> >> +	if (!ret) {
> >> +		d->connection.status = XE_EUDEBUG_STATUS_CONNECTED;
> >> +		d->xe = xe;
> >> +		d->target_task = target;
> >> +		d->session = ++xe->eudebug.session_count;
> >> +		kref_get(&d->ref);
> >> +		list_add_tail_rcu(&d->connection_link, &xe->eudebug.list);
> >> +	}
> >> +	spin_unlock(&xe->eudebug.lock);
> >> +
> >> +	if (ret)
> >> +		put_task_struct(target);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static bool xe_eudebug_detach(struct xe_device *xe,
> >> +			      struct xe_eudebug *d,
> >> +			      const int err)
> >> +{
> >> +	bool detached = false;
> >> +
> >> +	XE_WARN_ON(err > 0);
> >> +
> >> +	spin_lock(&d->connection.lock);
> >> +	if (d->connection.status == XE_EUDEBUG_STATUS_CONNECTED) {
> >> +		d->connection.status = err;
> >> +		detached = true;
> >> +	}
> >> +	spin_unlock(&d->connection.lock);
> >> +
> >> +	if (!detached)
> >> +		return false;
> >> +
> >> +	spin_lock(&xe->eudebug.lock);
> >> +	list_del_rcu(&d->connection_link);
> >> +	spin_unlock(&xe->eudebug.lock);
> >> +
> >> +	eu_dbg(d, "session %lld detached with %d", d->session, err);
> >> +
> >> +	/* Our ref with the connection_link */
> >> +	xe_eudebug_put(d);
> >> +
> >> +	return true;
> >> +}
> >> +
> >> +static int _xe_eudebug_disconnect(struct xe_eudebug *d,
> >> +				  const int err)
> >> +{
> >> +	wake_up_all(&d->events.write_done);
> >> +	wake_up_all(&d->events.read_done);
> >> +
> >> +	return xe_eudebug_detach(d->xe, d, err);
> >> +}
> >> +
> >> +#define xe_eudebug_disconnect(_d, _err) ({ \
> >> +	if (_xe_eudebug_disconnect((_d), (_err))) { \
> >> +		if ((_err) == 0 || (_err) == -ETIMEDOUT) \
> >> +			eu_dbg(d, "Session closed (%d)", (_err)); \
> >> +		else \
> >> +			eu_err(d, "Session disconnected, err = %d (%s:%d)", \
> >> +			       (_err), __func__, __LINE__); \
> >> +	} \
> >> +})
> >> +
> >> +static int xe_eudebug_release(struct inode *inode, struct file *file)
> >> +{
> >> +	struct xe_eudebug *d = file->private_data;
> >> +
> >> +	xe_eudebug_disconnect(d, 0);
> >> +	xe_eudebug_put(d);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +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 (xe_eudebug_error(d))
> >> +			ret |= EPOLLERR;
> >> +	}
> >> +
> >> +	if (event_fifo_num_events_peek(d))
> >> +		ret |= EPOLLIN;
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static ssize_t xe_eudebug_read(struct file *file,
> >> +			       char __user *buf,
> >> +			       size_t count,
> >> +			       loff_t *ppos)
> >> +{
> >> +	return -EINVAL;
> >> +}
> >> +
> >> +static struct xe_eudebug *
> >> +xe_eudebug_for_task_get(struct xe_device *xe,
> >> +			struct task_struct *task)
> >> +{
> >> +	struct xe_eudebug *d, *iter;
> >> +
> >> +	d = NULL;
> >> +
> >> +	rcu_read_lock();
> >> +	for_each_debugger_rcu(iter, &xe->eudebug.list) {
> >> +		if (!same_thread_group(iter->target_task, task))
> >> +			continue;
> >> +
> >> +		if (kref_get_unless_zero(&iter->ref))
> >> +			d = iter;
> >> +
> >> +		break;
> >> +	}
> >> +	rcu_read_unlock();
> >> +
> >> +	return d;
> >> +}
> >> +
> >> +static struct task_struct *find_task_get(struct xe_file *xef)
> >> +{
> >> +	struct task_struct *task;
> >> +	struct pid *pid;
> >> +
> >> +	rcu_read_lock();
> >> +	pid = rcu_dereference(xef->drm->pid);
> >> +	task = pid_task(pid, PIDTYPE_PID);
> >> +	if (task)
> >> +		get_task_struct(task);
> >> +	rcu_read_unlock();
> >> +
> >> +	return task;
> >> +}
> >> +
> >> +static struct xe_eudebug *
> >> +xe_eudebug_get(struct xe_file *xef)
> >> +{
> >> +	struct task_struct *task;
> >> +	struct xe_eudebug *d;
> >> +
> >> +	d = NULL;
> >> +	task = find_task_get(xef);
> >> +	if (task) {
> >> +		d = xe_eudebug_for_task_get(to_xe_device(xef->drm->minor->dev),
> >> +					    task);
> >> +		put_task_struct(task);
> >> +	}
> >> +
> >> +	if (!d)
> >> +		return NULL;
> >> +
> >> +	if (xe_eudebug_detached(d)) {
> >> +		xe_eudebug_put(d);
> >> +		return NULL;
> >> +	}
> >> +
> >> +	return d;
> >> +}
> >> +
> >> +static int xe_eudebug_queue_event(struct xe_eudebug *d,
> >> +				  struct xe_eudebug_event *event)
> >> +{
> >> +	const u64 wait_jiffies = msecs_to_jiffies(1000);
> >> +	u64 last_read_detected_ts, last_head_seqno, start_ts;
> >> +
> >> +	xe_eudebug_assert(d, event->len > sizeof(struct xe_eudebug_event));
> >> +	xe_eudebug_assert(d, event->type);
> >> +	xe_eudebug_assert(d, event->type != DRM_XE_EUDEBUG_EVENT_READ);
> >> +
> >> +	start_ts = ktime_get();
> >> +	last_read_detected_ts = start_ts;
> >> +	last_head_seqno = 0;
> >> +
> >> +	do  {
> >> +		struct xe_eudebug_event *head;
> >> +		u64 head_seqno;
> >> +		bool was_queued;
> >> +
> >> +		if (xe_eudebug_detached(d))
> >> +			break;
> >> +
> >> +		spin_lock(&d->events.lock);
> >> +		head = event_fifo_pending(d);
> >> +		if (head)
> >> +			head_seqno = event->seqno;
> >> +		else
> >> +			head_seqno = 0;
> >> +
> >> +		was_queued = kfifo_in(&d->events.fifo, &event, 1);
> >> +		spin_unlock(&d->events.lock);
> >> +
> >> +		wake_up_all(&d->events.write_done);
> >> +
> >> +		if (was_queued) {
> >> +			event = NULL;
> >> +			break;
> >> +		}
> >> +
> >> +		XE_WARN_ON(!head_seqno);
> >> +
> >> +		/* If we detect progress, restart timeout */
> >> +		if (last_head_seqno != head_seqno)
> >> +			last_read_detected_ts = ktime_get();
> >> +
> >> +		last_head_seqno = head_seqno;
> >> +
> >> +		wait_event_interruptible_timeout(d->events.read_done,
> >> +						 !kfifo_is_full(&d->events.fifo),
> >> +						 wait_jiffies);
> >> +
> >> +	} while (ktime_ms_delta(ktime_get(), last_read_detected_ts) <
> >> +		 XE_EUDEBUG_NO_READ_DETECTED_TIMEOUT_MS);
> >> +
> >> +	if (event) {
> >> +		eu_dbg(d,
> >> +		       "event %llu queue failed (blocked %lld ms, avail %d)",
> >> +		       event ? event->seqno : 0,
> >> +		       ktime_ms_delta(ktime_get(), start_ts),
> >> +		       kfifo_avail(&d->events.fifo));
> >> +
> >> +		kfree(event);
> >> +
> >> +		return -ETIMEDOUT;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static struct xe_eudebug_handle *
> >> +alloc_handle(const int type, const u64 key)
> >> +{
> >> +	struct xe_eudebug_handle *h;
> >> +
> >> +	h = kzalloc(sizeof(*h), GFP_ATOMIC);
> >> +	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 find_handle(struct xe_eudebug_resources *res,
> >> +		       const int type,
> >> +		       const void *p)
> >> +{
> >> +	const u64 key = (u64)p;
> >> +	struct xe_eudebug_resource *r;
> >> +	struct xe_eudebug_handle *h;
> >> +	int id;
> >> +
> >> +	if (XE_WARN_ON(!key))
> >> +		return -EINVAL;
> >> +
> >> +	r = resource_from_type(res, type);
> >> +
> >> +	mutex_lock(&res->lock);
> >> +	h = __find_handle(r, key);
> >> +	id = h ? h->id : -ENOENT;
> >> +	mutex_unlock(&res->lock);
> >> +
> >> +	return id;
> >> +}
> >> +
> >> +static int _xe_eudebug_add_handle(struct xe_eudebug *d,
> >> +				  int type,
> >> +				  void *p,
> >> +				  u64 *seqno,
> >> +				  int *handle)
> >> +{
> >> +	const u64 key = (u64)p;
> >> +	struct xe_eudebug_resource *r;
> >> +	struct xe_eudebug_handle *h, *o;
> >> +	int err;
> >> +
> >> +	if (XE_WARN_ON(p == NULL))
> >> +		return -EINVAL;
> >> +
> >> +	if (xe_eudebug_detached(d))
> >> +		return -ENOTCONN;
> >> +
> >> +	h = alloc_handle(type, key);
> >> +	if (!h)
> >> +		return -ENOMEM;
> >> +
> >> +	r = resource_from_type(d->res, type);
> >> +
> >> +	mutex_lock(&d->res->lock);
> >> +	o = __find_handle(r, key);
> >> +	if (!o) {
> >> +		err = xa_alloc(&r->xa, &h->id, h, xa_limit_31b, GFP_KERNEL);
> >> +
> >> +		if (h->id >= INT_MAX) {
> >> +			xa_erase(&r->xa, h->id);
> >> +			err = -ENOSPC;
> >> +		}
> >> +
> >> +		if (!err)
> >> +			err = rhashtable_insert_fast(&r->rh,
> >> +						     &h->rh_head,
> >> +						     rhash_res);
> >> +
> >> +		if (err) {
> >> +			xa_erase(&r->xa, h->id);
> >> +		} else {
> >> +			if (seqno)
> >> +				*seqno = atomic_long_inc_return(&d->events.seqno);
> >> +		}
> >> +	} else {
> >> +		xe_eudebug_assert(d, o->id);
> >> +		err = -EEXIST;
> >> +	}
> >> +	mutex_unlock(&d->res->lock);
> >> +
> >> +	if (handle)
> >> +		*handle = o ? o->id : h->id;
> >> +
> >> +	if (err) {
> >> +		kfree(h);
> >> +		XE_WARN_ON(err > 0);
> >> +		return err;
> >> +	}
> >> +
> >> +	xe_eudebug_assert(d, h->id);
> >> +
> >> +	return h->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, NULL);
> >> +	if (ret == -EEXIST || ret == -ENOTCONN) {
> >> +		eu_dbg(d, "%d on adding %d", ret, type);
> >> +		return 0;
> >> +	}
> >> +
> >> +	if (ret < 0)
> >> +		xe_eudebug_disconnect(d, ret);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int _xe_eudebug_remove_handle(struct xe_eudebug *d, int type, void *p,
> >> +				     u64 *seqno)
> >> +{
> >> +	const u64 key = (u64)p;
> >> +	struct xe_eudebug_resource *r;
> >> +	struct xe_eudebug_handle *h, *xa_h;
> >> +	int ret;
> >> +
> >> +	if (XE_WARN_ON(!key))
> >> +		return -EINVAL;
> >> +
> >> +	if (xe_eudebug_detached(d))
> >> +		return -ENOTCONN;
> >> +
> >> +	r = resource_from_type(d->res, type);
> >> +
> >> +	mutex_lock(&d->res->lock);
> >> +	h = __find_handle(r, key);
> >> +	if (h) {
> >> +		ret = rhashtable_remove_fast(&r->rh,
> >> +					     &h->rh_head,
> >> +					     rhash_res);
> >> +		xe_eudebug_assert(d, !ret);
> >> +		xa_h = xa_erase(&r->xa, h->id);
> >> +		xe_eudebug_assert(d, xa_h == h);
> >> +		if (!ret) {
> >> +			ret = h->id;
> >> +			if (seqno)
> >> +				*seqno = atomic_long_inc_return(&d->events.seqno);
> >> +		}
> >> +	} else {
> >> +		ret = -ENOENT;
> >> +	}
> >> +	mutex_unlock(&d->res->lock);
> >> +
> >> +	kfree(h);
> >> +
> >> +	xe_eudebug_assert(d, ret);
> >> +
> >> +	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);
> >> +	if (ret == -ENOENT || ret == -ENOTCONN) {
> >> +		eu_dbg(d, "%d on removing %d", ret, type);
> >> +		return 0;
> >> +	}
> >> +
> >> +	if (ret < 0)
> >> +		xe_eudebug_disconnect(d, ret);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static struct xe_eudebug_event *
> >> +__xe_eudebug_create_event(struct xe_eudebug *d,
> >> +			  u64 seqno, u16 type, u16 flags, u32 len, gfp_t gfp)
> >> +{
> >> +	struct xe_eudebug_event *event;
> >> +
> >> +	xe_eudebug_assert(d, len > sizeof(*event));
> >> +
> >> +	event = kzalloc(len, gfp);
> >> +	if (!event)
> >> +		return NULL;
> >> +
> >> +	event->type = type;
> >> +	event->flags = flags;
> >> +	event->len = len;
> >> +	event->seqno = seqno;
> >> +
> >> +	return event;
> >> +}
> >> +
> >> +static struct xe_eudebug_event *
> >> +xe_eudebug_create_event(struct xe_eudebug *d, u16 type, u64 seqno, u16 flags,
> >> +			u32 len, gfp_t gfp)
> >> +{
> >> +	return __xe_eudebug_create_event(d, seqno, type, flags, len, gfp);
> >> +}
> >> +
> >> +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 drm_xe_eudebug_event user_event;
> >> +	struct xe_eudebug_event *event;
> >> +	long ret = 0;
> >> +
> >> +	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))
> >> +		return -EINVAL;
> >> +
> >> +	if (XE_IOCTL_DBG(xe, user_event.type > DRM_XE_EUDEBUG_EVENT_MAX_EVENT))
> >> +		return -EINVAL;
> >> +
> >> +	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.reserved))
> >> +		return -EINVAL;
> >> +
> >> +	/* 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;
> >> +	}
> >> +
> >> +	ret = 0;
> >> +	spin_lock(&d->events.lock);
> >> +	event = event_fifo_pending(d);
> >> +	if (event) {
> >> +		if (user_event.len < event->len) {
> >> +			ret = -EMSGSIZE;
> >> +		} else if (!kfifo_out(&d->events.fifo, &event, 1)) {
> >> +			eu_warn(d, "internal fifo corruption");
> >> +			ret = -ENOTCONN;
> >> +		}
> >> +	}
> >> +	spin_unlock(&d->events.lock);
> >> +
> >> +	wake_up_all(&d->events.read_done);
> >> +
> >> +	if (XE_IOCTL_DBG(xe, ret))
> >> +		return ret;
> >> +
> >> +	if (!event) {
> >> +		if (xe_eudebug_detached(d))
> >> +			return -ENOTCONN;
> >> +		if (!wait)
> >> +			return -EAGAIN;
> >> +
> >> +		return -ENOENT;
> >> +	}
> >> +
> >> +	if (copy_to_user(user_orig, event, event->len))
> >> +		ret = -EFAULT;
> >> +	else
> >> +		eu_dbg(d, "event read: type=%u, flags=0x%x, seqno=%llu", event->type,
> >> +		       event->flags, event->seqno);
> >> +
> >> +	kfree(event);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +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,
> >> +	.llseek		= no_llseek,
> >> +	.release	= xe_eudebug_release,
> >> +	.poll		= xe_eudebug_poll,
> >> +	.read		= xe_eudebug_read,
> >> +	.unlocked_ioctl	= xe_eudebug_ioctl,
> >> +};
> >> +
> >> +static int
> >> +xe_eudebug_connect(struct xe_device *xe,
> >> +		   struct drm_xe_eudebug_connect *param)
> >> +{
> >> +	const u64 known_open_flags = 0;
> >> +	unsigned long f_flags = 0;
> >> +	struct xe_eudebug *d;
> >> +	int fd, err;
> >> +
> >> +	if (param->extensions)
> >> +		return -EINVAL;
> >> +
> >> +	if (!param->pid)
> >> +		return -EINVAL;
> >> +
> >> +	if (param->flags & ~known_open_flags)
> >> +		return -EINVAL;
> >> +
> >> +	if (param->version && param->version != DRM_XE_EUDEBUG_VERSION)
> >> +		return -EINVAL;
> >> +
> >> +	param->version = DRM_XE_EUDEBUG_VERSION;
> >> +
> >> +	if (!xe->eudebug.available)
> >> +		return -EOPNOTSUPP;
> >> +
> >> +	d = kzalloc(sizeof(*d), GFP_KERNEL);
> >> +	if (!d)
> >> +		return -ENOMEM;
> >> +
> >> +	kref_init(&d->ref);
> >> +	spin_lock_init(&d->connection.lock);
> >> +	init_waitqueue_head(&d->events.write_done);
> >> +	init_waitqueue_head(&d->events.read_done);
> >> +
> >> +	spin_lock_init(&d->events.lock);
> >> +	INIT_KFIFO(d->events.fifo);
> >> +
> >> +	d->res = xe_eudebug_resources_alloc();
> >> +	if (IS_ERR(d->res)) {
> >> +		err = PTR_ERR(d->res);
> >> +		goto err_free;
> >> +	}
> >> +
> >> +	err = xe_eudebug_attach(xe, d, param->pid);
> >> +	if (err)
> >> +		goto err_free_res;
> >> +
> >> +	fd = anon_inode_getfd("[xe_eudebug]", &fops, d, f_flags);
> >> +	if (fd < 0) {
> >> +		err = fd;
> >> +		goto err_detach;
> >> +	}
> >> +
> >> +	eu_dbg(d, "connected session %lld", d->session);
> >> +
> >> +	return fd;
> >> +
> >> +err_detach:
> >> +	xe_eudebug_detach(xe, d, err);
> >> +err_free_res:
> >> +	xe_eudebug_destroy_resources(d);
> >> +err_free:
> >> +	kfree(d);
> >> +
> >> +	return err;
> >> +}
> >> +
> >> +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;
> >> +	int ret = 0;
> >> +
> >> +	ret = xe_eudebug_connect(xe, param);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +void xe_eudebug_init(struct xe_device *xe)
> >> +{
> >> +	spin_lock_init(&xe->eudebug.lock);
> >> +	INIT_LIST_HEAD(&xe->eudebug.list);
> >> +
> >> +	xe->eudebug.available = true;
> >> +}
> >> +
> >> +void xe_eudebug_fini(struct xe_device *xe)
> >> +{
> >> +	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
> >> +}
> >> +
> >> +static int send_open_event(struct xe_eudebug *d, u32 flags, const u64 handle,
> >> +			   const u64 seqno)
> >> +{
> >> +	struct xe_eudebug_event *event;
> >> +	struct xe_eudebug_event_open *eo;
> >> +
> >> +	if (!handle)
> >> +		return -EINVAL;
> >> +
> >> +	if (XE_WARN_ON((long)handle >= INT_MAX))
> >> +		return -EINVAL;
> >> +
> >> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_OPEN, seqno,
> >> +					flags, sizeof(*eo), GFP_KERNEL);
> >> +	if (!event)
> >> +		return -ENOMEM;
> >> +
> >> +	eo = cast_event(eo, event);
> >> +
> >> +	write_member(struct drm_xe_eudebug_event_client, eo,
> >> +		     client_handle, handle);
> >> +
> >> +	return xe_eudebug_queue_event(d, event);
> >> +}
> >> +
> >> +static int client_create_event(struct xe_eudebug *d, struct xe_file *xef)
> >> +{
> >> +	u64 seqno;
> >> +	int ret;
> >> +
> >> +	ret = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT, xef, &seqno);
> >> +	if (ret > 0)
> >> +		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_CREATE,
> >> +					     ret, seqno);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int client_destroy_event(struct xe_eudebug *d, struct xe_file *xef)
> >> +{
> >> +	u64 seqno;
> >> +	int ret;
> >> +
> >> +	ret = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_CLIENT,
> >> +				       xef, &seqno);
> >> +	if (ret > 0)
> >> +		ret = send_open_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY,
> >> +				      ret, seqno);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +#define xe_eudebug_event_put(_d, _err) ({ \
> >> +	if ((_err)) \
> >> +		xe_eudebug_disconnect((_d), (_err)); \
> >> +	xe_eudebug_put((_d)); \
> >> +	})
> >> +
> >> +void xe_eudebug_file_open(struct xe_file *xef)
> >> +{
> >> +	struct xe_eudebug *d;
> >> +
> >> +	d = xe_eudebug_get(xef);
> >> +	if (!d)
> >> +		return;
> >> +
> >> +	xe_eudebug_event_put(d, client_create_event(d, xef));
> >> +}
> >> +
> >> +void xe_eudebug_file_close(struct xe_file *xef)
> >> +{
> >> +	struct xe_eudebug *d;
> >> +
> >> +	d = xe_eudebug_get(xef);
> >> +	if (!d)
> >> +		return;
> >> +
> >> +	xe_eudebug_event_put(d, client_destroy_event(d, xef));
> >> +}
> >> +
> >> +static int send_vm_event(struct xe_eudebug *d, u32 flags,
> >> +			 const u64 client_handle,
> >> +			 const u64 vm_handle,
> >> +			 const u64 seqno)
> >> +{
> >> +	struct xe_eudebug_event *event;
> >> +	struct xe_eudebug_event_vm *e;
> >> +
> >> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM,
> >> +					seqno, flags, sizeof(*e), GFP_KERNEL);
> >> +	if (!event)
> >> +		return -ENOMEM;
> >> +
> >> +	e = cast_event(e, event);
> >> +
> >> +	write_member(struct drm_xe_eudebug_event_vm, e, client_handle, client_handle);
> >> +	write_member(struct drm_xe_eudebug_event_vm, e, vm_handle, vm_handle);
> >> +
> >> +	return xe_eudebug_queue_event(d, event);
> >> +}
> >> +
> >> +static int vm_create_event(struct xe_eudebug *d,
> >> +			   struct xe_file *xef, struct xe_vm *vm)
> >> +{
> >> +	int h_c, h_vm;
> >> +	u64 seqno;
> >> +	int ret;
> >> +
> >> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
> >> +	if (h_c < 0)
> >> +		return h_c;
> >> +
> >> +	xe_eudebug_assert(d, h_c);
> >> +
> >> +	h_vm = xe_eudebug_add_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
> >> +	if (h_vm <= 0)
> >> +		return h_vm;
> >> +
> >> +	ret = send_vm_event(d, DRM_XE_EUDEBUG_EVENT_CREATE, h_c, h_vm, seqno);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int vm_destroy_event(struct xe_eudebug *d,
> >> +			    struct xe_file *xef, struct xe_vm *vm)
> >> +{
> >> +	int h_c, h_vm;
> >> +	u64 seqno;
> >> +
> >> +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, xef);
> >> +	if (h_c < 0) {
> >> +		XE_WARN_ON("no client found for vm");
> >> +		eu_warn(d, "no client found for vm");
> >> +		return h_c;
> >> +	}
> >> +
> >> +	xe_eudebug_assert(d, h_c);
> >> +
> >> +	h_vm = xe_eudebug_remove_handle(d, XE_EUDEBUG_RES_TYPE_VM, vm, &seqno);
> >> +	if (h_vm <= 0)
> >> +		return h_vm;
> >> +
> >> +	return send_vm_event(d, DRM_XE_EUDEBUG_EVENT_DESTROY, h_c, h_vm, seqno);
> >> +}
> >> +
> >> +void xe_eudebug_vm_create(struct xe_file *xef, struct xe_vm *vm)
> >> +{
> >> +	struct xe_eudebug *d;
> >> +
> >> +	d = xe_eudebug_get(xef);
> >> +	if (!d)
> >> +		return;
> >> +
> >> +	xe_eudebug_event_put(d, vm_create_event(d, xef, vm));
> >> +}
> >> +
> >> +void xe_eudebug_vm_destroy(struct xe_file *xef, struct xe_vm *vm)
> >> +{
> >> +	struct xe_eudebug *d;
> >> +
> >> +	d = xe_eudebug_get(xef);
> >> +	if (!d)
> >> +		return;
> >> +
> >> +	xe_eudebug_event_put(d, vm_destroy_event(d, xef, vm));
> >> +}
> >> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> >> new file mode 100644
> >> index 000000000000..df577b581364
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> >> @@ -0,0 +1,27 @@
> >> +/* SPDX-License-Identifier: MIT */
> >> +/*
> >> + * Copyright © 2023 Intel Corporation
> >> + */
> >> +
> >> +#ifndef _XE_EUDEBUG_H_
> >> +
> >> +struct drm_device;
> >> +struct drm_file;
> >> +struct xe_device;
> >> +struct xe_file;
> >> +struct xe_vm;
> >> +
> >> +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_fini(struct xe_device *xe);
> >> +
> >> +void xe_eudebug_file_open(struct xe_file *xef);
> >> +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);
> >> +
> >> +#endif
> >> 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..093221a707df
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> >> @@ -0,0 +1,169 @@
> >> +/* SPDX-License-Identifier: MIT */
> >> +/*
> >> + * Copyright © 2023 Intel Corporation
> >> + */
> >> +
> >> +#ifndef __XE_EUDEBUG_TYPES_H_
> >> +
> >> +#include <linux/mutex.h>
> >> +#include <linux/kref.h>
> >> +#include <linux/kfifo.h>
> >> +#include <linux/completion.h>
> >> +#include <linux/wait.h>
> >> +#include <linux/xarray.h>
> >> +#include <linux/rbtree.h>
> >> +#include <linux/rhashtable.h>
> >> +
> >> +#include <uapi/drm/xe_drm.h>
> >> +
> >> +struct xe_device;
> >> +struct task_struct;
> >> +struct xe_eudebug_event;
> >> +
> >> +#define CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE 64
> >> +
> >> +/**
> >> + * 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 {
> >> +	/** @xa: xarrays for <id->key> */
> >> +	struct xarray xa;
> >> +
> >> +	/** @rh rhashtable for <key->id> */
> >> +	struct rhashtable rh;
> >> +};
> >> +
> >> +#define XE_EUDEBUG_RES_TYPE_CLIENT	0
> >> +#define XE_EUDEBUG_RES_TYPE_VM		1
> >> +#define XE_EUDEBUG_RES_TYPE_COUNT	(XE_EUDEBUG_RES_TYPE_VM + 1)
> >> +
> >> +/**
> >> + * struct xe_eudebug_resources - eudebug resources for all types
> >> + */
> >> +struct xe_eudebug_resources {
> >> +	/** @lock: guards access into rt */
> >> +	struct mutex lock;
> >> +
> >> +	/** @rt: resource maps for all types */
> >> +	struct xe_eudebug_resource rt[XE_EUDEBUG_RES_TYPE_COUNT];
> >> +};
> >> +
> >> +/**
> >> + * struct xe_eudebug - Top level struct for eudebug: the connection
> >> + */
> >> +struct xe_eudebug {
> >> +	/** @ref: kref counter for this struct */
> >> +	struct kref ref;
> >> +
> >> +	/** @rcu: rcu_head for rcu destruction */
> >> +	struct rcu_head rcu;
> >> +
> >> +	/** @connection_link: our link into the xe_device:eudebug.list */
> >> +	struct list_head connection_link;
> >> +
> >> +	struct {
> >> +		/** @status: connected = 1, disconnected = error */
> >> +#define XE_EUDEBUG_STATUS_CONNECTED 1
> >> +		int status;
> >> +
> >> +		/** @lock: guards access to status */
> >> +		spinlock_t lock;
> >> +	} connection;
> >> +
> >> +	/** @xe: the parent device we are serving */
> >> +	struct xe_device *xe;
> >> +
> >> +	/** @target_task: the task that we are debugging */
> >> +	struct task_struct *target_task;
> >> +
> >> +	/** @res: the resource maps we track for target_task */
> >> +	struct xe_eudebug_resources *res;
> >> +
> >> +	/** @session: session number for this connection (for logs) */
> >> +	u64 session;
> >> +
> >> +	/** @events: kfifo queue of to-be-delivered events */
> >> +	struct {
> >> +		/** @lock: guards access to fifo */
> >> +		spinlock_t lock;
> >> +
> >> +		/** @fifo: queue of events pending */
> >> +		DECLARE_KFIFO(fifo,
> >> +			      struct xe_eudebug_event *,
> >> +			      CONFIG_DRM_XE_DEBUGGER_EVENT_QUEUE_SIZE);
> >> +
> >> +		/** @write_done: waitqueue for signalling write to fifo */
> >> +		wait_queue_head_t write_done;
> >> +
> >> +		/** @read_done: waitqueue for signalling read from fifo */
> >> +		wait_queue_head_t read_done;
> >> +
> >> +		/** @event_seqno: seqno counter to stamp events for fifo */
> >> +		atomic_long_t seqno;
> >> +	} events;
> >> +
> >> +};
> >> +
> >> +/**
> >> + * struct xe_eudebug_event - Internal base event struct for eudebug
> >> + */
> >> +struct xe_eudebug_event {
> >> +	/** @len: length of this event, including payload */
> >> +	u32 len;
> >> +
> >> +	/** @type: message type */
> >> +	u16 type;
> >> +
> >> +	/** @flags: message flags */
> >> +	u16 flags;
> >> +
> >> +	/** @seqno: sequence number for ordering */
> >> +	u64 seqno;
> >> +
> >> +	/** @reserved: reserved field MBZ */
> >> +	u64 reserved;
> >> +
> >> +	/** @data: payload bytes */
> >> +	u8 data[];
> >> +};
> >> +
> >> +/**
> >> + * struct xe_eudebug_event_open - Internal event for client open/close
> >> + */
> >> +struct xe_eudebug_event_open {
> >> +	/** @base: base event */
> >> +	struct xe_eudebug_event base;
> >> +
> >> +	/** @client_handle: opaque handle for client */
> >> +	u64 client_handle;
> >> +};
> >> +
> >> +/**
> >> + * struct xe_eudebug_event_vm - Internal event for vm open/close
> >> + */
> >> +struct xe_eudebug_event_vm {
> >> +	/** @base: base event */
> >> +	struct xe_eudebug_event base;
> >> +
> >> +	/** @client_handle: client containing the vm open/close */
> >> +	u64 client_handle;
> >> +
> >> +	/** @vm_handle: vm handle it's open/close */
> >> +	u64 vm_handle;
> >> +};
> >> +
> >> +#endif
> >> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> >> index f225107bdd65..9e101c992d9c 100644
> >> --- a/drivers/gpu/drm/xe/xe_vm.c
> >> +++ b/drivers/gpu/drm/xe/xe_vm.c
> >> @@ -39,6 +39,7 @@
> >>  #include "xe_trace_bo.h"
> >>  #include "xe_wa.h"
> >>  #include "xe_hmm.h"
> >> +#include "xe_eudebug.h"
> >>  
> >>  static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
> >>  {
> >> @@ -1818,6 +1819,8 @@ 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
> >>  
> >> +	xe_eudebug_vm_create(xef, vm);
> >> +
> >>  	return 0;
> >>  
> >>  err_free_id:
> >> @@ -1853,8 +1856,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 29425d7fdc77..a68734ff12f4 100644
> >> --- a/include/uapi/drm/xe_drm.h
> >> +++ b/include/uapi/drm/xe_drm.h
> >> @@ -102,6 +102,7 @@ extern "C" {
> >>  #define DRM_XE_EXEC			0x09
> >>  #define DRM_XE_WAIT_USER_FENCE		0x0a
> >>  #define DRM_XE_OBSERVATION		0x0b
> >> +#define DRM_XE_EUDEBUG_CONNECT		0x0c
> >>  
> >>  /* Must be kept compact -- no holes */
> >>  
> >> @@ -117,6 +118,7 @@ extern "C" {
> >>  #define DRM_IOCTL_XE_EXEC			DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC, struct drm_xe_exec)
> >>  #define DRM_IOCTL_XE_WAIT_USER_FENCE		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence)
> >>  #define DRM_IOCTL_XE_OBSERVATION		DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param)
> >> +#define DRM_IOCTL_XE_EUDEBUG_CONNECT		DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_EUDEBUG_CONNECT, struct drm_xe_eudebug_connect)
> >>  
> >>  /**
> >>   * DOC: Xe IOCTL Extensions
> >> @@ -1694,6 +1696,25 @@ struct drm_xe_oa_stream_info {
> >>  	__u64 reserved[3];
> >>  };
> >>  
> >> +/*
> >> + * Debugger ABI (ioctl and events) Version History:
> >> + * 0 - No debugger available
> >> + * 1 - Initial version
> >> + */
> >> +#define DRM_XE_EUDEBUG_VERSION 1
> >> +
> >> +struct drm_xe_eudebug_connect {
> >> +	/** @extensions: Pointer to the first extension struct, if any */
> >> +	__u64 extensions;
> >> +
> >> +	__u64 pid; /* input: Target process ID */
> >> +	__u32 flags; /* MBZ */
> >> +
> >> +	__u32 version; /* output: current ABI (ioctl / events) version */
> >> +};
> >> +
> >> +#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..a1cad9c005fc
> >> --- /dev/null
> >> +++ b/include/uapi/drm/xe_drm_eudebug.h
> >> @@ -0,0 +1,57 @@
> >> +/* SPDX-License-Identifier: MIT */
> >> +/*
> >> + * Copyright © 2023 Intel Corporation
> >> + */
> >> +
> >> +#ifndef _UAPI_XE_DRM_EUDEBUG_H_
> >> +#define _UAPI_XE_DRM_EUDEBUG_H_
> >> +
> >> +#if defined(__cplusplus)
> >> +extern "C" {
> >> +#endif
> >> +
> >> +/**
> >> + * Do a eudebug event read for a debugger connection.
> >> + *
> >> + * This ioctl is available in debug version 1.
> >> + */
> >> +#define DRM_XE_EUDEBUG_IOCTL_READ_EVENT _IO('j', 0x0)
> >> +
> >> +/* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
> >> +struct drm_xe_eudebug_event {
> >> +	__u32 len;
> >> +
> >> +	__u16 type;
> >> +#define DRM_XE_EUDEBUG_EVENT_NONE		0
> >> +#define DRM_XE_EUDEBUG_EVENT_READ		1
> >> +#define DRM_XE_EUDEBUG_EVENT_OPEN		2
> >> +#define DRM_XE_EUDEBUG_EVENT_VM			3
> >> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM
> >> +
> >> +	__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)
> >> +	__u64 seqno;
> >> +	__u64 reserved;
> >> +};
> >> +
> >> +struct drm_xe_eudebug_event_client {
> >> +	struct drm_xe_eudebug_event base;
> >> +
> >> +	__u64 client_handle; /* This is unique per debug connection */
> >> +};
> >> +
> >> +struct drm_xe_eudebug_event_vm {
> >> +	struct drm_xe_eudebug_event base;
> >> +
> >> +	__u64 client_handle;
> >> +	__u64 vm_handle;
> >> +};
> >> +
> >> +#if defined(__cplusplus)
> >> +}
> >> +#endif
> >> +
> >> +#endif
> >> -- 
> >> 2.34.1
> >> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker
  2024-07-29 10:10     ` Grzegorzek, Dominik
@ 2024-07-31  1:25       ` Matthew Brost
  0 siblings, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-31  1:25 UTC (permalink / raw)
  To: Grzegorzek, Dominik
  Cc: mika.kuoppala@linux.intel.com, intel-xe@lists.freedesktop.org,
	Patelczyk, Maciej, Manszewski, Christoph

On Mon, Jul 29, 2024 at 04:10:24AM -0600, Grzegorzek, Dominik wrote:
> /On Sat, 2024-07-27 at 05:08 +0000, Matthew Brost wrote:
> > On Fri, Jul 26, 2024 at 05:08:07PM +0300, Mika Kuoppala wrote:
> > > 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 10 times slower when there is no debugger
> > > connection open. Send attention event whenever we see attention with
> > > debugger presence. If there is no debugger connection active - reset.
> > > 
> > > Based on work by authors and other folks who were part of attentions in
> > > i915.
> > > 
> > > - v2 Do not validate potentially active hwe against engine->hwe.
> > >   Whenever the engine has width > 1, this field contains only the first
> > >   hwe of the class.
> > > - squash dss walking and semaphore to mutex
> > > - v3 error path fix in xe_send_gt_attention (Christoph)
> > > - v4 runalone active fix (Mika)
> > > - v5 q->lrc changes (Mika)
> > > - v6 Use C99 flexible arrays (Maciej, checkpatch)
> > >      function with 'for_each' in name (Maciej, checkpatch)
> > > - v7 long running active fix (Dominik)
> > > - v8 resource handling errors rebase (Mika)
> > > - v9 find out lrc handles first before sending event (Mika)
> > > - v10 adjust runalone shift according to hw
> > > 
> > > 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>
> > > ---
> > >  drivers/gpu/drm/xe/Makefile              |   1 +
> > >  drivers/gpu/drm/xe/regs/xe_engine_regs.h |   3 +
> > >  drivers/gpu/drm/xe/regs/xe_gt_regs.h     |   7 +
> > >  drivers/gpu/drm/xe/xe_device.c           |   2 +
> > >  drivers/gpu/drm/xe/xe_device_types.h     |   3 +
> > >  drivers/gpu/drm/xe/xe_eudebug.c          | 389 ++++++++++++++++++++++-
> > >  drivers/gpu/drm/xe/xe_eudebug.h          |   1 +
> > >  drivers/gpu/drm/xe/xe_eudebug_types.h    |  32 ++
> > >  drivers/gpu/drm/xe/xe_gt_debug.c         | 152 +++++++++
> > >  drivers/gpu/drm/xe/xe_gt_debug.h         |  21 ++
> > >  include/uapi/drm/xe_drm_eudebug.h        |  15 +-
> > >  11 files changed, 624 insertions(+), 2 deletions(-)
> > >  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 06badc5f99af..b7b6b047c02c 100644
> > > --- a/drivers/gpu/drm/xe/Makefile
> > > +++ b/drivers/gpu/drm/xe/Makefile
> > > @@ -49,6 +49,7 @@ xe-y += xe_bb.o \
> > >  	xe_gt_debugfs.o \
> > >  	xe_gt_freq.o \
> > >  	xe_gt_idle.o \
> > > +	xe_gt_debug.o \
> > >  	xe_gt_mcr.o \
> > >  	xe_gt_pagefault.o \
> > >  	xe_gt_sysfs.o \
> > > diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > > index 764c270599d0..b9d713a2061d 100644
> > > --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > > +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
> > > @@ -132,6 +132,9 @@
> > >  #define RING_EXECLIST_STATUS_LO(base)		XE_REG((base) + 0x234)
> > >  #define RING_EXECLIST_STATUS_HI(base)		XE_REG((base) + 0x234 + 4)
> > >  
> > > +#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_OAC_CONTEXT_ENABLE		REG_BIT(8)
> > >  #define	  CTX_CTRL_RUN_ALONE			REG_BIT(7)
> > > diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > > index 96a59a96dd4c..03e83ce3e35d 100644
> > > --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > > +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> > > @@ -437,6 +437,8 @@
> > >  #define   DISABLE_ECC				REG_BIT(5)
> > >  #define   ENABLE_PREFETCH_INTO_IC		REG_BIT(3)
> > >  
> > > +#define TD_ATT(x)				XE_REG_MCR(0xe470 + (x) * 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)
> > > @@ -516,6 +518,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 FORCEWAKE_ACK_GT			XE_REG(0x130044)
> > >  
> > >  /* Applicable for all FORCEWAKE_DOMAIN and FORCEWAKE_ACK_DOMAIN regs */
> > > diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> > > index 90bb0a8b1881..ba1c80089906 100644
> > > --- a/drivers/gpu/drm/xe/xe_device.c
> > > +++ b/drivers/gpu/drm/xe/xe_device.c
> > > @@ -768,6 +768,8 @@ int xe_device_probe(struct xe_device *xe)
> > >  
> > >  	xe_debugfs_register(xe);
> > >  
> > > +	xe_eudebug_init_late(xe);
> > > +
> > >  	xe_hwmon_register(xe);
> > >  
> > >  	for_each_gt(gt, xe, id)
> > > diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> > > index 4dcfd39cb909..3b33add576be 100644
> > > --- a/drivers/gpu/drm/xe/xe_device_types.h
> > > +++ b/drivers/gpu/drm/xe/xe_device_types.h
> > > @@ -516,6 +516,9 @@ struct xe_device {
> > >  
> > >  		/** @ordered_wq: used to discovery */
> > >  		struct workqueue_struct *ordered_wq;
> > > +
> > > +		/** @attention_scan: attention scan worker */
> > > +		struct delayed_work attention_scan;
> > >  	} eudebug;
> > >  
> > >  	/* private: */
> > > diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> > > index 9611acedeee9..c2de001cc33a 100644
> > > --- a/drivers/gpu/drm/xe/xe_eudebug.c
> > > +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> > > @@ -11,19 +11,29 @@
> > >  
> > >  #include <drm/drm_managed.h>
> > >  
> > > -#include "regs/xe_gt_regs.h"
> > >  #include "regs/xe_engine_regs.h"
> > > +#include "regs/xe_gt_regs.h"
> > >  #include "xe_device.h"
> > >  #include "xe_assert.h"
> > >  #include "xe_macros.h"
> > >  #include "xe_gt.h"
> > > +#include "xe_gt_debug.h"
> > > +#include "xe_lrc.h"
> > > +#include "xe_hw_engine.h"
> > > +#include "xe_exec_queue.h"
> > >  #include "xe_eudebug_types.h"
> > >  #include "xe_eudebug.h"
> > >  #include "xe_exec_queue_types.h"
> > > +#include "xe_guc_exec_queue_types.h"
> > > +#include "xe_execlist_types.h"
> > > +#include "xe_mmio.h"
> > >  #include "xe_module.h"
> > > +#include "xe_pm.h"
> > >  #include "xe_rtp.h"
> > > +#include "xe_sched_job.h"
> > >  #include "xe_vm.h"
> > >  #include "xe_wa.h"
> > > +#include "xe_force_wake.h"
> > >  
> > >  /*
> > >   * If there is no detected event read by userspace, during this period, assume
> > > @@ -843,6 +853,371 @@ static const struct file_operations fops = {
> > >  	.unlocked_ioctl	= xe_eudebug_ioctl,
> > >  };
> > >  
> > > +static bool queue_has_active_job(struct xe_exec_queue *q)
> > 
> > This should probably be a generic function in xe_exec_queue.c. We seemly
> > already have one - xe_exec_queue_is_idle.
> > 
> > > +{
> > > +
> > > +	struct drm_gpu_scheduler *sched;
> > > +	struct drm_sched_job *drm_job;
> > > +
> > > +	if (xe_device_uc_enabled(gt_to_xe(q->gt)))
> > 
> > General comment, we likely don't want to the EU debugger enabled unless
> > GuC submission is enabled as the execlist backend really doesn't work. 
> > 
> > > +		sched = &q->guc->sched.base;
> > > +	else
> > > +		sched = &q->execlist->sched;
> > > +
> > > +	drm_job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list);
> > 
> > Random musing that don't apply as we have xe_exec_queue_is_idle but...
> > 
> > You need a scheduler lock here which is missing. If you wanted to see
> > the scheduler pending list was not empty, we'd call into the drm
> > scheduler layer.
> > 
> > That being said, I think the EU debugger only support LR VMs? If so,
> > then this always going to be empty.
> Up until now, we were not requiring a VM to be in lr mode, thus I wanted to support both paths.
> However, we do depend on LR mode, as job timeouts would make debugging effectively ineffective.
> Therefore, we should add this constraint.
> 

It would great if we could enable EU debug for non-LR VM's but we'd
have to throw dma-fencing rules out the window then (e.g. disable job
timeouts) and I don't think that is likely to get accepted. I think we'd
also have to intercept some dma-fences from signaling too which this
series doesn't do. 

> Thanks for your comments! I will reuse xe_exec_queue_is_idle here as proposed, and I will try to

+1

> follow your hints with respect to locking and forcewake.
>

s/forcewake/pm, taking a forcewake ref where ever is safe while taking a
pm ref is not.

Matt

> Regards,
> Dominik
> > 
> > > +
> > > +	if (drm_job) {
> > > +		struct xe_sched_job *job = to_xe_sched_job(drm_job);
> > > +
> > > +		return xe_sched_job_started(job) && !xe_sched_job_completed(job);
> > > +	} else if (xe_exec_queue_is_lr(q) &&
> > > +		   (xe_lrc_ring_head(q->lrc[0]) != xe_lrc_ring_tail(q->lrc[0]))) {
> > > +		return true;
> > > +	}
> > > +
> > > +	return false;
> > > +}
> > > +
> > > +static int current_lrc(struct xe_hw_engine *hwe, u32 *lrc_hw)
> > > +{
> > > +	u32 lrc_reg;
> > > +	int err;
> > > +
> > > +	err = xe_force_wake_get(gt_to_fw(hwe->gt), hwe->domain);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	lrc_reg = hw_engine_mmio_read32(hwe, RING_CURRENT_LRCA(0));
> > > +
> > > +	xe_force_wake_put(gt_to_fw(hwe->gt), hwe->domain);
> > > +
> > > +	if (!(lrc_reg & CURRENT_LRCA_VALID))
> > > +		return -ENOENT;
> > > +
> > > +	*lrc_hw = lrc_reg & GENMASK(31, 12);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int match_engine_lrc(struct xe_exec_queue *q, u32 lrc_hw)
> > > +{
> > > +	int i;
> > > +	u32 lrc_ggtt;
> > > +
> > > +	for (i = 0; i < q->width; i++) {
> > > +		lrc_ggtt = lower_32_bits(xe_lrc_descriptor(q->lrc[i]));
> > > +		lrc_ggtt &= GENMASK(31, 12);
> > > +		if (lrc_ggtt == lrc_hw)
> > > +			return i;
> > > +	}
> > > +
> > > +	return -1;
> > > +}
> > > +
> > > +static u32 engine_status(const struct xe_hw_engine * const hwe,
> > > +			 u32 rcu_debug1)
> > > +{
> > > +	const bool xe1 = GRAPHICS_VER(gt_to_xe(hwe->gt)) < 20;
> > > +	unsigned int shift;
> > > +
> > > +	if (hwe->class == XE_ENGINE_CLASS_RENDER) {
> > > +		shift = 7;
> > > +		XE_WARN_ON(hwe->instance != 0);
> > > +	} else if (hwe->class == XE_ENGINE_CLASS_COMPUTE) {
> > > +		XE_WARN_ON(hwe->instance > 3);
> > > +
> > > +		if (xe1)
> > > +			shift = 10 + (hwe->instance * 3);
> > > +		else
> > > +			shift = 11 + (hwe->instance * 4);
> > > +	} else {
> > > +		XE_WARN_ON(hwe->class);
> > > +		return 0;
> > > +	}
> > > +
> > > +	return (rcu_debug1 >> shift) & RCU_DEBUG_1_ENGINE_STATUS;
> > > +}
> > > +
> > > +static bool engine_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_context_set(const struct xe_hw_engine * const hwe,
> > > +			       u32 rcu_debug1)
> > > +{
> > > +	return engine_status(hwe, rcu_debug1) & RCU_DEBUG_1_CONTEXT_ACTIVE;
> > > +}
> > > +
> > > +static bool engine_has_runalone(const struct xe_hw_engine * const hwe)
> > > +{
> > > +	return hwe->class == XE_ENGINE_CLASS_RENDER ||
> > > +		hwe->class == XE_ENGINE_CLASS_COMPUTE;
> > > +}
> > > +
> > > +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;
> > > +	u32 val;
> > > +
> > > +	if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GT)) {
> > > +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone failed to get force wake\n");
> > > +		return NULL;
> > > +	}
> > > +
> > > +	val = xe_mmio_read32(gt, RCU_DEBUG_1);
> > > +	xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
> > > +
> > > +	drm_dbg(&gt_to_xe(gt)->drm, "eudbg: runalone RCU_DEBUG_1 = 0x%08x\n", val);
> > > +
> > > +	num_active = 0;
> > > +	for_each_hw_engine(hwe, gt, id) {
> > > +		bool runalone, ctx;
> > > +
> > > +		if (!engine_has_runalone(hwe))
> > > +			continue;
> > > +
> > > +		runalone = engine_runalone_set(hwe, val);
> > > +		ctx = engine_context_set(hwe, val);
> > > +
> > > +		drm_dbg(&gt_to_xe(gt)->drm, "eudbg: engine %s: runalone=%s, context=%s",
> > > +			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(&gt_to_xe(gt)->drm, "eudbg: runalone engine %s %s",
> > > +				hwe->name, first ? "selected" : "found");
> > > +			if (!first)
> > > +				first = hwe;
> > > +		}
> > > +	}
> > > +
> > > +	if (num_active > 1)
> > > +		drm_err(&gt_to_xe(gt)->drm, "eudbg: %d runalone engines active!",
> > > +			num_active);
> > > +
> > > +	return first;
> > > +}
> > > +
> > > +static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lrc_idx)
> > > +{
> > > +	struct xe_device *xe = gt_to_xe(gt);
> > > +	struct xe_exec_queue *q, *found = NULL;
> > > +	struct xe_hw_engine *active;
> > > +	struct xe_file *xef, *tmp;
> > > +	unsigned long i;
> > > +	int idx, err;
> > > +	u32 lrc_hw;
> > > +
> > > +	active = get_runalone_active_hw_engine(gt);
> > > +	if (!active) {
> > > +		drm_dbg(&gt_to_xe(gt)->drm, "Runalone engine not found!");
> > > +		return ERR_PTR(-ENOENT);
> > > +	}
> > > +
> > > +	err = current_lrc(active, &lrc_hw);
> > > +	if (err)
> > > +		return ERR_PTR(err);
> > > +
> > > +	mutex_lock(&xe->files.lock);
> > > +	list_for_each_entry_safe(xef, tmp, &xe->files.list, link) {
> > > +		mutex_lock(&xef->exec_queue.lock);
> > > +		xa_for_each(&xef->exec_queue.xa, i, q) {
> > 
> > Same comment here as [1]. Don't hold xe->files.lock or
> > xef->exec_queue.lock for anything but the lookup. Holding locks longer
> > than needed creates unwanted lock dep chains which creates all sorts of
> > problems. The only time chains should exist is when we have well defined
> > locking chain like we have for a VM (vm->lock -> dma-resv -> notifier
> > lock).
> > 
> > So this should look something like this:
> > 
> > mutex_lock(&xe->files.lock);
> > xa_for_each(.., xef) {
> > 	xe_file_get(xef);
> > 	mutex_unlock(&xe->files.lock);
> > 
> > 	mutex_lock(&xef->exec_queue.lock);
> > 	xa_for_each(&xef->exec_queue.xa, i, q) {
> > 		xe_exec_queue_get(q);
> > 		mutex_unlock(&xef->exec_queue.lock);
> > 
> > 		/* Do something */
> > 	
> > 		xe_exec_queue_put(q);
> > 		mutex_lock(&xef->exec_queue.lock);
> > 	}
> > 	mutex_unlock(&xef->exec_queue.lock);
> > 	
> > 	xe_file_put(xef);
> > 	mutex_lock(&xe->files.lock);
> > }
> > mutex_unlock(&xe->files.lock);
> > 
> > Note you will need to change xe->files.list to an xarray to make this
> > safe too.
> > 
> > Matt
> > 
> > [1] https://patchwork.freedesktop.org/patch/606052/?series=136572&rev=1
> > 
> > > +			if (q->gt != gt)
> > > +				continue;
> > > +
> > > +			if (q->class != active->class)
> > > +				continue;
> > > +
> > > +			if (!queue_has_active_job(q))
> > > +				continue;
> > > +
> > > +			idx = match_engine_lrc(q, lrc_hw);
> > > +			if (idx < 0)
> > > +				continue;
> > > +
> > > +			xe_exec_queue_get(q);
> > > +			found = q;
> > > +
> > > +			if (lrc_idx)
> > > +				*lrc_idx = idx;
> > > +
> > > +			break;
> > > +		}
> > > +		mutex_unlock(&xef->exec_queue.lock);
> > > +
> > > +		if (found)
> > > +			break;
> > > +	}
> > > +	mutex_unlock(&xe->files.lock);
> > > +
> > > +	if (!found)
> > > +		return ERR_PTR(-ENOENT);
> > > +
> > > +	if (XE_WARN_ON(current_lrc(active, &lrc_hw)) &&
> > > +	    XE_WARN_ON(match_engine_lrc(found, lrc_hw) < 0)) {
> > > +		xe_exec_queue_put(found);
> > > +		return ERR_PTR(-ENOENT);
> > > +	}
> > > +
> > > +	return found;
> > > +}
> > > +
> > > +static int send_attention_event(struct xe_eudebug *d, struct xe_exec_queue *q, int lrc_idx)
> > > +{
> > > +	struct xe_eudebug_event_eu_attention *ea;
> > > +	struct xe_eudebug_event *event;
> > > +	int h_c, h_queue, h_lrc;
> > > +	u32 size = xe_gt_eu_attention_bitmap_size(q->gt);
> > > +	u32 sz = struct_size(ea, bitmask, size);
> > > +	int ret;
> > > +
> > > +	XE_WARN_ON(lrc_idx < 0 || lrc_idx >= q->width);
> > > +
> > > +	h_c = find_handle(d->res, XE_EUDEBUG_RES_TYPE_CLIENT, q->vm->xef);
> > > +	if (h_c < 0)
> > > +		return h_c;
> > > +
> > > +	h_queue = find_handle(d->res, XE_EUDEBUG_RES_TYPE_EXEC_QUEUE, q);
> > > +	if (h_queue < 0)
> > > +		return h_queue;
> > > +
> > > +	h_lrc = find_handle(d->res, XE_EUDEBUG_RES_TYPE_LRC, q->lrc[lrc_idx]);
> > > +	if (h_lrc < 0)
> > > +		return h_lrc;
> > > +
> > > +	event = __xe_eudebug_create_event(d, 0, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
> > > +					  DRM_XE_EUDEBUG_EVENT_STATE_CHANGE, sz, GFP_KERNEL);
> > > +
> > > +	if (!event)
> > > +		return -ENOSPC;
> > > +
> > > +	ea = cast_event(ea, event);
> > > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, client_handle, (u64)h_c);
> > > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, exec_queue_handle, (u64)h_queue);
> > > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, lrc_handle, (u64)h_lrc);
> > > +	write_member(struct drm_xe_eudebug_event_eu_attention, ea, bitmask_size, size);
> > > +
> > > +	mutex_lock(&d->eu_lock);
> > > +	event->seqno = atomic_long_inc_return(&d->events.seqno);
> > > +	ret = xe_gt_eu_attention_bitmap(q->gt, &ea->bitmask[0], ea->bitmask_size);
> > > +	mutex_unlock(&d->eu_lock);
> > > +
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	return xe_eudebug_queue_event(d, event);
> > > +}
> > > +
> > > +
> > > +static int xe_send_gt_attention(struct xe_gt *gt)
> > > +{
> > > +	struct xe_eudebug *d;
> > > +	struct xe_exec_queue *q;
> > > +	int ret, lrc_idx;
> > > +
> > > +	if (list_empty_careful(&gt_to_xe(gt)->eudebug.list))
> > > +		return -ENOTCONN;
> > > +
> > > +	q = runalone_active_queue_get(gt, &lrc_idx);
> > > +	if (IS_ERR(q))
> > > +		return PTR_ERR(q);
> > > +
> > > +	d = xe_eudebug_get(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);
> > > +	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)
> > > +{
> > > +	int ret;
> > > +
> > > +	ret = xe_gt_eu_threads_needing_attention(gt);
> > > +	if (ret <= 0)
> > > +		return ret;
> > > +
> > > +	ret = xe_send_gt_attention(gt);
> > > +
> > > +	/* Discovery in progress, fake it */
> > > +	if (ret == -EBUSY)
> > > +		return 0;
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +#define XE_EUDEBUG_ATTENTION_INTERVAL 100
> > > +static void attention_scan_fn(struct work_struct *work)
> > > +{
> > > +	struct xe_device *xe = container_of(work, typeof(*xe), eudebug.attention_scan.work);
> > > +	long delay = msecs_to_jiffies(XE_EUDEBUG_ATTENTION_INTERVAL);
> > > +	struct xe_gt *gt;
> > > +	u8 gt_id;
> > > +
> > > +	if (list_empty_careful(&xe->eudebug.list))
> > > +		delay *= 10;
> > > +
> > > +	if (delay >= HZ)
> > > +		delay = round_jiffies_up_relative(delay);
> > > +
> > > +	if (pm_runtime_active(xe->drm.dev)) {
> > > +		for_each_gt(gt, xe, gt_id) {
> > > +			int ret;
> > > +
> > > +			ret = xe_eudebug_handle_gt_attention(gt);
> > > +			if (ret) {
> > > +				// TODO: error capture
> > > +				drm_info(&gt_to_xe(gt)->drm,
> > > +					 "gt:%d unable to handle eu attention ret=%d\n",
> > > +					 gt_id, ret);
> > > +
> > > +				xe_gt_reset_async(gt);
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	schedule_delayed_work(&xe->eudebug.attention_scan, delay);
> > > +}
> > > +
> > > +static void attention_scan_cancel(struct xe_device *xe)
> > > +{
> > > +	cancel_delayed_work_sync(&xe->eudebug.attention_scan);
> > > +}
> > > +
> > > +static void attention_scan_flush(struct xe_device *xe)
> > > +{
> > > +	mod_delayed_work(system_wq, &xe->eudebug.attention_scan, 0);
> > > +}
> > > +
> > >  static void discovery_work_fn(struct work_struct *work);
> > >  
> > >  static int
> > > @@ -877,6 +1252,7 @@ xe_eudebug_connect(struct xe_device *xe,
> > >  
> > >  	kref_init(&d->ref);
> > >  	spin_lock_init(&d->connection.lock);
> > > +	mutex_init(&d->eu_lock);
> > >  	init_waitqueue_head(&d->events.write_done);
> > >  	init_waitqueue_head(&d->events.read_done);
> > >  	init_completion(&d->discovery);
> > > @@ -903,6 +1279,7 @@ xe_eudebug_connect(struct xe_device *xe,
> > >  
> > >  	kref_get(&d->ref);
> > >  	queue_work(xe->eudebug.ordered_wq, &d->discovery_work);
> > > +	attention_scan_flush(xe);
> > >  
> > >  	eu_dbg(d, "connected session %lld", d->session);
> > >  
> > > @@ -979,12 +1356,22 @@ void xe_eudebug_init(struct xe_device *xe)
> > >  {
> > >  	spin_lock_init(&xe->eudebug.lock);
> > >  	INIT_LIST_HEAD(&xe->eudebug.list);
> > > +	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
> > >  
> > >  	xe->eudebug.available = true;
> > >  }
> > >  
> > > +void xe_eudebug_init_late(struct xe_device *xe)
> > > +{
> > > +	if (!xe->eudebug.available)
> > > +		return;
> > > +
> > > +	attention_scan_flush(xe);
> > > +}
> > > +
> > >  void xe_eudebug_fini(struct xe_device *xe)
> > >  {
> > > +	attention_scan_cancel(xe);
> > >  	xe_assert(xe, list_empty_careful(&xe->eudebug.list));
> > >  }
> > >  
> > > diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> > > index ac89a3d1ee1d..1e233c4683d6 100644
> > > --- a/drivers/gpu/drm/xe/xe_eudebug.h
> > > +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> > > @@ -18,6 +18,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
> > >  			     struct drm_file *file);
> > >  
> > >  void xe_eudebug_init(struct xe_device *xe);
> > > +void xe_eudebug_init_late(struct xe_device *xe);
> > >  void xe_eudebug_fini(struct xe_device *xe);
> > >  void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
> > >  
> > > diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
> > > index 6e3c23023933..16667b4dfe45 100644
> > > --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
> > > +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> > > @@ -105,6 +105,9 @@ struct xe_eudebug {
> > >  	/** @discovery_work: worker to discover resources for target_task */
> > >  	struct work_struct discovery_work;
> > >  
> > > +	/** eu_lock: guards operations on eus (eu thread control and attention) */
> > > +	struct mutex eu_lock;
> > > +
> > >  	/** @events: kfifo queue of to-be-delivered events */
> > >  	struct {
> > >  		/** @lock: guards access to fifo */
> > > @@ -202,4 +205,33 @@ struct xe_eudebug_event_exec_queue {
> > >  	u64 lrc_handle[];
> > >  };
> > >  
> > > +/**
> > > + * struct xe_eudebug_event_eu_attention - Internal event for EU attention
> > > + */
> > > +struct xe_eudebug_event_eu_attention {
> > > +	/** @base: base event */
> > > +	struct xe_eudebug_event base;
> > > +
> > > +	/** @client_handle: client for the attention */
> > > +	u64 client_handle;
> > > +
> > > +	/** @exec_queue_handle: handle of exec_queue which raised attention */
> > > +	u64 exec_queue_handle;
> > > +
> > > +	/** @lrc_handle: lrc handle of the workload which raised attention */
> > > +	u64 lrc_handle;
> > > +
> > > +	/** @flags: eu attention event flags, currently MBZ */
> > > +	u32 flags;
> > > +
> > > +	/** @bitmask_size: size of the bitmask, specific to device */
> > > +	u32 bitmask_size;
> > > +
> > > +	/**
> > > +	 * @bitmask: reflects threads currently signalling attention,
> > > +	 * starting from natural hardware order of DSS=0, eu=0
> > > +	 */
> > > +	u8 bitmask[];
> > > +};
> > > +
> > >  #endif
> > > 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..04d2d43ce249
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/xe/xe_gt_debug.c
> > > @@ -0,0 +1,152 @@
> > > +// 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"
> > > +
> > > +static int xe_gt_foreach_dss_group_instance(struct xe_gt *gt,
> > > +					    int (*fn)(struct xe_gt *gt,
> > > +						      void *data,
> > > +						      u16 group,
> > > +						      u16 instance),
> > > +					    void *data)
> > > +{
> > > +	const enum xe_force_wake_domains fw_domains = XE_FW_GT | XE_FW_RENDER;
> > > +	unsigned int dss;
> > > +	u16 group, instance;
> > > +	int ret;
> > > +
> > > +	xe_pm_runtime_get(gt_to_xe(gt));
> > > +	ret = xe_force_wake_get(gt_to_fw(gt), fw_domains);
> > > +	if (ret)
> > > +		goto pm_runtime_put;
> > > +
> > > +	for_each_dss_steering(dss, gt, group, instance) {
> > > +		ret = fn(gt, data, group, instance);
> > > +		if (ret)
> > > +			break;
> > > +	}
> > > +
> > > +	xe_force_wake_put(gt_to_fw(gt), fw_domains);
> > > +pm_runtime_put:
> > > +	xe_pm_runtime_put(gt_to_xe(gt));
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static int read_first_attention_mcr(struct xe_gt *gt, void *data,
> > > +				    u16 group, u16 instance)
> > > +{
> > > +	unsigned int row;
> > > +
> > > +	for (row = 0; row < 2; row++) {
> > > +		u32 val;
> > > +
> > > +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(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);
> > > +
> > > +	return  bitmap_weight(dss_mask, XE_MAX_DSS_FUSE_BITS) *
> > > +		TD_EU_ATTENTION_MAX_ROWS * 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)
> > > +{
> > > +	struct attn_read_iter * const iter = data;
> > > +	unsigned int row;
> > > +
> > > +	for (row = 0; row < TD_EU_ATTENTION_MAX_ROWS; row++) {
> > > +		u32 val;
> > > +
> > > +		if (iter->i >= iter->size)
> > > +			return 0;
> > > +
> > > +		XE_WARN_ON(iter->i + sizeof(val) > xe_gt_eu_attention_bitmap_size(gt));
> > > +
> > > +		val = xe_gt_mcr_unicast_read(gt, TD_ATT(row), group, instance);
> > > +
> > > +
> > > +		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
> > > +	};
> > > +
> > > +	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..3f13dbb17a5f
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/xe/xe_gt_debug.h
> > > @@ -0,0 +1,21 @@
> > > +/* SPDX-License-Identifier: MIT */
> > > +/*
> > > + * Copyright © 2023 Intel Corporation
> > > + */
> > > +
> > > +#ifndef __XE_GT_DEBUG_
> > > +#define __XE_GT_DEBUG_
> > > +
> > > +#define TD_EU_ATTENTION_MAX_ROWS 2u
> > > +
> > > +#include "xe_gt_types.h"
> > > +
> > > +#define XE_GT_ATTENTION_TIMEOUT_MS 100
> > > +
> > > +int xe_gt_eu_threads_needing_attention(struct xe_gt *gt);
> > > +
> > > +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/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> > > index 25dddb8b22f4..453269ac8307 100644
> > > --- a/include/uapi/drm/xe_drm_eudebug.h
> > > +++ b/include/uapi/drm/xe_drm_eudebug.h
> > > @@ -27,13 +27,15 @@ struct drm_xe_eudebug_event {
> > >  #define DRM_XE_EUDEBUG_EVENT_OPEN		2
> > >  #define DRM_XE_EUDEBUG_EVENT_VM			3
> > >  #define DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE		4
> > > -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE
> > > +#define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
> > > +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_EU_ATTENTION
> > >  
> > >  	__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)
> > > +
> > >  	__u64 seqno;
> > >  	__u64 reserved;
> > >  };
> > > @@ -62,6 +64,17 @@ struct drm_xe_eudebug_event_exec_queue {
> > >  	__u64 lrc_handle[];
> > >  };
> > >  
> > > +struct drm_xe_eudebug_event_eu_attention {
> > > +	struct drm_xe_eudebug_event base;
> > > +
> > > +	__u64 client_handle;
> > > +	__u64 exec_queue_handle;
> > > +	__u64 lrc_handle;
> > > +	__u32 flags;
> > > +	__u32 bitmask_size;
> > > +	__u8 bitmask[];
> > > +};
> > > +
> > >  #if defined(__cplusplus)
> > >  }
> > >  #endif
> > > -- 
> > > 2.34.1
> > > 
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks
  2024-07-30 14:05     ` Mika Kuoppala
@ 2024-07-31  1:33       ` Matthew Brost
  0 siblings, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-31  1:33 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe

On Tue, Jul 30, 2024 at 05:05:30PM +0300, Mika Kuoppala wrote:
> Matthew Brost <matthew.brost@intel.com> writes:
> 
> > On Fri, Jul 26, 2024 at 05:08:10PM +0300, Mika Kuoppala wrote:
> >> When vma is in place, debugger needs to intercept before
> >> userspace proceeds with the workload. For example to install
> >> a breakpoint in a eu shader.
> >> 
> >> Attach debugger in xe_user_fence, send UFENCE event
> >> and stall normal user fence signal path to yield if
> >> there is debugger attached to ufence.
> >> 
> >> When ack (ioctl) is received for the corresponding seqno,
> >> signal ufence.
> >> 
> >> v2: ufence worker in own workqueue
> >> 
> >
> > Not a complete review again, just a couple of quick comments.
> >
> >> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> >> ---
> >>  drivers/gpu/drm/xe/xe_eudebug.c       | 239 +++++++++++++++++++++++++-
> >>  drivers/gpu/drm/xe/xe_eudebug.h       |   6 +
> >>  drivers/gpu/drm/xe/xe_eudebug_types.h |  12 ++
> >>  drivers/gpu/drm/xe/xe_exec.c          |   2 +-
> >>  drivers/gpu/drm/xe/xe_sync.c          |  49 ++++--
> >>  drivers/gpu/drm/xe/xe_sync.h          |   8 +-
> >>  drivers/gpu/drm/xe/xe_sync_types.h    |  26 ++-
> >>  drivers/gpu/drm/xe/xe_vm.c            |   4 +-
> >>  include/uapi/drm/xe_drm_eudebug.h     |  15 +-
> >>  9 files changed, 333 insertions(+), 28 deletions(-)
> >> 
> >> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> >> index 8f0e6a56a65e..5dcb7c9464e9 100644
> >> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> >> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> >> @@ -35,6 +35,7 @@
> >>  #include "xe_vm.h"
> >>  #include "xe_wa.h"
> >>  #include "xe_force_wake.h"
> >> +#include "xe_sync.h"
> >>  
> >>  /*
> >>   * If there is no detected event read by userspace, during this period, assume
> >> @@ -240,11 +241,115 @@ static void xe_eudebug_free(struct kref *ref)
> >>  	kfree_rcu(d, rcu);
> >>  }
> >>  
> >> -static void xe_eudebug_put(struct xe_eudebug *d)
> >> +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;
> >
> > Here we have a seqno but then an RB tree for search which is a bit
> > incongruent. Let me explain, seqno typically mean something which
> > signals sequentially in order. But then you have RB tree for searching,
> > if everything signaled in order a list would be sufficient.
> >
> > So without looking too much I think we want one of two things.
> >
> > 1. seqno + list
> > 2. key + rb tree
> >
> > Make sense?
> >
> > Kinda a nit but naming matters in this case as a name implies in-order
> > vs out-of-order signaling.
> 
> This is the seqno of event that was associated with ufence. If userspace
> does multiple binds with ufences, it can then pinpoint, with ack ioctl,
> the particular bind it wants to be released, with this seqno.
> 
> And userspace can ack out of sequence. As it can potentially
> receive events out of sequence.
>
> Would it help if it would be event_seqno instead of just seqno?

If userspace can ack out of sequence, I'd rename it 'event_id'.

So s/events.seqno/events.id too.

Does that work?

Matt

> 
> -Mika
> 
> >
> > Matt
> >
> >> +	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);
> >> +
> >> +	if (READ_ONCE(ufence->signalled))
> >> +		xe_sync_ufence_signal(ufence);
> >> +
> >> +	xe_sync_ufence_put(ufence);
> >> +}
> >> +
> >> +static void kick_ufence_worker(struct xe_user_fence *f)
> >> +{
> >> +	INIT_WORK(&f->eudebug.worker, ufence_signal_worker);
> >> +	queue_work(f->xe->eudebug.ordered_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;
> >> +	u64 signaller_ack, signalled_by;
> >> +
> >> +	signaller_ack = cmpxchg64(&f->eudebug.signalled_seqno, 0, ack->seqno);
> >> +	signalled_by = f->eudebug.signalled_seqno;
> >> +
> >> +	if (!signaller_ack)
> >> +		kick_ufence_worker(f);
> >> +	else
> >> +		xe_sync_ufence_put(f);
> >> +
> >> +	eu_dbg(d, "ACK: seqno=%llu: %ssignalled by %s (%llu) (held %lluus)",
> >> +	       ack->seqno, signaller_ack ? "already " : "",
> >> +	       on_disconnect ? "disconnect" : "debugger",
> >> +	       signalled_by,
> >> +	       ktime_us_delta(ktime_get(), ack->ts_insert));
> >> +
> >> +	kfree(ack);
> >> +}
> >> +
> >> +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 struct task_struct *find_get_target(const pid_t nr)
> >>  {
> >>  	struct task_struct *task;
> >> @@ -328,6 +433,8 @@ static bool xe_eudebug_detach(struct xe_device *xe,
> >>  
> >>  	eu_dbg(d, "session %lld detached with %d", d->session, err);
> >>  
> >> +	release_acks(d);
> >> +
> >>  	/* Our ref with the connection_link */
> >>  	xe_eudebug_put(d);
> >>  
> >> @@ -428,7 +535,7 @@ static struct task_struct *find_task_get(struct xe_file *xef)
> >>  	return task;
> >>  }
> >>  
> >> -static struct xe_eudebug *
> >> +struct xe_eudebug *
> >>  xe_eudebug_get(struct xe_file *xef)
> >>  {
> >>  	struct task_struct *task;
> >> @@ -889,6 +996,44 @@ static long xe_eudebug_read_event(struct xe_eudebug *d,
> >>  	return ret;
> >>  }
> >>  
> >> +static long
> >> +xe_eudebug_ack_event_ioctl(struct xe_eudebug *d,
> >> +			   const unsigned int cmd,
> >> +			   const u64 arg)
> >> +{
> >> +	struct drm_xe_eudebug_ack_event __user * const user_ptr =
> >> +		u64_to_user_ptr(arg);
> >> +	struct drm_xe_eudebug_ack_event user_arg;
> >> +	struct xe_eudebug_ack *ack;
> >> +	struct xe_device *xe = d->xe;
> >> +
> >> +	if (XE_IOCTL_DBG(xe, _IOC_SIZE(cmd) < sizeof(user_arg)))
> >> +		return -EINVAL;
> >> +
> >> +	/* Userland write */
> >> +	if (XE_IOCTL_DBG(xe, !(_IOC_DIR(cmd) & _IOC_WRITE)))
> >> +		return -EINVAL;
> >> +
> >> +	if (XE_IOCTL_DBG(xe, 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, 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;
> >> +}
> >> +
> >>  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)
> >> @@ -1070,7 +1215,10 @@ static long xe_eudebug_ioctl(struct file *file,
> >>  		ret = xe_eudebug_eu_control(d, arg);
> >>  		eu_dbg(d, "ioctl cmd=EU_CONTROL ret=%ld\n", ret);
> >>  		break;
> >> -
> >> +	case DRM_XE_EUDEBUG_IOCTL_ACK_EVENT:
> >> +		ret = xe_eudebug_ack_event_ioctl(d, cmd, arg);
> >> +		eu_dbg(d, "ioctl cmd=EVENT_ACK ret=%ld\n", ret);
> >> +		break;
> >>  	default:
> >>  		ret = -EINVAL;
> >>  	}
> >> @@ -1759,6 +1907,9 @@ xe_eudebug_connect(struct xe_device *xe,
> >>  	INIT_KFIFO(d->events.fifo);
> >>  	INIT_WORK(&d->discovery_work, discovery_work_fn);
> >>  
> >> +	spin_lock_init(&d->acks.lock);
> >> +	d->acks.tree = RB_ROOT;
> >> +
> >>  	d->res = xe_eudebug_resources_alloc();
> >>  	if (IS_ERR(d->res)) {
> >>  		err = PTR_ERR(d->res);
> >> @@ -2337,6 +2488,70 @@ static int vm_bind_op(struct xe_eudebug *d, struct xe_vm *vm,
> >>  	return 0;
> >>  }
> >>  
> >> +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(sizeof(*ack), GFP_KERNEL);
> >> +	if (!ack)
> >> +		return -ENOMEM;
> >> +
> >> +	ack->seqno = seqno;
> >> +	ack->ts_insert = ktime_get();
> >> +
> >> +	spin_lock(&d->acks.lock);
> >> +	old = rb_find_add(&ack->rb_node,
> >> +			  &d->acks.tree, ack_insert_cmp);
> >> +	if (!old) {
> >> +		kref_get(&f->refcount);
> >> +		ack->ufence = f;
> >> +	}
> >> +	spin_unlock(&d->acks.lock);
> >> +
> >> +	if (old) {
> >> +		eu_dbg(d, "ACK: seqno=%llu: already exists", seqno);
> >> +		kfree(ack);
> >> +		return -EEXIST;
> >> +	}
> >> +
> >> +	eu_dbg(d, "ACK: seqno=%llu: tracking started", seqno);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int vm_bind_ufence_event(struct xe_eudebug *d,
> >> +				struct xe_user_fence *ufence)
> >> +{
> >> +	struct xe_eudebug_event *event;
> >> +	struct 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;
> >> +
> >> +	seqno = atomic_long_inc_return(&d->events.seqno);
> >> +
> >> +	event = xe_eudebug_create_event(d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
> >> +					seqno, flags, sz, GFP_KERNEL);
> >> +	if (!event)
> >> +		return -ENOMEM;
> >> +
> >> +	e = cast_event(e, event);
> >> +
> >> +	write_member(struct drm_xe_eudebug_event_vm_bind_ufence,
> >> +		     e, vm_bind_ref_seqno, ufence->eudebug.bind_ref_seqno);
> >> +
> >> +	ret = xe_eudebug_track_ufence(d, ufence, seqno);
> >> +	if (!ret)
> >> +		ret = xe_eudebug_queue_event(d, event);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >>  void xe_eudebug_vm_bind_start(struct xe_vm *vm)
> >>  {
> >>  	struct xe_eudebug *d;
> >> @@ -2507,6 +2722,24 @@ void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int bind_err)
> >>  		xe_eudebug_put(d);
> >>  }
> >>  
> >> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence)
> >> +{
> >> +	struct xe_eudebug *d;
> >> +	int err;
> >> +
> >> +	d = ufence->eudebug.debugger;
> >> +	if (!d || xe_eudebug_detached(d))
> >> +		return -ENOTCONN;
> >> +
> >> +	err = vm_bind_ufence_event(d, ufence);
> >> +	if (err) {
> >> +		eu_err(d, "error %d on %s", err, __func__);
> >> +		xe_eudebug_disconnect(d, err);
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >>  static int discover_client(struct xe_eudebug *d, struct xe_file *xef)
> >>  {
> >>  	struct xe_exec_queue *q;
> >> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> >> index 2cab90773b21..3de54802a6ca 100644
> >> --- a/drivers/gpu/drm/xe/xe_eudebug.h
> >> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> >> @@ -15,6 +15,7 @@ struct xe_vm;
> >>  struct xe_vma;
> >>  struct xe_exec_queue;
> >>  struct xe_hw_engine;
> >> +struct xe_user_fence;
> >>  
> >>  int xe_eudebug_connect_ioctl(struct drm_device *dev,
> >>  			     void *data,
> >> @@ -38,4 +39,9 @@ void xe_eudebug_vm_bind_start(struct xe_vm *vm);
> >>  void xe_eudebug_vm_bind_op_add(struct xe_vm *vm, u32 op, u64 addr, u64 range);
> >>  void xe_eudebug_vm_bind_end(struct xe_vm *vm, bool has_ufence, int err);
> >>  
> >> +int xe_eudebug_vm_bind_ufence(struct xe_user_fence *ufence);
> >> +
> >> +struct xe_eudebug *xe_eudebug_get(struct xe_file *xef);
> >> +void xe_eudebug_put(struct xe_eudebug *d);
> >> +
> >>  #endif
> >> diff --git a/drivers/gpu/drm/xe/xe_eudebug_types.h b/drivers/gpu/drm/xe/xe_eudebug_types.h
> >> index 1ffe33f15409..a32c51416b5f 100644
> >> --- a/drivers/gpu/drm/xe/xe_eudebug_types.h
> >> +++ b/drivers/gpu/drm/xe/xe_eudebug_types.h
> >> @@ -86,6 +86,7 @@ struct xe_eudebug_eu_control_ops {
> >>  	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
> >>   */
> >> @@ -149,6 +150,12 @@ struct xe_eudebug {
> >>  		atomic_long_t seqno;
> >>  	} events;
> >>  
> >> +	/* user fences tracked by this debugger */
> >> +	struct {
> >> +		spinlock_t lock;
> >> +		struct rb_root tree;
> >> +	} acks;
> >> +
> >>  	/** @ops operations for eu_control */
> >>  	struct xe_eudebug_eu_control_ops *ops;
> >>  };
> >> @@ -286,4 +293,9 @@ struct xe_eudebug_event_vm_bind_op {
> >>  	u64 range; /* Zero for unmap all ? */
> >>  };
> >>  
> >> +struct xe_eudebug_event_vm_bind_ufence {
> >> +	struct xe_eudebug_event base;
> >> +	u64 vm_bind_ref_seqno;
> >> +};
> >> +
> >>  #endif
> >> diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
> >> index f36980aa26e6..400cb576f3b9 100644
> >> --- a/drivers/gpu/drm/xe/xe_exec.c
> >> +++ b/drivers/gpu/drm/xe/xe_exec.c
> >> @@ -157,7 +157,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
> >>  	vm = q->vm;
> >>  
> >>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
> >> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
> >> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
> >>  					  &syncs_user[num_syncs], SYNC_PARSE_FLAG_EXEC |
> >>  					  (xe_vm_in_lr_mode(vm) ?
> >>  					   SYNC_PARSE_FLAG_LR_MODE : 0));
> >> diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
> >> index 533246f42256..52d56bfdf932 100644
> >> --- a/drivers/gpu/drm/xe/xe_sync.c
> >> +++ b/drivers/gpu/drm/xe/xe_sync.c
> >> @@ -18,17 +18,7 @@
> >>  #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;
> >> -};
> >> +#include "xe_eudebug.h"
> >>  
> >>  static void user_fence_destroy(struct kref *kref)
> >>  {
> >> @@ -36,6 +26,10 @@ static void user_fence_destroy(struct kref *kref)
> >>  						 refcount);
> >>  
> >>  	mmdrop(ufence->mm);
> >> +
> >> +	if (ufence->eudebug.debugger)
> >> +		xe_eudebug_put(ufence->eudebug.debugger);
> >> +
> >>  	kfree(ufence);
> >>  }
> >>  
> >> @@ -49,7 +43,10 @@ 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,
> >> +					       struct xe_file *xef,
> >> +					       struct xe_vm *vm,
> >> +					       u64 addr,
> >>  					       u64 value)
> >>  {
> >>  	struct xe_user_fence *ufence;
> >> @@ -58,7 +55,7 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
> >>  	if (!access_ok(ptr, sizeof(ptr)))
> >>  		return ERR_PTR(-EFAULT);
> >>  
> >> -	ufence = kmalloc(sizeof(*ufence), GFP_KERNEL);
> >> +	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
> >>  	if (!ufence)
> >>  		return ERR_PTR(-ENOMEM);
> >>  
> >> @@ -69,12 +66,17 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
> >>  	ufence->mm = current->mm;
> >>  	mmgrab(ufence->mm);
> >>  
> >> +	if (vm->eudebug_bind.ref) {
> >> +		ufence->eudebug.debugger = xe_eudebug_get(xef);
> >> +		ufence->eudebug.bind_ref_seqno = vm->eudebug_bind.ref;
> >> +	}
> >> +
> >>  	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);
> >> +	XE_WARN_ON(!ufence->signalled);
> >>  
> >>  	if (mmget_not_zero(ufence->mm)) {
> >>  		kthread_use_mm(ufence->mm);
> >> @@ -85,7 +87,20 @@ static void user_fence_worker(struct work_struct *w)
> >>  	}
> >>  
> >>  	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);
> >> +	int ret;
> >> +
> >>  	WRITE_ONCE(ufence->signalled, 1);
> >> +
> >> +	/* Lets see if debugger wants to track this */
> >> +	ret = xe_eudebug_vm_bind_ufence(ufence);
> >> +	if (ret)
> >> +		xe_sync_ufence_signal(ufence);
> >> +
> >>  	user_fence_put(ufence);
> >>  }
> >>  
> >> @@ -104,6 +119,7 @@ static void user_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
> >>  }
> >>  
> >>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
> >> +			struct xe_vm *vm,
> >>  			struct xe_sync_entry *sync,
> >>  			struct drm_xe_sync __user *sync_user,
> >>  			unsigned int flags)
> >> @@ -185,7 +201,8 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
> >>  		if (exec) {
> >>  			sync->addr = sync_in.addr;
> >>  		} else {
> >> -			sync->ufence = user_fence_create(xe, sync_in.addr,
> >> +			sync->ufence = user_fence_create(xe, xef, vm,
> >> +							 sync_in.addr,
> >>  							 sync_in.timeline_value);
> >>  			if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence)))
> >>  				return PTR_ERR(sync->ufence);
> >> diff --git a/drivers/gpu/drm/xe/xe_sync.h b/drivers/gpu/drm/xe/xe_sync.h
> >> index 256ffc1e54dc..f5bec2b1b4f6 100644
> >> --- a/drivers/gpu/drm/xe/xe_sync.h
> >> +++ b/drivers/gpu/drm/xe/xe_sync.h
> >> @@ -9,8 +9,12 @@
> >>  #include "xe_sync_types.h"
> >>  
> >>  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;
> >>  
> >> @@ -19,6 +23,7 @@ struct xe_vm;
> >>  #define SYNC_PARSE_FLAG_DISALLOW_USER_FENCE	BIT(2)
> >>  
> >>  int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
> >> +			struct xe_vm *vm,
> >>  			struct xe_sync_entry *sync,
> >>  			struct drm_xe_sync __user *sync_user,
> >>  			unsigned int flags);
> >> @@ -40,5 +45,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 30ac3f51993b..907c601a6d8c 100644
> >> --- a/drivers/gpu/drm/xe/xe_sync_types.h
> >> +++ b/drivers/gpu/drm/xe/xe_sync_types.h
> >> @@ -7,12 +7,28 @@
> >>  #define _XE_SYNC_TYPES_H_
> >>  
> >>  #include <linux/types.h>
> >> +#include <linux/spinlock.h>
> >> +#include <linux/kref.h>
> >> +#include <linux/dma-fence-array.h>
> >>  
> >> -struct drm_syncobj;
> >> -struct dma_fence;
> >> -struct dma_fence_chain;
> >> -struct drm_xe_sync;
> >> -struct user_fence;
> >> +struct xe_eudebug;
> >> +
> >> +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;
> >> +	struct {
> >> +		struct xe_eudebug *debugger;
> >> +		u64 bind_ref_seqno;
> >> +		u64 signalled_seqno;
> >> +		struct work_struct worker;
> >> +	} eudebug;
> >> +};
> >>  
> >>  struct xe_sync_entry {
> >>  	struct drm_syncobj *syncobj;
> >> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> >> index 657a54b74eea..b117a892e386 100644
> >> --- a/drivers/gpu/drm/xe/xe_vm.c
> >> +++ b/drivers/gpu/drm/xe/xe_vm.c
> >> @@ -3049,9 +3049,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
> >>  		}
> >>  	}
> >>  
> >> +	xe_eudebug_vm_bind_start(vm);
> >> +
> >>  	syncs_user = u64_to_user_ptr(args->syncs);
> >>  	for (num_syncs = 0; num_syncs < args->num_syncs; num_syncs++) {
> >> -		err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs],
> >> +		err = xe_sync_entry_parse(xe, xef, vm, &syncs[num_syncs],
> >>  					  &syncs_user[num_syncs],
> >>  					  (xe_vm_in_lr_mode(vm) ?
> >>  					   SYNC_PARSE_FLAG_LR_MODE : 0) |
> >> diff --git a/include/uapi/drm/xe_drm_eudebug.h b/include/uapi/drm/xe_drm_eudebug.h
> >> index 789c8aa81c09..1875192e92bd 100644
> >> --- a/include/uapi/drm/xe_drm_eudebug.h
> >> +++ b/include/uapi/drm/xe_drm_eudebug.h
> >> @@ -17,6 +17,7 @@ extern "C" {
> >>   */
> >>  #define DRM_XE_EUDEBUG_IOCTL_READ_EVENT		_IO('j', 0x0)
> >>  #define DRM_XE_EUDEBUG_IOCTL_EU_CONTROL		_IOWR('j', 0x2, struct drm_xe_eudebug_eu_control)
> >> +#define DRM_XE_EUDEBUG_IOCTL_ACK_EVENT		_IOW('j', 0x4, struct drm_xe_eudebug_ack_event)
> >>  
> >>  /* XXX: Document events to match their internal counterparts when moved to xe_drm.h */
> >>  struct drm_xe_eudebug_event {
> >> @@ -31,7 +32,8 @@ struct drm_xe_eudebug_event {
> >>  #define DRM_XE_EUDEBUG_EVENT_EU_ATTENTION	5
> >>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND		6
> >>  #define DRM_XE_EUDEBUG_EVENT_VM_BIND_OP		7
> >> -#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_OP
> >> +#define DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE	8
> >> +#define DRM_XE_EUDEBUG_EVENT_MAX_EVENT		DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE
> >>  
> >>  	__u16 flags;
> >>  #define DRM_XE_EUDEBUG_EVENT_CREATE		(1 << 0)
> >> @@ -158,6 +160,17 @@ struct drm_xe_eudebug_event_vm_bind_op {
> >>  	__u64 range; /* XXX: Zero for unmap all? */
> >>  };
> >>  
> >> +struct drm_xe_eudebug_event_vm_bind_ufence {
> >> +	struct drm_xe_eudebug_event base;
> >> +	__u64 vm_bind_ref_seqno; /* *_event_vm_bind.base.seqno */
> >> +};
> >> +
> >> +struct drm_xe_eudebug_ack_event {
> >> +	__u32 type;
> >> +	__u32 flags; /* MBZ */
> >> +	__u64 seqno;
> >> +};
> >> +
> >>  #if defined(__cplusplus)
> >>  }
> >>  #endif
> >> -- 
> >> 2.34.1
> >> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH] fixup! drm/xe/eudebug: implement userptr_vma access
  2024-07-27  1:45       ` Matthew Brost
@ 2024-07-31 11:11         ` Andrzej Hajda
  2024-07-31 17:51           ` Matthew Brost
  0 siblings, 1 reply; 78+ messages in thread
From: Andrzej Hajda @ 2024-07-31 11:11 UTC (permalink / raw)
  To: Matthew Brost; +Cc: Andrzej Hajda, Mika Kuoppala, intel-xe, Maciej Patelczyk

This fixup pulls call to xe_vma_userptr_pin_pages out of
vm->userptr.notifier_lock.

Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
---
Hi Matthew,

I hope this fixup should answer your concerns.
It was tested on LNL with lockdep turned on and with your
two patches mentioned earlier.

Posted in form of fixup to underline the difference,
let me know if you insist on full patch.

Regards
Andrzej
---
 drivers/gpu/drm/xe/xe_eudebug.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 472d9314505a..80d6f886969a 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -3343,6 +3343,7 @@ static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
 	struct xe_res_cursor cur = {};
 	int cur_len, ret = 0;
 
+lock_notifier:
 	/* lock notifier in non-invalidation state */
 	for (unsigned long nseq = uvma->userptr.notifier_seq; true;
 	     nseq = mmu_interval_read_begin(&uvma->userptr.notifier)) {
@@ -3358,9 +3359,11 @@ static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
 		list_del_init(&uvma->userptr.invalidate_link);
 		spin_unlock(&vm->userptr.invalidated_lock);
 
+		up_read(&vm->userptr.notifier_lock);
 		ret = xe_vma_userptr_pin_pages(uvma);
 		if (ret)
-			goto out_unlock_notifier;
+			return ret;
+		goto lock_notifier;
 	}
 
 	if (!up->sg) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* Re: [PATCH] fixup! drm/xe/eudebug: implement userptr_vma access
  2024-07-31 11:11         ` [PATCH] fixup! " Andrzej Hajda
@ 2024-07-31 17:51           ` Matthew Brost
  2024-08-05 16:54             ` [PATCH v2] " Andrzej Hajda
  2024-08-26 14:40             ` [PATCH v2.5] " Andrzej Hajda
  0 siblings, 2 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-31 17:51 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: Mika Kuoppala, intel-xe, Maciej Patelczyk

On Wed, Jul 31, 2024 at 01:11:12PM +0200, Andrzej Hajda wrote:
> This fixup pulls call to xe_vma_userptr_pin_pages out of
> vm->userptr.notifier_lock.
> 
> Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
> ---
> Hi Matthew,
> 
> I hope this fixup should answer your concerns.
> It was tested on LNL with lockdep turned on and with your
> two patches mentioned earlier.
> 
> Posted in form of fixup to underline the difference,
> let me know if you insist on full patch.
> 

I think you change will work but I think this can be written cleaner and
also in a way in which the EU debug layer doesn't have to call into mmu
notifier functions (eventually we want to move all notifier interaction
to a DRM layer too).

How about:

retry:
	down_read(&vm->userptr.notifier_lock)

	/* re-pin if necessary */
	if (xe_vma_userptr_check_repin(uvma)) {
		up_read(&vm->userptr.notifier_lock)
		
		spin_lock(&vm->userptr.invalidated_lock);
		list_del_init(&uvma->userptr.invalidate_link);
		spin_unlock(&vm->userptr.invalidated_lock);

		ret = xe_vma_userptr_pin_pages(uvma);
		if (ret)
			return err;

		goto retry;
	}

	/* Do copy */

Also while you are here, maybe move the implementation for this function
in xe_vm.c as that seems to be a better place for this as this all
userptr specific code.

Matt

> Regards
> Andrzej
> ---
>  drivers/gpu/drm/xe/xe_eudebug.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 472d9314505a..80d6f886969a 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -3343,6 +3343,7 @@ static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
>  	struct xe_res_cursor cur = {};
>  	int cur_len, ret = 0;
>  
> +lock_notifier:
>  	/* lock notifier in non-invalidation state */
>  	for (unsigned long nseq = uvma->userptr.notifier_seq; true;
>  	     nseq = mmu_interval_read_begin(&uvma->userptr.notifier)) {
> @@ -3358,9 +3359,11 @@ static int xe_eudebug_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
>  		list_del_init(&uvma->userptr.invalidate_link);
>  		spin_unlock(&vm->userptr.invalidated_lock);
>  
> +		up_read(&vm->userptr.notifier_lock);
>  		ret = xe_vma_userptr_pin_pages(uvma);
>  		if (ret)
> -			goto out_unlock_notifier;
> +			return ret;
> +		goto lock_notifier;
>  	}
>  
>  	if (!up->sg) {
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality
  2024-07-30 15:01     ` Manszewski, Christoph
@ 2024-07-31 18:03       ` Matthew Brost
  0 siblings, 0 replies; 78+ messages in thread
From: Matthew Brost @ 2024-07-31 18:03 UTC (permalink / raw)
  To: Manszewski, Christoph
  Cc: Mika Kuoppala, intel-xe, Dominik Grzegorzek, Maciej Patelczyk,
	Joonas Lahtinen

On Tue, Jul 30, 2024 at 05:01:17PM +0200, Manszewski, Christoph wrote:
> Hi Matt,
> 
> On 28.07.2024 06:50, Matthew Brost wrote:
> > On Fri, Jul 26, 2024 at 05:08:17PM +0300, Mika Kuoppala wrote:
> > > From: Christoph Manszewski <christoph.manszewski@intel.com>
> > > 
> > > Make it possible to dynamically enable/disable debugger funtionality,
> > > including the setting and unsetting of required hw register values via a
> > > sysfs entry located at '/sys/class/drm/card<X>/device/enable_eudebug'.
> > > 
> > > This entry uses 'kstrtobool' and as such it accepts inputs as documented
> > > by this function, in particular '0' and '1'.
> > > 
> > > 1) Adjust to xe_rtp graphics ranges changes.
> > > 2) Fix pile placement. Wa 14019869343 (aka. 16021232320) was
> > > added later in the pile, move disablement to appropriate commit.
> > > 3) flush reset (Christoph)
> > > 4) dont allow exec queue enable if feature is disabled (Dominik)
> > > 5) bind to drm sysfs functions (Maciej)
> > > 
> > > Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
> > > 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/xe_device.c       |   2 -
> > >   drivers/gpu/drm/xe/xe_device_types.h |   5 +
> > >   drivers/gpu/drm/xe/xe_eudebug.c      | 174 +++++++++++++++++++++++----
> > >   drivers/gpu/drm/xe/xe_eudebug.h      |   2 -
> > >   drivers/gpu/drm/xe/xe_exec_queue.c   |   3 +
> > >   drivers/gpu/drm/xe/xe_hw_engine.c    |   1 -
> > >   drivers/gpu/drm/xe/xe_reg_sr.c       |  21 +++-
> > >   drivers/gpu/drm/xe/xe_reg_sr.h       |   4 +-
> > >   drivers/gpu/drm/xe/xe_rtp.c          |   2 +-
> > >   drivers/gpu/drm/xe/xe_rtp_types.h    |   1 +
> > >   10 files changed, 178 insertions(+), 37 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> > > index 268faa1800c4..30a2bf2a7e00 100644
> > > --- a/drivers/gpu/drm/xe/xe_device.c
> > > +++ b/drivers/gpu/drm/xe/xe_device.c
> > > @@ -785,8 +785,6 @@ int xe_device_probe(struct xe_device *xe)
> > >   	xe_debugfs_register(xe);
> > > -	xe_eudebug_init_late(xe);
> > > -
> > >   	xe_hwmon_register(xe);
> > >   	for_each_gt(gt, xe, id)
> > > diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> > > index beb1f3c8dc63..17aedbba3130 100644
> > > --- a/drivers/gpu/drm/xe/xe_device_types.h
> > > +++ b/drivers/gpu/drm/xe/xe_device_types.h
> > > @@ -517,6 +517,11 @@ struct xe_device {
> > >   		/** @ordered_wq: used to discovery */
> > >   		struct workqueue_struct *ordered_wq;
> > > +		/** @enable_lock: protects the enable toggle */
> > > +		struct mutex enable_lock;
> > > +		/** @enable: is the debugging functionality enabled */
> > > +		bool enable;
> > > +
> > >   		/** @attention_scan: attention scan worker */
> > >   		struct delayed_work attention_scan;
> > >   	} eudebug;
> > > diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> > > index a80ffb64df15..80066f787ec2 100644
> > > --- a/drivers/gpu/drm/xe/xe_eudebug.c
> > > +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> > > @@ -2000,9 +2000,6 @@ xe_eudebug_connect(struct xe_device *xe,
> > >   	param->version = DRM_XE_EUDEBUG_VERSION;
> > > -	if (!xe->eudebug.available)
> > > -		return -EOPNOTSUPP;
> > > -
> > >   	d = kzalloc(sizeof(*d), GFP_KERNEL);
> > >   	if (!d)
> > >   		return -ENOMEM;
> > > @@ -2064,70 +2061,199 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
> > >   	struct drm_xe_eudebug_connect * const param = data;
> > >   	int ret = 0;
> > > +	mutex_lock(&xe->eudebug.enable_lock);
> > > +
> > > +	if (!xe->eudebug.enable) {
> > > +		mutex_unlock(&xe->eudebug.enable_lock);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > >   	ret = xe_eudebug_connect(xe, param);
> > > +	mutex_unlock(&xe->eudebug.enable_lock);
> > > +
> > >   	return ret;
> > >   }
> > >   #undef XE_REG_MCR
> > >   #define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
> > > -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
> > > +static void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
> > >   {
> > >   	const struct xe_rtp_entry_sr eudebug_was[] = {
> > > -		{ XE_RTP_NAME("GlobalDebugEnable"),
> > > -		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
> > > -			       ENGINE_CLASS(RENDER)),
> > > -		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
> > > -				     GLOBAL_DEBUG_ENABLE))
> > > -		},
> > >   		{ XE_RTP_NAME("TdCtlDebugEnable"),
> > >   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
> > >   			       FUNC(xe_rtp_match_first_render_or_compute)),
> > >   		  XE_RTP_ACTIONS(SET(TD_CTL,
> > >   				     TD_CTL_BREAKPOINT_ENABLE |
> > >   				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
> > > -				     TD_CTL_FEH_AND_FEE_ENABLE))
> > > +				     TD_CTL_FEH_AND_FEE_ENABLE,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > >   		},
> > >   		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
> > >   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
> > >   			       FUNC(xe_rtp_match_first_render_or_compute)),
> > > -		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
> > > +		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > >   		},
> > >   		{ XE_RTP_NAME("18022722726"),
> > >   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
> > >   			       FUNC(xe_rtp_match_first_render_or_compute)),
> > > -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
> > > +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > >   		},
> > >   		{ XE_RTP_NAME("14015527279"),
> > >   		  XE_RTP_RULES(PLATFORM(PVC),
> > >   			       FUNC(xe_rtp_match_first_render_or_compute)),
> > > -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
> > > +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > >   		},
> > >   		{}
> > >   	};
> > >   	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
> > > -	struct xe_device *xe = gt_to_xe(hwe->gt);
> > > -	if (xe->eudebug.available)
> > > -		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
> > > +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
> > > +}
> > > +
> > > +static void xe_eudebug_fini_hw_engine(struct xe_hw_engine *hwe)
> > > +{
> > > +	const struct xe_rtp_entry_sr eudebug_was[] = {
> > > +		{ XE_RTP_NAME("TdCtlDebugEnable"),
> > > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
> > > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > > +		  XE_RTP_ACTIONS(CLR(TD_CTL,
> > > +				     TD_CTL_BREAKPOINT_ENABLE |
> > > +				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
> > > +				     TD_CTL_FEH_AND_FEE_ENABLE,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > > +		},
> > > +		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
> > > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
> > > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > > +		  XE_RTP_ACTIONS(CLR(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > > +		},
> > > +		{ XE_RTP_NAME("18022722726"),
> > > +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
> > > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > > +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > > +		},
> > > +		{ XE_RTP_NAME("14015527279"),
> > > +		  XE_RTP_RULES(PLATFORM(PVC),
> > > +			       FUNC(xe_rtp_match_first_render_or_compute)),
> > > +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
> > > +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
> > > +		},
> > > +		{}
> > > +	};
> > > +	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
> > > +
> > > +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
> > > +}
> > > +
> > > +static int xe_eudebug_enable(struct xe_device *xe, bool enable)
> > > +{
> > > +	struct xe_gt *gt;
> > > +	int i;
> > > +	u8 id;
> > > +
> > > +	if (!xe->eudebug.available)
> > > +		return -EOPNOTSUPP;
> > > +
> > > +	/* XXX: TODO hold list lock? */
> > > +	mutex_lock(&xe->eudebug.enable_lock);
> > > +
> > > +	if (!enable && !list_empty(&xe->eudebug.list)) {
> > > +		mutex_unlock(&xe->eudebug.enable_lock);
> > > +		return -EBUSY;
> > > +	}
> > > +
> > > +	if (enable == xe->eudebug.enable) {
> > > +		mutex_unlock(&xe->eudebug.enable_lock);
> > > +		return 0;
> > > +	}
> > > +
> > > +	for_each_gt(gt, xe, id) {
> > > +		for (i = 0; i < ARRAY_SIZE(gt->hw_engines); i++) {
> > > +			if (!(gt->info.engine_mask & BIT(i)))
> > > +				continue;
> > > +
> > > +			if (enable)
> > > +				xe_eudebug_init_hw_engine(&gt->hw_engines[i]);
> > > +			else
> > > +				xe_eudebug_fini_hw_engine(&gt->hw_engines[i]);
> > > +		}
> > > +
> > > +		xe_gt_reset_async(gt);
> > 
> > What are you trying to accomplish with the reset? Reinit of some HW
> > settings? Doing GT reset does have a side affect of killing exec queues
> > with jobs active on the GPU which is not ideal. Please explain exactly
> > what needs to be done, and maybe we can brainstorm something that won't
> > kill things.
> 
> Yes, the intention is to set the required registers using the modified
> reg_sr entries. The reason for performing a reset here, instead of directly
> writing the mmio registers, is that to my best knowledge the register values
> are fetched on thread dispatch. Thus, modifying them directly would result
> in having inconsistent TD_CTL values across threads, which would break
> debugging. Resetting is a harsh way of ensuring consistency.
> 
> Of course, I am more than happy to discuss a better approach.
> 

I'm thinking more or less a GT reset but with an extra step which attempts
to idle the GT. If I have time, perhaps I can post a RFC for that
implementation as I think it should be fairly straight forward. 

> > 
> > Also exposing a GT reset via sysfs might be potential security issue
> > too.
> 
> I assumed that since it is only available for privileged users, security
> should not be a concern here.
> 

Yea I guess it isn't truely a security issue more of an issue where ww
expose something to the via sysfs user which can cause bad things.
debugfs would be fine to do something bad, but sysfs really shouldn't
allow bad things.

For example, what is user enables EU debug and a compositor has a job
running? This could crash the compositor. Users will not be happy and
perplexed by an interface we expose doing bad things.

Matt

> > 
> > > +		flush_work(&gt->reset.worker);
> > 
> > Flushing the reset worker here creates a lock dependency chain with
> > xe->eudebug.enable_lock and all locks taken during a GT reset which is
> > not ideal either. If we need to do a GT reset (or something else with a
> > worker that takes locks) it probably best to flush the worker after
> > dropping xe->eudebug.enable_lock. This relates to my other comments on
> > locking, we shouldn't create lock depeendecy chains unless we have to
> > and the chains are well defined.
> 
> Got it.
> 
> Thanks for your feeback,
> Christoph
> 
> > 
> > Matt
> > 
> > > +	}
> > > +
> > > +	if (enable)
> > > +		attention_scan_flush(xe);
> > > +	else
> > > +		attention_scan_cancel(xe);
> > > +
> > > +	xe->eudebug.enable = enable;
> > > +	mutex_unlock(&xe->eudebug.enable_lock);
> > > +
> > > +	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.enable);
> > > +}
> > > +
> > > +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;
> > > +
> > > +	sysfs_remove_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
> > >   }
> > >   void xe_eudebug_init(struct xe_device *xe)
> > >   {
> > > +	struct device *dev = xe->drm.dev;
> > > +	int ret;
> > > +
> > >   	spin_lock_init(&xe->eudebug.lock);
> > >   	INIT_LIST_HEAD(&xe->eudebug.list);
> > >   	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
> > > -	xe->eudebug.available = true;
> > > -}
> > > +	drmm_mutex_init(&xe->drm, &xe->eudebug.enable_lock);
> > > +	xe->eudebug.enable = false;
> > > -void xe_eudebug_init_late(struct xe_device *xe)
> > > -{
> > > -	if (!xe->eudebug.available)
> > > -		return;
> > > -	attention_scan_flush(xe);
> > > +	ret = sysfs_create_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
> > > +	if (ret)
> > > +		drm_warn(&xe->drm, "eudebug sysfs init failed: %d, debugger unavailable\n", ret);
> > > +	else
> > > +		devm_add_action_or_reset(dev, xe_eudebug_sysfs_fini, xe);
> > > +
> > > +	xe->eudebug.available = ret == 0;
> > >   }
> > >   void xe_eudebug_fini(struct xe_device *xe)
> > > diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
> > > index 02c9ba56e752..2f66aa87a0f6 100644
> > > --- a/drivers/gpu/drm/xe/xe_eudebug.h
> > > +++ b/drivers/gpu/drm/xe/xe_eudebug.h
> > > @@ -24,9 +24,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
> > >   			     struct drm_file *file);
> > >   void xe_eudebug_init(struct xe_device *xe);
> > > -void xe_eudebug_init_late(struct xe_device *xe);
> > >   void xe_eudebug_fini(struct xe_device *xe);
> > > -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
> > >   void xe_eudebug_file_open(struct xe_file *xef);
> > >   void xe_eudebug_file_close(struct xe_file *xef);
> > > diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
> > > index bc2edade5e5b..b6fc65ab8aa9 100644
> > > --- a/drivers/gpu/drm/xe/xe_exec_queue.c
> > > +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
> > > @@ -360,6 +360,9 @@ static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
> > >   			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
> > >   		return -EINVAL;
> > > +	if (XE_IOCTL_DBG(xe, !xe->eudebug.enable))
> > > +		return -EPERM;
> > > +
> > >   	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
> > >   	return 0;
> > > diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> > > index 74813bc20787..0f90416be0ba 100644
> > > --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> > > +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> > > @@ -504,7 +504,6 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
> > >   	xe_tuning_process_engine(hwe);
> > >   	xe_wa_process_engine(hwe);
> > >   	hw_engine_setup_default_state(hwe);
> > > -	xe_eudebug_init_hw_engine(hwe);
> > >   	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
> > >   	xe_reg_whitelist_process_engine(hwe);
> > > diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
> > > index 440ac572f6e5..a7671722a84e 100644
> > > --- a/drivers/gpu/drm/xe/xe_reg_sr.c
> > > +++ b/drivers/gpu/drm/xe/xe_reg_sr.c
> > > @@ -92,22 +92,31 @@ static void reg_sr_inc_error(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);
> > >   	int ret;
> > >   	if (pentry) {
> > > -		if (!compatible_entries(pentry, e)) {
> > > +		if (overwrite && e->set_bits) {
> > > +			pentry->clr_bits |= e->clr_bits;
> > > +			pentry->set_bits |= e->set_bits;
> > > +			pentry->read_mask |= e->read_mask;
> > > +		} else if (overwrite && !e->set_bits) {
> > > +			pentry->clr_bits |= e->clr_bits;
> > > +			pentry->set_bits &= ~e->clr_bits;
> > > +			pentry->read_mask |= e->read_mask;
> > > +		} else if (!compatible_entries(pentry, e)) {
> > >   			ret = -EINVAL;
> > >   			goto fail;
> > > +		} else {
> > > +			pentry->clr_bits |= e->clr_bits;
> > > +			pentry->set_bits |= e->set_bits;
> > > +			pentry->read_mask |= e->read_mask;
> > >   		}
> > > -		pentry->clr_bits |= e->clr_bits;
> > > -		pentry->set_bits |= e->set_bits;
> > > -		pentry->read_mask |= e->read_mask;
> > > -
> > >   		return 0;
> > >   	}
> > > diff --git a/drivers/gpu/drm/xe/xe_reg_sr.h b/drivers/gpu/drm/xe/xe_reg_sr.h
> > > index 51fbba423e27..d67fafdcd847 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_
> > >   #define _XE_REG_SR_
> > > +#include <linux/types.h>
> > > +
> > >   /*
> > >    * Reg save/restore bookkeeping
> > >    */
> > > @@ -21,7 +23,7 @@ int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe)
> > >   void xe_reg_sr_dump(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_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
> > > index 02e28274282f..5643bcde52bd 100644
> > > --- a/drivers/gpu/drm/xe/xe_rtp.c
> > > +++ b/drivers/gpu/drm/xe/xe_rtp.c
> > > @@ -153,7 +153,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, action->flags & XE_RTP_ACTION_FLAG_OVERWRITE);
> > >   }
> > >   static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry,
> > > diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h
> > > index 1b76b947c706..20d228067da3 100644
> > > --- a/drivers/gpu/drm/xe/xe_rtp_types.h
> > > +++ b/drivers/gpu/drm/xe/xe_rtp_types.h
> > > @@ -33,6 +33,7 @@ struct xe_rtp_action {
> > >   	/** @read_mask: mask for bits to consider when reading value back */
> > >   	u32			read_mask;
> > >   #define XE_RTP_ACTION_FLAG_ENGINE_BASE		BIT(0)
> > > +#define XE_RTP_ACTION_FLAG_OVERWRITE		BIT(1)
> > >   	/** @flags: flags to apply on rule evaluation or action */
> > >   	u8			flags;
> > >   };
> > > -- 
> > > 2.34.1
> > > 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v2] drm/xe/eudebug: implement userptr_vma access
  2024-07-31 17:51           ` Matthew Brost
@ 2024-08-05 16:54             ` Andrzej Hajda
  2024-08-05 19:20               ` Cavitt, Jonathan
  2024-08-26 14:40             ` [PATCH v2.5] " Andrzej Hajda
  1 sibling, 1 reply; 78+ messages in thread
From: Andrzej Hajda @ 2024-08-05 16:54 UTC (permalink / raw)
  To: intel-xe, Matthew Brost; +Cc: Andrzej Hajda, Mika Kuoppala, Maciej Patelczyk

Debugger needs to read/write program's vmas including userptr_vma.
Since hmm_range_fault is used to pin userptr vmas, it is possible
to map those vmas from debugger context.

v2: kmap to kmap_local (Maciej)
v3: simplified locking, moved to xe_vm.c (Matthew)

Signed-off-by: Andrzej Hajda <andrzej.hajda@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 |  2 +-
 drivers/gpu/drm/xe/xe_vm.c      | 47 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_vm.h      |  3 +++
 3 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 62be0879e651..baed2812438a 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -2905,7 +2905,7 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
 	if (bo)
 		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
 
-	return -EOPNOTSUPP;
+	return xe_uvma_access(to_userptr_vma(vma), offset, buf, bytes, write);
 }
 
 static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index b117a892e386..f1aadd5068a6 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3429,3 +3429,50 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap)
 	}
 	kvfree(snap);
 }
+
+int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
+		   void *buf, u64 len, bool write)
+{
+	struct xe_vm *vm = xe_vma_vm(&uvma->vma);
+	struct xe_userptr *up = &uvma->userptr;
+	struct xe_res_cursor cur = {};
+	int cur_len, ret = 0;
+
+	while (true) {
+		down_read(&vm->userptr.notifier_lock);
+		if (!xe_vma_userptr_check_repin(uvma))
+			break;
+
+		spin_lock(&vm->userptr.invalidated_lock);
+		list_del_init(&uvma->userptr.invalidate_link);
+		spin_unlock(&vm->userptr.invalidated_lock);
+
+		up_read(&vm->userptr.notifier_lock);
+		ret = xe_vma_userptr_pin_pages(uvma);
+		if (ret)
+			return ret;
+	}
+
+	if (!up->sg) {
+		ret = -EINVAL;
+		goto out_unlock_notifier;
+	}
+
+	for (xe_res_first_sg(up->sg, offset, len, &cur); cur.remaining;
+	     xe_res_next(&cur, cur_len)) {
+		void *ptr = kmap_local_page(sg_page(cur.sgl)) + cur.start;
+
+		cur_len = min(cur.size, cur.remaining);
+		if (write)
+			memcpy(ptr, buf, cur_len);
+		else
+			memcpy(buf, ptr, cur_len);
+		kunmap_local(ptr);
+		buf += cur_len;
+	}
+	ret = len;
+
+out_unlock_notifier:
+	up_read(&vm->userptr.notifier_lock);
+	return ret;
+}
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index c864dba35e1d..99b9a9b011de 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -281,3 +281,6 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm);
 void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap);
 void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p);
 void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
+
+int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
+		   void *buf, u64 len, bool write);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* RE: [PATCH v2] drm/xe/eudebug: implement userptr_vma access
  2024-08-05 16:54             ` [PATCH v2] " Andrzej Hajda
@ 2024-08-05 19:20               ` Cavitt, Jonathan
  0 siblings, 0 replies; 78+ messages in thread
From: Cavitt, Jonathan @ 2024-08-05 19:20 UTC (permalink / raw)
  To: Hajda, Andrzej, intel-xe@lists.freedesktop.org, Brost, Matthew
  Cc: Hajda, Andrzej, Mika Kuoppala, Patelczyk, Maciej,
	Cavitt, Jonathan

-----Original Message-----
From: Intel-xe <intel-xe-bounces@lists.freedesktop.org> On Behalf Of Andrzej Hajda
Sent: Monday, August 5, 2024 9:54 AM
To: intel-xe@lists.freedesktop.org; Brost, Matthew <matthew.brost@intel.com>
Cc: Hajda, Andrzej <andrzej.hajda@intel.com>; Mika Kuoppala <mika.kuoppala@linux.intel.com>; Patelczyk, Maciej <maciej.patelczyk@intel.com>
Subject: [PATCH v2] drm/xe/eudebug: implement userptr_vma access
> 
> Debugger needs to read/write program's vmas including userptr_vma.
> Since hmm_range_fault is used to pin userptr vmas, it is possible
> to map those vmas from debugger context.
> 
> v2: kmap to kmap_local (Maciej)
> v3: simplified locking, moved to xe_vm.c (Matthew)

I get why it was requested to move the xe_uvma_access code from
xe_eudebug.c to xe_vm.c, but if I may ask, do we have any plans
for using the new functionality outside of the eudebugger?  It
might be good to add some additional use cases while we're
implementing the function for eudebug.  Though, I guess at that
point we'd want to implement the xe_uvma_access code in
drm-xe-next first before fixing up xe_eudebug_vma_access to
support userptr vma access.

I personally won't block on it, though it might come up when
upstreaming this.
Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
-Jonathan Cavitt

> 
> Signed-off-by: Andrzej Hajda <andrzej.hajda@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 |  2 +-
>  drivers/gpu/drm/xe/xe_vm.c      | 47 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_vm.h      |  3 +++
>  3 files changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 62be0879e651..baed2812438a 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -2905,7 +2905,7 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
>  	if (bo)
>  		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
>  
> -	return -EOPNOTSUPP;
> +	return xe_uvma_access(to_userptr_vma(vma), offset, buf, bytes, write);
>  }
>  
>  static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index b117a892e386..f1aadd5068a6 100644
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
> @@ -3429,3 +3429,50 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap)
>  	}
>  	kvfree(snap);
>  }
> +
> +int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> +		   void *buf, u64 len, bool write)
> +{
> +	struct xe_vm *vm = xe_vma_vm(&uvma->vma);
> +	struct xe_userptr *up = &uvma->userptr;
> +	struct xe_res_cursor cur = {};
> +	int cur_len, ret = 0;
> +
> +	while (true) {
> +		down_read(&vm->userptr.notifier_lock);
> +		if (!xe_vma_userptr_check_repin(uvma))
> +			break;
> +
> +		spin_lock(&vm->userptr.invalidated_lock);
> +		list_del_init(&uvma->userptr.invalidate_link);
> +		spin_unlock(&vm->userptr.invalidated_lock);
> +
> +		up_read(&vm->userptr.notifier_lock);
> +		ret = xe_vma_userptr_pin_pages(uvma);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (!up->sg) {
> +		ret = -EINVAL;
> +		goto out_unlock_notifier;
> +	}
> +
> +	for (xe_res_first_sg(up->sg, offset, len, &cur); cur.remaining;
> +	     xe_res_next(&cur, cur_len)) {
> +		void *ptr = kmap_local_page(sg_page(cur.sgl)) + cur.start;
> +
> +		cur_len = min(cur.size, cur.remaining);
> +		if (write)
> +			memcpy(ptr, buf, cur_len);
> +		else
> +			memcpy(buf, ptr, cur_len);
> +		kunmap_local(ptr);
> +		buf += cur_len;
> +	}
> +	ret = len;
> +
> +out_unlock_notifier:
> +	up_read(&vm->userptr.notifier_lock);
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
> index c864dba35e1d..99b9a9b011de 100644
> --- a/drivers/gpu/drm/xe/xe_vm.h
> +++ b/drivers/gpu/drm/xe/xe_vm.h
> @@ -281,3 +281,6 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm);
>  void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap);
>  void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p);
>  void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
> +
> +int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> +		   void *buf, u64 len, bool write);
> -- 
> 2.34.1
> 
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-07-26 14:08 ` [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support Mika Kuoppala
  2024-07-26 19:20   ` Matthew Brost
@ 2024-08-07  9:34   ` Zbigniew Kempczyński
  2024-08-21 11:37     ` Mika Kuoppala
  2024-08-12 12:02   ` Zbigniew Kempczyński
  2 siblings, 1 reply; 78+ messages in thread
From: Zbigniew Kempczyński @ 2024-08-07  9:34 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
	Andi Shyti, Matt Roper, Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:00PM +0300, Mika Kuoppala wrote:

<cut>

> +
> +static int
> +xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
> +		  const pid_t pid_nr)
> +{
> +	struct task_struct *target;
> +	struct xe_eudebug *iter;
> +	kuid_t uid = current_uid();
> +	int ret = 0;
> +
> +	target = find_get_target(pid_nr);
> +	if (!target)
> +		return -ENOENT;

This goes outside and is returned via ioctl() what reminds me some LKML
thread this code is reserved for file operations only.

--
Zbigniew


^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality
  2024-07-28  4:50   ` Matthew Brost
  2024-07-30 15:01     ` Manszewski, Christoph
@ 2024-08-07 10:09     ` Manszewski, Christoph
  1 sibling, 0 replies; 78+ messages in thread
From: Manszewski, Christoph @ 2024-08-07 10:09 UTC (permalink / raw)
  To: Matthew Brost, Mika Kuoppala
  Cc: intel-xe, Dominik Grzegorzek, Maciej Patelczyk

Hi Matt,

On 28.07.2024 06:50, Matthew Brost wrote:
> On Fri, Jul 26, 2024 at 05:08:17PM +0300, Mika Kuoppala wrote:
>> From: Christoph Manszewski <christoph.manszewski@intel.com>
>>
>> Make it possible to dynamically enable/disable debugger funtionality,
>> including the setting and unsetting of required hw register values via a
>> sysfs entry located at '/sys/class/drm/card<X>/device/enable_eudebug'.
>>
>> This entry uses 'kstrtobool' and as such it accepts inputs as documented
>> by this function, in particular '0' and '1'.
>>
>> 1) Adjust to xe_rtp graphics ranges changes.
>> 2) Fix pile placement. Wa 14019869343 (aka. 16021232320) was
>> added later in the pile, move disablement to appropriate commit.
>> 3) flush reset (Christoph)
>> 4) dont allow exec queue enable if feature is disabled (Dominik)
>> 5) bind to drm sysfs functions (Maciej)
>>
>> Signed-off-by: Christoph Manszewski <christoph.manszewski@intel.com>
>> 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/xe_device.c       |   2 -
>>   drivers/gpu/drm/xe/xe_device_types.h |   5 +
>>   drivers/gpu/drm/xe/xe_eudebug.c      | 174 +++++++++++++++++++++++----
>>   drivers/gpu/drm/xe/xe_eudebug.h      |   2 -
>>   drivers/gpu/drm/xe/xe_exec_queue.c   |   3 +
>>   drivers/gpu/drm/xe/xe_hw_engine.c    |   1 -
>>   drivers/gpu/drm/xe/xe_reg_sr.c       |  21 +++-
>>   drivers/gpu/drm/xe/xe_reg_sr.h       |   4 +-
>>   drivers/gpu/drm/xe/xe_rtp.c          |   2 +-
>>   drivers/gpu/drm/xe/xe_rtp_types.h    |   1 +
>>   10 files changed, 178 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
>> index 268faa1800c4..30a2bf2a7e00 100644
>> --- a/drivers/gpu/drm/xe/xe_device.c
>> +++ b/drivers/gpu/drm/xe/xe_device.c
>> @@ -785,8 +785,6 @@ int xe_device_probe(struct xe_device *xe)
>>   
>>   	xe_debugfs_register(xe);
>>   
>> -	xe_eudebug_init_late(xe);
>> -
>>   	xe_hwmon_register(xe);
>>   
>>   	for_each_gt(gt, xe, id)
>> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
>> index beb1f3c8dc63..17aedbba3130 100644
>> --- a/drivers/gpu/drm/xe/xe_device_types.h
>> +++ b/drivers/gpu/drm/xe/xe_device_types.h
>> @@ -517,6 +517,11 @@ struct xe_device {
>>   		/** @ordered_wq: used to discovery */
>>   		struct workqueue_struct *ordered_wq;
>>   
>> +		/** @enable_lock: protects the enable toggle */
>> +		struct mutex enable_lock;
>> +		/** @enable: is the debugging functionality enabled */
>> +		bool enable;
>> +
>>   		/** @attention_scan: attention scan worker */
>>   		struct delayed_work attention_scan;
>>   	} eudebug;
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
>> index a80ffb64df15..80066f787ec2 100644
>> --- a/drivers/gpu/drm/xe/xe_eudebug.c
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
>> @@ -2000,9 +2000,6 @@ xe_eudebug_connect(struct xe_device *xe,
>>   
>>   	param->version = DRM_XE_EUDEBUG_VERSION;
>>   
>> -	if (!xe->eudebug.available)
>> -		return -EOPNOTSUPP;
>> -
>>   	d = kzalloc(sizeof(*d), GFP_KERNEL);
>>   	if (!d)
>>   		return -ENOMEM;
>> @@ -2064,70 +2061,199 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>>   	struct drm_xe_eudebug_connect * const param = data;
>>   	int ret = 0;
>>   
>> +	mutex_lock(&xe->eudebug.enable_lock);
>> +
>> +	if (!xe->eudebug.enable) {
>> +		mutex_unlock(&xe->eudebug.enable_lock);
>> +		return -ENODEV;
>> +	}
>> +
>>   	ret = xe_eudebug_connect(xe, param);
>>   
>> +	mutex_unlock(&xe->eudebug.enable_lock);
>> +
>>   	return ret;
>>   }
>>   
>>   #undef XE_REG_MCR
>>   #define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
>>   
>> -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
>> +static void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe)
>>   {
>>   	const struct xe_rtp_entry_sr eudebug_was[] = {
>> -		{ XE_RTP_NAME("GlobalDebugEnable"),
>> -		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210),
>> -			       ENGINE_CLASS(RENDER)),
>> -		  XE_RTP_ACTIONS(SET(CS_DEBUG_MODE2(RENDER_RING_BASE),
>> -				     GLOBAL_DEBUG_ENABLE))
>> -		},
>>   		{ XE_RTP_NAME("TdCtlDebugEnable"),
>>   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>>   		  XE_RTP_ACTIONS(SET(TD_CTL,
>>   				     TD_CTL_BREAKPOINT_ENABLE |
>>   				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
>> -				     TD_CTL_FEH_AND_FEE_ENABLE))
>> +				     TD_CTL_FEH_AND_FEE_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
>>   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>> -		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE))
>> +		  XE_RTP_ACTIONS(SET(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{ XE_RTP_NAME("18022722726"),
>>   		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>> -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE))
>> +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{ XE_RTP_NAME("14015527279"),
>>   		  XE_RTP_RULES(PLATFORM(PVC),
>>   			       FUNC(xe_rtp_match_first_render_or_compute)),
>> -		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB))
>> +		  XE_RTP_ACTIONS(SET(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>>   		},
>>   		{}
>>   	};
>>   	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
>> -	struct xe_device *xe = gt_to_xe(hwe->gt);
>>   
>> -	if (xe->eudebug.available)
>> -		xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>> +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>> +}
>> +
>> +static void xe_eudebug_fini_hw_engine(struct xe_hw_engine *hwe)
>> +{
>> +	const struct xe_rtp_entry_sr eudebug_was[] = {
>> +		{ XE_RTP_NAME("TdCtlDebugEnable"),
>> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 3499),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(TD_CTL,
>> +				     TD_CTL_BREAKPOINT_ENABLE |
>> +				     TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE |
>> +				     TD_CTL_FEH_AND_FEE_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{ XE_RTP_NAME("TdCtlGlobalDebugEnable"),
>> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, XE_RTP_END_VERSION_UNDEFINED),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(TD_CTL, TD_CTL_GLOBAL_DEBUG_ENABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{ XE_RTP_NAME("18022722726"),
>> +		  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1250, 1274),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN, STALL_DOP_GATING_DISABLE,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{ XE_RTP_NAME("14015527279"),
>> +		  XE_RTP_RULES(PLATFORM(PVC),
>> +			       FUNC(xe_rtp_match_first_render_or_compute)),
>> +		  XE_RTP_ACTIONS(CLR(ROW_CHICKEN2, XEHPC_DISABLE_BTB,
>> +				     XE_RTP_ACTION_FLAG(OVERWRITE)))
>> +		},
>> +		{}
>> +	};
>> +	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe);
>> +
>> +	xe_rtp_process_to_sr(&ctx, eudebug_was, &hwe->reg_sr);
>> +}
>> +
>> +static int xe_eudebug_enable(struct xe_device *xe, bool enable)
>> +{
>> +	struct xe_gt *gt;
>> +	int i;
>> +	u8 id;
>> +
>> +	if (!xe->eudebug.available)
>> +		return -EOPNOTSUPP;
>> +
>> +	/* XXX: TODO hold list lock? */
>> +	mutex_lock(&xe->eudebug.enable_lock);
>> +
>> +	if (!enable && !list_empty(&xe->eudebug.list)) {
>> +		mutex_unlock(&xe->eudebug.enable_lock);
>> +		return -EBUSY;
>> +	}
>> +
>> +	if (enable == xe->eudebug.enable) {
>> +		mutex_unlock(&xe->eudebug.enable_lock);
>> +		return 0;
>> +	}
>> +
>> +	for_each_gt(gt, xe, id) {
>> +		for (i = 0; i < ARRAY_SIZE(gt->hw_engines); i++) {
>> +			if (!(gt->info.engine_mask & BIT(i)))
>> +				continue;
>> +
>> +			if (enable)
>> +				xe_eudebug_init_hw_engine(&gt->hw_engines[i]);
>> +			else
>> +				xe_eudebug_fini_hw_engine(&gt->hw_engines[i]);
>> +		}
>> +
>> +		xe_gt_reset_async(gt);
> 
> What are you trying to accomplish with the reset? Reinit of some HW
> settings? Doing GT reset does have a side affect of killing exec queues
> with jobs active on the GPU which is not ideal. Please explain exactly
> what needs to be done, and maybe we can brainstorm something that won't
> kill things.
> 
> Also exposing a GT reset via sysfs might be potential security issue
> too.
> 
>> +		flush_work(&gt->reset.worker);
> 
> Flushing the reset worker here creates a lock dependency chain with
> xe->eudebug.enable_lock and all locks taken during a GT reset which is
> not ideal either. If we need to do a GT reset (or something else with a
> worker that takes locks) it probably best to flush the worker after
> dropping xe->eudebug.enable_lock. This relates to my other comments on
> locking, we shouldn't create lock depeendecy chains unless we have to
> and the chains are well defined.

Well the problem I see with doing the flush outside the lock is that 
other processes may try to write to the sysfs entry and the flush/hw 
reinitialization may happen for a inconsistent state (with some engines 
having reg_sr entries set to enable and others to disable debugging).

Of course that would happen for a brief period since after the final 
write to the sysfs node, the state would be well defined. So it's a 
question whether the above scenario is actually a problem? Should the 
kernel allow for such things to happen?

Thanks,
Christoph
> 
> Matt
> 
>> +	}
>> +
>> +	if (enable)
>> +		attention_scan_flush(xe);
>> +	else
>> +		attention_scan_cancel(xe);
>> +
>> +	xe->eudebug.enable = enable;
>> +	mutex_unlock(&xe->eudebug.enable_lock);
>> +
>> +	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.enable);
>> +}
>> +
>> +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;
>> +
>> +	sysfs_remove_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
>>   }
>>   
>>   void xe_eudebug_init(struct xe_device *xe)
>>   {
>> +	struct device *dev = xe->drm.dev;
>> +	int ret;
>> +
>>   	spin_lock_init(&xe->eudebug.lock);
>>   	INIT_LIST_HEAD(&xe->eudebug.list);
>>   	INIT_DELAYED_WORK(&xe->eudebug.attention_scan, attention_scan_fn);
>>   
>> -	xe->eudebug.available = true;
>> -}
>> +	drmm_mutex_init(&xe->drm, &xe->eudebug.enable_lock);
>> +	xe->eudebug.enable = false;
>>   
>> -void xe_eudebug_init_late(struct xe_device *xe)
>> -{
>> -	if (!xe->eudebug.available)
>> -		return;
>>   
>> -	attention_scan_flush(xe);
>> +	ret = sysfs_create_file(&xe->drm.dev->kobj, &dev_attr_enable_eudebug.attr);
>> +	if (ret)
>> +		drm_warn(&xe->drm, "eudebug sysfs init failed: %d, debugger unavailable\n", ret);
>> +	else
>> +		devm_add_action_or_reset(dev, xe_eudebug_sysfs_fini, xe);
>> +
>> +	xe->eudebug.available = ret == 0;
>>   }
>>   
>>   void xe_eudebug_fini(struct xe_device *xe)
>> diff --git a/drivers/gpu/drm/xe/xe_eudebug.h b/drivers/gpu/drm/xe/xe_eudebug.h
>> index 02c9ba56e752..2f66aa87a0f6 100644
>> --- a/drivers/gpu/drm/xe/xe_eudebug.h
>> +++ b/drivers/gpu/drm/xe/xe_eudebug.h
>> @@ -24,9 +24,7 @@ int xe_eudebug_connect_ioctl(struct drm_device *dev,
>>   			     struct drm_file *file);
>>   
>>   void xe_eudebug_init(struct xe_device *xe);
>> -void xe_eudebug_init_late(struct xe_device *xe);
>>   void xe_eudebug_fini(struct xe_device *xe);
>> -void xe_eudebug_init_hw_engine(struct xe_hw_engine *hwe);
>>   
>>   void xe_eudebug_file_open(struct xe_file *xef);
>>   void xe_eudebug_file_close(struct xe_file *xef);
>> diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
>> index bc2edade5e5b..b6fc65ab8aa9 100644
>> --- a/drivers/gpu/drm/xe/xe_exec_queue.c
>> +++ b/drivers/gpu/drm/xe/xe_exec_queue.c
>> @@ -360,6 +360,9 @@ static int exec_queue_set_eudebug(struct xe_device *xe, struct xe_exec_queue *q,
>>   			 !(value & DRM_XE_EXEC_QUEUE_EUDEBUG_FLAG_ENABLE)))
>>   		return -EINVAL;
>>   
>> +	if (XE_IOCTL_DBG(xe, !xe->eudebug.enable))
>> +		return -EPERM;
>> +
>>   	q->eudebug_flags = EXEC_QUEUE_EUDEBUG_FLAG_ENABLE;
>>   
>>   	return 0;
>> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
>> index 74813bc20787..0f90416be0ba 100644
>> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
>> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
>> @@ -504,7 +504,6 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
>>   	xe_tuning_process_engine(hwe);
>>   	xe_wa_process_engine(hwe);
>>   	hw_engine_setup_default_state(hwe);
>> -	xe_eudebug_init_hw_engine(hwe);
>>   
>>   	xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt));
>>   	xe_reg_whitelist_process_engine(hwe);
>> diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
>> index 440ac572f6e5..a7671722a84e 100644
>> --- a/drivers/gpu/drm/xe/xe_reg_sr.c
>> +++ b/drivers/gpu/drm/xe/xe_reg_sr.c
>> @@ -92,22 +92,31 @@ static void reg_sr_inc_error(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);
>>   	int ret;
>>   
>>   	if (pentry) {
>> -		if (!compatible_entries(pentry, e)) {
>> +		if (overwrite && e->set_bits) {
>> +			pentry->clr_bits |= e->clr_bits;
>> +			pentry->set_bits |= e->set_bits;
>> +			pentry->read_mask |= e->read_mask;
>> +		} else if (overwrite && !e->set_bits) {
>> +			pentry->clr_bits |= e->clr_bits;
>> +			pentry->set_bits &= ~e->clr_bits;
>> +			pentry->read_mask |= e->read_mask;
>> +		} else if (!compatible_entries(pentry, e)) {
>>   			ret = -EINVAL;
>>   			goto fail;
>> +		} else {
>> +			pentry->clr_bits |= e->clr_bits;
>> +			pentry->set_bits |= e->set_bits;
>> +			pentry->read_mask |= e->read_mask;
>>   		}
>>   
>> -		pentry->clr_bits |= e->clr_bits;
>> -		pentry->set_bits |= e->set_bits;
>> -		pentry->read_mask |= e->read_mask;
>> -
>>   		return 0;
>>   	}
>>   
>> diff --git a/drivers/gpu/drm/xe/xe_reg_sr.h b/drivers/gpu/drm/xe/xe_reg_sr.h
>> index 51fbba423e27..d67fafdcd847 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_
>>   #define _XE_REG_SR_
>>   
>> +#include <linux/types.h>
>> +
>>   /*
>>    * Reg save/restore bookkeeping
>>    */
>> @@ -21,7 +23,7 @@ int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe)
>>   void xe_reg_sr_dump(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_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c
>> index 02e28274282f..5643bcde52bd 100644
>> --- a/drivers/gpu/drm/xe/xe_rtp.c
>> +++ b/drivers/gpu/drm/xe/xe_rtp.c
>> @@ -153,7 +153,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, action->flags & XE_RTP_ACTION_FLAG_OVERWRITE);
>>   }
>>   
>>   static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry,
>> diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h
>> index 1b76b947c706..20d228067da3 100644
>> --- a/drivers/gpu/drm/xe/xe_rtp_types.h
>> +++ b/drivers/gpu/drm/xe/xe_rtp_types.h
>> @@ -33,6 +33,7 @@ struct xe_rtp_action {
>>   	/** @read_mask: mask for bits to consider when reading value back */
>>   	u32			read_mask;
>>   #define XE_RTP_ACTION_FLAG_ENGINE_BASE		BIT(0)
>> +#define XE_RTP_ACTION_FLAG_OVERWRITE		BIT(1)
>>   	/** @flags: flags to apply on rule evaluation or action */
>>   	u8			flags;
>>   };
>> -- 
>> 2.34.1
>>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors
  2024-07-26 14:07 ` [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors Mika Kuoppala
  2024-07-27  5:45   ` Matthew Brost
@ 2024-08-08 11:04   ` Andi Shyti
  1 sibling, 0 replies; 78+ messages in thread
From: Andi Shyti @ 2024-08-08 11:04 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

Hi Mika,

On Fri, Jul 26, 2024 at 05:07:58PM +0300, Mika Kuoppala wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> 
> Declare hw engine's mmio accessors in header file.
> This is in preparation to use these from eudebug code.
> 
> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>

with the renames suggested by Matt:

Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>

Thanks,
Andi

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup.
  2024-07-26 14:07 ` [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup Mika Kuoppala
  2024-07-27  5:49   ` Matthew Brost
@ 2024-08-08 11:08   ` Andi Shyti
  1 sibling, 0 replies; 78+ messages in thread
From: Andi Shyti @ 2024-08-08 11:08 UTC (permalink / raw)
  To: Mika Kuoppala; +Cc: intel-xe, Dominik Grzegorzek

On Fri, Jul 26, 2024 at 05:07:59PM +0300, Mika Kuoppala wrote:
> From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> 
> Move and export xe_hw_engine lookup. This is in preparation
> to use this in eudebug code where we want to find active
> engine.
> 
> v2: s/tile/gt due to uapi changes (Mika)
> 
> Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>

I see this is already appled, so that I'm too late to add my rb
here.

Thanks,
Andi

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 04/21] kernel: export ptrace_may_access
  2024-07-26 14:08 ` [PATCH 04/21] kernel: export ptrace_may_access Mika Kuoppala
  2024-07-29 18:56   ` Lucas De Marchi
@ 2024-08-08 11:18   ` Andi Shyti
  2024-08-21 11:46     ` Mika Kuoppala
  1 sibling, 1 reply; 78+ messages in thread
From: Andi Shyti @ 2024-08-08 11:18 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Lucas De Marchi, Maciej Patelczyk, Jonathan Cavitt

Hi Mika,

On Fri, Jul 26, 2024 at 05:08:01PM +0300, Mika Kuoppala wrote:
> We need to export ptrace_may_access to be able to
> allow debugger connection to check for debuggee access and
> at the same time allow xe.ko module build.
> 
> CC: Lucas De Marchi <lucas.demarchi@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> CC: Andi Shyti <andi.shyti@intel.com>
> CC: Maciej Patelczyk <maciej.patelczyk@linux.intel.com>
> Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>

Just one note here: the tag order matters a little, the signature
of from the sender should take the last place.

> ---
>  kernel/ptrace.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/kernel/ptrace.c b/kernel/ptrace.c
> index d5f89f9ef29f..86be1805ebd8 100644
> --- a/kernel/ptrace.c
> +++ b/kernel/ptrace.c
> @@ -354,6 +354,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
>  	task_unlock(task);
>  	return !err;
>  }
> +EXPORT_SYMBOL_GPL(ptrace_may_access);

I also believe, as suggested, that we should seek an ack from the
maintainers here. Maybe we could have CC'ed just for this single
patch. (You can add people in CC even after the '---' section not
to pollute the commit log. This way you let git-send-email handle
it).

Nevertheless, same as I agreed earlier:

Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>

Thanks,
Andi

>  static int check_ptrace_options(unsigned long data)
>  {
> -- 
> 2.34.1

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-07-26 14:08 ` [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support Mika Kuoppala
  2024-07-26 19:20   ` Matthew Brost
  2024-08-07  9:34   ` Zbigniew Kempczyński
@ 2024-08-12 12:02   ` Zbigniew Kempczyński
  2024-08-21 11:38     ` Mika Kuoppala
  2 siblings, 1 reply; 78+ messages in thread
From: Zbigniew Kempczyński @ 2024-08-12 12:02 UTC (permalink / raw)
  To: Mika Kuoppala
  Cc: intel-xe, Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
	Andi Shyti, Matt Roper, Maciej Patelczyk

On Fri, Jul 26, 2024 at 05:08:00PM +0300, Mika Kuoppala wrote:

<cut>

> +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 drm_xe_eudebug_event user_event;
> +	struct xe_eudebug_event *event;
> +	long ret = 0;
> +
> +	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))
> +		return -EINVAL;
> +
> +	if (XE_IOCTL_DBG(xe, user_event.type > DRM_XE_EUDEBUG_EVENT_MAX_EVENT))
> +		return -EINVAL;
> +
> +	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.reserved))
> +		return -EINVAL;
> +
> +	/* 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;
> +	}
> +
> +	ret = 0;
> +	spin_lock(&d->events.lock);
> +	event = event_fifo_pending(d);
> +	if (event) {
> +		if (user_event.len < event->len) {
> +			ret = -EMSGSIZE;

Maybe it is worth to copy event->len to user_orig? I wonder how
userspace guesses the size of the buffer to allocate for the event.

--
Zbigniew


^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-08-07  9:34   ` Zbigniew Kempczyński
@ 2024-08-21 11:37     ` Mika Kuoppala
  0 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-08-21 11:37 UTC (permalink / raw)
  To: Zbigniew Kempczyński
  Cc: intel-xe, Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
	Andi Shyti, Matt Roper, Maciej Patelczyk

Zbigniew Kempczyński <zbigniew.kempczynski@intel.com> writes:

> On Fri, Jul 26, 2024 at 05:08:00PM +0300, Mika Kuoppala wrote:
>
> <cut>
>
>> +
>> +static int
>> +xe_eudebug_attach(struct xe_device *xe, struct xe_eudebug *d,
>> +		  const pid_t pid_nr)
>> +{
>> +	struct task_struct *target;
>> +	struct xe_eudebug *iter;
>> +	kuid_t uid = current_uid();
>> +	int ret = 0;
>> +
>> +	target = find_get_target(pid_nr);
>> +	if (!target)
>> +		return -ENOENT;
>
> This goes outside and is returned via ioctl() what reminds me some LKML
> thread this code is reserved for file operations only.

Yes, my excuse here is that I try to mimic what other xe code
does. And I can't think of other than EINVAL here.
-Mika

>
> --
> Zbigniew

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support
  2024-08-12 12:02   ` Zbigniew Kempczyński
@ 2024-08-21 11:38     ` Mika Kuoppala
  0 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-08-21 11:38 UTC (permalink / raw)
  To: Zbigniew Kempczyński
  Cc: intel-xe, Maarten Lankhorst, Lucas De Marchi, Dominik Grzegorzek,
	Andi Shyti, Matt Roper, Maciej Patelczyk

Zbigniew Kempczyński <zbigniew.kempczynski@intel.com> writes:

> On Fri, Jul 26, 2024 at 05:08:00PM +0300, Mika Kuoppala wrote:
>
> <cut>
>
>> +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 drm_xe_eudebug_event user_event;
>> +	struct xe_eudebug_event *event;
>> +	long ret = 0;
>> +
>> +	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))
>> +		return -EINVAL;
>> +
>> +	if (XE_IOCTL_DBG(xe, user_event.type > DRM_XE_EUDEBUG_EVENT_MAX_EVENT))
>> +		return -EINVAL;
>> +
>> +	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.reserved))
>> +		return -EINVAL;
>> +
>> +	/* 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;
>> +	}
>> +
>> +	ret = 0;
>> +	spin_lock(&d->events.lock);
>> +	event = event_fifo_pending(d);
>> +	if (event) {
>> +		if (user_event.len < event->len) {
>> +			ret = -EMSGSIZE;
>
> Maybe it is worth to copy event->len to user_orig? I wonder how
> userspace guesses the size of the buffer to allocate for the event.

Makes sense. I will deliver event->len in v2. Thanks.
-Mika

>
> --
> Zbigniew

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH 04/21] kernel: export ptrace_may_access
  2024-08-08 11:18   ` Andi Shyti
@ 2024-08-21 11:46     ` Mika Kuoppala
  0 siblings, 0 replies; 78+ messages in thread
From: Mika Kuoppala @ 2024-08-21 11:46 UTC (permalink / raw)
  To: Andi Shyti; +Cc: intel-xe, Lucas De Marchi, Maciej Patelczyk, Jonathan Cavitt

Andi Shyti <andi.shyti@linux.intel.com> writes:

> Hi Mika,
>
> On Fri, Jul 26, 2024 at 05:08:01PM +0300, Mika Kuoppala wrote:
>> We need to export ptrace_may_access to be able to
>> allow debugger connection to check for debuggee access and
>> at the same time allow xe.ko module build.
>> 
>> CC: Lucas De Marchi <lucas.demarchi@intel.com>
>> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>> CC: Andi Shyti <andi.shyti@intel.com>
>> CC: Maciej Patelczyk <maciej.patelczyk@linux.intel.com>
>> Signed-off-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
>
> Just one note here: the tag order matters a little, the signature
> of from the sender should take the last place.

I will ping Jonathan to remove the sob as this might be residue
of splitting patches. He is credited on the actual application
of ptrace_may_access and the original EXPORT parts are mine.

>
>> ---
>>  kernel/ptrace.c | 1 +
>>  1 file changed, 1 insertion(+)
>> 
>> diff --git a/kernel/ptrace.c b/kernel/ptrace.c
>> index d5f89f9ef29f..86be1805ebd8 100644
>> --- a/kernel/ptrace.c
>> +++ b/kernel/ptrace.c
>> @@ -354,6 +354,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
>>  	task_unlock(task);
>>  	return !err;
>>  }
>> +EXPORT_SYMBOL_GPL(ptrace_may_access);
>
> I also believe, as suggested, that we should seek an ack from the
> maintainers here. Maybe we could have CC'ed just for this single
> patch. (You can add people in CC even after the '---' section not
> to pollute the commit log. This way you let git-send-email handle
> it).

I will move this patch to be first in series with ptrace author
and lkml included in cc.

>
> Nevertheless, same as I agreed earlier:
>
> Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
Thanks,
-Mika

>
> Thanks,
> Andi
>
>>  static int check_ptrace_options(unsigned long data)
>>  {
>> -- 
>> 2.34.1

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v2.5] drm/xe/eudebug: implement userptr_vma access
  2024-07-31 17:51           ` Matthew Brost
  2024-08-05 16:54             ` [PATCH v2] " Andrzej Hajda
@ 2024-08-26 14:40             ` Andrzej Hajda
  2024-08-26 16:45               ` Andrzej Hajda
  2024-08-26 17:02               ` Matthew Brost
  1 sibling, 2 replies; 78+ messages in thread
From: Andrzej Hajda @ 2024-08-26 14:40 UTC (permalink / raw)
  To: Matthew Brost
  Cc: Andrzej Hajda, Mika Kuoppala, intel-xe, Maciej Patelczyk,
	Jonathan Cavitt

Debugger needs to read/write program's vmas including userptr_vma.

v2.5: use access_process_vm

Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
---
Hi Matthew,

With recent changes in drm(?) v1 and v2 versions do not work anymore.
I am wondering if using access_process_vm could be alternative approach,
at least igt tests do not fail :)

Regards
Andrzej
---
 drivers/gpu/drm/xe/xe_eudebug.c |  2 +-
 drivers/gpu/drm/xe/xe_vm.c      | 12 ++++++++++++
 drivers/gpu/drm/xe/xe_vm.h      |  3 +++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 7e62b0ffca83..39b33bb7893d 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -3392,7 +3392,7 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
 	if (bo)
 		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
 
-	return -EOPNOTSUPP;
+	return xe_uvma_access(to_userptr_vma(vma), offset, buf, bytes, write);
 }
 
 static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index ec4dd2c611d3..ee6e2ee078f9 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3607,3 +3607,15 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap)
 	}
 	kvfree(snap);
 }
+
+int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
+		   void *buf, u64 len, bool write)
+{
+	struct mm_struct *mm = uvma->userptr.notifier.mm;
+	unsigned long addr = uvma->vma.gpuva.gem.offset;
+
+	if (!mm || !mm->owner)
+		return -EINVAL;
+
+	return access_process_vm(mm->owner, addr, buf, len, write ? FOLL_WRITE : 0);
+}
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index c864dba35e1d..99b9a9b011de 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -281,3 +281,6 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm);
 void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap);
 void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p);
 void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
+
+int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
+		   void *buf, u64 len, bool write);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* Re: [PATCH v2.5] drm/xe/eudebug: implement userptr_vma access
  2024-08-26 14:40             ` [PATCH v2.5] " Andrzej Hajda
@ 2024-08-26 16:45               ` Andrzej Hajda
  2024-08-26 17:02               ` Matthew Brost
  1 sibling, 0 replies; 78+ messages in thread
From: Andrzej Hajda @ 2024-08-26 16:45 UTC (permalink / raw)
  To: Matthew Brost; +Cc: Mika Kuoppala, intel-xe, Maciej Patelczyk, Jonathan Cavitt



On 26.08.2024 16:40, Andrzej Hajda wrote:
> Debugger needs to read/write program's vmas including userptr_vma.
>
> v2.5: use access_process_vm
>
> Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>

> Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Ups, these three tags are not valid in this case.

Regards
Andrzej
> ---
> Hi Matthew,
>
> With recent changes in drm(?) v1 and v2 versions do not work anymore.
> I am wondering if using access_process_vm could be alternative approach,
> at least igt tests do not fail :)
>
> Regards
> Andrzej
> ---
>   drivers/gpu/drm/xe/xe_eudebug.c |  2 +-
>   drivers/gpu/drm/xe/xe_vm.c      | 12 ++++++++++++
>   drivers/gpu/drm/xe/xe_vm.h      |  3 +++
>   3 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 7e62b0ffca83..39b33bb7893d 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -3392,7 +3392,7 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
>   	if (bo)
>   		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
>   
> -	return -EOPNOTSUPP;
> +	return xe_uvma_access(to_userptr_vma(vma), offset, buf, bytes, write);
>   }
>   
>   static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index ec4dd2c611d3..ee6e2ee078f9 100644
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
> @@ -3607,3 +3607,15 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap)
>   	}
>   	kvfree(snap);
>   }
> +
> +int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> +		   void *buf, u64 len, bool write)
> +{
> +	struct mm_struct *mm = uvma->userptr.notifier.mm;
> +	unsigned long addr = uvma->vma.gpuva.gem.offset;
> +
> +	if (!mm || !mm->owner)
> +		return -EINVAL;
> +
> +	return access_process_vm(mm->owner, addr, buf, len, write ? FOLL_WRITE : 0);
> +}
> diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
> index c864dba35e1d..99b9a9b011de 100644
> --- a/drivers/gpu/drm/xe/xe_vm.h
> +++ b/drivers/gpu/drm/xe/xe_vm.h
> @@ -281,3 +281,6 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm);
>   void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap);
>   void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p);
>   void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
> +
> +int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> +		   void *buf, u64 len, bool write);


^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v2.5] drm/xe/eudebug: implement userptr_vma access
  2024-08-26 14:40             ` [PATCH v2.5] " Andrzej Hajda
  2024-08-26 16:45               ` Andrzej Hajda
@ 2024-08-26 17:02               ` Matthew Brost
  2024-08-27  8:41                 ` [PATCH v3] " Andrzej Hajda
  1 sibling, 1 reply; 78+ messages in thread
From: Matthew Brost @ 2024-08-26 17:02 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: Mika Kuoppala, intel-xe, Maciej Patelczyk, Jonathan Cavitt

On Mon, Aug 26, 2024 at 04:40:00PM +0200, Andrzej Hajda wrote:
> Debugger needs to read/write program's vmas including userptr_vma.
> 
> v2.5: use access_process_vm
> 
> Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
> Signed-off-by: Maciej Patelczyk <maciej.patelczyk@intel.com>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
> ---
> Hi Matthew,
> 
> With recent changes in drm(?) v1 and v2 versions do not work anymore.
> I am wondering if using access_process_vm could be alternative approach,
> at least igt tests do not fail :)
> 

Yes but s/xe_uvma_access/xe_vm_userptr_access

Matt

> Regards
> Andrzej
> ---
>  drivers/gpu/drm/xe/xe_eudebug.c |  2 +-
>  drivers/gpu/drm/xe/xe_vm.c      | 12 ++++++++++++
>  drivers/gpu/drm/xe/xe_vm.h      |  3 +++
>  3 files changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
> index 7e62b0ffca83..39b33bb7893d 100644
> --- a/drivers/gpu/drm/xe/xe_eudebug.c
> +++ b/drivers/gpu/drm/xe/xe_eudebug.c
> @@ -3392,7 +3392,7 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
>  	if (bo)
>  		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
>  
> -	return -EOPNOTSUPP;
> +	return xe_uvma_access(to_userptr_vma(vma), offset, buf, bytes, write);
>  }
>  
>  static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index ec4dd2c611d3..ee6e2ee078f9 100644
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
> @@ -3607,3 +3607,15 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap)
>  	}
>  	kvfree(snap);
>  }
> +
> +int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> +		   void *buf, u64 len, bool write)
> +{
> +	struct mm_struct *mm = uvma->userptr.notifier.mm;
> +	unsigned long addr = uvma->vma.gpuva.gem.offset;
> +
> +	if (!mm || !mm->owner)
> +		return -EINVAL;
> +
> +	return access_process_vm(mm->owner, addr, buf, len, write ? FOLL_WRITE : 0);
> +}
> diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
> index c864dba35e1d..99b9a9b011de 100644
> --- a/drivers/gpu/drm/xe/xe_vm.h
> +++ b/drivers/gpu/drm/xe/xe_vm.h
> @@ -281,3 +281,6 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm);
>  void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap);
>  void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p);
>  void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
> +
> +int xe_uvma_access(struct xe_userptr_vma *uvma, u64 offset,
> +		   void *buf, u64 len, bool write);
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v3] drm/xe/eudebug: implement userptr_vma access
  2024-08-26 17:02               ` Matthew Brost
@ 2024-08-27  8:41                 ` Andrzej Hajda
  0 siblings, 0 replies; 78+ messages in thread
From: Andrzej Hajda @ 2024-08-27  8:41 UTC (permalink / raw)
  To: Matthew Brost; +Cc: Andrzej Hajda, Mika Kuoppala, intel-xe

Debugger needs to read/write program's vmas including userptr_vma.

v2: pin pages vs notifier, move to vm.c (Matthew)
v3: use access_process_vm core helper

Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com>
---
 drivers/gpu/drm/xe/xe_eudebug.c |  2 +-
 drivers/gpu/drm/xe/xe_vm.c      | 12 ++++++++++++
 drivers/gpu/drm/xe/xe_vm.h      |  3 +++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index 7e62b0ffca83..bc0b32c47ed5 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -3392,7 +3392,7 @@ static int xe_eudebug_vma_access(struct xe_vma *vma, u64 offset,
 	if (bo)
 		return xe_eudebug_bovma_access(bo, offset, buf, bytes, write);
 
-	return -EOPNOTSUPP;
+	return xe_vm_userptr_access(to_userptr_vma(vma), offset, buf, bytes, write);
 }
 
 static int xe_eudebug_vm_access(struct xe_vm *vm, u64 offset,
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index ec4dd2c611d3..f46c8fc05218 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3607,3 +3607,15 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap)
 	}
 	kvfree(snap);
 }
+
+int xe_vm_userptr_access(struct xe_userptr_vma *uvma, u64 offset,
+			 void *buf, u64 len, bool write)
+{
+	struct mm_struct *mm = uvma->userptr.notifier.mm;
+	unsigned long addr = uvma->vma.gpuva.gem.offset;
+
+	if (!mm || !mm->owner)
+		return -EINVAL;
+
+	return access_process_vm(mm->owner, addr, buf, len, write ? FOLL_WRITE : 0);
+}
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index c864dba35e1d..165eab494d59 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -281,3 +281,6 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm);
 void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap);
 void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p);
 void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
+
+int xe_vm_userptr_access(struct xe_userptr_vma *uvma, u64 offset,
+			 void *buf, u64 len, bool write);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

end of thread, other threads:[~2024-08-27  8:42 UTC | newest]

Thread overview: 78+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-26 14:07 [PATCH 00/21] GPU debug support (eudebug) Mika Kuoppala
2024-07-26 14:07 ` [PATCH 01/21] drm/xe: Export xe_hw_engine's mmio accessors Mika Kuoppala
2024-07-27  5:45   ` Matthew Brost
2024-08-08 11:04   ` Andi Shyti
2024-07-26 14:07 ` [PATCH 02/21] drm/xe: Move and export xe_hw_engine lookup Mika Kuoppala
2024-07-27  5:49   ` Matthew Brost
2024-08-08 11:08   ` Andi Shyti
2024-07-26 14:08 ` [PATCH 03/21] drm/xe/eudebug: Introduce eudebug support Mika Kuoppala
2024-07-26 19:20   ` Matthew Brost
2024-07-30 14:12     ` Mika Kuoppala
2024-07-31  1:18       ` Matthew Brost
2024-08-07  9:34   ` Zbigniew Kempczyński
2024-08-21 11:37     ` Mika Kuoppala
2024-08-12 12:02   ` Zbigniew Kempczyński
2024-08-21 11:38     ` Mika Kuoppala
2024-07-26 14:08 ` [PATCH 04/21] kernel: export ptrace_may_access Mika Kuoppala
2024-07-29 18:56   ` Lucas De Marchi
2024-08-08 11:18   ` Andi Shyti
2024-08-21 11:46     ` Mika Kuoppala
2024-07-26 14:08 ` [PATCH 05/21] drm/xe/eudebug: Use ptrace_may_access for xe_eudebug_attach Mika Kuoppala
2024-07-29 19:00   ` Lucas De Marchi
2024-07-26 14:08 ` [PATCH 06/21] drm/xe/eudebug: Introduce discovery for resources Mika Kuoppala
2024-07-26 14:08 ` [PATCH 07/21] drm/xe/eudebug: Introduce exec_queue events Mika Kuoppala
2024-07-26 14:08 ` [PATCH 08/21] drm/xe/eudebug: hw enablement for eudebug Mika Kuoppala
2024-07-29 19:05   ` Lucas De Marchi
2024-07-29 19:16     ` Lucas De Marchi
2024-07-30  9:01     ` Grzegorzek, Dominik
2024-07-30 13:56       ` Lucas De Marchi
2024-07-26 14:08 ` [PATCH 09/21] drm/xe: Add EUDEBUG_ENABLE exec queue property Mika Kuoppala
2024-07-26 18:35   ` Matthew Brost
2024-07-27  0:54   ` Matthew Brost
2024-07-26 14:08 ` [PATCH 10/21] drm/xe/eudebug: Introduce per device attention scan worker Mika Kuoppala
2024-07-27  5:08   ` Matthew Brost
2024-07-29 10:10     ` Grzegorzek, Dominik
2024-07-31  1:25       ` Matthew Brost
2024-07-27  5:39   ` Matthew Brost
2024-07-26 14:08 ` [PATCH 11/21] drm/xe/eudebug: Introduce EU control interface Mika Kuoppala
2024-07-26 14:08 ` [PATCH 12/21] drm/xe/eudebug: Add vm bind and vm bind ops Mika Kuoppala
2024-07-26 14:08 ` [PATCH 13/21] drm/xe/eudebug: Add UFENCE events with acks Mika Kuoppala
2024-07-27  0:40   ` Matthew Brost
2024-07-30 14:05     ` Mika Kuoppala
2024-07-31  1:33       ` Matthew Brost
2024-07-26 14:08 ` [PATCH 14/21] drm/xe/eudebug: vm open/pread/pwrite Mika Kuoppala
2024-07-26 18:59   ` Matthew Brost
2024-07-26 14:08 ` [PATCH 15/21] drm/xe/eudebug: implement userptr_vma access Mika Kuoppala
2024-07-26 18:46   ` Matthew Brost
2024-07-26 18:50     ` Matthew Brost
2024-07-27  1:45       ` Matthew Brost
2024-07-31 11:11         ` [PATCH] fixup! " Andrzej Hajda
2024-07-31 17:51           ` Matthew Brost
2024-08-05 16:54             ` [PATCH v2] " Andrzej Hajda
2024-08-05 19:20               ` Cavitt, Jonathan
2024-08-26 14:40             ` [PATCH v2.5] " Andrzej Hajda
2024-08-26 16:45               ` Andrzej Hajda
2024-08-26 17:02               ` Matthew Brost
2024-08-27  8:41                 ` [PATCH v3] " Andrzej Hajda
2024-07-26 14:08 ` [PATCH 16/21] drm/xe: Debug metadata create/destroy ioctls Mika Kuoppala
2024-07-26 14:08 ` [PATCH 17/21] drm/xe: Attach debug metadata to vma Mika Kuoppala
2024-07-26 21:25   ` Matthew Brost
2024-07-26 14:08 ` [PATCH 18/21] drm/xe/eudebug: Add debug metadata support for xe_eudebug Mika Kuoppala
2024-07-26 14:08 ` [PATCH 19/21] drm/xe/eudebug: Implement vm_bind_op discovery Mika Kuoppala
2024-07-27  4:39   ` Matthew Brost
2024-07-26 14:08 ` [PATCH 20/21] drm/xe/eudebug: Dynamically toggle debugger functionality Mika Kuoppala
2024-07-28  4:50   ` Matthew Brost
2024-07-30 15:01     ` Manszewski, Christoph
2024-07-31 18:03       ` Matthew Brost
2024-08-07 10:09     ` Manszewski, Christoph
2024-07-26 14:08 ` [PATCH 21/21] drm/xe/eudebug_test: Introduce xe_eudebug wa kunit test Mika Kuoppala
2024-07-26 14:32 ` ✓ CI.Patch_applied: success for GPU debug support (eudebug) Patchwork
2024-07-26 14:33 ` ✗ CI.checkpatch: warning " Patchwork
2024-07-26 14:34 ` ✓ CI.KUnit: success " Patchwork
2024-07-26 14:46 ` ✓ CI.Build: " Patchwork
2024-07-26 14:48 ` ✗ CI.Hooks: failure " Patchwork
2024-07-26 14:49 ` ✓ CI.checksparse: success " Patchwork
2024-07-26 15:10 ` ✓ CI.BAT: " Patchwork
2024-07-27  2:37 ` ✓ CI.FULL: " Patchwork
2024-07-27  5:23 ` [PATCH 00/21] " Matthew Brost
2024-07-29  8:27   ` Gwan-gyeong Mun

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).