Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Nareshkumar Gollakoti <naresh.kumar.g@intel.com>
To: intel-xe@lists.freedesktop.org
Cc: tejas.upadhyay@intel.com,
	Nareshkumar Gollakoti <naresh.kumar.g@intel.com>
Subject: [PATCH v5 1/7] drm/xe/devcoredump: Capture GT fuse registers in devcoredump
Date: Fri, 23 Oct 2026 11:35:48 +0530	[thread overview]
Message-ID: <20261023060554.2643515-2-naresh.kumar.g@intel.com> (raw)
In-Reply-To: <20261023060554.2643515-1-naresh.kumar.g@intel.com>

Capture fuse-related GT register state in the Xe devcoredump to preserve
additional hardware configuration information for postmortem debugging.

Add generic register snapshot storage and helpers for capturing,
printing, and freeing MMIO register dumps. Use them to record both
primary GT and media GT fuse register state during devcoredump snapshot
collection and print the captured values in the coredump output.

Also add the required GT register definitions for RPM and mirror
copy-enable state used by the new dump paths.

v2:(Sashiko)
- Fix GT/media fuse snapshot capture to use the correct GT context.
- Add non-fault GT force wake for cross-GT register capture.
- Skip reading registers when SR-IOV VF.
- Skip media GT capture when media GT is absent.
- Add RPM snapshot print/free handling explicitly.
- Add POWERGATE_ENABLE register to get render awake status

v3:(Sashiko)
- Check RENDER_POWERGATE_ENABLE of POWERGATE_ENABLE register
- Replace "render is not awake" message with "render powergating
  appears not enabled"

v4:
- Reduce multiple apis and optimize the suggest way of struct arrays(Tejas)
- Add document for struct xe_gt_regset gt member(Hook failure)
- Change struct reg_desc to header file
- Remove Graphics version check for these registers set

v5:
- Fix possible Null dereference using valid gt instead of q->gt(sashiko)
- refactor struct member commenting(Tejas)
- Avoid using xe3p naming as the regs are for all platforms

Signed-off-by: Nareshkumar Gollakoti <naresh.kumar.g@intel.com>
---
 drivers/gpu/drm/xe/regs/xe_gt_regs.h      |   2 +
 drivers/gpu/drm/xe/xe_devcoredump.c       | 228 +++++++++++++++++++++-
 drivers/gpu/drm/xe/xe_devcoredump_types.h |  52 +++++
 3 files changed, 281 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index f5cd3a94e47f..e93895e0c731 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -22,6 +22,8 @@
 #define   MTL_CC_MASK					REG_GENMASK(12, 9)
 #define   MTL_CRST					0xf
 
+#define RPM_GCD						XE_REG(0xc98)
+
 /* RPM unit config (Gen8+) */
 #define RPM_CONFIG0					XE_REG(0xd00)
 #define   RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK		REG_GENMASK(5, 3)
diff --git a/drivers/gpu/drm/xe/xe_devcoredump.c b/drivers/gpu/drm/xe/xe_devcoredump.c
index 133cbe196d66..f59f93ba5949 100644
--- a/drivers/gpu/drm/xe/xe_devcoredump.c
+++ b/drivers/gpu/drm/xe/xe_devcoredump.c
@@ -25,6 +25,8 @@
 #include "xe_pm.h"
 #include "xe_sched_job.h"
 #include "xe_vm.h"
+#include "xe_mmio.h"
+#include "regs/xe_gt_regs.h"
 
 /**
  * DOC: Xe device coredump
@@ -69,6 +71,179 @@
 /* 1 hour timeout */
 #define XE_COREDUMP_TIMEOUT_JIFFIES (60 * 60 * HZ)
 
+#define XE_REG_DESC(_reg, _name)	{ .reg = (_reg), .name = (_name) }
+
+static const struct xe_reg_desc xe_dbg_gt_fuse_reglist[] = {
+	XE_REG_DESC(XELP_GT_GEOMETRY_DSS_ENABLE, "GT_GEOMETRY_DSS_ENABLE"),
+	XE_REG_DESC(XEHP_GT_COMPUTE_DSS_ENABLE, "GT_COMPUTE_DSS_ENABLE"),
+	XE_REG_DESC(XELP_EU_ENABLE, "EU_ENABLE"),
+	XE_REG_DESC(MIRROR_FUSE1, "MIRROR_FUSE1"),
+	XE_REG_DESC(GT_VEBOX_VDBOX_DISABLE, "GT_VEBOX_VDBOX_DISABLE"),
+	XE_REG_DESC(SERVICE_COPY_ENABLE, "SERVICE_COPY_ENABLE"),
+	XE_REG_DESC(RESOURCE_COPY_ENABLE, "COPY_ENABLE_GTFS_GCD"),
+	XE_REG_DESC(XE2_GT_GEOMETRY_DSS_1, "GT_GEOMETRY_DSS_1"),
+	XE_REG_DESC(XE2_GT_GEOMETRY_DSS_2, "GT_GEOMETRY_DSS_2"),
+	XE_REG_DESC(XE2_GT_COMPUTE_DSS_2, "GT_COMPUTE_DSS_2"),
+	XE_REG_DESC(XEHPC_GT_COMPUTE_DSS_ENABLE_EXT, "GT_COMPUTE_DSS_ENABLE_EXT"),
+	XE_REG_DESC(XE3P_XPC_GT_GEOMETRY_DSS_3, "GT_GEOMETRY_DSS_3"),
+	XE_REG_DESC(XE3P_XPC_GT_COMPUTE_DSS_3, "GT_COMPUTE_DSS_3"),
+};
+
+static const struct xe_reg_desc xe_dbg_media_gt_fuse_reglist[] = {
+	XE_REG_DESC(SERVICE_COPY_ENABLE, "SERVICE_COPY_ENABLE"),
+	XE_REG_DESC(RESOURCE_COPY_ENABLE, "COPY_ENABLE_GTFS_GCD"),
+};
+
+static const struct xe_reg_desc xe_dbg_gt_rpm_reglist[] = {
+	XE_REG_DESC(RPM_GCD, "RPM_GCD"),
+	XE_REG_DESC(POWERGATE_ENABLE, "POWERGATE_ENABLE"),
+};
+
+static const struct xe_reg_desc xe_dbg_media_gt_rpm_reglist[] = {
+	XE_REG_DESC(RPM_GCD, "RPM_GCD"),
+};
+
+/**
+ * struct xe_gt_regset - Struct for register descriptor list for GT
+ *
+ * This struct is used to reference the corresponding reglist of
+ * Main GT and media GT
+ */
+struct xe_gt_regset {
+	/**
+	 * @gt: GT array indexed by enum xe_gt_type starting at 1
+	 *	(UNINITIALIZED=0, MAIN=1, MEDIA=2)
+	 */
+	struct xe_reg_desc_list gt[XE_MAX_GT_PER_TILE + 1];
+};
+
+/**
+ * enum xe_dbg_regset_type - debug register set types
+ * @XE_DBG_REGSET_FUSE: Fuse register set
+ * @XE_DBG_REGSET_RPM: RPM register set
+ * @XE_DBG_REGSET_MAX: Number of debug register set types
+ */
+enum xe_dbg_regset_type {
+	XE_DBG_REGSET_FUSE,
+	XE_DBG_REGSET_RPM,
+	XE_DBG_REGSET_MAX,
+};
+
+static const struct xe_gt_regset xe_dbg_regsets[XE_DBG_REGSET_MAX] = {
+	[XE_DBG_REGSET_FUSE] = {
+		.gt[XE_GT_TYPE_MAIN]  = { xe_dbg_gt_fuse_reglist,
+					  ARRAY_SIZE(xe_dbg_gt_fuse_reglist) },
+		.gt[XE_GT_TYPE_MEDIA] = { xe_dbg_media_gt_fuse_reglist,
+					  ARRAY_SIZE(xe_dbg_media_gt_fuse_reglist) },
+	},
+	[XE_DBG_REGSET_RPM] = {
+		.gt[XE_GT_TYPE_MAIN]  = { xe_dbg_gt_rpm_reglist,
+					  ARRAY_SIZE(xe_dbg_gt_rpm_reglist) },
+		.gt[XE_GT_TYPE_MEDIA] = { xe_dbg_media_gt_rpm_reglist,
+					  ARRAY_SIZE(xe_dbg_media_gt_rpm_reglist) },
+	},
+};
+
+static void xe_dbg_reg_snapshot_print(struct drm_printer *p,
+				      const char *title,
+				      const struct xe_dbg_reg_snapshot *snap)
+{
+	u32 i;
+
+	if (!snap)
+		return;
+
+	if (title)
+		drm_printf(p, "\n**** %s ****\n", title);
+
+	for (i = 0; i < snap->num_regs; i++)
+		drm_printf(p, " %s [0x%x] = 0x%08x\n",
+			   snap->desc->regs[i].name,
+			   snap->desc->regs[i].reg.addr,
+			   snap->values[i]);
+}
+
+static void xe_dbg_reg_snapshot_free(struct xe_dbg_reg_snapshot *snap)
+{
+	kfree(snap);
+}
+
+static const u32 *xe_dbg_find_value(const struct xe_dbg_reg_snapshot *snap,
+				    struct xe_reg reg)
+{
+	int i;
+
+	if (!snap)
+		return NULL;
+
+	for (i = 0; i < snap->num_regs; i++)
+		if (snap->desc->regs[i].reg.addr == reg.addr)
+			return &snap->values[i];
+
+	return NULL;
+}
+
+static void xe_gt_rpm_snapshot_print(struct drm_printer *p,
+				     const char *title,
+				     const struct xe_dbg_reg_snapshot *snap)
+{
+	const u32 *val;
+
+	xe_dbg_reg_snapshot_print(p, title, snap);
+
+	if (!snap)
+		return;
+
+	val = xe_dbg_find_value(snap, POWERGATE_ENABLE);
+	if (val && !(*val & RENDER_POWERGATE_ENABLE))
+		drm_puts(p, "render powergating appears not enabled\n");
+}
+
+static struct xe_dbg_reg_snapshot *
+xe_dbg_reg_snapshot_capture_target(struct xe_gt *gt,
+				   const struct xe_reg_desc_list *reglist)
+{
+	struct xe_dbg_reg_snapshot *snap;
+	int i;
+
+	if (IS_SRIOV_VF(gt_to_xe(gt)))
+		return NULL;
+
+	snap = kmalloc(struct_size(snap, values, reglist->num_regs), GFP_ATOMIC);
+	if (!snap)
+		return NULL;
+
+	snap->desc	= reglist;
+	snap->num_regs = reglist->num_regs;
+	for (i = 0; i < reglist->num_regs; i++)
+		snap->values[i] = xe_mmio_read32(&gt->mmio, reglist->regs[i].reg);
+
+	return snap;
+}
+
+static struct xe_dbg_reg_snapshot *
+xe_dbg_gt_snapshot_capture(struct xe_gt *fault_gt, struct xe_gt *other_gt,
+			   enum xe_dbg_regset_type type,
+			   enum xe_gt_type gt_type)
+{
+	struct xe_gt *target_gt;
+
+	if (!fault_gt || !fault_gt->tile)
+		return NULL;
+
+	target_gt = gt_type == XE_GT_TYPE_MEDIA ? fault_gt->tile->media_gt
+						 : fault_gt->tile->primary_gt;
+	if (!target_gt)
+		return NULL;
+
+	/* non-fault GT needs the caller's confirmed forcewake */
+	if (target_gt != fault_gt && target_gt != other_gt)
+		return NULL;
+
+	return xe_dbg_reg_snapshot_capture_target(target_gt,
+						  &xe_dbg_regsets[type].gt[gt_type]);
+}
+
 static struct xe_device *coredump_to_xe(const struct xe_devcoredump *coredump)
 {
 	return container_of(coredump, struct xe_device, devcoredump);
@@ -109,6 +284,11 @@ static ssize_t __xe_devcoredump_read(char *buffer, ssize_t count,
 	drm_printf(&p, "\n**** GT #%d ****\n", ss->gt->info.id);
 	drm_printf(&p, "\tTile: %d\n", ss->gt->tile->id);
 
+	xe_dbg_reg_snapshot_print(&p, "GT Fuse Register Dump", ss->gt_fuse);
+	xe_dbg_reg_snapshot_print(&p, "Media GT Fuse Register Dump", ss->media_fuse);
+	xe_gt_rpm_snapshot_print(&p, "GT RPM Register Dump", ss->gt_rpm);
+	xe_dbg_reg_snapshot_print(&p, "Media GT RPM Register Dump", ss->media_gt_rpm);
+
 	drm_puts(&p, "\n**** GuC Log ****\n");
 	xe_guc_log_snapshot_print(ss->guc.log, &p, ss->gt);
 	drm_puts(&p, "\n**** GuC CT ****\n");
@@ -146,6 +326,18 @@ static void xe_devcoredump_snapshot_free(struct xe_devcoredump_snapshot *ss)
 	xe_guc_ct_snapshot_free(ss->guc.ct);
 	ss->guc.ct = NULL;
 
+	xe_dbg_reg_snapshot_free(ss->gt_fuse);
+	ss->gt_fuse = NULL;
+
+	xe_dbg_reg_snapshot_free(ss->media_fuse);
+	ss->media_fuse = NULL;
+
+	xe_dbg_reg_snapshot_free(ss->gt_rpm);
+	ss->gt_rpm = NULL;
+
+	xe_dbg_reg_snapshot_free(ss->media_gt_rpm);
+	ss->media_gt_rpm = NULL;
+
 	if (!IS_ERR_OR_NULL(ss->gt))
 		xe_guc_capture_put_matched_nodes(&ss->gt->uc.guc);
 	ss->matched_node = NULL;
@@ -319,6 +511,27 @@ static void xe_devcoredump_deferred_snap_work(struct work_struct *work)
 	}
 }
 
+static void xe_devcoredump_capture_gt_regs(struct xe_devcoredump_snapshot *ss,
+					   struct xe_gt *gt, struct xe_gt *other_gt)
+{
+	ss->gt_fuse      = xe_dbg_gt_snapshot_capture(gt,
+						      other_gt,
+						      XE_DBG_REGSET_FUSE,
+						      XE_GT_TYPE_MAIN);
+	ss->media_fuse   = xe_dbg_gt_snapshot_capture(gt,
+						      other_gt,
+						      XE_DBG_REGSET_FUSE,
+						      XE_GT_TYPE_MEDIA);
+	ss->gt_rpm       = xe_dbg_gt_snapshot_capture(gt,
+						      other_gt,
+						      XE_DBG_REGSET_RPM,
+						      XE_GT_TYPE_MAIN);
+	ss->media_gt_rpm = xe_dbg_gt_snapshot_capture(gt,
+						      other_gt,
+						      XE_DBG_REGSET_RPM,
+						      XE_GT_TYPE_MEDIA);
+}
+
 static void devcoredump_snapshot(struct xe_devcoredump *coredump,
 				 struct xe_gt *gt,
 				 struct xe_exec_queue *q,
@@ -328,6 +541,7 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump,
 	struct xe_guc *guc = &gt->uc.guc;
 	const char *process_name = "no process";
 	bool cookie;
+	struct xe_gt *other_gt;
 
 	ss->snapshot_time = ktime_get_real();
 	ss->boot_time = ktime_get_boottime();
@@ -342,11 +556,23 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump,
 	ss->gt = gt;
 	INIT_WORK(&ss->work, xe_devcoredump_deferred_snap_work);
 
-	/* keep going if fw fails as we still want to save the memory and SW data */
+	/* fw_ref_other must stay in scope through the register captures below */
 	CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL);
 
 	cookie = dma_fence_begin_signalling();
 
+	other_gt = gt->tile->media_gt == gt ? gt->tile->primary_gt
+					    : gt->tile->media_gt;
+	if (other_gt) {
+		CLASS(xe_force_wake, fw_ref_other)(gt_to_fw(other_gt),
+						   XE_FORCEWAKE_ALL);
+		if (!xe_force_wake_ref_has_domain(fw_ref_other.domains, XE_FORCEWAKE_ALL))
+			other_gt = NULL;
+		xe_devcoredump_capture_gt_regs(ss, gt, other_gt);
+	} else {
+		xe_devcoredump_capture_gt_regs(ss, gt, NULL);
+	}
+
 	ss->guc.log = xe_guc_log_snapshot_capture(&guc->log, true);
 	ss->guc.ct = xe_guc_ct_snapshot_capture(&guc->ct);
 
diff --git a/drivers/gpu/drm/xe/xe_devcoredump_types.h b/drivers/gpu/drm/xe/xe_devcoredump_types.h
index a174385a6d83..e2fac33dce09 100644
--- a/drivers/gpu/drm/xe/xe_devcoredump_types.h
+++ b/drivers/gpu/drm/xe/xe_devcoredump_types.h
@@ -14,6 +14,48 @@
 struct xe_device;
 struct xe_gt;
 
+/**
+ * struct xe_reg_desc - Register descriptor struct to make reg list
+ *
+ * This struct is used as descriptor containing reg address and name
+ * of the register to dump its value during coredump for debug purpose.
+ */
+struct xe_reg_desc {
+	/** @reg: The register */
+	struct xe_reg reg;
+	/** @name: Name of the register */
+	const char *name;
+};
+
+/**
+ * struct xe_reg_desc_list - Struct for register descriptor list
+ *
+ * This struct is used to reference the corresponding reglist of
+ * various component
+ */
+struct xe_reg_desc_list {
+	/** @regs: Pointer to an array of register descriptors. */
+	const struct xe_reg_desc *regs;
+	/** @num_regs: number of registers in the descriptor list*/
+	u32 num_regs;
+};
+
+/**
+ * struct xe_dbg_reg_snapshot - Register snapshot
+ *
+ * This struct contains the register values captured at the time of the crash.
+ * It is used to store the register values in a human-readable format for
+ * debugging purposes.
+ */
+struct xe_dbg_reg_snapshot {
+	/** @desc: register descriptor list. */
+	const struct xe_reg_desc_list *desc;
+	/** @num_regs: Number of registers needed for capture. */
+	u32 num_regs;
+	/** @values: register values*/
+	u32 values[];
+};
+
 /**
  * struct xe_devcoredump_snapshot - Crash snapshot
  *
@@ -35,6 +77,16 @@ struct xe_devcoredump_snapshot {
 
 	/** @gt: Affected GT, used by forcewake for delayed capture */
 	struct xe_gt *gt;
+
+	/** @gt_fuse: Fuse snapshot */
+	struct xe_dbg_reg_snapshot *gt_fuse;
+	/** @media_fuse: Media Fuse snapshot */
+	struct xe_dbg_reg_snapshot *media_fuse;
+	/** @gt_rpm: GT RPM snapshot */
+	struct xe_dbg_reg_snapshot *gt_rpm;
+	/** @media_gt_rpm: Media GT RPM snapshot */
+	struct xe_dbg_reg_snapshot *media_gt_rpm;
+
 	/** @work: Workqueue for deferred capture outside of signaling context */
 	struct work_struct work;
 
-- 
2.43.0


  reply	other threads:[~2026-10-23  6:08 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-23  6:05 [PATCH v5 0/7] drm/xe: Capture additional HW register state in devcoredump Nareshkumar Gollakoti
2026-10-23  6:05 ` Nareshkumar Gollakoti [this message]
2026-10-23 13:27   ` [PATCH v5 1/7] drm/xe/devcoredump: Capture GT fuse registers " Upadhyay, Tejas
2026-10-23  6:05 ` [PATCH v5 2/7] drm/xe/devcoredump: Add GuC register snapshot to devcoredump Nareshkumar Gollakoti
2026-10-26  6:35   ` Upadhyay, Tejas
2026-10-23  6:05 ` [PATCH v5 3/7] drm/xe/guc: Print register addresses in capture snapshot output Nareshkumar Gollakoti
2026-10-23 13:14   ` Upadhyay, Tejas
2026-10-26  6:37   ` Upadhyay, Tejas
2026-10-23  6:05 ` [PATCH v5 4/7] drm/xe: dump GAM page fault report registers in devcoredump Nareshkumar Gollakoti
2026-10-23  6:31   ` sashiko-bot
2026-10-26  6:48   ` Upadhyay, Tejas
2026-10-23  6:05 ` [PATCH v5 5/7] drm/xe/guc: add TDL, SLICE gfx registers to capture list Nareshkumar Gollakoti
2026-10-26  6:55   ` Upadhyay, Tejas
2026-10-23  6:05 ` [PATCH v5 6/7] drm/xe: capture L3 node status registers in devcoredump Nareshkumar Gollakoti
2026-10-23  6:24   ` sashiko-bot
2026-10-23  6:05 ` [PATCH v5 7/7] drm/xe/guc: capture additional engine state registers Nareshkumar Gollakoti
2026-10-23  6:26   ` sashiko-bot
2026-10-26  9:15   ` Upadhyay, Tejas
2026-10-23  6:14 ` ✗ CI.checkpatch: warning for drm/xe: Capture additional HW register state in devcoredump (rev6) Patchwork
2026-10-23  6:16 ` ✓ CI.KUnit: success " Patchwork
2026-10-23  6:56 ` ✓ Xe.CI.BAT: " Patchwork
2026-10-23  8:26 ` ✗ Xe.CI.FULL: failure " Patchwork
  -- strict thread matches above, loose matches on Subject: below --
2026-10-22 13:29 [PATCH v5 0/7] drm/xe: Capture additional HW register state in devcoredump Nareshkumar Gollakoti
2026-10-22 13:29 ` [PATCH v5 1/7] drm/xe/devcoredump: Capture GT fuse registers " Nareshkumar Gollakoti

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261023060554.2643515-2-naresh.kumar.g@intel.com \
    --to=naresh.kumar.g@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=tejas.upadhyay@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox