[RFC 03/15] drm/xe: Stub out new access_counter layer

Himal Prasad Ghimiray
2026-03-18T07:10:21Z

Add access counter infrastructure with type definitions, header files,
and stub implementation. This follows a two-layer producer-consumer
architecture similar to the pagefault layer.

Signed-off-by: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
---
drivers/gpu/drm/xe/Makefile | 3 +-
drivers/gpu/drm/xe/xe_access_counter.c | 55 +++++++++
drivers/gpu/drm/xe/xe_access_counter.h | 17 +++
drivers/gpu/drm/xe/xe_access_counter_types.h | 123 +++++++++++++++++++
4 files changed, 197 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/xe/xe_access_counter.c
create mode 100644 drivers/gpu/drm/xe/xe_access_counter.h
create mode 100644 drivers/gpu/drm/xe/xe_access_counter_types.h

diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 3a3f9f22d42a..92d8d6e4a447 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -32,7 +32,8 @@ $(obj)/generated/%_device_wa_oob.c $(obj)/generated/%_device_wa_oob.h: $(obj)/xe

# core driver code

-xe-y += xe_bb.o \
+xe-y += xe_access_counter.o \
+ xe_bb.o \
xe_bo.o \
xe_bo_evict.o \
xe_dep_scheduler.o \
diff --git a/drivers/gpu/drm/xe/xe_access_counter.c b/drivers/gpu/drm/xe/xe_access_counter.c
new file mode 100644
index 000000000000..f3a8a93b5135
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_access_counter.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <linux/circ_buf.h>
+
+#include <drm/drm_exec.h>
+#include <drm/drm_managed.h>
+
+#include "xe_access_counter.h"
+#include "xe_access_counter_types.h"
+#include "xe_device.h"
+
+/**
+ * DOC: Xe access counters
+ *
+ * Xe access counters are handled in two layers with one-way communication.
+ * The producer layer interacts with hardware or firmware to receive and parse
+ * access counter notifications into struct xe_access_counter, then forwards them
+ * to the consumer. The consumer layer services the notifications (e.g., memory
+ * migration hints, binding decisions). No acknowledgment is sent back to the
+ * producer. The consumer uses an access counter queue sized to absorb all potential
+ * notifications and a multi-threaded worker to process them. Multiple producers
+ * are supported, with a single shared consumer.
+ *
+ * xe_access_counter.c implements the consumer layer.
+ */
+
+/**
+ * xe_access_counter_init - Initialize access counter consumer layer
+ * @xe: xe device
+ *
+ * Return: 0 on success, negative error code on error
+ */
+int xe_access_counter_init(struct xe_device *xe)
+{
+ /* Stub implementation - to be filled in */
+ return 0;
+}
+
+/**
+ * xe_access_counter_handler - Handle an access counter notification
+ * @xe: xe device
+ * @ac: access counter notification
+ *
+ * Process an access counter notification from the producer layer.
+ *
+ * Return: 0 on success, negative error code on error
+ */
+int xe_access_counter_handler(struct xe_device *xe, struct xe_access_counter *ac)
+{
+ /* Stub implementation - to be filled in */
+ return 0;
+}
diff --git a/drivers/gpu/drm/xe/xe_access_counter.h b/drivers/gpu/drm/xe/xe_access_counter.h
new file mode 100644
index 000000000000..b3a331687f13
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_access_counter.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_ACCESS_COUNTER_H_
+#define _XE_ACCESS_COUNTER_H_
+
+struct xe_device;
+struct xe_gt;
+struct xe_access_counter;
+
+int xe_access_counter_init(struct xe_device *xe);
+
+int xe_access_counter_handler(struct xe_device *xe, struct xe_access_counter *ac);
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_access_counter_types.h b/drivers/gpu/drm/xe/xe_access_counter_types.h
new file mode 100644
index 000000000000..74b903b9461b
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_access_counter_types.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_ACCESS_COUNTER_TYPES_H_
+#define _XE_ACCESS_COUNTER_TYPES_H_
+
+#include <linux/sizes.h>
+#include <linux/types.h>
+
+struct xe_gt;
+struct xe_access_counter;
+
+/** enum xe_access_counter_type - Xe access counter type */
+enum xe_access_counter_type {
+ /** @XE_ACCESS_COUNTER_TYPE_TRIGGER */
+ XE_ACCESS_COUNTER_TYPE_TRIGGER = 0,
+ /** @XE_ACCESS_COUNTER_TYPE_NOTIFY*/
+ XE_ACCESS_COUNTER_TYPE_NOTIFY = 1,
+};
+
+/** enum xe_access_counter_granularity - Xe access counter granularity */
+enum xe_access_counter_granularity {
+ /** @XE_ACCESS_COUNTER_GRANULARITY_128K: 128K granularity */
+ XE_ACCESS_COUNTER_GRANULARITY_128K = 0,
+ /** @XE_ACCESS_COUNTER_GRANULARITY_2M: 2M granularity */
+ XE_ACCESS_COUNTER_GRANULARITY_2M = 1,
+ /** @XE_ACCESS_COUNTER_GRANULARITY_16M: 16M granularity */
+ XE_ACCESS_COUNTER_GRANULARITY_16M = 2,
+ /** @XE_ACCESS_COUNTER_GRANULARITY_64M: 64M granularity */
+ XE_ACCESS_COUNTER_GRANULARITY_64M = 3,
+};
+
+static inline int xe_access_counter_granularity_in_byte(int val)
+{
+ switch (val) {
+ case XE_ACCESS_COUNTER_GRANULARITY_128K:
+ return SZ_128K;
+ case XE_ACCESS_COUNTER_GRANULARITY_2M:
+ return SZ_2M;
+ case XE_ACCESS_COUNTER_GRANULARITY_16M:
+ return SZ_16M;
+ case XE_ACCESS_COUNTER_GRANULARITY_64M:
+ return SZ_64M;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * struct xe_access_counter - Xe access counter
+ *
+ * Generic access counter structure for communication between producer and consumer.
+ * Carefully sized to be 64 bytes. Upon a device access counter notification, the
+ * producer populates this structure, and the consumer copies it into the access
+ * counter queue for deferred handling.
+ */
+struct xe_access_counter {
+ /**
+ * @gt: GT of access counter
+ */
+ struct xe_gt *gt;
+ /**
+ * @consumer: State for the software handling the access counter.
+ * Populated by the producer and may be modified by the consumer to
+ * communicate information back to the producer upon acknowledgment.
+ */
+ struct {
+ /** @consumer.va_range_base: base virtual address of range */
+ u64 va_range_base;
+ /** @consumer.sub_granularity: sub-granularity */
+ u32 sub_granularity;
+ /**
+ * @consumer.counter_type: counter type, u8 rather than enum to
+ * keep size compact
+ */
+ u8 counter_type;
+ /**
+ * @consumer.granularity: access granularity, u8 rather than enum
+ * to keep size compact
+ */
+ u8 granularity;
+ /** @consumer.reserved: reserved bits for alignment */
+ u8 reserved[2];
+ /** @consumer: Platform-specific fields */
+ union {
+ /** @consumer.xe3: Xe3-specific fields */
+ struct {
+ /** @consumer.xe3.asid: address space ID */
+ u32 asid;
+ /** @consumer.xe3.engine_class: engine class */
+ u8 engine_class;
+ /** @consumer.xe3.engine_instance: engine instance */
+ u8 engine_instance;
+ /** @consumer.xe3.vfid: VFID */
+ u8 vfid;
+ /** @consumer.xe3.reserved: reserved bits */
+ u8 reserved;
+ } xe3;
+ };
+ } consumer;
+ /**
+ * @producer: State for the producer (i.e., HW/FW interface). Populated
+ * by the producer and should not be modified—or even inspected—by the
+ * consumer, except for calling operations.
+ */
+ struct {
+ /** @producer.private: private pointer */
+ void *private;
+#define XE_ACCESS_COUNTER_PRODUCER_MSG_LEN_DW 4
+ /**
+ * @producer.msg: access counter message, used by producer in
+ * acknowledgment to formulate response to HW/FW interface.
+ * Included in the access counter message because the producer
+ * typically receives the notification in a context where memory
+ * cannot be allocated (e.g., atomic context or the reclaim path).
+ */
+ u32 msg[XE_ACCESS_COUNTER_PRODUCER_MSG_LEN_DW];
+ } producer;
+};
+
+#endif
--
2.34.1