[PATCH v3 3/4] drm/xe/sysctrl: Add loopback test debugfs interface

"Anoop, Vijay" <[email protected]>
Newsgroups org.freedesktop.lists.intel-xe
Message-ID <[email protected]>
From: Anoop Vijay <[email protected]>

Add debugfs interface for testing sysctrl mailbox loopback
functionality. This allows userspace to send test payloads
and verify firmware communication.

Command details:
- Group ID: 0xFF (core group)
- Command ID: 0x03 (Inverted loopback)
- Usage: echo "0x11 0x22 0x33 0x44" > /sys/kernel/debug/dri/0/sc/loopback
         cat /sys/kernel/debug/dri/0/sc/loopback

Signed-off-by: Anoop Vijay <[email protected]>
---
 drivers/gpu/drm/xe/xe_sysctrl_debugfs.c       | 130 ++++++++++++++++++
 drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h |   2 +
 drivers/gpu/drm/xe/xe_sysctrl_types.h         |  28 ++++
 3 files changed, 160 insertions(+)

diff --git a/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c b/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c
index 0238ff093831..2144d9d43fba 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c
+++ b/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c
@@ -3,13 +3,139 @@
  * Copyright © 2026 Intel Corporation
  */
 
+#include <linux/cleanup.h>
 #include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/kstrtox.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
 
 #include "xe_device.h"
+#include "xe_pm.h"
+#include "xe_printk.h"
 #include "xe_sysctrl.h"
 #include "xe_sysctrl_debugfs.h"
+#include "xe_sysctrl_mailbox.h"
+#include "xe_sysctrl_mailbox_types.h"
 #include "xe_sysctrl_types.h"
 
+static ssize_t xe_sysctrl_loopback_write(struct file *file, const char __user *ubuf,
+					 size_t len, loff_t *offp)
+{
+	char *kbuf __free(kfree) = NULL;
+	u8 *input __free(kfree) = NULL;
+	struct seq_file *m = file->private_data;
+	struct xe_sysctrl_debugfs_entry *entry = m->private;
+	struct xe_device *xe = sc_to_xe(entry->sc);
+	struct xe_sysctrl_mailbox_command cmd = {};
+	char *token, *tmp;
+	unsigned long val;
+	size_t input_len = 0;
+	size_t max_input;
+	size_t out_len = 0;
+
+	if (len == 0 || len >= PAGE_SIZE)
+		return -EINVAL;
+
+	kbuf = kmalloc(len + 1, GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+
+	max_input = min_t(size_t, len, XE_SYSCTRL_MB_MAX_MESSAGE_SIZE);
+	input = kmalloc(max_input, GFP_KERNEL);
+	if (!input)
+		return -ENOMEM;
+
+	if (copy_from_user(kbuf, ubuf, len))
+		return -EFAULT;
+	kbuf[len] = '\0';
+
+	tmp = kbuf;
+	while ((token = strsep(&tmp, " \t\n")) != NULL) {
+		if (*token == '\0')
+			continue;
+
+		if (input_len >= max_input) {
+			xe_err(xe, "sysctrl: loopback payload too large (max %d bytes)\n",
+			       XE_SYSCTRL_MB_MAX_MESSAGE_SIZE);
+			return -EINVAL;
+		}
+
+		if (kstrtoul(token, 0, &val) || val > 0xFF) {
+			xe_err(xe, "sysctrl: invalid loopback token '%s'\n", token);
+			return -EINVAL;
+		}
+
+		input[input_len++] = (u8)val;
+	}
+
+	if (input_len == 0) {
+		xe_err(xe, "sysctrl: no loopback payload given\n");
+		return -EINVAL;
+	}
+
+	xe_sysctrl_create_command(&cmd, entry->group, entry->command,
+				  input, input_len, entry->response_buf, input_len);
+
+	guard(xe_pm_runtime)(xe);
+	entry->status = xe_sysctrl_send_command(entry->sc, &cmd, &out_len);
+	entry->response_len = entry->status ? 0 : out_len;
+
+	return entry->status ? entry->status : len;
+}
+
+static int xe_sysctrl_loopback_show(struct seq_file *m, void *data)
+{
+	struct xe_sysctrl_debugfs_entry *entry = m->private;
+	size_t i;
+
+	seq_printf(m, "Command: group=0x%02x cmd=0x%02x\n", entry->group, entry->command);
+	seq_printf(m, "Status: %d (%s)\n", entry->status, entry->status ? "FAILED" : "SUCCESS");
+	seq_printf(m, "Response: %zu bytes\n", entry->response_len);
+
+	if (entry->response_len) {
+		seq_puts(m, "Response data:\n");
+		for (i = 0; i < entry->response_len; i++) {
+			if (i && (i % 16) == 0)
+				seq_putc(m, '\n');
+			seq_printf(m, "%02x ", entry->response_buf[i]);
+		}
+		seq_putc(m, '\n');
+	}
+
+	return 0;
+}
+
+static int xe_sysctrl_loopback_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, xe_sysctrl_loopback_show, inode->i_private);
+}
+
+static const struct file_operations xe_sysctrl_loopback_fops = {
+	.owner = THIS_MODULE,
+	.open = xe_sysctrl_loopback_open,
+	.read = seq_read,
+	.write = xe_sysctrl_loopback_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static void xe_sysctrl_register_entry(struct dentry *root, struct xe_sysctrl_debugfs_entry *entry,
+				      struct xe_sysctrl *sc, const char *name,
+				      u8 group, u8 command,
+				      const struct file_operations *fops)
+{
+	entry->sc = sc;
+	entry->group = group;
+	entry->command = command;
+	entry->response_len = 0;
+	entry->status = 0;
+
+	debugfs_create_file(name, 0644, root, entry, fops);
+}
+
 /**
  * xe_sysctrl_debugfs_register - Register debugfs entries for System Controller
  * @sc: xe_sysctrl instance
@@ -24,4 +150,8 @@ void xe_sysctrl_debugfs_register(struct xe_sysctrl *sc, struct dentry *parent)
 		return;
 
 	sc->debugfs.root = root;
+
+	xe_sysctrl_register_entry(root, &sc->debugfs.loopback, sc, "loopback",
+				  XE_SYSCTRL_GROUP_CORE, XE_SYSCTRL_CMD_LOOPBACK,
+				  &xe_sysctrl_loopback_fops);
 }
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
index b507e1553cbb..ed80fe63e1c4 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h
@@ -43,9 +43,11 @@ enum xe_sysctrl_gfsp_cmd {
 /**
  * enum xe_sysctrl_core_cmd - Commands supported by Core group
  *
+ * @XE_SYSCTRL_CMD_LOOPBACK: Loopback test command
  * @XE_SYSCTRL_CMD_GET_APP_STATUS_BY_ID: Retrieve application status by ID
  */
 enum xe_sysctrl_core_cmd {
+	XE_SYSCTRL_CMD_LOOPBACK				= 0x03,
 	XE_SYSCTRL_CMD_GET_APP_STATUS_BY_ID		= 0x05,
 };
 
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h b/drivers/gpu/drm/xe/xe_sysctrl_types.h
index d50a35fefb7a..53d82e61383a 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_types.h
+++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h
@@ -10,9 +10,34 @@
 #include <linux/types.h>
 #include <linux/workqueue_types.h>
 
+#include "xe_sysctrl_mailbox_types.h"
+
 struct xe_mmio;
 struct dentry;
 
+/**
+ * struct xe_sysctrl_debugfs_entry - Debugfs entry for a raw mailbox test command
+ */
+struct xe_sysctrl_debugfs_entry {
+	/** @sc: Back pointer to parent sysctrl instance */
+	struct xe_sysctrl *sc;
+
+	/** @group: Command group ID */
+	u8 group;
+
+	/** @command: Command ID within group */
+	u8 command;
+
+	/** @response_buf: Response data buffer, sized to the maximum mailbox message */
+	u8 response_buf[XE_SYSCTRL_MB_MAX_MESSAGE_SIZE];
+
+	/** @response_len: Actual response length from firmware */
+	size_t response_len;
+
+	/** @status: Last command result */
+	int status;
+};
+
 /**
  * struct xe_sysctrl - System Controller driver context
  *
@@ -40,6 +65,9 @@ struct xe_sysctrl {
 	struct {
 		/** @debugfs.root: Root debugfs directory */
 		struct dentry *root;
+
+		/** @debugfs.loopback: Loopback test entry */
+		struct xe_sysctrl_debugfs_entry loopback;
 	} debugfs;
 };
 
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.