Re: [PATCH v3 4/4] drm/xe/sysctrl: Add RAS error injection debugfs interface
Anoop Vijay <[email protected]>
| Newsgroups | org.freedesktop.lists.intel-xe |
|---|---|
| Message-ID | <[email protected]> |
On 08-08-2026 00:19, Rodrigo Vivi wrote: > On Fri, Aug 07, 2026 at 11:15:59AM -0400, Gupta, Anshuman wrote: >> >>> -----Original Message----- >>> From: Vijay, Anoop C <[email protected]> >>> Sent: Friday, August 7, 2026 8:26 PM >>> To: [email protected] >>> Cc: Nerlige Ramappa, Umesh <[email protected]>; Nilawar, >>> Badal <[email protected]>; Vivi, Rodrigo <[email protected]>; >>> Iddamsetty, Aravind <[email protected]>; Tauro, Riana >>> <[email protected]>; Gupta, Anshuman <[email protected]>; >>> Roper, Matthew D <[email protected]>; Ruhl, Michael J >>> <[email protected]>; Luse, Paul E <[email protected]>; V, >>> Mohamed Mansoor <[email protected]>; Nasim, Kam >>> <[email protected]>; Vijay, Anoop C <[email protected]> >>> Subject: [PATCH v3 4/4] drm/xe/sysctrl: Add RAS error injection debugfs >>> interface >>> >>> From: Anoop Vijay <[email protected]> >>> >>> Add debugfs interface for exercising System Controller's RAS error injection >>> command, used to validate RAS error detection and recovery paths. >>> >>> Command details: >>> - Group ID: 0x02 (diag group) >>> - Command ID: 0x7E (XE_SYSCTRL_CMD_DIAG_RAS_ERR_INJECT) >>> - Usage: echo "<ras_block_id> <ras_sub_block_id> <err_type> [params]" \ >>> > /sys/kernel/debug/dri/0/sc/ras_error_inject >>> cat /sys/kernel/debug/dri/0/sc/ras_error_inject >>> >>> This command requires the diag application to have completed firmware >>> boot and initialization (late-bind loaded); writes are rejected with -ENODEV >>> until xe_sysctrl_is_diag_fw_ready() reports the diag firmware as ready. >>> >>> Signed-off-by: Anoop Vijay <[email protected]> >>> --- >>> drivers/gpu/drm/xe/xe_sysctrl_debugfs.c | 123 ++++++++++++++++++ >>> drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 31 +++++ >>> drivers/gpu/drm/xe/xe_sysctrl_types.h | 3 + >>> 3 files changed, 157 insertions(+) >>> >>> diff --git a/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c >>> b/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c >>> index 2144d9d43fba..7b8846d739cb 100644 >>> --- a/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c >>> +++ b/drivers/gpu/drm/xe/xe_sysctrl_debugfs.c >>> @@ -10,6 +10,7 @@ >>> #include <linux/seq_file.h> >>> #include <linux/slab.h> >>> #include <linux/string.h> >>> +#include <linux/string_choices.h> >>> #include <linux/uaccess.h> >>> >>> #include "xe_device.h" >>> @@ -122,6 +123,124 @@ static const struct file_operations >>> xe_sysctrl_loopback_fops = { >>> .release = single_release, >>> }; >>> >>> +static ssize_t xe_sysctrl_ras_error_inject_write(struct file *file, const char >>> __user *ubuf, >>> + size_t len, loff_t *offp) >>> +{ >>> + char *kbuf __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_diag_ras_err_inj_req req = {}; >>> + struct xe_sysctrl_mailbox_command cmd = {}; >>> + u8 resp_hdr_only[sizeof(u32)]; >>> + unsigned int nfields = 0; >>> + char *token, *tmp; >>> + unsigned long val; >>> + size_t out_len = 0; >>> + >>> + if (!xe_sysctrl_is_diag_fw_ready(xe)) { >>> + xe_err(xe, "sysctrl: diag firmware not ready, cannot inject RAS >>> error\n"); >> Wild thought, >> How it would be register the debugfs only if diag firmware is loaded ? >> That way nobody will be having access to these debugfs ? > I agree with this. It is better not even register the file if the > firmware is not loaded. So it doesn't even appear in the filesystem. Unlike oCode, diag firmware initialization is not driven by KMD and can complete asynchronously. We don't have a notification from SysCtrl when diag firmware app becomes ready. Since xe_sysctrl_check_app_status() is a lightweight synchronous query that always reflects current firmware state, a possible middle ground would be to move the readiness check to .open() rather than .write(). This would cause both cat and echo to fail with -ENODEV until diag firmware is initialized. The file would remain visible under sc/, but would be inaccessible until the firmware is ready. Would that be an acceptable compromise, or would you still prefer the entry to remain hidden until diag firmware is loaded? >> Thanks, >> Anshuman. >> >>> + return -ENODEV; >>> + } >>> + >>> + if (len == 0 || len >= PAGE_SIZE) >>> + return -EINVAL; >>> + >>> + kbuf = kmalloc(len + 1, GFP_KERNEL); >>> + if (!kbuf) >>> + 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 (kstrtoul(token, 0, &val)) >>> + goto inval; >>> + >>> + switch (nfields) { >>> + case 0: >>> + if (val > U16_MAX) >>> + goto inval; >>> + req.ras_block_id = val; >>> + break; >>> + case 1: >>> + if (val > U16_MAX) >>> + goto inval; >>> + req.ras_sub_block_id = val; >>> + break; >>> + case 2: >>> + if (val > U16_MAX) >>> + goto inval; >>> + req.err_type = val; >>> + break; >>> + case 3: >>> + if (val > U32_MAX) >>> + goto inval; >>> + req.params = val; >>> + break; >>> + default: >>> + xe_err(xe, "sysctrl: too many ras_error_inject >>> arguments\n"); >>> + return -EINVAL; >>> + } >>> + nfields++; >>> + } >>> + >>> + if (nfields < 3) { >>> + xe_err(xe, >>> + "sysctrl: usage: <ras_block_id> <ras_sub_block_id> >>> <err_type> [params]\n"); >>> + return -EINVAL; >>> + } >>> + >>> + xe_sysctrl_create_command(&cmd, entry->group, entry->command, >>> + &req, sizeof(req), resp_hdr_only, >>> + sizeof(resp_hdr_only)); >>> + >>> + guard(xe_pm_runtime)(xe); >>> + entry->status = xe_sysctrl_send_command(entry->sc, &cmd, >>> &out_len); >>> + >>> + return entry->status ? entry->status : len; >>> + >>> +inval: >>> + xe_err(xe, "sysctrl: invalid ras_error_inject token '%s'\n", token); >>> + return -EINVAL; >>> +} >>> + >>> +static int xe_sysctrl_ras_error_inject_show(struct seq_file *m, void >>> +*data) { >>> + struct xe_sysctrl_debugfs_entry *entry = m->private; >>> + struct xe_device *xe = sc_to_xe(entry->sc); >>> + >>> + seq_printf(m, "Command: group=0x%02x cmd=0x%02x\n", entry- >>>> group, entry->command); >>> + seq_printf(m, "Diag firmware ready: %s\n", >>> + str_yes_no(xe_sysctrl_is_diag_fw_ready(xe))); >>> + seq_printf(m, "Status: %d (%s)\n", entry->status, entry->status ? >>> +"FAILED" : "SUCCESS"); >>> + >>> + seq_puts(m, "\nUsage:\n"); >>> + seq_puts(m, " echo \"<ras_block_id> <ras_sub_block_id> >>> <err_type> [params]\" > ras_error_inject\n"); >>> + seq_puts(m, " cat ras_error_inject\n"); >>> + >>> + return 0; >>> +} >>> + >>> +static int xe_sysctrl_ras_error_inject_open(struct inode *inode, struct >>> +file *file) { >>> + return single_open(file, xe_sysctrl_ras_error_inject_show, >>> +inode->i_private); } >>> + >>> +static const struct file_operations xe_sysctrl_ras_error_inject_fops = { >>> + .owner = THIS_MODULE, >>> + .open = xe_sysctrl_ras_error_inject_open, >>> + .read = seq_read, >>> + .write = xe_sysctrl_ras_error_inject_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, >>> @@ -154,4 +273,8 @@ void xe_sysctrl_debugfs_register(struct xe_sysctrl >>> *sc, struct dentry *parent) >>> xe_sysctrl_register_entry(root, &sc->debugfs.loopback, sc, >>> "loopback", >>> XE_SYSCTRL_GROUP_CORE, >>> XE_SYSCTRL_CMD_LOOPBACK, >>> &xe_sysctrl_loopback_fops); >>> + >>> + xe_sysctrl_register_entry(root, &sc->debugfs.ras_error_inject, sc, >>> "ras_error_inject", >>> + XE_SYSCTRL_GROUP_DIAG, >>> XE_SYSCTRL_CMD_DIAG_RAS_ERR_INJECT, >>> + &xe_sysctrl_ras_error_inject_fops); >>> } >>> diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h >>> b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h >>> index ed80fe63e1c4..43ae0049b316 100644 >>> --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h >>> +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h >>> @@ -14,10 +14,12 @@ >>> * enum xe_sysctrl_group - System Controller command groups >>> * >>> * @XE_SYSCTRL_GROUP_GFSP: GFSP group >>> + * @XE_SYSCTRL_GROUP_DIAG: Diag group >>> * @XE_SYSCTRL_GROUP_CORE: Core group >>> */ >>> enum xe_sysctrl_group { >>> XE_SYSCTRL_GROUP_GFSP = 0x01, >>> + XE_SYSCTRL_GROUP_DIAG = 0x02, >>> XE_SYSCTRL_GROUP_CORE = 0xFF, >>> }; >>> >>> @@ -51,6 +53,35 @@ enum xe_sysctrl_core_cmd { >>> XE_SYSCTRL_CMD_GET_APP_STATUS_BY_ID = 0x05, >>> }; >>> >>> +/** >>> + * enum xe_sysctrl_diag_cmd - Commands supported by Diag group >>> + * >>> + * @XE_SYSCTRL_CMD_DIAG_RAS_ERR_INJECT: RAS error injection */ >>> enum >>> +xe_sysctrl_diag_cmd { >>> + XE_SYSCTRL_CMD_DIAG_RAS_ERR_INJECT = 0x7E, >>> +}; >>> + >>> +/** >>> + * struct xe_sysctrl_diag_ras_err_inj_req - DIAG_RAS_ERR_INJECT request >>> +payload >>> + * >>> + * Request payload for XE_SYSCTRL_CMD_DIAG_RAS_ERR_INJECT. The >>> mailbox >>> +layer >>> + * prepends the application message header before sending. >>> + * >>> + * @ras_block_id: RAS block (subsystem) to inject the error into >>> + * @ras_sub_block_id: RAS sub-block (IP) within @ras_block_id >>> + * @err_type: Type of test error to inject >>> + * @reserved: Must be zero >>> + * @params: Optional injection parameters (default 0) */ struct >>> +xe_sysctrl_diag_ras_err_inj_req { >>> + u16 ras_block_id; >>> + u16 ras_sub_block_id; >>> + u16 err_type; >>> + u16 reserved; >>> + u32 params; >>> +} __packed; >>> + >>> /** >>> * struct xe_sysctrl_app_status_req - Get application status request >>> * >>> diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h >>> b/drivers/gpu/drm/xe/xe_sysctrl_types.h >>> index 53d82e61383a..3a97a10d1b7d 100644 >>> --- a/drivers/gpu/drm/xe/xe_sysctrl_types.h >>> +++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h >>> @@ -68,6 +68,9 @@ struct xe_sysctrl { >>> >>> /** @debugfs.loopback: Loopback test entry */ >>> struct xe_sysctrl_debugfs_entry loopback; >>> + >>> + /** @debugfs.ras_error_inject: RAS error injection test entry >>> */ >>> + struct xe_sysctrl_debugfs_entry ras_error_inject; >>> } debugfs; >>> }; >>> >>> -- >>> 2.43.0