[PATCH 1/5] lib/xe: cache engine class masks from debugfs info

Xin Wang
2026-04-03T01:41:07Z

Read the multi_lrc_engine_classes and multi_queue_engine_classes lines
from the xe debugfs info node and cache them in struct xe_device as
bitmasks indexed by DRM_XE_ENGINE_CLASS_* values.

The new fields are set to UINT16_MAX when the kernel does not yet expose
the information (i.e. when the key is not present in the info node), so
callers can distinguish "not available" from "empty set".

Signed-off-by: Xin Wang <x.wang@intel.com>
---
lib/xe/xe_query.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
lib/xe/xe_query.h | 12 +++++++
2 files changed, 98 insertions(+)

diff --git a/lib/xe/xe_query.c b/lib/xe/xe_query.c
index 00331c628..441e95794 100644
--- a/lib/xe/xe_query.c
+++ b/lib/xe/xe_query.c
@@ -6,6 +6,7 @@
* Matthew Brost <matthew.brost@intel.com>
*/

+#include <fcntl.h>
#include <stdlib.h>
#include <pthread.h>

@@ -19,6 +20,7 @@
#endif

#include "drmtest.h"
+#include "igt_debugfs.h"
#include "ioctl_wrappers.h"
#include "igt_map.h"
#include "intel_pat.h"
@@ -134,6 +136,85 @@ static uint32_t __mem_default_alignment(struct drm_xe_query_mem_regions *mem_reg
return alignment;
}

+/*
+ * parse_engine_class_mask - parse a space-separated list of engine class names
+ * into a bitmask indexed by DRM_XE_ENGINE_CLASS_* values.
+ *
+ * @names: the engine class names string, e.g. " vcs vecs" or "bcs ccs"
+ *
+ * The kernel debugfs "info" output for multi_lrc_engine_classes and
+ * multi_queue_engine_classes uses the same short names as
+ * xe_engine_class_short_string(): "rcs", "bcs", "vcs", "vecs", "ccs".
+ *
+ * Returns the bitmask, or 0 if no known class names were found.
+ */
+static uint16_t parse_engine_class_mask(const char *names)
+{
+ static const struct {
+ const char *name;
+ uint32_t engine_class;
+ } class_map[] = {
+ { "rcs", DRM_XE_ENGINE_CLASS_RENDER },
+ { "bcs", DRM_XE_ENGINE_CLASS_COPY },
+ { "vcs", DRM_XE_ENGINE_CLASS_VIDEO_DECODE },
+ { "vecs", DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE },
+ { "ccs", DRM_XE_ENGINE_CLASS_COMPUTE },
+ };
+ uint16_t mask = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(class_map); i++) {
+ if (strstr(names, class_map[i].name))
+ mask |= BIT(class_map[i].engine_class);
+ }
+
+ return mask;
+}
+
+/*
+ * Read the debugfs "info" file and OR together the engine class bitmasks from
+ * every line that contains @key. Returns UINT16_MAX if @key is not found
+ * (kernel too old to expose this information).
+ *
+ * multi_lrc_engine_classes is printed once at device level; multi_queue_engine_classes
+ * is printed once per GT, so the OR handles the multi-GT case transparently.
+ */
+static uint16_t xe_device_query_engine_class_mask(int fd, const char *key)
+{
+ char *line = NULL;
+ size_t line_len = 0;
+ uint16_t mask = UINT16_MAX;
+ size_t key_len = strlen(key);
+ int dbgfs_fd;
+ FILE *dbgfs_file;
+
+ dbgfs_fd = igt_debugfs_open(fd, "info", O_RDONLY);
+ if (dbgfs_fd < 0)
+ return mask;
+
+ dbgfs_file = fdopen(dbgfs_fd, "r");
+ if (!dbgfs_file) {
+ close(dbgfs_fd);
+ return mask;
+ }
+
+ while (getline(&line, &line_len, dbgfs_file) != -1) {
+ const char *p = strstr(line, key);
+
+ if (!p)
+ continue;
+
+ if (mask == UINT16_MAX)
+ mask = 0;
+ mask |= parse_engine_class_mask(p + key_len);
+ }
+
+ free(line);
+ fclose(dbgfs_file);
+
+ return mask;
+}
+
/**
* xe_engine_class_supports_multi_queue:
* @engine_class: engine class
@@ -330,6 +411,11 @@ struct xe_device *xe_device_get(int fd)
}
pthread_mutex_unlock(&cache.cache_mutex);

+ xe_dev->multi_lrc_mask =
+ xe_device_query_engine_class_mask(fd, "multi_lrc_engine_classes");
+ xe_dev->multi_queue_engine_class_mask =
+ xe_device_query_engine_class_mask(fd, "multi_queue_engine_classes");
+
return xe_dev;
}

diff --git a/lib/xe/xe_query.h b/lib/xe/xe_query.h
index 05e2ad84f..f33562bda 100644
--- a/lib/xe/xe_query.h
+++ b/lib/xe/xe_query.h
@@ -79,6 +79,18 @@ struct xe_device {

/** @pat_cache: cached PAT index configuration, NULL if not yet populated */
struct intel_pat_cache *pat_cache;
+
+ /**
+ * @multi_lrc_mask: bitmask of engine classes supporting multi-LRC.
+ * UINT16_MAX if not available (older kernel).
+ */
+ uint16_t multi_lrc_mask;
+
+ /**
+ * @multi_queue_engine_class_mask: bitmask of engine classes supporting
+ * multi-queue. UINT16_MAX if not available (older kernel).
+ */
+ uint16_t multi_queue_engine_class_mask;
};

#define xe_for_each_engine(__fd, __hwe) \
--
2.43.0