All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/10] Add GuC Error Capture Support
@ 2022-01-26 10:48 ` Alan Previn
  0 siblings, 0 replies; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx
  Cc: Matthew Brost, Tvrtko Ursulin, John Harrison, dri-devel, Alan Previn

This series:
  1. Enables support of GuC to execute error-
     state-capture based on a list of MMIO
     registers the driver registers and GuC will
     dump and report back right before a GuC
     triggered engine-reset event.
  2. Updates the ADS blob creation to register lists
     of global and engine registers with GuC.
  3. Defines tables of register lists that are global or
     engine class or engine instance in scope.
  4. Separates GuC log-buffer access locks for relay logging
     vs the new region for the error state capture data.
  5. Allocates an additional interim circular buffer store
     to copy snapshots of new GuC reported error-state-capture
     dumps in response to the G2H notification.
  6. Connects the i915_gpu_coredump reporting function
     to the GuC error capture module to print all GuC
     error state capture dumps that is reported.

This is the 5th rev of this series with the first 3 revs
labelled as RFC.

Prior receipts of rvb's:
  - Patch #5 has received R-v-b from Matthew Brost
    <matthew.brost@intel.com>

Changes from prior revs:
  v5: - Added Gen9->Gen11 register list for CI coverage that
        included Gen9 with GuC submission.
      - Redesigned the extraction of the GuC error-capture
        dumps by grouping them into complete per-engine-reset
        nodes. Complete here means each node includes the
        global, engine-class and engine-instance register
        lists in a single structure.
      - Extraction is decoupled from the print-out. We now
        do the extraction immediately when receiving the
        G2H for error-capture notification. A link list of
        nodes is maintained with a FIFO based threshold
        while awaiting retrieval from i915_gpu_coredump's
        capture_engine function.
      - Added new plumbing through the i915_gpu_coredump
        allocation and capture functions to include a flag
        that is used indicate that GuC had triggered the
        reset. This new plumbing guarantees an exact match
        from i915_gpu_coredump's per-engine vma recording
        and node-retrieval from the guc-error-capture.
      - Broke the coredump gt_global capture and recording
        functions into smaller subsets so we can reuse as
        much of the existing legacy register reading + printing
        functions and only rely on GuC error-capture for
        the smaller subset of registers that are tied to
        engine workload execution.
      - Updated the register list to follow the legacy execlist
        format of printout.
  v4:
      - Rebased on latest drm-tip that has been merged with the
        support of GuC firmware version 69.0.3 that is required
        for GuC error-state-catpure to work.
      - Added register list for DG2 which is the same as XE_LP
        except an additional steering register set.
      - Fixed a bug in the end of capture parsing loop in
        intel_guc_capture_out_print_next_group that was not
        properly comparing the engine-instance and engine-
        class being parsed against the one that triggered
        the i915_gpu_coredump.
  v3:
      - Fixed all review comments from rev2 except the following:
          - Michal Wajdeczko proposed adding a seperate function
            to lookup register string nameslookup (based on offset)
            but decided against it because of offset conflicts
            and the current table layout is easier to maintain.
          - Last set of checkpatch errors pertaining to "COMPLEX
            MACROS" should be fixed on next rev.
      - Abstracted internal-to-guc-capture information into a new
        __guc_state_capture_priv structure that allows the exclusion
        of intel_guc.h and intel_guc_fwif.h from intel_guc_capture.h.
        Now, only the first 2 patches have a wider build time
        impact because of the changes to intel_guc_fwif.h but
        subsequent changes to guc-capture internal structures
        or firmware interfaces used solely by guc-capture module
        shoudn't impact the rest of the driver build.
      - Added missing Gen12LP registers and added slice+subslice
        indices when reporting extended steered registers.
      - Add additional checks to ensure that the GuC reported
        error capture information matches the i915_gpu_coredump
        that is being printed before we print out the corresponding
        VMA dumps such as the batch buffer.
   v2:
      - Ignore - failed CI retest.


Alan Previn (10):
  drm/i915/guc: Update GuC ADS size for error capture lists
  drm/i915/guc: Add XE_LP registers for GuC error state capture.
  drm/i915/guc: Add DG2 registers for GuC error state capture.
  drm/i915/guc: Add Gen9 registers for GuC error state capture.
  drm/i915/guc: Add GuC's error state capture output structures.
  drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  drm/i915/guc: Extract GuC error capture lists on G2H notification.
  drm/i915/guc: Plumb GuC-capture into gpu_coredump
  drm/i915/guc: Follow legacy register names
  drm/i915/guc: Print the GuC error capture output register list.

 drivers/gpu/drm/i915/Makefile                 |    1 +
 drivers/gpu/drm/i915/gt/intel_engine_cs.c     |    4 +-
 .../drm/i915/gt/intel_execlists_submission.c  |    4 +-
 drivers/gpu/drm/i915/gt/intel_reset.c         |    2 +-
 .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h  |    7 +
 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |  121 ++
 drivers/gpu/drm/i915/gt/uc/intel_guc.c        |   13 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   13 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c    |   36 +-
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 1478 +++++++++++++++++
 .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   31 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |   21 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    |  155 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |   20 +-
 .../gpu/drm/i915/gt/uc/intel_guc_submission.c |   16 +-
 drivers/gpu/drm/i915/i915_debugfs.c           |    3 +-
 drivers/gpu/drm/i915/i915_gpu_error.c         |  279 +++-
 drivers/gpu/drm/i915/i915_gpu_error.h         |   36 +-
 18 files changed, 2035 insertions(+), 205 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
 create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
 create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 00/10] Add GuC Error Capture Support
@ 2022-01-26 10:48 ` Alan Previn
  0 siblings, 0 replies; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel, Alan Previn

This series:
  1. Enables support of GuC to execute error-
     state-capture based on a list of MMIO
     registers the driver registers and GuC will
     dump and report back right before a GuC
     triggered engine-reset event.
  2. Updates the ADS blob creation to register lists
     of global and engine registers with GuC.
  3. Defines tables of register lists that are global or
     engine class or engine instance in scope.
  4. Separates GuC log-buffer access locks for relay logging
     vs the new region for the error state capture data.
  5. Allocates an additional interim circular buffer store
     to copy snapshots of new GuC reported error-state-capture
     dumps in response to the G2H notification.
  6. Connects the i915_gpu_coredump reporting function
     to the GuC error capture module to print all GuC
     error state capture dumps that is reported.

This is the 5th rev of this series with the first 3 revs
labelled as RFC.

Prior receipts of rvb's:
  - Patch #5 has received R-v-b from Matthew Brost
    <matthew.brost@intel.com>

Changes from prior revs:
  v5: - Added Gen9->Gen11 register list for CI coverage that
        included Gen9 with GuC submission.
      - Redesigned the extraction of the GuC error-capture
        dumps by grouping them into complete per-engine-reset
        nodes. Complete here means each node includes the
        global, engine-class and engine-instance register
        lists in a single structure.
      - Extraction is decoupled from the print-out. We now
        do the extraction immediately when receiving the
        G2H for error-capture notification. A link list of
        nodes is maintained with a FIFO based threshold
        while awaiting retrieval from i915_gpu_coredump's
        capture_engine function.
      - Added new plumbing through the i915_gpu_coredump
        allocation and capture functions to include a flag
        that is used indicate that GuC had triggered the
        reset. This new plumbing guarantees an exact match
        from i915_gpu_coredump's per-engine vma recording
        and node-retrieval from the guc-error-capture.
      - Broke the coredump gt_global capture and recording
        functions into smaller subsets so we can reuse as
        much of the existing legacy register reading + printing
        functions and only rely on GuC error-capture for
        the smaller subset of registers that are tied to
        engine workload execution.
      - Updated the register list to follow the legacy execlist
        format of printout.
  v4:
      - Rebased on latest drm-tip that has been merged with the
        support of GuC firmware version 69.0.3 that is required
        for GuC error-state-catpure to work.
      - Added register list for DG2 which is the same as XE_LP
        except an additional steering register set.
      - Fixed a bug in the end of capture parsing loop in
        intel_guc_capture_out_print_next_group that was not
        properly comparing the engine-instance and engine-
        class being parsed against the one that triggered
        the i915_gpu_coredump.
  v3:
      - Fixed all review comments from rev2 except the following:
          - Michal Wajdeczko proposed adding a seperate function
            to lookup register string nameslookup (based on offset)
            but decided against it because of offset conflicts
            and the current table layout is easier to maintain.
          - Last set of checkpatch errors pertaining to "COMPLEX
            MACROS" should be fixed on next rev.
      - Abstracted internal-to-guc-capture information into a new
        __guc_state_capture_priv structure that allows the exclusion
        of intel_guc.h and intel_guc_fwif.h from intel_guc_capture.h.
        Now, only the first 2 patches have a wider build time
        impact because of the changes to intel_guc_fwif.h but
        subsequent changes to guc-capture internal structures
        or firmware interfaces used solely by guc-capture module
        shoudn't impact the rest of the driver build.
      - Added missing Gen12LP registers and added slice+subslice
        indices when reporting extended steered registers.
      - Add additional checks to ensure that the GuC reported
        error capture information matches the i915_gpu_coredump
        that is being printed before we print out the corresponding
        VMA dumps such as the batch buffer.
   v2:
      - Ignore - failed CI retest.


Alan Previn (10):
  drm/i915/guc: Update GuC ADS size for error capture lists
  drm/i915/guc: Add XE_LP registers for GuC error state capture.
  drm/i915/guc: Add DG2 registers for GuC error state capture.
  drm/i915/guc: Add Gen9 registers for GuC error state capture.
  drm/i915/guc: Add GuC's error state capture output structures.
  drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  drm/i915/guc: Extract GuC error capture lists on G2H notification.
  drm/i915/guc: Plumb GuC-capture into gpu_coredump
  drm/i915/guc: Follow legacy register names
  drm/i915/guc: Print the GuC error capture output register list.

 drivers/gpu/drm/i915/Makefile                 |    1 +
 drivers/gpu/drm/i915/gt/intel_engine_cs.c     |    4 +-
 .../drm/i915/gt/intel_execlists_submission.c  |    4 +-
 drivers/gpu/drm/i915/gt/intel_reset.c         |    2 +-
 .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h  |    7 +
 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |  121 ++
 drivers/gpu/drm/i915/gt/uc/intel_guc.c        |   13 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   13 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c    |   36 +-
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 1478 +++++++++++++++++
 .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   31 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |   21 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    |  155 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |   20 +-
 .../gpu/drm/i915/gt/uc/intel_guc_submission.c |   16 +-
 drivers/gpu/drm/i915/i915_debugfs.c           |    3 +-
 drivers/gpu/drm/i915/i915_gpu_error.c         |  279 +++-
 drivers/gpu/drm/i915/i915_gpu_error.h         |   36 +-
 18 files changed, 2035 insertions(+), 205 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
 create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
 create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-01-26 18:09   ` Jani Nikula
                     ` (2 more replies)
  -1 siblings, 3 replies; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Update GuC ADS size allocation to include space for
the lists of error state capture register descriptors.

Also, populate the lists of registers we want GuC to report back to
Host on engine reset events. This list should include global,
engine-class and engine-instance registers for every engine-class
type on the current hardware.

NOTE: Start with a sample table of register lists to layout the
framework before adding real registers in subsequent patch.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |  36 ++
 drivers/gpu/drm/i915/gt/uc/intel_guc.c        |  13 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc.h        |  11 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c    |  36 +-
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 450 ++++++++++++++++++
 .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |  20 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |  17 +
 8 files changed, 555 insertions(+), 29 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
 create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
 create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index a26e6736bebb..236bcd6cd8ea 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -183,6 +183,7 @@ i915-y += gt/uc/intel_uc.o \
 	  gt/uc/intel_uc_fw.o \
 	  gt/uc/intel_guc.o \
 	  gt/uc/intel_guc_ads.o \
+	  gt/uc/intel_guc_capture.o \
 	  gt/uc/intel_guc_ct.o \
 	  gt/uc/intel_guc_debugfs.o \
 	  gt/uc/intel_guc_fw.o \
diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
new file mode 100644
index 000000000000..15b8c02b8a76
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021-2021 Intel Corporation
+ */
+
+#ifndef _INTEL_GUC_CAPTURE_FWIF_H
+#define _INTEL_GUC_CAPTURE_FWIF_H
+
+#include <linux/types.h>
+#include "intel_guc_fwif.h"
+
+struct intel_guc;
+
+struct __guc_mmio_reg_descr {
+	i915_reg_t reg;
+	u32 flags;
+	u32 mask;
+	const char *regname;
+};
+
+struct __guc_mmio_reg_descr_group {
+	struct __guc_mmio_reg_descr *list;
+	u32 num_regs;
+	u32 owner; /* see enum guc_capture_owner */
+	u32 type; /* see enum guc_capture_type */
+	u32 engine; /* as per MAX_ENGINE_CLASS */
+};
+
+struct __guc_state_capture_priv {
+	struct __guc_mmio_reg_descr_group *reglists;
+	u16 num_instance_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
+	u16 num_class_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
+	u16 num_global_regs[GUC_CAPTURE_LIST_INDEX_MAX];
+};
+
+#endif /* _INTEL_GUC_CAPTURE_FWIF_H */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
index ba2a67f9e500..d035a3ba8700 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
@@ -8,8 +8,9 @@
 #include "gt/intel_gt_irq.h"
 #include "gt/intel_gt_pm_irq.h"
 #include "intel_guc.h"
-#include "intel_guc_slpc.h"
 #include "intel_guc_ads.h"
+#include "intel_guc_capture.h"
+#include "intel_guc_slpc.h"
 #include "intel_guc_submission.h"
 #include "i915_drv.h"
 #include "i915_irq.h"
@@ -361,9 +362,14 @@ int intel_guc_init(struct intel_guc *guc)
 	if (ret)
 		goto err_fw;
 
-	ret = intel_guc_ads_create(guc);
+	ret = intel_guc_capture_init(guc);
 	if (ret)
 		goto err_log;
+
+	ret = intel_guc_ads_create(guc);
+	if (ret)
+		goto err_capture;
+
 	GEM_BUG_ON(!guc->ads_vma);
 
 	ret = intel_guc_ct_init(&guc->ct);
@@ -402,6 +408,8 @@ int intel_guc_init(struct intel_guc *guc)
 	intel_guc_ct_fini(&guc->ct);
 err_ads:
 	intel_guc_ads_destroy(guc);
+err_capture:
+	intel_guc_capture_destroy(guc);
 err_log:
 	intel_guc_log_destroy(&guc->log);
 err_fw:
@@ -429,6 +437,7 @@ void intel_guc_fini(struct intel_guc *guc)
 	intel_guc_ct_fini(&guc->ct);
 
 	intel_guc_ads_destroy(guc);
+	intel_guc_capture_destroy(guc);
 	intel_guc_log_destroy(&guc->log);
 	intel_uc_fw_fini(&guc->fw);
 }
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index 697d9d66acef..4e819853ec2e 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -9,18 +9,19 @@
 #include <linux/xarray.h>
 #include <linux/delay.h>
 
-#include "intel_uncore.h"
+#include "intel_guc_ct.h"
 #include "intel_guc_fw.h"
 #include "intel_guc_fwif.h"
-#include "intel_guc_ct.h"
 #include "intel_guc_log.h"
 #include "intel_guc_reg.h"
 #include "intel_guc_slpc_types.h"
 #include "intel_uc_fw.h"
+#include "intel_uncore.h"
 #include "i915_utils.h"
 #include "i915_vma.h"
 
 struct __guc_ads_blob;
+struct __guc_state_capture_priv;
 
 /**
  * struct intel_guc - Top level structure of GuC.
@@ -37,6 +38,10 @@ struct intel_guc {
 	struct intel_guc_ct ct;
 	/** @slpc: sub-structure containing SLPC related data and objects */
 	struct intel_guc_slpc slpc;
+	/** @capture: the error-state-capture module's data and objects */
+	struct intel_guc_state_capture {
+		struct __guc_state_capture_priv *priv;
+	} capture;
 
 	/** @sched_engine: Global engine used to submit requests to GuC */
 	struct i915_sched_engine *sched_engine;
@@ -152,6 +157,8 @@ struct intel_guc {
 	u32 ads_regset_size;
 	/** @ads_golden_ctxt_size: size of the golden contexts in the ADS */
 	u32 ads_golden_ctxt_size;
+	/** @ads_capture_size: size of register lists in the ADS used for error capture */
+	u32 ads_capture_size;
 	/** @ads_engine_usage_size: size of engine usage in the ADS */
 	u32 ads_engine_usage_size;
 
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 668bf4ac9b0c..4597ba0a4177 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -10,6 +10,7 @@
 #include "gt/intel_lrc.h"
 #include "gt/shmem_utils.h"
 #include "intel_guc_ads.h"
+#include "intel_guc_capture.h"
 #include "intel_guc_fwif.h"
 #include "intel_uc.h"
 #include "i915_drv.h"
@@ -72,8 +73,7 @@ static u32 guc_ads_golden_ctxt_size(struct intel_guc *guc)
 
 static u32 guc_ads_capture_size(struct intel_guc *guc)
 {
-	/* FIXME: Allocate a proper capture list */
-	return PAGE_ALIGN(PAGE_SIZE);
+	return PAGE_ALIGN(guc->ads_capture_size);
 }
 
 static u32 guc_ads_private_data_size(struct intel_guc *guc)
@@ -520,26 +520,6 @@ static void guc_init_golden_context(struct intel_guc *guc)
 	GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
 }
 
-static void guc_capture_list_init(struct intel_guc *guc, struct __guc_ads_blob *blob)
-{
-	int i, j;
-	u32 addr_ggtt, offset;
-
-	offset = guc_ads_capture_offset(guc);
-	addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
-
-	/* FIXME: Populate a proper capture list */
-
-	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
-		for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
-			blob->ads.capture_instance[i][j] = addr_ggtt;
-			blob->ads.capture_class[i][j] = addr_ggtt;
-		}
-
-		blob->ads.capture_global[i] = addr_ggtt;
-	}
-}
-
 static void __guc_ads_init(struct intel_guc *guc)
 {
 	struct intel_gt *gt = guc_to_gt(guc);
@@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
 
 	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
 
-	/* Capture list for hang debug */
-	guc_capture_list_init(guc, blob);
-
+	/* Lists for error capture debug */
+	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
+				     guc_ads_capture_offset(guc), &blob->system_info);
 	/* ADS */
 	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
 	blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
@@ -615,6 +595,12 @@ int intel_guc_ads_create(struct intel_guc *guc)
 		return ret;
 	guc->ads_golden_ctxt_size = ret;
 
+	/* Likewise the capture lists: */
+	ret = intel_guc_capture_prep_lists(guc, NULL, 0, 0, NULL);
+	if (ret < 0)
+		return ret;
+	guc->ads_capture_size = ret;
+
 	/* Now the total size can be determined: */
 	size = guc_ads_blob_size(guc);
 
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
new file mode 100644
index 000000000000..06873d617b8b
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021-2021 Intel Corporation
+ */
+
+#include <linux/types.h>
+
+#include <drm/drm_print.h>
+
+#include "gt/intel_engine_regs.h"
+#include "gt/intel_gt.h"
+#include "guc_capture_fwif.h"
+#include "intel_guc_fwif.h"
+#include "i915_drv.h"
+#include "i915_memcpy.h"
+
+/*
+ * Define all device tables of GuC error capture register lists
+ * NOTE: For engine-registers, GuC only needs the register offsets
+ *       from the engine-mmio-base
+ */
+/* XE_LPD - Global */
+static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
+	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
+};
+
+/* XE_LPD - Render / Compute Per-Class */
+static struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
+	{EIR,                      0,      0, "EIR"}
+};
+
+/* XE_LPD - Render / Compute Per-Engine-Instance */
+static struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
+	{RING_HEAD(0),             0,      0, "RING_HEAD"},
+	{RING_TAIL(0),             0,      0, "RING_TAIL"},
+};
+
+/* XE_LPD - Media Decode/Encode Per-Class */
+static struct __guc_mmio_reg_descr xe_lpd_vd_class_regs[] = {
+};
+
+/* XE_LPD - Media Decode/Encode Per-Engine-Instance */
+static struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
+	{RING_HEAD(0),             0,      0, "RING_HEAD"},
+	{RING_TAIL(0),             0,      0, "RING_TAIL"},
+};
+
+/* XE_LPD - Video Enhancement Per-Class */
+static struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
+};
+
+/* XE_LPD - Video Enhancement Per-Engine-Instance */
+static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
+	{RING_HEAD(0),             0,      0, "RING_HEAD"},
+	{RING_TAIL(0),             0,      0, "RING_TAIL"},
+};
+
+#define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
+#define TO_GCAP_DEF_TYPE(x) (GUC_CAPTURE_LIST_TYPE_##x)
+#define MAKE_REGLIST(regslist, regsowner, regstype, class) \
+	{ \
+		.list = regslist, \
+		.num_regs = ARRAY_SIZE(regslist), \
+		.owner = TO_GCAP_DEF_OWNER(regsowner), \
+		.type = TO_GCAP_DEF_TYPE(regstype), \
+		.engine = class, \
+	}
+
+/* List of lists */
+static struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
+	MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
+	MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
+	MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
+	MAKE_REGLIST(xe_lpd_vd_class_regs, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
+	MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
+	MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
+	MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
+	{}
+};
+
+static struct __guc_mmio_reg_descr_group *
+guc_capture_get_device_reglist(struct intel_guc *guc)
+{
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+
+	if (IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915) ||
+	    IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) {
+		/*
+		 * For certain engine classes, there are slice and subslice
+		 * level registers requiring steering. We allocate and populate
+		 * these at init time based on hw config add it as an extension
+		 * list at the end of the pre-populated render list.
+		 */
+		return xe_lpd_lists;
+	}
+
+	return NULL;
+}
+
+static struct __guc_mmio_reg_descr_group *
+guc_capture_get_one_list(struct __guc_mmio_reg_descr_group *reglists, u32 owner, u32 type, u32 id)
+{
+	int i;
+
+	if (!reglists)
+		return NULL;
+
+	for (i = 0; reglists[i].list; i++) {
+		if (reglists[i].owner == owner && reglists[i].type == type &&
+		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
+		return &reglists[i];
+	}
+
+	return NULL;
+}
+
+static const char *
+guc_capture_stringify_owner(u32 owner)
+{
+	switch (owner) {
+	case GUC_CAPTURE_LIST_INDEX_PF:
+		return "PF";
+	case GUC_CAPTURE_LIST_INDEX_VF:
+		return "VF";
+	default:
+		return "unknown";
+	}
+
+	return "";
+}
+
+static const char *
+guc_capture_stringify_type(u32 type)
+{
+	switch (type) {
+	case GUC_CAPTURE_LIST_TYPE_GLOBAL:
+		return "Global";
+	case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
+		return "Class";
+	case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
+		return "Instance";
+	default:
+		return "unknown";
+	}
+
+	return "";
+}
+
+static const char *
+guc_capture_stringify_engclass(u32 class)
+{
+	switch (class) {
+	case GUC_RENDER_CLASS:
+		return "Render";
+	case GUC_VIDEO_CLASS:
+		return "Video";
+	case GUC_VIDEOENHANCE_CLASS:
+		return "VideoEnhance";
+	case GUC_BLITTER_CLASS:
+		return "Blitter";
+	case GUC_RESERVED_CLASS:
+		return "Reserved";
+	default:
+		return "unknown";
+	}
+
+	return "";
+}
+
+static void
+guc_capture_warn_with_list_info(struct drm_i915_private *i915, char *msg,
+				u32 owner, u32 type, u32 classid)
+{
+	if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
+		drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers.\n", msg,
+			guc_capture_stringify_owner(owner), guc_capture_stringify_type(type));
+	else
+		drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers on %s-Engine\n", msg,
+			guc_capture_stringify_owner(owner), guc_capture_stringify_type(type),
+			guc_capture_stringify_engclass(classid));
+}
+
+static int
+guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
+		      struct guc_mmio_reg *ptr, u16 num_entries)
+{
+	u32 j = 0;
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
+	struct __guc_mmio_reg_descr_group *match;
+
+	if (!reglists)
+		return -ENODEV;
+
+	match = guc_capture_get_one_list(reglists, owner, type, classid);
+	if (match) {
+		for (j = 0; j < num_entries && j < match->num_regs; ++j) {
+			ptr[j].offset = match->list[j].reg.reg;
+			ptr[j].value = 0xDEADF00D;
+			ptr[j].flags = match->list[j].flags;
+			ptr[j].mask = match->list[j].mask;
+		}
+		return 0;
+	}
+
+	guc_capture_warn_with_list_info(i915, "Missing register list init", owner, type,
+					classid);
+
+	return -ENODATA;
+}
+
+static int
+guc_capture_fill_reglist(struct intel_guc *guc, struct guc_ads *ads,
+			 u32 owner, int type, int classid, u16 numregs,
+			 u8 **p_virt, u32 *p_ggtt, u32 null_ggtt)
+{
+	struct guc_debug_capture_list *listnode;
+	u32 *p_capturelist_ggtt;
+	int size = 0;
+
+	/*
+	 * For enabled capture lists, we not only need to call capture module to help
+	 * populate the list-descriptor into the correct ads capture structures, but
+	 * we also need to increment the virtual pointers and ggtt offsets so that
+	 * caller has the subsequent gfx memory location.
+	 */
+	size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
+			  (numregs * sizeof(struct guc_mmio_reg)));
+	/* if caller hasn't allocated ADS blob, return size and counts, we're done */
+	if (!ads)
+		return size;
+
+	/*
+	 * If caller allocated ADS blob, populate the capture register descriptors into
+	 * the designated ADS location based on list-owner, list-type and engine-classid
+	 */
+	if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
+		p_capturelist_ggtt = &ads->capture_global[owner];
+	else if (type == GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS)
+		p_capturelist_ggtt = &ads->capture_class[owner][classid];
+	else /*GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE*/
+		p_capturelist_ggtt = &ads->capture_instance[owner][classid];
+
+	if (!numregs) {
+		*p_capturelist_ggtt = null_ggtt;
+	} else {
+		/* get ptr and populate header info: */
+		*p_capturelist_ggtt = *p_ggtt;
+		listnode = (struct guc_debug_capture_list *)*p_virt;
+		*p_ggtt += sizeof(struct guc_debug_capture_list);
+		*p_virt += sizeof(struct guc_debug_capture_list);
+		listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, numregs);
+
+		/* get ptr and populate register descriptor list: */
+		guc_capture_list_init(guc, owner, type, classid,
+				      (struct guc_mmio_reg *)*p_virt,
+				      numregs);
+
+		/* increment ptrs for that header: */
+		*p_ggtt += size - sizeof(struct guc_debug_capture_list);
+		*p_virt += size - sizeof(struct guc_debug_capture_list);
+	}
+
+	return size;
+}
+
+static int
+guc_capture_list_count(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
+		       u16 *num_entries)
+{
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
+	struct __guc_mmio_reg_descr_group *match;
+
+	if (!reglists)
+		return -ENODEV;
+
+	match = guc_capture_get_one_list(reglists, owner, type, classid);
+	if (!match) {
+		guc_capture_warn_with_list_info(i915, "Missing register list size",
+						owner, type, classid);
+		return -ENODATA;
+	}
+
+	*num_entries = match->num_regs;
+	return 0;
+}
+
+static void
+guc_capture_fill_engine_enable_masks(struct intel_gt *gt,
+				     struct guc_gt_system_info *info)
+{
+	info->engine_enabled_masks[GUC_RENDER_CLASS] = 1;
+	info->engine_enabled_masks[GUC_BLITTER_CLASS] = 1;
+	info->engine_enabled_masks[GUC_VIDEO_CLASS] = VDBOX_MASK(gt);
+	info->engine_enabled_masks[GUC_VIDEOENHANCE_CLASS] = VEBOX_MASK(gt);
+}
+
+int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
+				 u32 capture_offset, struct guc_gt_system_info *sysinfo)
+{
+	struct intel_gt *gt = guc_to_gt(guc);
+	struct guc_gt_system_info *info, local_info;
+	struct guc_debug_capture_list *listnode;
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+	struct __guc_state_capture_priv *gc = guc->capture.priv;
+	int i, j, size;
+	u32 ggtt, null_ggtt, alloc_size = 0;
+	u16 tmpnumreg = 0;
+	u8 *ptr = NULL;
+
+	GEM_BUG_ON(!gc);
+
+	if (blob) {
+		ptr = ((u8 *)blob) + capture_offset;
+		ggtt = blob_ggtt + capture_offset;
+		GEM_BUG_ON(!sysinfo);
+		info = sysinfo;
+	} else {
+		memset(&local_info, 0, sizeof(local_info));
+		info = &local_info;
+		guc_capture_fill_engine_enable_masks(gt, info);
+	}
+
+	/* first, set aside the first page for a capture_list with zero descriptors */
+	alloc_size = PAGE_SIZE;
+	if (blob) {
+		listnode = (struct guc_debug_capture_list *)ptr;
+		listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, 0);
+		null_ggtt = ggtt;
+		ggtt += PAGE_SIZE;
+		ptr +=  PAGE_SIZE;
+	}
+
+#define COUNT_REGS guc_capture_list_count
+#define FILL_REGS guc_capture_fill_reglist
+#define TYPE_GLOBAL GUC_CAPTURE_LIST_TYPE_GLOBAL
+#define TYPE_CLASS GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS
+#define TYPE_INSTANCE GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE
+#define OWNER2STR guc_capture_stringify_owner
+#define ENGCLS2STR guc_capture_stringify_engclass
+#define TYPE2STR guc_capture_stringify_type
+
+	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
+		for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
+			if (!info->engine_enabled_masks[j]) {
+				if (gc->num_class_regs[i][j])
+					drm_warn(&i915->drm, "GuC-Cap %s's %s class-"
+						 "list enable mismatch was=%d now off\n",
+						 OWNER2STR(i), ENGCLS2STR(j),
+						 gc->num_class_regs[i][j]);
+				if (gc->num_instance_regs[i][j])
+					drm_warn(&i915->drm, "GuC-Cap %s's %s inst-"
+						 "list enable mismatch was=%d now off!\n",
+						 OWNER2STR(i), ENGCLS2STR(j),
+						 gc->num_instance_regs[i][j]);
+				gc->num_class_regs[i][j] = 0;
+				gc->num_instance_regs[i][j] = 0;
+				if (blob) {
+					blob->capture_class[i][j] = null_ggtt;
+					blob->capture_instance[i][j] = null_ggtt;
+				}
+			} else {
+				if (!COUNT_REGS(guc, i, TYPE_CLASS, j, &tmpnumreg)) {
+					if (blob && tmpnumreg > gc->num_class_regs[i][j]) {
+						drm_warn(&i915->drm, "GuC-Cap %s's %s-%s-list "
+							 "count overflow cap from %d to %d",
+							 OWNER2STR(i), ENGCLS2STR(j),
+							 TYPE2STR(TYPE_CLASS),
+							 gc->num_class_regs[i][j], tmpnumreg);
+						tmpnumreg = gc->num_class_regs[i][j];
+					}
+					size = FILL_REGS(guc, blob, i, TYPE_CLASS, j,
+							 tmpnumreg, &ptr, &ggtt, null_ggtt);
+					alloc_size += size;
+					gc->num_class_regs[i][j] = tmpnumreg;
+				} else {
+					gc->num_class_regs[i][j] = 0;
+					if (blob)
+						blob->capture_class[i][j] = null_ggtt;
+				}
+				if (!COUNT_REGS(guc, i, TYPE_INSTANCE, j, &tmpnumreg)) {
+					if (blob && tmpnumreg > gc->num_instance_regs[i][j]) {
+						drm_warn(&i915->drm, "GuC-Cap %s's %s-%s-list "
+							 "count overflow cap from %d to %d",
+							 OWNER2STR(i), ENGCLS2STR(j),
+							 TYPE2STR(TYPE_INSTANCE),
+							 gc->num_instance_regs[i][j], tmpnumreg);
+						tmpnumreg = gc->num_instance_regs[i][j];
+					}
+					size = FILL_REGS(guc, blob, i, TYPE_INSTANCE, j,
+							 tmpnumreg, &ptr, &ggtt, null_ggtt);
+					alloc_size += size;
+					gc->num_instance_regs[i][j] = tmpnumreg;
+				} else {
+					gc->num_instance_regs[i][j] = 0;
+					if (blob)
+						blob->capture_instance[i][j] = null_ggtt;
+				}
+			}
+		}
+		if (!COUNT_REGS(guc, i, TYPE_GLOBAL, 0, &tmpnumreg)) {
+			if (blob && tmpnumreg > gc->num_global_regs[i]) {
+				drm_warn(&i915->drm, "GuC-Cap %s's %s-list count increased from %d to %d",
+					 OWNER2STR(i), TYPE2STR(TYPE_GLOBAL),
+					 gc->num_global_regs[i], tmpnumreg);
+				tmpnumreg = gc->num_global_regs[i];
+			}
+			size = FILL_REGS(guc, blob, i, TYPE_GLOBAL, 0, tmpnumreg,
+					 &ptr, &ggtt, null_ggtt);
+			alloc_size += size;
+			gc->num_global_regs[i] = tmpnumreg;
+		} else {
+			gc->num_global_regs[i] = 0;
+			if (blob)
+				blob->capture_global[i] = null_ggtt;
+		}
+	}
+
+#undef COUNT_REGS
+#undef FILL_REGS
+#undef TYPE_GLOBAL
+#undef TYPE_CLASS
+#undef TYPE_INSTANCE
+#undef OWNER2STR
+#undef ENGCLS2STR
+#undef TYPE2STR
+
+	if (guc->ads_capture_size && guc->ads_capture_size != PAGE_ALIGN(alloc_size))
+		drm_warn(&i915->drm, "GuC->ADS->Capture alloc size changed from %d to %d\n",
+			 guc->ads_capture_size, PAGE_ALIGN(alloc_size));
+
+	return PAGE_ALIGN(alloc_size);
+}
+
+void intel_guc_capture_destroy(struct intel_guc *guc)
+{
+	kfree(guc->capture.priv);
+	guc->capture.priv = NULL;
+}
+
+int intel_guc_capture_init(struct intel_guc *guc)
+{
+	guc->capture.priv = kzalloc(sizeof(*guc->capture.priv), GFP_KERNEL);
+	if (!guc->capture.priv)
+		return -ENOMEM;
+	guc->capture.priv->reglists = guc_capture_get_device_reglist(guc);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
new file mode 100644
index 000000000000..6b5594ca529d
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021-2021 Intel Corporation
+ */
+
+#ifndef _INTEL_GUC_CAPTURE_H
+#define _INTEL_GUC_CAPTURE_H
+
+#include <linux/types.h>
+
+struct intel_guc;
+struct guc_ads;
+struct guc_gt_system_info;
+
+int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
+				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
+void intel_guc_capture_destroy(struct intel_guc *guc);
+int intel_guc_capture_init(struct intel_guc *guc);
+
+#endif /* _INTEL_GUC_CAPTURE_H */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
index 6a4612a852e2..92bfe25a5e85 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
@@ -297,6 +297,23 @@ enum {
 	GUC_CAPTURE_LIST_INDEX_MAX = 2,
 };
 
+/*Register-types of GuC capture register lists */
+enum guc_capture_type {
+	GUC_CAPTURE_LIST_TYPE_GLOBAL = 0,
+	GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
+	GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
+	GUC_CAPTURE_LIST_TYPE_MAX,
+};
+
+struct guc_debug_capture_list_header {
+	u32 info;
+		#define GUC_CAPTURELISTHDR_NUMDESCR GENMASK(15, 0)
+} __packed;
+
+struct guc_debug_capture_list {
+	struct guc_debug_capture_list_header header;
+} __packed;
+
 /* GuC Additional Data Struct */
 struct guc_ads {
 	struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS];
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 02/10] drm/i915/guc: Add XE_LP registers for GuC error state capture.
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
  (?)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-01-26 18:13   ` Jani Nikula
  -1 siblings, 1 reply; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Add device specific tables and register lists to cover different engines
class types for GuC error state capture for XE_LP products.

Also, add runtime allocation and freeing of extended register lists
for registers that need steering identifiers that depend on
the detected HW config.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |   2 +
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 207 +++++++++++++++---
 drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |   4 +-
 3 files changed, 180 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
index 15b8c02b8a76..a2f97d04ff18 100644
--- a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
@@ -24,6 +24,8 @@ struct __guc_mmio_reg_descr_group {
 	u32 owner; /* see enum guc_capture_owner */
 	u32 type; /* see enum guc_capture_type */
 	u32 engine; /* as per MAX_ENGINE_CLASS */
+	int num_ext;
+	struct __guc_mmio_reg_descr *ext;
 };
 
 struct __guc_state_capture_priv {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 06873d617b8b..b6882074fc8d 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -19,40 +19,101 @@
  * NOTE: For engine-registers, GuC only needs the register offsets
  *       from the engine-mmio-base
  */
+#define COMMON_GEN12BASE_GLOBAL() \
+	{GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0"}, \
+	{GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1"}, \
+	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}, \
+	{GEN12_AUX_ERR_DBG,        0,      0, "GEN12_AUX_ERR_DBG"}, \
+	{GEN12_GAM_DONE,           0,      0, "GEN12_GAM_DONE"}, \
+	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
+
+#define COMMON_GEN12BASE_ENGINE_INSTANCE() \
+	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
+	{RING_ESR(0),              0,      0, "RING_ESR"}, \
+	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \
+	{RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UP32"}, \
+	{RING_IPEIR(0),            0,      0, "RING_IPEIR"}, \
+	{RING_IPEHR(0),            0,      0, "RING_IPEHR"}, \
+	{RING_INSTPS(0),           0,      0, "RING_INSTPS"}, \
+	{RING_BBADDR(0),           0,      0, "RING_BBADDR_LOW32"}, \
+	{RING_BBADDR_UDW(0),       0,      0, "RING_BBADDR_UP32"}, \
+	{RING_BBSTATE(0),          0,      0, "RING_BBSTATE"}, \
+	{CCID(0),                  0,      0, "CCID"}, \
+	{RING_ACTHD(0),            0,      0, "RING_ACTHD_LOW32"}, \
+	{RING_ACTHD_UDW(0),        0,      0, "RING_ACTHD_UP32"}, \
+	{RING_INSTPM(0),           0,      0, "RING_INSTPM"}, \
+	{RING_NOPID(0),            0,      0, "RING_NOPID"}, \
+	{RING_START(0),            0,      0, "RING_START"}, \
+	{RING_HEAD(0),             0,      0, "RING_HEAD"}, \
+	{RING_TAIL(0),             0,      0, "RING_TAIL"}, \
+	{RING_CTL(0),              0,      0, "RING_CTL"}, \
+	{RING_MI_MODE(0),          0,      0, "RING_MI_MODE"}, \
+	{RING_CONTEXT_CONTROL(0),  0,      0, "RING_CONTEXT_CONTROL"}, \
+	{RING_INSTDONE(0),         0,      0, "RING_INSTDONE"}, \
+	{RING_HWS_PGA(0),          0,      0, "RING_HWS_PGA"}, \
+	{RING_MODE_GEN7(0),        0,      0, "RING_MODE_GEN7"}, \
+	{GEN8_RING_PDP_LDW(0, 0),  0,      0, "GEN8_RING_PDP0_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 0),  0,      0, "GEN8_RING_PDP0_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 1),  0,      0, "GEN8_RING_PDP1_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 1),  0,      0, "GEN8_RING_PDP1_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 2),  0,      0, "GEN8_RING_PDP2_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 2),  0,      0, "GEN8_RING_PDP2_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "GEN8_RING_PDP3_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "GEN8_RING_PDP3_UDW"}
+
+#define COMMON_GEN12BASE_HAS_EU() \
+	{EIR,                      0,      0, "EIR"}
+
+#define COMMON_GEN12BASE_RENDER() \
+	{GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE"}, \
+	{GEN12_SC_INSTDONE_EXTRA,  0,      0, "GEN12_SC_INSTDONE_EXTRA"}, \
+	{GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2"}
+
+#define COMMON_GEN12BASE_VEC() \
+	{GEN12_SFC_DONE(0),        0,      0, "GEN12_SFC_DONE0"}, \
+	{GEN12_SFC_DONE(1),        0,      0, "GEN12_SFC_DONE1"}, \
+	{GEN12_SFC_DONE(2),        0,      0, "GEN12_SFC_DONE2"}, \
+	{GEN12_SFC_DONE(3),        0,      0, "GEN12_SFC_DONE3"}
+
 /* XE_LPD - Global */
 static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
-	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
+	COMMON_GEN12BASE_GLOBAL(),
 };
 
 /* XE_LPD - Render / Compute Per-Class */
 static struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
-	{EIR,                      0,      0, "EIR"}
+	COMMON_GEN12BASE_HAS_EU(),
+	COMMON_GEN12BASE_RENDER(),
 };
 
 /* XE_LPD - Render / Compute Per-Engine-Instance */
 static struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
-	{RING_HEAD(0),             0,      0, "RING_HEAD"},
-	{RING_TAIL(0),             0,      0, "RING_TAIL"},
-};
-
-/* XE_LPD - Media Decode/Encode Per-Class */
-static struct __guc_mmio_reg_descr xe_lpd_vd_class_regs[] = {
+	COMMON_GEN12BASE_ENGINE_INSTANCE(),
 };
 
 /* XE_LPD - Media Decode/Encode Per-Engine-Instance */
 static struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
-	{RING_HEAD(0),             0,      0, "RING_HEAD"},
-	{RING_TAIL(0),             0,      0, "RING_TAIL"},
+	COMMON_GEN12BASE_ENGINE_INSTANCE(),
 };
 
 /* XE_LPD - Video Enhancement Per-Class */
 static struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
+	COMMON_GEN12BASE_VEC(),
 };
 
 /* XE_LPD - Video Enhancement Per-Engine-Instance */
 static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
-	{RING_HEAD(0),             0,      0, "RING_HEAD"},
-	{RING_TAIL(0),             0,      0, "RING_TAIL"},
+	COMMON_GEN12BASE_ENGINE_INSTANCE(),
+};
+
+/* XE_LPD - Blitter Per-Engine-Instance */
+static struct __guc_mmio_reg_descr xe_lpd_blt_inst_regs[] = {
+	COMMON_GEN12BASE_ENGINE_INSTANCE(),
+};
+
+/* XE_LPD - Blitter Per-Class */
+/* XE_LPD - Media Decode/Encode Per-Class */
+static struct __guc_mmio_reg_descr empty_regs_list[] = {
 };
 
 #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
@@ -64,6 +125,8 @@ static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
 		.owner = TO_GCAP_DEF_OWNER(regsowner), \
 		.type = TO_GCAP_DEF_TYPE(regstype), \
 		.engine = class, \
+		.num_ext = 0, \
+		.ext = NULL, \
 	}
 
 /* List of lists */
@@ -71,13 +134,96 @@ static struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
 	MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
 	MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
 	MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
-	MAKE_REGLIST(xe_lpd_vd_class_regs, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
 	MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
 	MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
 	MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
+	MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
 	{}
 };
 
+static struct __guc_mmio_reg_descr_group *
+guc_capture_get_one_list(struct __guc_mmio_reg_descr_group *reglists, u32 owner, u32 type, u32 id)
+{
+	int i;
+
+	if (!reglists)
+		return NULL;
+
+	for (i = 0; reglists[i].list; i++) {
+		if (reglists[i].owner == owner && reglists[i].type == type &&
+		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
+		return &reglists[i];
+	}
+
+	return NULL;
+}
+
+static void guc_capture_clear_ext_regs(struct __guc_mmio_reg_descr_group *lists)
+{
+	while (lists->list) {
+		kfree(lists->ext);
+		lists->ext = NULL;
+		++lists;
+	}
+}
+
+struct __ext_steer_reg {
+	const char *name;
+	i915_reg_t reg;
+};
+
+static struct __ext_steer_reg xelpd_extregs[] = {
+	{"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE},
+	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
+};
+
+static void
+guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
+				     struct __guc_mmio_reg_descr_group *lists)
+{
+	struct intel_gt *gt = guc_to_gt(guc);
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+	struct sseu_dev_info *sseu;
+	int slice, subslice, i, num_tot_regs = 0;
+	struct __guc_mmio_reg_descr_group *list;
+	struct __guc_mmio_reg_descr *extarray;
+	int num_steer_regs = ARRAY_SIZE(xelpd_extregs);
+
+	/* In XE_LP we only care about render-class steering registers during error-capture */
+	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
+					GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, GUC_RENDER_CLASS);
+	if (!list)
+		return;
+
+	if (list->ext)
+		return; /* already populated */
+
+	sseu = &gt->info.sseu;
+	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
+		num_tot_regs += num_steer_regs;
+	}
+	if (!num_tot_regs)
+		return;
+
+	list->ext = kcalloc(num_tot_regs, sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL);
+	if (!list->ext)
+		return;
+
+	extarray = list->ext;
+	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
+		for (i = 0; i < num_steer_regs; i++) {
+			extarray->reg = xelpd_extregs[i].reg;
+			extarray->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice);
+			extarray->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice);
+			extarray->regname = xelpd_extregs[i].name;
+			++extarray;
+		}
+	}
+	list->num_ext = num_tot_regs;
+}
+
 static struct __guc_mmio_reg_descr_group *
 guc_capture_get_device_reglist(struct intel_guc *guc)
 {
@@ -91,29 +237,13 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
 		 * these at init time based on hw config add it as an extension
 		 * list at the end of the pre-populated render list.
 		 */
+		guc_capture_alloc_steered_list_xelpd(guc, xe_lpd_lists);
 		return xe_lpd_lists;
 	}
 
 	return NULL;
 }
 
-static struct __guc_mmio_reg_descr_group *
-guc_capture_get_one_list(struct __guc_mmio_reg_descr_group *reglists, u32 owner, u32 type, u32 id)
-{
-	int i;
-
-	if (!reglists)
-		return NULL;
-
-	for (i = 0; reglists[i].list; i++) {
-		if (reglists[i].owner == owner && reglists[i].type == type &&
-		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
-		return &reglists[i];
-	}
-
-	return NULL;
-}
-
 static const char *
 guc_capture_stringify_owner(u32 owner)
 {
@@ -184,7 +314,7 @@ static int
 guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
 		      struct guc_mmio_reg *ptr, u16 num_entries)
 {
-	u32 j = 0;
+	u32 j = 0, k = 0;
 	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
 	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
 	struct __guc_mmio_reg_descr_group *match;
@@ -200,6 +330,18 @@ guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
 			ptr[j].flags = match->list[j].flags;
 			ptr[j].mask = match->list[j].mask;
 		}
+		if (match->ext) {
+			for (j = match->num_regs, k = 0; j < num_entries &&
+			     j < (match->num_regs + match->num_ext); ++j, ++k) {
+				ptr[j].offset = match->ext[k].reg.reg;
+				ptr[j].value = 0xDEADF00D;
+				ptr[j].flags = match->ext[k].flags;
+				ptr[j].mask = match->ext[k].mask;
+			}
+		}
+		if (j < num_entries)
+			drm_dbg(&i915->drm, "GuC-capture: Init reglist short %d out %d.\n",
+				(int)j, (int)num_entries);
 		return 0;
 	}
 
@@ -282,7 +424,7 @@ guc_capture_list_count(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
 		return -ENODATA;
 	}
 
-	*num_entries = match->num_regs;
+	*num_entries = match->num_regs + match->num_ext;
 	return 0;
 }
 
@@ -435,6 +577,7 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
 
 void intel_guc_capture_destroy(struct intel_guc *guc)
 {
+	guc_capture_clear_ext_regs(guc->capture.priv->reglists);
 	kfree(guc->capture.priv);
 	guc->capture.priv = NULL;
 }
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
index 92bfe25a5e85..50fcd987f2a2 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
@@ -271,10 +271,12 @@ struct guc_mmio_reg {
 	u32 offset;
 	u32 value;
 	u32 flags;
-	u32 mask;
 #define GUC_REGSET_MASKED		BIT(0)
 #define GUC_REGSET_MASKED_WITH_VALUE	BIT(2)
 #define GUC_REGSET_RESTORE_ONLY		BIT(3)
+#define GUC_REGSET_STEERING_GROUP       GENMASK(15, 12)
+#define GUC_REGSET_STEERING_INSTANCE    GENMASK(23, 20)
+	u32 mask;
 } __packed;
 
 /* GuC register sets */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 03/10] drm/i915/guc: Add DG2 registers for GuC error state capture.
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (2 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-02-05  1:28   ` Umesh Nerlige Ramappa
  -1 siblings, 1 reply; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Add additional DG2 registers for GuC error state capture.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 64 ++++++++++++++-----
 1 file changed, 49 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index b6882074fc8d..19719daffed4 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -179,19 +179,23 @@ static struct __ext_steer_reg xelpd_extregs[] = {
 	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
 };
 
+static struct __ext_steer_reg xehpg_extregs[] = {
+	{"XEHPG_INSTDONE_GEOM_SVG", XEHPG_INSTDONE_GEOM_SVG}
+};
+
 static void
-guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
-				     struct __guc_mmio_reg_descr_group *lists)
+guc_capture_alloc_steered_list_xe_lpd_hpg(struct intel_guc *guc,
+					  struct __guc_mmio_reg_descr_group *lists,
+					  u32 ipver)
 {
 	struct intel_gt *gt = guc_to_gt(guc);
 	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
 	struct sseu_dev_info *sseu;
-	int slice, subslice, i, num_tot_regs = 0;
+	int slice, subslice, i, iter, num_steer_regs, num_tot_regs = 0;
 	struct __guc_mmio_reg_descr_group *list;
 	struct __guc_mmio_reg_descr *extarray;
-	int num_steer_regs = ARRAY_SIZE(xelpd_extregs);
 
-	/* In XE_LP we only care about render-class steering registers during error-capture */
+	/* In XE_LP / HPG we only have render-class steering registers during error-capture */
 	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
 					GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, GUC_RENDER_CLASS);
 	if (!list)
@@ -200,10 +204,21 @@ guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
 	if (list->ext)
 		return; /* already populated */
 
+	num_steer_regs = ARRAY_SIZE(xelpd_extregs);
+	if (ipver >= IP_VER(12, 55))
+		num_steer_regs += ARRAY_SIZE(xehpg_extregs);
+
 	sseu = &gt->info.sseu;
-	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
-		num_tot_regs += num_steer_regs;
+	if (ipver >= IP_VER(12, 50)) {
+		for_each_instdone_gslice_dss_xehp(i915, sseu, iter, slice, subslice) {
+			num_tot_regs += num_steer_regs;
+		}
+	} else {
+		for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
+			num_tot_regs += num_steer_regs;
+		}
 	}
+
 	if (!num_tot_regs)
 		return;
 
@@ -212,15 +227,31 @@ guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
 		return;
 
 	extarray = list->ext;
-	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
-		for (i = 0; i < num_steer_regs; i++) {
-			extarray->reg = xelpd_extregs[i].reg;
-			extarray->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice);
-			extarray->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice);
-			extarray->regname = xelpd_extregs[i].name;
-			++extarray;
+
+#define POPULATE_NEXT_EXTREG(ext, list, idx, slicenum, subslicenum) \
+	{ \
+		(ext)->reg = list[idx].reg; \
+		(ext)->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slicenum); \
+		(ext)->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslicenum); \
+		(ext)->regname = xelpd_extregs[i].name; \
+		++(ext); \
+	}
+	if (ipver >= IP_VER(12, 50)) {
+		for_each_instdone_gslice_dss_xehp(i915, sseu, iter, slice, subslice) {
+			for (i = 0; i < ARRAY_SIZE(xelpd_extregs); i++)
+				POPULATE_NEXT_EXTREG(extarray, xelpd_extregs, i, slice, subslice)
+			for (i = 0; i < ARRAY_SIZE(xehpg_extregs) && ipver >= IP_VER(12, 55);
+			     i++)
+				POPULATE_NEXT_EXTREG(extarray, xehpg_extregs, i, slice, subslice)
+		}
+	} else {
+		for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
+			for (i = 0; i < num_steer_regs; i++)
+				POPULATE_NEXT_EXTREG(extarray, xelpd_extregs, i, slice, subslice)
 		}
 	}
+#undef POPULATE_NEXT_EXTREG
+
 	list->num_ext = num_tot_regs;
 }
 
@@ -237,7 +268,10 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
 		 * these at init time based on hw config add it as an extension
 		 * list at the end of the pre-populated render list.
 		 */
-		guc_capture_alloc_steered_list_xelpd(guc, xe_lpd_lists);
+		guc_capture_alloc_steered_list_xe_lpd_hpg(guc, xe_lpd_lists, IP_VER(12, 0));
+		return xe_lpd_lists;
+	} else if (IS_DG2(i915)) {
+		guc_capture_alloc_steered_list_xe_lpd_hpg(guc, xe_lpd_lists, IP_VER(12, 55));
 		return xe_lpd_lists;
 	}
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 04/10] drm/i915/guc: Add Gen9 registers for GuC error state capture.
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (3 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-02-07 19:14   ` Umesh Nerlige Ramappa
  -1 siblings, 1 reply; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Abstract out a Gen9 register list as the default for all other
platforms we don't yet formally support GuC submission on.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 74 +++++++++++++++----
 1 file changed, 58 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 19719daffed4..70d2ee841289 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -19,15 +19,24 @@
  * NOTE: For engine-registers, GuC only needs the register offsets
  *       from the engine-mmio-base
  */
+#define COMMON_BASE_GLOBAL() \
+	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}
+
+#define COMMON_GEN9BASE_GLOBAL() \
+	{GEN8_FAULT_TLB_DATA0,     0,      0, "GEN8_FAULT_TLB_DATA0"}, \
+	{GEN8_FAULT_TLB_DATA1,     0,      0, "GEN8_FAULT_TLB_DATA1"}, \
+	{ERROR_GEN6,               0,      0, "ERROR_GEN6"}, \
+	{DONE_REG,                 0,      0, "DONE_REG"}, \
+	{HSW_GTT_CACHE_EN,         0,      0, "HSW_GTT_CACHE_EN"}
+
 #define COMMON_GEN12BASE_GLOBAL() \
 	{GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0"}, \
 	{GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1"}, \
-	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}, \
 	{GEN12_AUX_ERR_DBG,        0,      0, "GEN12_AUX_ERR_DBG"}, \
 	{GEN12_GAM_DONE,           0,      0, "GEN12_GAM_DONE"}, \
 	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
 
-#define COMMON_GEN12BASE_ENGINE_INSTANCE() \
+#define COMMON_BASE_ENGINE_INSTANCE() \
 	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
 	{RING_ESR(0),              0,      0, "RING_ESR"}, \
 	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \
@@ -61,11 +70,13 @@
 	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "GEN8_RING_PDP3_LDW"}, \
 	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "GEN8_RING_PDP3_UDW"}
 
-#define COMMON_GEN12BASE_HAS_EU() \
+#define COMMON_BASE_HAS_EU() \
 	{EIR,                      0,      0, "EIR"}
 
+#define COMMON_BASE_RENDER() \
+	{GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE"}
+
 #define COMMON_GEN12BASE_RENDER() \
-	{GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE"}, \
 	{GEN12_SC_INSTDONE_EXTRA,  0,      0, "GEN12_SC_INSTDONE_EXTRA"}, \
 	{GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2"}
 
@@ -77,23 +88,26 @@
 
 /* XE_LPD - Global */
 static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
+	COMMON_BASE_GLOBAL(),
+	COMMON_GEN9BASE_GLOBAL(),
 	COMMON_GEN12BASE_GLOBAL(),
 };
 
 /* XE_LPD - Render / Compute Per-Class */
 static struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
-	COMMON_GEN12BASE_HAS_EU(),
+	COMMON_BASE_HAS_EU(),
+	COMMON_BASE_RENDER(),
 	COMMON_GEN12BASE_RENDER(),
 };
 
-/* XE_LPD - Render / Compute Per-Engine-Instance */
+/* GEN9/XE_LPD - Render / Compute Per-Engine-Instance */
 static struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
+	COMMON_BASE_ENGINE_INSTANCE(),
 };
 
-/* XE_LPD - Media Decode/Encode Per-Engine-Instance */
+/* GEN9/XE_LPD - Media Decode/Encode Per-Engine-Instance */
 static struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
+	COMMON_BASE_ENGINE_INSTANCE(),
 };
 
 /* XE_LPD - Video Enhancement Per-Class */
@@ -101,18 +115,33 @@ static struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
 	COMMON_GEN12BASE_VEC(),
 };
 
-/* XE_LPD - Video Enhancement Per-Engine-Instance */
+/* GEN9/XE_LPD - Video Enhancement Per-Engine-Instance */
 static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
+	COMMON_BASE_ENGINE_INSTANCE(),
 };
 
-/* XE_LPD - Blitter Per-Engine-Instance */
+/* GEN9/XE_LPD - Blitter Per-Engine-Instance */
 static struct __guc_mmio_reg_descr xe_lpd_blt_inst_regs[] = {
-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
+	COMMON_BASE_ENGINE_INSTANCE(),
+};
+
+/* GEN9 - Global */
+static struct __guc_mmio_reg_descr default_global_regs[] = {
+	COMMON_BASE_GLOBAL(),
+	COMMON_GEN9BASE_GLOBAL(),
 };
 
-/* XE_LPD - Blitter Per-Class */
-/* XE_LPD - Media Decode/Encode Per-Class */
+static struct __guc_mmio_reg_descr default_rc_class_regs[] = {
+	COMMON_BASE_HAS_EU(),
+	COMMON_BASE_RENDER(),
+};
+
+/*
+ * Empty lists:
+ * GEN9/XE_LPD - Blitter-Class
+ * GEN9/XE_LPD - Media Class
+ * GEN9 - VEC Class
+ */
 static struct __guc_mmio_reg_descr empty_regs_list[] = {
 };
 
@@ -130,6 +159,18 @@ static struct __guc_mmio_reg_descr empty_regs_list[] = {
 	}
 
 /* List of lists */
+static struct __guc_mmio_reg_descr_group default_lists[] = {
+	MAKE_REGLIST(default_global_regs, PF, GLOBAL, 0),
+	MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
+	MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
+	MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
+	MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
+	MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
+	{}
+};
 static struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
 	MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
 	MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
@@ -275,7 +316,8 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
 		return xe_lpd_lists;
 	}
 
-	return NULL;
+	/* if GuC submission is enabled on a non-POR platform, just use a common baseline */
+	return default_lists;
 }
 
 static const char *
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 05/10] drm/i915/guc: Add GuC's error state capture output structures.
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (4 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  -1 siblings, 0 replies; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Add GuC's error capture output structures and definitions as how
they would appear in GuC log buffer's error capture subregion after
an error state capture G2H event notification.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
---
 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
index a2f97d04ff18..495cdb0228c6 100644
--- a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
@@ -28,6 +28,41 @@ struct __guc_mmio_reg_descr_group {
 	struct __guc_mmio_reg_descr *ext;
 };
 
+struct guc_state_capture_header_t {
+	u32 reserved1;
+	u32 info;
+		#define CAP_HDR_CAPTURE_TYPE GENMASK(3, 0) /* see enum guc_capture_type */
+		#define CAP_HDR_ENGINE_CLASS GENMASK(7, 4) /* see GUC_MAX_ENGINE_CLASSES */
+		#define CAP_HDR_ENGINE_INSTANCE GENMASK(11, 8)
+	u32 lrca; /* if type-instance, LRCA (address) that hung, else set to ~0 */
+	u32 guc_id; /* if type-instance, context index of hung context, else set to ~0 */
+	u32 num_mmios;
+		#define CAP_HDR_NUM_MMIOS GENMASK(9, 0)
+} __packed;
+
+struct guc_state_capture_t {
+	struct guc_state_capture_header_t header;
+	struct guc_mmio_reg mmio_entries[0];
+} __packed;
+
+enum guc_capture_group_types {
+	GUC_STATE_CAPTURE_GROUP_TYPE_FULL,
+	GUC_STATE_CAPTURE_GROUP_TYPE_PARTIAL,
+	GUC_STATE_CAPTURE_GROUP_TYPE_MAX,
+};
+
+struct guc_state_capture_group_header_t {
+	u32 reserved1;
+	u32 info;
+		#define CAP_GRP_HDR_NUM_CAPTURES GENMASK(7, 0)
+		#define CAP_GRP_HDR_CAPTURE_TYPE GENMASK(15, 8) /* guc_capture_group_types */
+} __packed;
+
+struct guc_state_capture_group_t {
+	struct guc_state_capture_group_header_t grp_header;
+	struct guc_state_capture_t capture_entries[0];
+} __packed;
+
 struct __guc_state_capture_priv {
 	struct __guc_mmio_reg_descr_group *reglists;
 	u16 num_instance_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (5 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-01-27  4:26   ` Teres Alexis, Alan Previn
  2022-02-04 18:19   ` Matthew Brost
  -1 siblings, 2 replies; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

GuC log buffer regions for debug-log-events, crash-dumps and
error-state-capture are all a single bo allocation that includes
the guc_log_buffer_state structures.

Since the error-capture region is accessed with high priority at non-
deterministic times (as part of gpu coredump) while the debug-log-event
region is populated and accessed with different priorities, timings and
consumers, let's split out separate locks for buffer-state accesses
of each region.

Also, ensure a global mapping is made up front for the entire bo
throughout GuC operation so that dynamic mapping and unmapping isn't
required for error capture log access if relay-logging isn't running.

Additionally, while here, make some readibility improvements:
1. change previous function names with "capture_logs" to
   "copy_debug_logs" to help make the distinction clearer.
2. Update the guc log region mapping comments to order them
   according to the enum definition as per the GuC interface.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
 .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
 5 files changed, 141 insertions(+), 60 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index 4e819853ec2e..be1ad7fa2bf8 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -34,6 +34,8 @@ struct intel_guc {
 	struct intel_uc_fw fw;
 	/** @log: sub-structure containing GuC log related data and objects */
 	struct intel_guc_log log;
+	/** @log_state: states and locks for each subregion of GuC's log buffer */
+	struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];
 	/** @ct: the command transport communication channel */
 	struct intel_guc_ct ct;
 	/** @slpc: sub-structure containing SLPC related data and objects */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 70d2ee841289..e7f99d051636 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
 	return PAGE_ALIGN(alloc_size);
 }
 
+#define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3
+int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
+{
+	struct intel_gt *gt = guc_to_gt(guc);
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+	int worst_min_size = 0, num_regs = 0;
+	u16 tmp = 0;
+
+	/*
+	 * If every single engine-instance suffered a failure in quick succession but
+	 * were all unrelated, then a burst of multiple error-capture events would dump
+	 * registers for every one engine instance, one at a time. In this case, GuC
+	 * would even dump the global-registers repeatedly.
+	 *
+	 * For each engine instance, there would be 1 x guc_state_capture_group_t output
+	 * followed by 3 x guc_state_capture_t lists. The latter is how the register
+	 * dumps are split across different register types (where the '3' are global vs class
+	 * vs instance). Finally, let's multiply the whole thing by 3x (just so we are
+	 * not limited to just 1 round of data in a worst case full register dump log)
+	 *
+	 * NOTE: intel_guc_log that allocates the log buffer would round this size up to
+	 * a power of two.
+	 */
+
+	for_each_engine(engine, gt, id) {
+		worst_min_size += sizeof(struct guc_state_capture_group_header_t) +
+				  (3 * sizeof(struct guc_state_capture_header_t));
+
+		if (!guc_capture_list_count(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp))
+			num_regs += tmp;
+
+		if (!guc_capture_list_count(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
+					    engine->class, &tmp)) {
+			num_regs += tmp;
+		}
+		if (!guc_capture_list_count(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
+					    engine->class, &tmp)) {
+			num_regs += tmp;
+		}
+	}
+
+	worst_min_size += (num_regs * sizeof(struct guc_mmio_reg));
+
+	return (worst_min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER);
+}
+
 void intel_guc_capture_destroy(struct intel_guc *guc)
 {
 	guc_capture_clear_ext_regs(guc->capture.priv->reglists);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
index 6b5594ca529d..4d3e5221128c 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
@@ -14,6 +14,7 @@ struct guc_gt_system_info;
 
 int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
 				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
+int intel_guc_capture_output_min_size_est(struct intel_guc *guc);
 void intel_guc_capture_destroy(struct intel_guc *guc);
 int intel_guc_capture_init(struct intel_guc *guc);
 
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
index b53f61f3101f..d6b1a3c0fb15 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
@@ -6,12 +6,13 @@
 #include <linux/debugfs.h>
 
 #include "gt/intel_gt.h"
+#include "intel_guc_capture.h"
+#include "intel_guc_log.h"
 #include "i915_drv.h"
 #include "i915_irq.h"
 #include "i915_memcpy.h"
-#include "intel_guc_log.h"
 
-static void guc_log_capture_logs(struct intel_guc_log *log);
+static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log);
 
 /**
  * DOC: GuC firmware log
@@ -136,7 +137,7 @@ static void guc_move_to_next_buf(struct intel_guc_log *log)
 	smp_wmb();
 
 	/* All data has been written, so now move the offset of sub buffer. */
-	relay_reserve(log->relay.channel, log->vma->obj->base.size);
+	relay_reserve(log->relay.channel, log->vma->obj->base.size - CAPTURE_BUFFER_SIZE);
 
 	/* Switch to the next sub buffer */
 	relay_flush(log->relay.channel);
@@ -156,25 +157,25 @@ static void *guc_get_write_buffer(struct intel_guc_log *log)
 	return relay_reserve(log->relay.channel, 0);
 }
 
-static bool guc_check_log_buf_overflow(struct intel_guc_log *log,
-				       enum guc_log_buffer_type type,
+static bool guc_check_log_buf_overflow(struct intel_guc *guc,
+				       struct intel_guc_log_stats *log_state,
 				       unsigned int full_cnt)
 {
-	unsigned int prev_full_cnt = log->stats[type].sampled_overflow;
+	unsigned int prev_full_cnt = log_state->sampled_overflow;
 	bool overflow = false;
 
 	if (full_cnt != prev_full_cnt) {
 		overflow = true;
 
-		log->stats[type].overflow = full_cnt;
-		log->stats[type].sampled_overflow += full_cnt - prev_full_cnt;
+		log_state->overflow = full_cnt;
+		log_state->sampled_overflow += full_cnt - prev_full_cnt;
 
 		if (full_cnt < prev_full_cnt) {
 			/* buffer_full_cnt is a 4 bit counter */
-			log->stats[type].sampled_overflow += 16;
+			log_state->sampled_overflow += 16;
 		}
 
-		dev_notice_ratelimited(guc_to_gt(log_to_guc(log))->i915->drm.dev,
+		dev_notice_ratelimited(guc_to_gt(guc)->i915->drm.dev,
 				       "GuC log buffer overflow\n");
 	}
 
@@ -197,8 +198,10 @@ static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
 	return 0;
 }
 
-static void guc_read_update_log_buffer(struct intel_guc_log *log)
+static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
 {
+	struct intel_guc *guc = log_to_guc(log);
+	struct intel_guc_log_stats *logstate;
 	unsigned int buffer_size, read_offset, write_offset, bytes_to_copy, full_cnt;
 	struct guc_log_buffer_state *log_buf_state, *log_buf_snapshot_state;
 	struct guc_log_buffer_state log_buf_state_local;
@@ -212,7 +215,7 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
 		goto out_unlock;
 
 	/* Get the pointer to shared GuC log buffer */
-	log_buf_state = src_data = log->relay.buf_addr;
+	log_buf_state = src_data = log->buf_addr;
 
 	/* Get the pointer to local buffer to store the logs */
 	log_buf_snapshot_state = dst_data = guc_get_write_buffer(log);
@@ -222,7 +225,7 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
 		 * Used rate limited to avoid deluge of messages, logs might be
 		 * getting consumed by User at a slow rate.
 		 */
-		DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n");
+		DRM_ERROR_RATELIMITED("no sub-buffer to copy general logs\n");
 		log->relay.full_count++;
 
 		goto out_unlock;
@@ -232,12 +235,16 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
 	src_data += PAGE_SIZE;
 	dst_data += PAGE_SIZE;
 
-	for (type = GUC_DEBUG_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) {
+	/* For relay logging, we exclude error state capture */
+	for (type = GUC_DEBUG_LOG_BUFFER; type <= GUC_CRASH_DUMP_LOG_BUFFER; type++) {
 		/*
+		 * Get a lock to the buffer_state we want to read and update.
 		 * Make a copy of the state structure, inside GuC log buffer
 		 * (which is uncached mapped), on the stack to avoid reading
 		 * from it multiple times.
 		 */
+		logstate = &guc->log_state[type];
+		mutex_lock(&logstate->lock);
 		memcpy(&log_buf_state_local, log_buf_state,
 		       sizeof(struct guc_log_buffer_state));
 		buffer_size = guc_get_log_buffer_size(type);
@@ -246,13 +253,14 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
 		full_cnt = log_buf_state_local.buffer_full_cnt;
 
 		/* Bookkeeping stuff */
-		log->stats[type].flush += log_buf_state_local.flush_to_file;
-		new_overflow = guc_check_log_buf_overflow(log, type, full_cnt);
+		logstate->flush += log_buf_state_local.flush_to_file;
+		new_overflow = guc_check_log_buf_overflow(guc, logstate, full_cnt);
 
 		/* Update the state of shared log buffer */
 		log_buf_state->read_ptr = write_offset;
 		log_buf_state->flush_to_file = 0;
 		log_buf_state++;
+		mutex_unlock(&logstate->lock);
 
 		/* First copy the state structure in snapshot buffer */
 		memcpy(log_buf_snapshot_state, &log_buf_state_local,
@@ -300,49 +308,49 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
 	mutex_unlock(&log->relay.lock);
 }
 
-static void capture_logs_work(struct work_struct *work)
+static void copy_debug_logs_work(struct work_struct *work)
 {
 	struct intel_guc_log *log =
 		container_of(work, struct intel_guc_log, relay.flush_work);
 
-	guc_log_capture_logs(log);
+	guc_log_copy_debuglogs_for_relay(log);
 }
 
-static int guc_log_map(struct intel_guc_log *log)
+static int guc_log_relay_map(struct intel_guc_log *log)
 {
-	void *vaddr;
-
 	lockdep_assert_held(&log->relay.lock);
 
-	if (!log->vma)
+	if (!log->vma || !log->buf_addr)
 		return -ENODEV;
 
 	/*
-	 * Create a WC (Uncached for read) vmalloc mapping of log
-	 * buffer pages, so that we can directly get the data
-	 * (up-to-date) from memory.
+	 * WC vmalloc mapping of log buffer pages was done at
+	 * GuC Init time, but lets keep a ref for book-keeping
 	 */
-	vaddr = i915_gem_object_pin_map_unlocked(log->vma->obj, I915_MAP_WC);
-	if (IS_ERR(vaddr))
-		return PTR_ERR(vaddr);
-
-	log->relay.buf_addr = vaddr;
+	i915_gem_object_get(log->vma->obj);
+	log->relay.buf_in_use = true;
 
 	return 0;
 }
 
-static void guc_log_unmap(struct intel_guc_log *log)
+static void guc_log_relay_unmap(struct intel_guc_log *log)
 {
 	lockdep_assert_held(&log->relay.lock);
 
-	i915_gem_object_unpin_map(log->vma->obj);
-	log->relay.buf_addr = NULL;
+	i915_gem_object_put(log->vma->obj);
+	log->relay.buf_in_use = false;
 }
 
 void intel_guc_log_init_early(struct intel_guc_log *log)
 {
+	struct intel_guc *guc = log_to_guc(log);
+	int n;
+
+	for (n = GUC_DEBUG_LOG_BUFFER; n < GUC_MAX_LOG_BUFFER; n++)
+		mutex_init(&guc->log_state[n].lock);
+
 	mutex_init(&log->relay.lock);
-	INIT_WORK(&log->relay.flush_work, capture_logs_work);
+	INIT_WORK(&log->relay.flush_work, copy_debug_logs_work);
 	log->relay.started = false;
 }
 
@@ -357,8 +365,11 @@ static int guc_log_relay_create(struct intel_guc_log *log)
 	lockdep_assert_held(&log->relay.lock);
 	GEM_BUG_ON(!log->vma);
 
-	 /* Keep the size of sub buffers same as shared log buffer */
-	subbuf_size = log->vma->size;
+	 /*
+	  * Keep the size of sub buffers same as shared log buffer
+	  * but GuC log-events excludes the error-state-capture logs
+	  */
+	subbuf_size = log->vma->size - CAPTURE_BUFFER_SIZE;
 
 	/*
 	 * Store up to 8 snapshots, which is large enough to buffer sufficient
@@ -393,13 +404,13 @@ static void guc_log_relay_destroy(struct intel_guc_log *log)
 	log->relay.channel = NULL;
 }
 
-static void guc_log_capture_logs(struct intel_guc_log *log)
+static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
 {
 	struct intel_guc *guc = log_to_guc(log);
 	struct drm_i915_private *dev_priv = guc_to_gt(guc)->i915;
 	intel_wakeref_t wakeref;
 
-	guc_read_update_log_buffer(log);
+	_guc_log_copy_debuglogs_for_relay(log);
 
 	/*
 	 * Generally device is expected to be active only at this
@@ -439,6 +450,7 @@ int intel_guc_log_create(struct intel_guc_log *log)
 {
 	struct intel_guc *guc = log_to_guc(log);
 	struct i915_vma *vma;
+	void *vaddr;
 	u32 guc_log_size;
 	int ret;
 
@@ -446,25 +458,29 @@ int intel_guc_log_create(struct intel_guc_log *log)
 
 	/*
 	 *  GuC Log buffer Layout
+	 * (this ordering must follow "enum guc_log_buffer_type" definition)
 	 *
 	 *  +===============================+ 00B
-	 *  |    Crash dump state header    |
-	 *  +-------------------------------+ 32B
 	 *  |      Debug state header       |
+	 *  +-------------------------------+ 32B
+	 *  |    Crash dump state header    |
 	 *  +-------------------------------+ 64B
 	 *  |     Capture state header      |
 	 *  +-------------------------------+ 96B
 	 *  |                               |
 	 *  +===============================+ PAGE_SIZE (4KB)
-	 *  |        Crash Dump logs        |
-	 *  +===============================+ + CRASH_SIZE
 	 *  |          Debug logs           |
 	 *  +===============================+ + DEBUG_SIZE
+	 *  |        Crash Dump logs        |
+	 *  +===============================+ + CRASH_SIZE
 	 *  |         Capture logs          |
 	 *  +===============================+ + CAPTURE_SIZE
 	 */
-	guc_log_size = PAGE_SIZE + CRASH_BUFFER_SIZE + DEBUG_BUFFER_SIZE +
-		       CAPTURE_BUFFER_SIZE;
+	if (intel_guc_capture_output_min_size_est(guc) > CAPTURE_BUFFER_SIZE)
+		DRM_WARN("GuC log buffer for state_capture maybe too small. %d < %d\n",
+			 CAPTURE_BUFFER_SIZE, intel_guc_capture_output_min_size_est(guc));
+
+	guc_log_size = PAGE_SIZE + CRASH_BUFFER_SIZE + DEBUG_BUFFER_SIZE + CAPTURE_BUFFER_SIZE;
 
 	vma = intel_guc_allocate_vma(guc, guc_log_size);
 	if (IS_ERR(vma)) {
@@ -473,6 +489,17 @@ int intel_guc_log_create(struct intel_guc_log *log)
 	}
 
 	log->vma = vma;
+	/*
+	 * Create a WC (Uncached for read) vmalloc mapping up front immediate access to
+	 * data from memory during  critical events such as error capture
+	 */
+	vaddr = i915_gem_object_pin_map_unlocked(log->vma->obj, I915_MAP_WC);
+	if (IS_ERR(vaddr)) {
+		ret = PTR_ERR(vaddr);
+		i915_vma_unpin_and_release(&log->vma, 0);
+		goto err;
+	}
+	log->buf_addr = vaddr;
 
 	log->level = __get_default_log_level(log);
 	DRM_DEBUG_DRIVER("guc_log_level=%d (%s, verbose:%s, verbosity:%d)\n",
@@ -483,13 +510,14 @@ int intel_guc_log_create(struct intel_guc_log *log)
 	return 0;
 
 err:
-	DRM_ERROR("Failed to allocate GuC log buffer. %d\n", ret);
+	DRM_ERROR("Failed to allocate or map GuC log buffer. %d\n", ret);
 	return ret;
 }
 
 void intel_guc_log_destroy(struct intel_guc_log *log)
 {
-	i915_vma_unpin_and_release(&log->vma, 0);
+	log->buf_addr = NULL;
+	i915_vma_unpin_and_release(&log->vma, I915_VMA_RELEASE_MAP);
 }
 
 int intel_guc_log_set_level(struct intel_guc_log *log, u32 level)
@@ -534,7 +562,7 @@ int intel_guc_log_set_level(struct intel_guc_log *log, u32 level)
 
 bool intel_guc_log_relay_created(const struct intel_guc_log *log)
 {
-	return log->relay.buf_addr;
+	return log->buf_addr;
 }
 
 int intel_guc_log_relay_open(struct intel_guc_log *log)
@@ -565,7 +593,7 @@ int intel_guc_log_relay_open(struct intel_guc_log *log)
 	if (ret)
 		goto out_unlock;
 
-	ret = guc_log_map(log);
+	ret = guc_log_relay_map(log);
 	if (ret)
 		goto out_relay;
 
@@ -615,8 +643,8 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log)
 	with_intel_runtime_pm(guc_to_gt(guc)->uncore->rpm, wakeref)
 		guc_action_flush_log(guc);
 
-	/* GuC would have updated log buffer by now, so capture it */
-	guc_log_capture_logs(log);
+	/* GuC would have updated log buffer by now, so copy it */
+	guc_log_copy_debuglogs_for_relay(log);
 }
 
 /*
@@ -645,7 +673,7 @@ void intel_guc_log_relay_close(struct intel_guc_log *log)
 
 	mutex_lock(&log->relay.lock);
 	GEM_BUG_ON(!intel_guc_log_relay_created(log));
-	guc_log_unmap(log);
+	guc_log_relay_unmap(log);
 	guc_log_relay_destroy(log);
 	mutex_unlock(&log->relay.lock);
 }
@@ -682,6 +710,7 @@ stringify_guc_log_type(enum guc_log_buffer_type type)
  */
 void intel_guc_log_info(struct intel_guc_log *log, struct drm_printer *p)
 {
+	struct intel_guc *guc = log_to_guc(log);
 	enum guc_log_buffer_type type;
 
 	if (!intel_guc_log_relay_created(log)) {
@@ -696,8 +725,8 @@ void intel_guc_log_info(struct intel_guc_log *log, struct drm_printer *p)
 	for (type = GUC_DEBUG_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) {
 		drm_printf(p, "\t%s:\tflush count %10u, overflow count %10u\n",
 			   stringify_guc_log_type(type),
-			   log->stats[type].flush,
-			   log->stats[type].sampled_overflow);
+			   guc->log_state[type].flush,
+			   guc->log_state[type].sampled_overflow);
 	}
 }
 
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
index d7e1b6471fed..b6e8e9ee37b7 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
@@ -46,23 +46,25 @@ struct intel_guc;
 #define GUC_VERBOSITY_TO_LOG_LEVEL(x)	((x) + 2)
 #define GUC_LOG_LEVEL_MAX GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)
 
+struct intel_guc_log_stats {
+	struct mutex lock; /* protects below and guc_log_buffer_state's read-ptr */
+	u32 sampled_overflow;
+	u32 overflow;
+	u32 flush;
+};
+
 struct intel_guc_log {
 	u32 level;
 	struct i915_vma *vma;
+	void *buf_addr;
 	struct {
-		void *buf_addr;
+		bool buf_in_use;
 		bool started;
 		struct work_struct flush_work;
 		struct rchan *channel;
 		struct mutex lock;
 		u32 full_count;
 	} relay;
-	/* logging related stats */
-	struct {
-		u32 sampled_overflow;
-		u32 overflow;
-		u32 flush;
-	} stats[GUC_MAX_LOG_BUFFER];
 };
 
 void intel_guc_log_init_early(struct intel_guc_log *log);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 07/10] drm/i915/guc: Extract GuC error capture lists on G2H notification.
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (6 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-02-11  1:36   ` Umesh Nerlige Ramappa
  -1 siblings, 1 reply; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

- Upon the G2H Notify-Err-Capture event, parse through the
  GuC Log Buffer (error-capture-region) and dynamically allocate
  capture-nodes, A single node represents a single "engine-
  instance-capture-dump" and contains at least 3 register lists:
  global, engine-class and engine-instance. An internal link
  list is maintained to store one or more nodes.
- The G2G error-capture notification event happens before the
  corresponding G2H context-reset that triggers the
  i915_gpu_coredump (where we want to avoid memory allocation
  moving forward).
- Because the link-list node allocations happen before the call
  to i915_gpu_codedump, duplicate global and engine-class register
  lists for each engine-instance register dump if we find
  dependent-engine resets in a engine-capture-group.
- Later when i915_gpu_coredump calls into capture_engine, (in
  the subsequent patch) we dettach the matching node (guc-id,
  LRCA, etc) from the link list above and attach it to
  i915_gpu_coredump's intel_engine_coredump structure when have
  matching LRCA/guc-id/engine-instance.
- Finally, when we reset GuC submission lets also parse
  all outstanding capture data here too.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h  |   7 +
 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |  52 +-
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 517 +++++++++++++++++-
 .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    |  26 +-
 drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |   4 +
 .../gpu/drm/i915/gt/uc/intel_guc_submission.c |  14 +-
 7 files changed, 608 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
index 7afdadc7656f..82a69f54cddb 100644
--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
@@ -173,4 +173,11 @@ enum intel_guc_sleep_state_status {
 #define GUC_LOG_CONTROL_VERBOSITY_MASK	(0xF << GUC_LOG_CONTROL_VERBOSITY_SHIFT)
 #define GUC_LOG_CONTROL_DEFAULT_LOGGING	(1 << 8)
 
+enum intel_guc_state_capture_event_status {
+	INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_SUCCESS = 0x0,
+	INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE = 0x1,
+};
+
+#define INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK      0x1
+
 #endif /* _ABI_GUC_ACTIONS_ABI_H */
diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
index 495cdb0228c6..14c497f12621 100644
--- a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
@@ -29,7 +29,8 @@ struct __guc_mmio_reg_descr_group {
 };
 
 struct guc_state_capture_header_t {
-	u32 reserved1;
+	u32 owner;
+		#define CAP_HDR_CAPTURE_VFID GENMASK(7, 0)
 	u32 info;
 		#define CAP_HDR_CAPTURE_TYPE GENMASK(3, 0) /* see enum guc_capture_type */
 		#define CAP_HDR_ENGINE_CLASS GENMASK(7, 4) /* see GUC_MAX_ENGINE_CLASSES */
@@ -52,7 +53,8 @@ enum guc_capture_group_types {
 };
 
 struct guc_state_capture_group_header_t {
-	u32 reserved1;
+	u32 owner;
+		#define CAP_GRP_HDR_CAPTURE_VFID GENMASK(7, 0)
 	u32 info;
 		#define CAP_GRP_HDR_NUM_CAPTURES GENMASK(7, 0)
 		#define CAP_GRP_HDR_CAPTURE_TYPE GENMASK(15, 8) /* guc_capture_group_types */
@@ -63,11 +65,57 @@ struct guc_state_capture_group_t {
 	struct guc_state_capture_t capture_entries[0];
 } __packed;
 
+struct __guc_capture_parsed_output {
+	/*
+	 * a single set of 3 capture lists: a global-list
+	 * an engine-class-list and an engine-instance list.
+	 * outlist in __guc_capture_parsed_output will keep
+	 * a linked list of these nodes that will eventually
+	 * be detached from outlist and attached into to
+	 * i915_gpu_codedump in response to a context reset
+	 */
+	struct list_head link;
+	bool is_partial;
+	u32 eng_class;
+	u32 eng_inst;
+	u32 guc_id;
+	u32 lrca;
+	struct gcap_reg_list_info {
+		u32 vfid;
+		u32 num;
+		struct guc_mmio_reg *regs;
+	} reginfo[GUC_CAPTURE_LIST_TYPE_MAX];
+	#define GCAP_PARSED_REGLIST_INDEX_GLOBAL   BIT(GUC_CAPTURE_LIST_TYPE_GLOBAL)
+	#define GCAP_PARSED_REGLIST_INDEX_ENGCLASS BIT(GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS)
+	#define GCAP_PARSED_REGLIST_INDEX_ENGINST  BIT(GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE)
+};
+
+#define MAX_NODE_LINKLIST_THRESHOLD     24
+	/* The maximum number of allocated __guc_capture_parsed_output nodes
+	 * that we shall keep in outlist. If we receive an error-capture
+	 * notification and need to allocate another node but have hit this
+	 * threshold, we shall free the oldest entry and add a new one (FIFO).
+	 */
+
+struct __guc_capture_bufstate {
+	unsigned int size;
+	void *data;
+	unsigned int rd;
+	unsigned int wr;
+};
+
 struct __guc_state_capture_priv {
 	struct __guc_mmio_reg_descr_group *reglists;
 	u16 num_instance_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
 	u16 num_class_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
 	u16 num_global_regs[GUC_CAPTURE_LIST_INDEX_MAX];
+	/* An interim linked list of parsed GuC error-capture-output before
+	 * reporting with formatting. Each node in this linked list shall
+	 * contain a single engine-capture including global, engine-class and
+	 * engine-instance register dumps as per guc_capture_parsed_output_node
+	 */
+	struct list_head outlist;
+	int listcount; /* see MAX_NODE_LINKLIST_THRESHOLD */
 };
 
 #endif /* _INTEL_GUC_CAPTURE_FWIF_H */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index e7f99d051636..0b6d743712a6 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -12,6 +12,8 @@
 #include "guc_capture_fwif.h"
 #include "intel_guc_fwif.h"
 #include "i915_drv.h"
+#include "i915_gpu_error.h"
+#include "i915_irq.h"
 #include "i915_memcpy.h"
 
 /*
@@ -660,6 +662,9 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
 	int worst_min_size = 0, num_regs = 0;
 	u16 tmp = 0;
 
+	if (!guc->capture.priv)
+		return -ENODEV;
+
 	/*
 	 * If every single engine-instance suffered a failure in quick succession but
 	 * were all unrelated, then a burst of multiple error-capture events would dump
@@ -698,8 +703,518 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
 	return (worst_min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER);
 }
 
+/*
+ * KMD Init time flows:
+ * --------------------
+ *     --> alloc A: GuC input capture regs lists (registered via ADS)
+ *                  List acquired via intel_guc_capture_list_count + intel_guc_capture_list_init
+ *                  Size = global-reg-list + (class-reg-list) + (num-instances x instance-reg-list)
+ *                  Device tables carry: 1x global, 1x per-class, 1x per-instance)
+ *                  Caller needs to call per-class and per-instance multiplie times
+ *
+ *     --> alloc B: GuC output capture buf (registered via guc_init_params(log_param))
+ *                  Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small)
+ *                  Note2: 'x 3' to hold multiple capture groups
+ *
+ *
+ * GUC Runtime notify capture:
+ * --------------------------
+ *     --> G2H STATE_CAPTURE_NOTIFICATION
+ *                   L--> intel_guc_capture_store_snapshot
+ *                           L--> Loop through B (head..tail) and for each engine instance
+ *                                register we find:
+ *      --> alloc C: A capture-output-node structure that includes misc capture info along
+ *                   with 3 register list dumps (global, engine-class and engine-
+ *                   instance). This node id added to a linked list stored in
+ *                   guc->capture->priv for matchup and printout when triggered by
+ *                   i915_gpu_coredump and err_print_gt (via error capture sysfs) later.
+ */
+
+static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
+{
+	if (buf->rd == buf->wr)
+		return 0;
+	if (buf->wr > buf->rd)
+		return (buf->wr - buf->rd);
+	return (buf->size - buf->rd) + buf->wr;
+}
+
+static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf)
+{
+	if (buf->rd > buf->wr)
+		return (buf->size - buf->rd);
+	return (buf->wr - buf->rd);
+}
+
+static int
+guc_capture_log_remove_dw(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
+			  u32 *dw)
+{
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+	int tries = 2;
+	int avail = 0;
+	u32 *src_data;
+
+	if (!guc_capture_buf_cnt(buf))
+		return 0;
+
+	while (tries--) {
+		avail = guc_capture_buf_cnt_to_end(buf);
+		if (avail >= sizeof(u32)) {
+			src_data = (u32 *)(buf->data + buf->rd);
+			*dw = *src_data;
+			buf->rd += 4;
+			return 4;
+		}
+		if (avail)
+			drm_warn(&i915->drm, "GuC-Cap-Logs not dword aligned, skipping.\n");
+		buf->rd = 0;
+	}
+
+	return 0;
+}
+
+static bool
+guc_capture_data_extracted(struct __guc_capture_bufstate *b,
+			   int s, void *p)
+{
+	if (guc_capture_buf_cnt_to_end(b) >= s) {
+		memcpy(p, (b->data + b->rd), s);
+		b->rd += s;
+		return true;
+	}
+	return false;
+}
+
+static int
+guc_capture_log_get_group_hdr(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
+			      struct guc_state_capture_group_header_t *ghdr)
+{
+	int read = 0;
+	int fullsize = sizeof(struct guc_state_capture_group_header_t);
+
+	if (fullsize > guc_capture_buf_cnt(buf))
+		return -1;
+
+	if (guc_capture_data_extracted(buf, fullsize, (void *)ghdr))
+		return 0;
+
+	read += guc_capture_log_remove_dw(guc, buf, &ghdr->owner);
+	read += guc_capture_log_remove_dw(guc, buf, &ghdr->info);
+	if (read != fullsize)
+		return -1;
+
+	return 0;
+}
+
+static int
+guc_capture_log_get_data_hdr(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
+			     struct guc_state_capture_header_t *hdr)
+{
+	int read = 0;
+	int fullsize = sizeof(struct guc_state_capture_header_t);
+
+	if (fullsize > guc_capture_buf_cnt(buf))
+		return -1;
+
+	if (guc_capture_data_extracted(buf, fullsize, (void *)hdr))
+		return 0;
+
+	read += guc_capture_log_remove_dw(guc, buf, &hdr->owner);
+	read += guc_capture_log_remove_dw(guc, buf, &hdr->info);
+	read += guc_capture_log_remove_dw(guc, buf, &hdr->lrca);
+	read += guc_capture_log_remove_dw(guc, buf, &hdr->guc_id);
+	read += guc_capture_log_remove_dw(guc, buf, &hdr->num_mmios);
+	if (read != fullsize)
+		return -1;
+
+	return 0;
+}
+
+static int
+guc_capture_log_get_register(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
+			     struct guc_mmio_reg *reg)
+{
+	int read = 0;
+	int fullsize = sizeof(struct guc_mmio_reg);
+
+	if (fullsize > guc_capture_buf_cnt(buf))
+		return -1;
+
+	if (guc_capture_data_extracted(buf, fullsize, (void *)reg))
+		return 0;
+
+	read += guc_capture_log_remove_dw(guc, buf, &reg->offset);
+	read += guc_capture_log_remove_dw(guc, buf, &reg->value);
+	read += guc_capture_log_remove_dw(guc, buf, &reg->flags);
+	read += guc_capture_log_remove_dw(guc, buf, &reg->mask);
+	if (read != fullsize)
+		return -1;
+
+	return 0;
+}
+
+static void
+guc_capture_del_all_nodes(struct intel_guc *guc)
+{
+	int i;
+
+	if (!list_empty(&guc->capture.priv->outlist)) {
+		struct __guc_capture_parsed_output *n, *ntmp;
+
+		list_for_each_entry_safe(n, ntmp, &guc->capture.priv->outlist, link) {
+			for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+				if (n->reginfo[i].regs)
+					kfree(n->reginfo[i].regs);
+			}
+			list_del(&n->link);
+			kfree(n);
+		}
+	}
+	guc->capture.priv->listcount = 0;
+}
+
+static void
+guc_capture_del_node(struct intel_guc *guc, struct __guc_capture_parsed_output *node)
+{
+	int i;
+	struct __guc_capture_parsed_output *found = NULL;
+
+	if (!list_empty(&guc->capture.priv->outlist)) {
+		struct __guc_capture_parsed_output *n, *ntmp;
+
+		if (node) {
+			found = node;
+		} else {
+			/* traverse down and get the oldest entry */
+			list_for_each_entry_safe(n, ntmp, &guc->capture.priv->outlist, link)
+				found = n;
+		}
+		if (found) {
+			for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+				if (found->reginfo[i].regs)
+					kfree(found->reginfo[i].regs);
+			}
+			list_del(&found->link);
+			kfree(found);
+			--guc->capture.priv->listcount;
+		}
+	}
+}
+
+static void
+guc_capture_add_node_to_list(struct intel_guc *guc, struct __guc_capture_parsed_output *node)
+{
+	GEM_BUG_ON(guc->capture.priv->listcount > MAX_NODE_LINKLIST_THRESHOLD);
+
+	if (guc->capture.priv->listcount == MAX_NODE_LINKLIST_THRESHOLD) {
+		/* discard oldest node */
+		guc_capture_del_node(guc, NULL);
+	}
+
+	++guc->capture.priv->listcount;
+	list_add_tail(&node->link, &guc->capture.priv->outlist);
+}
+
+static struct __guc_capture_parsed_output *
+guc_capture_create_node(struct intel_guc *guc, struct __guc_capture_parsed_output *ori,
+			u32 keep_reglist_mask)
+{
+	struct __guc_capture_parsed_output *new;
+	int i;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return NULL;
+	INIT_LIST_HEAD(&new->link);
+	if (!ori)
+		return new;
+	memcpy(new, ori, sizeof(*new));
+
+	/* reallocate individual reg-list pointers */
+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+		new->reginfo[i].regs = NULL;
+		new->reginfo[i].num = 0;
+	}
+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+		if (keep_reglist_mask & BIT(i)) {
+			new->reginfo[i].regs = kcalloc(ori->reginfo[i].num,
+						       sizeof(struct guc_mmio_reg), GFP_KERNEL);
+			if (!new->reginfo[i].regs)
+				goto bail_clone;
+			memcpy(new->reginfo[i].regs, ori->reginfo[i].regs, ori->reginfo[i].num *
+			       sizeof(struct guc_mmio_reg));
+			new->reginfo[i].num = ori->reginfo[i].num;
+		}
+	}
+
+	return new;
+
+bail_clone:
+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+		if (new->reginfo[i].regs)
+			kfree(new->reginfo[i].regs);
+	}
+	kfree(new);
+	return NULL;
+}
+
+static int
+guc_capture_extract_reglists(struct intel_guc *guc, struct __guc_capture_bufstate *buf)
+{
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+	struct guc_state_capture_group_header_t ghdr = {0};
+	struct guc_state_capture_header_t hdr = {0};
+	struct __guc_capture_parsed_output *node = NULL;
+	struct guc_mmio_reg *regs = NULL;
+	int i, numlists, numreg, ret = 0;
+	bool is_partial = false;
+	enum guc_capture_type datatype;
+
+	i = guc_capture_buf_cnt(buf);
+	if (!i)
+		return -ENODATA;
+	if (i % sizeof(u32)) {
+		drm_warn(&i915->drm, "GuC Capture new entries unaligned\n");
+		ret = -EIO;
+		goto bailout;
+	}
+
+	/* first get the capture group header */
+	if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) {
+		ret = -EIO;
+		goto bailout;
+	}
+	/*
+	 * we would typically expect a layout as below where n would be expected to be
+	 * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine
+	 * instances being reset together.
+	 * ____________________________________________
+	 * | Capture Group                            |
+	 * | ________________________________________ |
+	 * | | Capture Group Header:                | |
+	 * | |  - num_captures = 5                  | |
+	 * | |______________________________________| |
+	 * | ________________________________________ |
+	 * | | Capture1:                            | |
+	 * | |  Hdr: GLOBAL, numregs=a              | |
+	 * | | ____________________________________ | |
+	 * | | | Reglist                          | | |
+	 * | | | - reg1, reg2, ... rega           | | |
+	 * | | |__________________________________| | |
+	 * | |______________________________________| |
+	 * | ________________________________________ |
+	 * | | Capture2:                            | |
+	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=b| |
+	 * | | ____________________________________ | |
+	 * | | | Reglist                          | | |
+	 * | | | - reg1, reg2, ... regb           | | |
+	 * | | |__________________________________| | |
+	 * | |______________________________________| |
+	 * | ________________________________________ |
+	 * | | Capture3:                            | |
+	 * | |  Hdr: INSTANCE=RCS, numregs=c        | |
+	 * | | ____________________________________ | |
+	 * | | | Reglist                          | | |
+	 * | | | - reg1, reg2, ... regc           | | |
+	 * | | |__________________________________| | |
+	 * | |______________________________________| |
+	 * | ________________________________________ |
+	 * | | Capture4:                            | |
+	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=d| |
+	 * | | ____________________________________ | |
+	 * | | | Reglist                          | | |
+	 * | | | - reg1, reg2, ... regd           | | |
+	 * | | |__________________________________| | |
+	 * | |______________________________________| |
+	 * | ________________________________________ |
+	 * | | Capture5:                            | |
+	 * | |  Hdr: INSTANCE=CCS0, numregs=e       | |
+	 * | | ____________________________________ | |
+	 * | | | Reglist                          | | |
+	 * | | | - reg1, reg2, ... rege           | | |
+	 * | | |__________________________________| | |
+	 * | |______________________________________| |
+	 * |__________________________________________|
+	 */
+	is_partial = FIELD_GET(CAP_GRP_HDR_CAPTURE_TYPE, ghdr.info);
+	if (is_partial)
+		drm_warn(&i915->drm, "GuC Capture group is partial\n");
+	numlists = FIELD_GET(CAP_GRP_HDR_NUM_CAPTURES, ghdr.info);
+	while (numlists--) {
+
+		numreg = 0;
+		regs = NULL;
+		if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) {
+			ret = -EIO;
+			break;
+		}
+
+		datatype = FIELD_GET(CAP_HDR_CAPTURE_TYPE, hdr.info);
+		if (node) {
+			/* Based on the current capture type and what we have so far,
+			 * decide if we should add the current node into the internal
+			 * linked list for match-up when i915_gpu_coredump calls later
+			 * (and alloc a blank node for the next set of reglists)
+			 * or continue with the same node or clone the current node
+			 * but only retain the global or class registers (such as the
+			 * case of dependent engine resets).
+			 */
+			if (datatype == GUC_CAPTURE_LIST_TYPE_GLOBAL) {
+				guc_capture_add_node_to_list(guc, node);
+				node = NULL;
+			} else if (datatype == GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS &&
+				   node->reginfo[GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS].regs) {
+				/* Add to list, clone node and duplicate global list */
+				guc_capture_add_node_to_list(guc, node);
+				node = guc_capture_create_node(guc, node,
+							       GCAP_PARSED_REGLIST_INDEX_GLOBAL);
+			} else if (datatype == GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE &&
+				   node->reginfo[GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE].regs) {
+				/* Add to list, clone node and duplicate global + class lists */
+				guc_capture_add_node_to_list(guc, node);
+				node = guc_capture_create_node(guc, node,
+							       (GCAP_PARSED_REGLIST_INDEX_GLOBAL |
+							       GCAP_PARSED_REGLIST_INDEX_ENGCLASS));
+			}
+		}
+
+		if (!node) {
+			node = guc_capture_create_node(guc, NULL, 0);
+			if (!node) {
+				ret = -ENOMEM;
+				break;
+			}
+			if (datatype != GUC_CAPTURE_LIST_TYPE_GLOBAL)
+				drm_dbg(&i915->drm, "GuC Capture missing global dump: %08x!\n",
+					datatype);
+		}
+		node->is_partial = is_partial;
+		switch (datatype) {
+		case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
+			node->eng_inst = FIELD_GET(CAP_HDR_ENGINE_INSTANCE, hdr.info);
+			node->lrca = hdr.lrca;
+			node->guc_id = hdr.guc_id;
+			node->eng_class = FIELD_GET(CAP_HDR_ENGINE_CLASS, hdr.info);
+			break;
+		case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
+			node->eng_class = FIELD_GET(CAP_HDR_ENGINE_CLASS, hdr.info);
+			break;
+		default:
+			break;
+		}
+		regs = NULL;
+		numreg = FIELD_GET(CAP_HDR_NUM_MMIOS, hdr.num_mmios);
+		if (numreg) {
+			regs = kcalloc(numreg, sizeof(*regs), GFP_KERNEL);
+			if (!regs) {
+				ret = -ENOMEM;
+				break;
+			}
+		}
+		node->reginfo[datatype].num = numreg;
+		node->reginfo[datatype].regs = regs;
+		node->reginfo[datatype].vfid = FIELD_GET(CAP_HDR_CAPTURE_VFID, hdr.info);
+		i = 0;
+		while (numreg--) {
+			if (guc_capture_log_get_register(guc, buf, &regs[i++])) {
+				ret = -EIO;
+				break;
+			}
+		}
+	}
+
+bailout:
+	if (node) {
+		/* If we have data, add to linked list for match-up when i915_gpu_coredump calls */
+		for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+			if (node->reginfo[i].regs) {
+				guc_capture_add_node_to_list(guc, node);
+				node = NULL;
+				break;
+			}
+		}
+		if (node)
+			kfree(node);
+	}
+	return ret;
+}
+
+static void __guc_capture_store_snapshot_work(struct intel_guc *guc)
+{
+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+	unsigned int buffer_size, read_offset, write_offset, full_count;
+	struct guc_log_buffer_state *log_buf_state;
+	struct guc_log_buffer_state log_buf_state_local;
+	void *src_data = NULL;
+	bool new_overflow;
+	struct __guc_capture_bufstate buf;
+	int ret;
+
+	/* Lock to get the pointer to GuC capture-log-buffer-state */
+	mutex_lock(&guc->log_state[GUC_CAPTURE_LOG_BUFFER].lock);
+	log_buf_state = guc->log.buf_addr +
+			(sizeof(struct guc_log_buffer_state) * GUC_CAPTURE_LOG_BUFFER);
+	src_data = guc->log.buf_addr + intel_guc_get_log_buffer_offset(GUC_CAPTURE_LOG_BUFFER);
+
+	/*
+	 * Make a copy of the state structure, inside GuC log buffer
+	 * (which is uncached mapped), on the stack to avoid reading
+	 * from it multiple times.
+	 */
+	memcpy(&log_buf_state_local, log_buf_state, sizeof(struct guc_log_buffer_state));
+	buffer_size = intel_guc_get_log_buffer_size(GUC_CAPTURE_LOG_BUFFER);
+	read_offset = log_buf_state_local.read_ptr;
+	write_offset = log_buf_state_local.sampled_write_ptr;
+	full_count = log_buf_state_local.buffer_full_cnt;
+
+	/* Bookkeeping stuff */
+	guc->log_state[GUC_CAPTURE_LOG_BUFFER].flush += log_buf_state_local.flush_to_file;
+	new_overflow = intel_guc_check_log_buf_overflow(guc,
+							&guc->log_state[GUC_CAPTURE_LOG_BUFFER],
+							full_count);
+
+	/* Now copy the actual logs. */
+	if (unlikely(new_overflow)) {
+		/* copy the whole buffer in case of overflow */
+		read_offset = 0;
+		write_offset = buffer_size;
+	} else if (unlikely((read_offset > buffer_size) ||
+			(write_offset > buffer_size))) {
+		drm_err(&i915->drm, "invalid GuC log capture buffer state!\n");
+		/* copy whole buffer as offsets are unreliable */
+		read_offset = 0;
+		write_offset = buffer_size;
+	}
+
+	buf.size = buffer_size;
+	buf.rd = read_offset;
+	buf.wr = write_offset;
+	buf.data = src_data;
+	/*  */
+	do {
+		ret = guc_capture_extract_reglists(guc, &buf);
+	} while (ret >= 0);
+
+	/* Update the state of shared log buffer */
+	log_buf_state->read_ptr = write_offset;
+	log_buf_state->flush_to_file = 0;
+
+	mutex_unlock(&guc->log_state[GUC_CAPTURE_LOG_BUFFER].lock);
+}
+
+void intel_guc_capture_store_snapshot(struct intel_guc *guc)
+{
+	if (guc->capture.priv)
+		__guc_capture_store_snapshot_work(guc);
+}
+
 void intel_guc_capture_destroy(struct intel_guc *guc)
 {
+	if (!guc->capture.priv)
+		return;
+
+	guc_capture_del_all_nodes(guc);
 	guc_capture_clear_ext_regs(guc->capture.priv->reglists);
 	kfree(guc->capture.priv);
 	guc->capture.priv = NULL;
@@ -710,7 +1225,7 @@ int intel_guc_capture_init(struct intel_guc *guc)
 	guc->capture.priv = kzalloc(sizeof(*guc->capture.priv), GFP_KERNEL);
 	if (!guc->capture.priv)
 		return -ENOMEM;
+	INIT_LIST_HEAD(&guc->capture.priv->outlist);
 	guc->capture.priv->reglists = guc_capture_get_device_reglist(guc);
-
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
index 4d3e5221128c..c240a4cc046b 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
@@ -14,6 +14,7 @@ struct guc_gt_system_info;
 
 int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
 				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
+void intel_guc_capture_store_snapshot(struct intel_guc *guc);
 int intel_guc_capture_output_min_size_est(struct intel_guc *guc);
 void intel_guc_capture_destroy(struct intel_guc *guc);
 int intel_guc_capture_init(struct intel_guc *guc);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
index d6b1a3c0fb15..194b17e8c2ae 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
@@ -157,9 +157,9 @@ static void *guc_get_write_buffer(struct intel_guc_log *log)
 	return relay_reserve(log->relay.channel, 0);
 }
 
-static bool guc_check_log_buf_overflow(struct intel_guc *guc,
-				       struct intel_guc_log_stats *log_state,
-				       unsigned int full_cnt)
+bool intel_guc_check_log_buf_overflow(struct intel_guc *guc,
+				      struct intel_guc_log_stats *log_state,
+				      unsigned int full_cnt)
 {
 	unsigned int prev_full_cnt = log_state->sampled_overflow;
 	bool overflow = false;
@@ -182,7 +182,7 @@ static bool guc_check_log_buf_overflow(struct intel_guc *guc,
 	return overflow;
 }
 
-static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
+unsigned int intel_guc_get_log_buffer_size(enum guc_log_buffer_type type)
 {
 	switch (type) {
 	case GUC_DEBUG_LOG_BUFFER:
@@ -198,6 +198,20 @@ static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
 	return 0;
 }
 
+size_t intel_guc_get_log_buffer_offset(enum guc_log_buffer_type type)
+{
+	enum guc_log_buffer_type i;
+	size_t offset = PAGE_SIZE;/* for the log_buffer_states */
+
+	for (i = GUC_DEBUG_LOG_BUFFER; i < GUC_MAX_LOG_BUFFER; i++) {
+		if (i == type)
+			break;
+		offset += intel_guc_get_log_buffer_size(i);
+	}
+
+	return offset;
+}
+
 static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
 {
 	struct intel_guc *guc = log_to_guc(log);
@@ -247,14 +261,14 @@ static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
 		mutex_lock(&logstate->lock);
 		memcpy(&log_buf_state_local, log_buf_state,
 		       sizeof(struct guc_log_buffer_state));
-		buffer_size = guc_get_log_buffer_size(type);
+		buffer_size = intel_guc_get_log_buffer_size(type);
 		read_offset = log_buf_state_local.read_ptr;
 		write_offset = log_buf_state_local.sampled_write_ptr;
 		full_cnt = log_buf_state_local.buffer_full_cnt;
 
 		/* Bookkeeping stuff */
 		logstate->flush += log_buf_state_local.flush_to_file;
-		new_overflow = guc_check_log_buf_overflow(guc, logstate, full_cnt);
+		new_overflow = intel_guc_check_log_buf_overflow(guc, logstate, full_cnt);
 
 		/* Update the state of shared log buffer */
 		log_buf_state->read_ptr = write_offset;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
index b6e8e9ee37b7..f16de816447d 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
@@ -68,6 +68,10 @@ struct intel_guc_log {
 };
 
 void intel_guc_log_init_early(struct intel_guc_log *log);
+bool intel_guc_check_log_buf_overflow(struct intel_guc *guc, struct intel_guc_log_stats *state,
+				      unsigned int full_cnt);
+unsigned int intel_guc_get_log_buffer_size(enum guc_log_buffer_type type);
+size_t intel_guc_get_log_buffer_offset(enum guc_log_buffer_type type);
 int intel_guc_log_create(struct intel_guc_log *log);
 void intel_guc_log_destroy(struct intel_guc_log *log);
 
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index db9615dcb0ec..c19d6d682394 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -24,6 +24,7 @@
 #include "gt/intel_ring.h"
 
 #include "intel_guc_ads.h"
+#include "intel_guc_capture.h"
 #include "intel_guc_submission.h"
 
 #include "i915_drv.h"
@@ -1444,6 +1445,8 @@ void intel_guc_submission_reset_prepare(struct intel_guc *guc)
 	flush_work(&guc->ct.requests.worker);
 
 	scrub_guc_desc_for_outstanding_g2h(guc);
+
+	intel_guc_capture_store_snapshot(guc);
 }
 
 static struct intel_engine_cs *
@@ -4016,17 +4019,20 @@ int intel_guc_context_reset_process_msg(struct intel_guc *guc,
 int intel_guc_error_capture_process_msg(struct intel_guc *guc,
 					const u32 *msg, u32 len)
 {
-	int status;
+	u32 status;
 
 	if (unlikely(len != 1)) {
 		drm_dbg(&guc_to_gt(guc)->i915->drm, "Invalid length %u", len);
 		return -EPROTO;
 	}
 
-	status = msg[0];
-	drm_info(&guc_to_gt(guc)->i915->drm, "Got error capture: status = %d", status);
+	status = msg[0] & INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK;
+	if (status == INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE)
+		drm_warn(&guc_to_gt(guc)->i915->drm, "G2H-Error capture no space");
+	else
+		drm_info(&guc_to_gt(guc)->i915->drm, "G2H-Received error capture");
 
-	/* FIXME: Do something with the capture */
+	intel_guc_capture_store_snapshot(guc);
 
 	return 0;
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 08/10] drm/i915/guc: Plumb GuC-capture into gpu_coredump
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (7 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-02-11  2:11   ` Umesh Nerlige Ramappa
  -1 siblings, 1 reply; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Add a flags parameter through all of the coredump creation
functions. Add a bitmask flag to indicate if the top
level gpu_coredump event is triggered in response to
a GuC context reset notification.

Using that flag, ensure all coredump functions that
read or print mmio-register values related to work submission
or command-streamer engines are skipped and replaced with
a calls guc-capture module equivalent functions to retrieve
or print the register dump.

While here, split out display related register reading
and printing into its own function that is called agnostic
to whether GuC had triggered the reset.

For now, introduce an empty printing function that can
filled in on a subsequent patch just to handle formatting.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 .../drm/i915/gt/intel_execlists_submission.c  |   4 +-
 drivers/gpu/drm/i915/gt/intel_reset.c         |   2 +-
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  78 ++++++
 .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |  11 +-
 .../gpu/drm/i915/gt/uc/intel_guc_submission.c |   2 +-
 drivers/gpu/drm/i915/i915_debugfs.c           |   2 +-
 drivers/gpu/drm/i915/i915_gpu_error.c         | 263 ++++++++++++------
 drivers/gpu/drm/i915/i915_gpu_error.h         |  31 ++-
 8 files changed, 295 insertions(+), 98 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 960a9aaf4f3a..c8bb43863461 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -2230,11 +2230,11 @@ static struct execlists_capture *capture_regs(struct intel_engine_cs *engine)
 	if (!cap->error)
 		goto err_cap;
 
-	cap->error->gt = intel_gt_coredump_alloc(engine->gt, gfp);
+	cap->error->gt = intel_gt_coredump_alloc(engine->gt, gfp, CORE_DUMP_FLAG_NONE);
 	if (!cap->error->gt)
 		goto err_gpu;
 
-	cap->error->gt->engine = intel_engine_coredump_alloc(engine, gfp);
+	cap->error->gt->engine = intel_engine_coredump_alloc(engine, gfp, CORE_DUMP_FLAG_NONE);
 	if (!cap->error->gt->engine)
 		goto err_gt;
 
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
index 6f2821cca409..c1dc3f8b1108 100644
--- a/drivers/gpu/drm/i915/gt/intel_reset.c
+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
@@ -1305,7 +1305,7 @@ void intel_gt_handle_error(struct intel_gt *gt,
 	engine_mask &= gt->info.engine_mask;
 
 	if (flags & I915_ERROR_CAPTURE) {
-		i915_capture_error_state(gt, engine_mask);
+		i915_capture_error_state(gt, engine_mask, CORE_DUMP_FLAG_NONE);
 		intel_gt_clear_error_registers(gt, engine_mask);
 	}
 
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 0b6d743712a6..2f5dc413dddc 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -728,6 +728,17 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
  *                   instance). This node id added to a linked list stored in
  *                   guc->capture->priv for matchup and printout when triggered by
  *                   i915_gpu_coredump and err_print_gt (via error capture sysfs) later.
+ *
+ * GUC --> notify context reset:
+ * -----------------------------
+ *     --> G2H CONTEXT RESET
+ *                   L--> guc_handle_context_reset --> i915_capture_error_state
+ *                          L--> i915_gpu_coredump(..IS_GUC_CAPTURE) --> gt_record_engines
+ *                               --> capture_engine(..IS_GUC_CAPTURE)
+ *                                  L--> detach C from internal linked list and add into
+ *                                       intel_engine_coredump struct (if the context and
+ *                                       engine of the event notification matches a node
+ *                                       in the link list)
  */
 
 static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
@@ -1203,6 +1214,73 @@ static void __guc_capture_store_snapshot_work(struct intel_guc *guc)
 	mutex_unlock(&guc->log_state[GUC_CAPTURE_LOG_BUFFER].lock);
 }
 
+#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
+
+int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
+					const struct intel_engine_coredump *ee)
+{
+	return 0;
+}
+
+#endif //CONFIG_DRM_I915_DEBUG_GUC
+
+void intel_guc_capture_free_node(struct intel_engine_coredump *ee)
+{
+	int i;
+
+	if (!ee)
+		return;
+	if (!ee->guc_capture_node)
+		return;
+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+		if (ee->guc_capture_node->reginfo[i].regs)
+			kfree(ee->guc_capture_node->reginfo[i].regs);
+	}
+	kfree(ee->guc_capture_node);
+	ee->guc_capture_node = NULL;
+}
+
+void intel_guc_capture_get_matching_node(struct intel_gt *gt,
+					 struct intel_engine_coredump *ee,
+					 struct intel_context *ce)
+{
+	struct intel_guc *guc;
+	struct drm_i915_private *i915;
+
+	if (!gt || !ee || !ce)
+		return;
+
+	i915 = gt->i915;
+	guc = &gt->uc.guc;
+	if (!guc->capture.priv)
+		return;
+
+	GEM_BUG_ON(ee->guc_capture_node);
+	/*
+	 * Look for a matching GuC reported error capture node from
+	 * the internal output link-list based on lrca, guc-id and engine
+	 * identification.
+	 */
+	if (!list_empty(&guc->capture.priv->outlist)) {
+		struct __guc_capture_parsed_output *n, *ntmp;
+
+		list_for_each_entry_safe(n, ntmp, &guc->capture.priv->outlist, link) {
+			if (n->eng_inst == GUC_ID_TO_ENGINE_INSTANCE(ee->engine->guc_id) &&
+			    n->eng_class == GUC_ID_TO_ENGINE_CLASS(ee->engine->guc_id) &&
+			    n->guc_id == ce->guc_id.id &&
+			    (n->lrca & CTX_GTT_ADDRESS_MASK) ==
+			    (ce->lrc.lrca & CTX_GTT_ADDRESS_MASK)) {
+				list_del(&n->link);
+				--guc->capture.priv->listcount;
+				ee->guc_capture_node = n;
+				ee->capture = &guc->capture;
+				return;
+			}
+		}
+	}
+	drm_warn(&i915->drm, "GuC capture can't match ee to node\n");
+}
+
 void intel_guc_capture_store_snapshot(struct intel_guc *guc)
 {
 	if (guc->capture.priv)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
index c240a4cc046b..9a2037638e64 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
@@ -8,12 +8,21 @@
 
 #include <linux/types.h>
 
-struct intel_guc;
+struct drm_i915_error_state_buf;
 struct guc_ads;
 struct guc_gt_system_info;
+struct intel_context;
+struct intel_engine_coredump;
+struct intel_gt;
+struct intel_guc;
 
 int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
 				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
+int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *m,
+					const struct intel_engine_coredump *ee);
+void intel_guc_capture_get_matching_node(struct intel_gt *gt, struct intel_engine_coredump *ee,
+					 struct intel_context *ce);
+void intel_guc_capture_free_node(struct intel_engine_coredump *ee);
 void intel_guc_capture_store_snapshot(struct intel_guc *guc);
 int intel_guc_capture_output_min_size_est(struct intel_guc *guc);
 void intel_guc_capture_destroy(struct intel_guc *guc);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index c19d6d682394..45ec7db3a85f 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -3953,7 +3953,7 @@ static void capture_error_state(struct intel_guc *guc,
 
 	intel_engine_set_hung_context(engine, ce);
 	with_intel_runtime_pm(&i915->runtime_pm, wakeref)
-		i915_capture_error_state(gt, engine->mask);
+		i915_capture_error_state(gt, engine->mask, CORE_DUMP_FLAG_IS_GUC_CAPTURE);
 	atomic_inc(&i915->gpu_error.reset_engine_count[engine->uabi_class]);
 }
 
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f3141b58d912..d2af0d1f3a3e 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -294,7 +294,7 @@ static int i915_gpu_info_open(struct inode *inode, struct file *file)
 
 	gpu = NULL;
 	with_intel_runtime_pm(&i915->runtime_pm, wakeref)
-		gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES);
+		gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES, CORE_DUMP_FLAG_NONE);
 	if (IS_ERR(gpu))
 		return PTR_ERR(gpu);
 
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index aee42eae4729..d8c82589d86e 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -590,15 +590,11 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
 				   ee->vm_info.pp_dir_base);
 		}
 	}
-	err_printf(m, "  hung: %u\n", ee->hung);
-	err_printf(m, "  engine reset count: %u\n", ee->reset_count);
 
 	for (n = 0; n < ee->num_ports; n++) {
 		err_printf(m, "  ELSP[%d]:", n);
 		error_print_request(m, " ", &ee->execlist[n]);
 	}
-
-	error_print_context(m, "  Active context: ", &ee->context);
 }
 
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
@@ -710,23 +706,30 @@ static void err_print_gt_info(struct drm_i915_error_state_buf *m,
 	intel_sseu_print_topology(&gt->info.sseu, &p);
 }
 
-static void err_print_gt(struct drm_i915_error_state_buf *m,
-			 struct intel_gt_coredump *gt)
+static void err_print_gt_display(struct drm_i915_error_state_buf *m,
+				 struct intel_gt_coredump *gt)
+{
+	err_printf(m, "IER: 0x%08x\n", gt->ier);
+	err_printf(m, "DERRMR: 0x%08x\n", gt->derrmr);
+}
+
+static void err_print_gt_global_nonguc(struct drm_i915_error_state_buf *m,
+				       struct intel_gt_coredump *gt)
 {
-	const struct intel_engine_coredump *ee;
 	int i;
 
 	err_printf(m, "GT awake: %s\n", yesno(gt->awake));
 	err_printf(m, "EIR: 0x%08x\n", gt->eir);
-	err_printf(m, "IER: 0x%08x\n", gt->ier);
+	err_printf(m, "PGTBL_ER: 0x%08x\n", gt->pgtbl_er);
+
 	for (i = 0; i < gt->ngtier; i++)
 		err_printf(m, "GTIER[%d]: 0x%08x\n", i, gt->gtier[i]);
-	err_printf(m, "PGTBL_ER: 0x%08x\n", gt->pgtbl_er);
-	err_printf(m, "FORCEWAKE: 0x%08x\n", gt->forcewake);
-	err_printf(m, "DERRMR: 0x%08x\n", gt->derrmr);
+}
 
-	for (i = 0; i < gt->nfence; i++)
-		err_printf(m, "  fence[%d] = %08llx\n", i, gt->fence[i]);
+static void err_print_gt_global(struct drm_i915_error_state_buf *m,
+				struct intel_gt_coredump *gt)
+{
+	err_printf(m, "FORCEWAKE: 0x%08x\n", gt->forcewake);
 
 	if (IS_GRAPHICS_VER(m->i915, 6, 11)) {
 		err_printf(m, "ERROR: 0x%08x\n", gt->error);
@@ -765,19 +768,38 @@ static void err_print_gt(struct drm_i915_error_state_buf *m,
 
 		err_printf(m, "  GAM_DONE: 0x%08x\n", gt->gam_done);
 	}
+}
+
+static void err_print_gt_fences(struct drm_i915_error_state_buf *m,
+				struct intel_gt_coredump *gt)
+{
+	int i;
+
+	for (i = 0; i < gt->nfence; i++)
+		err_printf(m, "  fence[%d] = %08llx\n", i, gt->fence[i]);
+}
+
+static void err_print_gt_engines(struct drm_i915_error_state_buf *m,
+				 struct intel_gt_coredump *gt)
+{
+	const struct intel_engine_coredump *ee;
 
 	for (ee = gt->engine; ee; ee = ee->next) {
 		const struct i915_vma_coredump *vma;
 
-		error_print_engine(m, ee);
+		if (ee->guc_capture_node)
+			intel_guc_capture_print_engine_node(m, ee);
+		else
+			error_print_engine(m, ee);
+
+		err_printf(m, "  hung: %u\n", ee->hung);
+		err_printf(m, "  engine reset count: %u\n", ee->reset_count);
+		error_print_context(m, "  Active context: ", &ee->context);
+
 		for (vma = ee->vma; vma; vma = vma->next)
 			print_error_vma(m, ee->engine, vma);
 	}
 
-	if (gt->uc)
-		err_print_uc(m, gt->uc);
-
-	err_print_gt_info(m, gt);
 }
 
 static void __err_print_to_sgl(struct drm_i915_error_state_buf *m,
@@ -833,8 +855,30 @@ static void __err_print_to_sgl(struct drm_i915_error_state_buf *m,
 	err_printf(m, "RPM wakelock: %s\n", yesno(error->wakelock));
 	err_printf(m, "PM suspended: %s\n", yesno(error->suspended));
 
-	if (error->gt)
-		err_print_gt(m, error->gt);
+	if (error->gt) {
+		bool print_guc_capture = false;
+
+		if (error->gt->uc && error->gt->uc->is_guc_capture)
+			print_guc_capture = true;
+
+		err_print_gt_display(m, error->gt);
+		err_print_gt_global_nonguc(m, error->gt);
+		err_print_gt_fences(m, error->gt);
+
+		/*
+		 * GuC dumped global, eng-class and eng-instance registers together
+		 * as part of engine state dump so we print in err_print_gt_engines
+		 */
+		if (!print_guc_capture)
+			err_print_gt_global(m, error->gt);
+
+		err_print_gt_engines(m, error->gt);
+
+		if (error->gt->uc)
+			err_print_uc(m, error->gt->uc);
+
+		err_print_gt_info(m, error->gt);
+	}
 
 	if (error->overlay)
 		intel_overlay_print_error_state(m, error->overlay);
@@ -982,6 +1026,7 @@ static void cleanup_gt(struct intel_gt_coredump *gt)
 		gt->engine = ee->next;
 
 		i915_vma_coredump_free(ee->vma);
+		intel_guc_capture_free_node(ee);
 		kfree(ee);
 	}
 
@@ -1433,7 +1478,7 @@ static void add_vma_coredump(struct intel_engine_coredump *ee,
 }
 
 struct intel_engine_coredump *
-intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp)
+intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp, u32 dump_flags)
 {
 	struct intel_engine_coredump *ee;
 
@@ -1443,8 +1488,10 @@ intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp)
 
 	ee->engine = engine;
 
-	engine_record_registers(ee);
-	engine_record_execlists(ee);
+	if (!(dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE)) {
+		engine_record_registers(ee);
+		engine_record_execlists(ee);
+	}
 
 	return ee;
 }
@@ -1508,7 +1555,8 @@ intel_engine_coredump_add_vma(struct intel_engine_coredump *ee,
 
 static struct intel_engine_coredump *
 capture_engine(struct intel_engine_cs *engine,
-	       struct i915_vma_compress *compress)
+	       struct i915_vma_compress *compress,
+	       u32 dump_flags)
 {
 	struct intel_engine_capture_vma *capture = NULL;
 	struct intel_engine_coredump *ee;
@@ -1516,7 +1564,7 @@ capture_engine(struct intel_engine_cs *engine,
 	struct i915_request *rq = NULL;
 	unsigned long flags;
 
-	ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL);
+	ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL, dump_flags);
 	if (!ee)
 		return NULL;
 
@@ -1549,6 +1597,8 @@ capture_engine(struct intel_engine_cs *engine,
 		i915_request_put(rq);
 		goto no_request_capture;
 	}
+	if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE)
+		intel_guc_capture_get_matching_node(engine->gt, ee, ce);
 
 	intel_engine_coredump_add_vma(ee, capture, compress);
 	i915_request_put(rq);
@@ -1563,7 +1613,8 @@ capture_engine(struct intel_engine_cs *engine,
 static void
 gt_record_engines(struct intel_gt_coredump *gt,
 		  intel_engine_mask_t engine_mask,
-		  struct i915_vma_compress *compress)
+		  struct i915_vma_compress *compress,
+		  u32 dump_flags)
 {
 	struct intel_engine_cs *engine;
 	enum intel_engine_id id;
@@ -1574,7 +1625,7 @@ gt_record_engines(struct intel_gt_coredump *gt,
 		/* Refill our page pool before entering atomic section */
 		pool_refill(&compress->pool, ALLOW_FAIL);
 
-		ee = capture_engine(engine, compress);
+		ee = capture_engine(engine, compress, dump_flags);
 		if (!ee)
 			continue;
 
@@ -1617,8 +1668,74 @@ gt_record_uc(struct intel_gt_coredump *gt,
 	return error_uc;
 }
 
-/* Capture all registers which don't fit into another category. */
-static void gt_record_regs(struct intel_gt_coredump *gt)
+/* Capture display registers. */
+static void gt_record_display_regs(struct intel_gt_coredump *gt)
+{
+	struct intel_uncore *uncore = gt->_gt->uncore;
+	struct drm_i915_private *i915 = uncore->i915;
+
+	if (GRAPHICS_VER(i915) >= 6)
+		gt->derrmr = intel_uncore_read(uncore, DERRMR);
+
+	if (GRAPHICS_VER(i915) >= 8)
+		gt->ier = intel_uncore_read(uncore, GEN8_DE_MISC_IER);
+	else if (IS_VALLEYVIEW(i915))
+		gt->ier = intel_uncore_read(uncore, VLV_IER);
+	else if (HAS_PCH_SPLIT(i915))
+		gt->ier = intel_uncore_read(uncore, DEIER);
+	else if (GRAPHICS_VER(i915) == 2)
+		gt->ier = intel_uncore_read16(uncore, GEN2_IER);
+	else
+		gt->ier = intel_uncore_read(uncore, GEN2_IER);
+}
+
+/* Capture all other registers that GuC doesn't capture. */
+static void gt_record_global_nonguc_regs(struct intel_gt_coredump *gt)
+{
+	struct intel_uncore *uncore = gt->_gt->uncore;
+	struct drm_i915_private *i915 = uncore->i915;
+	int i;
+
+	if (IS_VALLEYVIEW(i915)) {
+		gt->gtier[0] = intel_uncore_read(uncore, GTIER);
+		gt->ngtier = 1;
+	} else if (GRAPHICS_VER(i915) >= 11) {
+		gt->gtier[0] =
+			intel_uncore_read(uncore,
+					  GEN11_RENDER_COPY_INTR_ENABLE);
+		gt->gtier[1] =
+			intel_uncore_read(uncore, GEN11_VCS_VECS_INTR_ENABLE);
+		gt->gtier[2] =
+			intel_uncore_read(uncore, GEN11_GUC_SG_INTR_ENABLE);
+		gt->gtier[3] =
+			intel_uncore_read(uncore,
+					  GEN11_GPM_WGBOXPERF_INTR_ENABLE);
+		gt->gtier[4] =
+			intel_uncore_read(uncore,
+					  GEN11_CRYPTO_RSVD_INTR_ENABLE);
+		gt->gtier[5] =
+			intel_uncore_read(uncore,
+					  GEN11_GUNIT_CSME_INTR_ENABLE);
+		gt->ngtier = 6;
+	} else if (GRAPHICS_VER(i915) >= 8) {
+		for (i = 0; i < 4; i++)
+			gt->gtier[i] =
+				intel_uncore_read(uncore, GEN8_GT_IER(i));
+		gt->ngtier = 4;
+	} else if (HAS_PCH_SPLIT(i915)) {
+		gt->gtier[0] = intel_uncore_read(uncore, GTIER);
+		gt->ngtier = 1;
+	}
+
+	gt->eir = intel_uncore_read(uncore, EIR);
+	gt->pgtbl_er = intel_uncore_read(uncore, PGTBL_ER);
+}
+
+/*
+ * Capture all registers that relate to workload submission.
+ * NOTE: In GuC submission, when GuC resets an engine, it can dump these for us
+ */
+static void gt_record_global_regs(struct intel_gt_coredump *gt)
 {
 	struct intel_uncore *uncore = gt->_gt->uncore;
 	struct drm_i915_private *i915 = uncore->i915;
@@ -1634,11 +1751,8 @@ static void gt_record_regs(struct intel_gt_coredump *gt)
 	 */
 
 	/* 1: Registers specific to a single generation */
-	if (IS_VALLEYVIEW(i915)) {
-		gt->gtier[0] = intel_uncore_read(uncore, GTIER);
-		gt->ier = intel_uncore_read(uncore, VLV_IER);
+	if (IS_VALLEYVIEW(i915))
 		gt->forcewake = intel_uncore_read_fw(uncore, FORCEWAKE_VLV);
-	}
 
 	if (GRAPHICS_VER(i915) == 7)
 		gt->err_int = intel_uncore_read(uncore, GEN7_ERR_INT);
@@ -1666,7 +1780,6 @@ static void gt_record_regs(struct intel_gt_coredump *gt)
 		gt->forcewake = intel_uncore_read_fw(uncore, FORCEWAKE_MT);
 
 	if (GRAPHICS_VER(i915) >= 6) {
-		gt->derrmr = intel_uncore_read(uncore, DERRMR);
 		if (GRAPHICS_VER(i915) < 12) {
 			gt->error = intel_uncore_read(uncore, ERROR_GEN6);
 			gt->done_reg = intel_uncore_read(uncore, DONE_REG);
@@ -1702,44 +1815,6 @@ static void gt_record_regs(struct intel_gt_coredump *gt)
 
 		gt->gam_done = intel_uncore_read(uncore, GEN12_GAM_DONE);
 	}
-
-	/* 4: Everything else */
-	if (GRAPHICS_VER(i915) >= 11) {
-		gt->ier = intel_uncore_read(uncore, GEN8_DE_MISC_IER);
-		gt->gtier[0] =
-			intel_uncore_read(uncore,
-					  GEN11_RENDER_COPY_INTR_ENABLE);
-		gt->gtier[1] =
-			intel_uncore_read(uncore, GEN11_VCS_VECS_INTR_ENABLE);
-		gt->gtier[2] =
-			intel_uncore_read(uncore, GEN11_GUC_SG_INTR_ENABLE);
-		gt->gtier[3] =
-			intel_uncore_read(uncore,
-					  GEN11_GPM_WGBOXPERF_INTR_ENABLE);
-		gt->gtier[4] =
-			intel_uncore_read(uncore,
-					  GEN11_CRYPTO_RSVD_INTR_ENABLE);
-		gt->gtier[5] =
-			intel_uncore_read(uncore,
-					  GEN11_GUNIT_CSME_INTR_ENABLE);
-		gt->ngtier = 6;
-	} else if (GRAPHICS_VER(i915) >= 8) {
-		gt->ier = intel_uncore_read(uncore, GEN8_DE_MISC_IER);
-		for (i = 0; i < 4; i++)
-			gt->gtier[i] =
-				intel_uncore_read(uncore, GEN8_GT_IER(i));
-		gt->ngtier = 4;
-	} else if (HAS_PCH_SPLIT(i915)) {
-		gt->ier = intel_uncore_read(uncore, DEIER);
-		gt->gtier[0] = intel_uncore_read(uncore, GTIER);
-		gt->ngtier = 1;
-	} else if (GRAPHICS_VER(i915) == 2) {
-		gt->ier = intel_uncore_read16(uncore, GEN2_IER);
-	} else if (!IS_VALLEYVIEW(i915)) {
-		gt->ier = intel_uncore_read(uncore, GEN2_IER);
-	}
-	gt->eir = intel_uncore_read(uncore, EIR);
-	gt->pgtbl_er = intel_uncore_read(uncore, PGTBL_ER);
 }
 
 static void gt_record_info(struct intel_gt_coredump *gt)
@@ -1851,7 +1926,7 @@ i915_gpu_coredump_alloc(struct drm_i915_private *i915, gfp_t gfp)
 #define DAY_AS_SECONDS(x) (24 * 60 * 60 * (x))
 
 struct intel_gt_coredump *
-intel_gt_coredump_alloc(struct intel_gt *gt, gfp_t gfp)
+intel_gt_coredump_alloc(struct intel_gt *gt, gfp_t gfp, u32 dump_flags)
 {
 	struct intel_gt_coredump *gc;
 
@@ -1862,7 +1937,21 @@ intel_gt_coredump_alloc(struct intel_gt *gt, gfp_t gfp)
 	gc->_gt = gt;
 	gc->awake = intel_gt_pm_is_awake(gt);
 
-	gt_record_regs(gc);
+	gt_record_display_regs(gc);
+	gt_record_global_nonguc_regs(gc);
+
+	/*
+	 * GuC dumps global, eng-class and eng-instance registers
+	 * (that can change as part of engine state during execution)
+	 * before an engine is reset due to a hung context.
+	 * GuC captures and reports all three groups of registers
+	 * together as a single set before the engine is reset.
+	 * Thus, if GuC triggered the context reset we retrieve
+	 * the register values as part of gt_record_engines.
+	 */
+	if (!(dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE))
+		gt_record_global_regs(gc);
+
 	gt_record_fences(gc);
 
 	return gc;
@@ -1896,7 +1985,7 @@ void i915_vma_capture_finish(struct intel_gt_coredump *gt,
 }
 
 static struct i915_gpu_coredump *
-__i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask)
+__i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags)
 {
 	struct drm_i915_private *i915 = gt->i915;
 	struct i915_gpu_coredump *error;
@@ -1910,7 +1999,7 @@ __i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask)
 	if (!error)
 		return ERR_PTR(-ENOMEM);
 
-	error->gt = intel_gt_coredump_alloc(gt, ALLOW_FAIL);
+	error->gt = intel_gt_coredump_alloc(gt, ALLOW_FAIL, dump_flags);
 	if (error->gt) {
 		struct i915_vma_compress *compress;
 
@@ -1921,11 +2010,19 @@ __i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask)
 			return ERR_PTR(-ENOMEM);
 		}
 
+		if (INTEL_INFO(i915)->has_gt_uc) {
+			error->gt->uc = gt_record_uc(error->gt, compress);
+			if (error->gt->uc) {
+				if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE)
+					error->gt->uc->is_guc_capture = true;
+				else
+					GEM_BUG_ON(error->gt->uc->is_guc_capture);
+			}
+		}
+
 		gt_record_info(error->gt);
-		gt_record_engines(error->gt, engine_mask, compress);
+		gt_record_engines(error->gt, engine_mask, compress, dump_flags);
 
-		if (INTEL_INFO(i915)->has_gt_uc)
-			error->gt->uc = gt_record_uc(error->gt, compress);
 
 		i915_vma_capture_finish(error->gt, compress);
 
@@ -1938,7 +2035,7 @@ __i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask)
 }
 
 struct i915_gpu_coredump *
-i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask)
+i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags)
 {
 	static DEFINE_MUTEX(capture_mutex);
 	int ret = mutex_lock_interruptible(&capture_mutex);
@@ -1947,7 +2044,7 @@ i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask)
 	if (ret)
 		return ERR_PTR(ret);
 
-	dump = __i915_gpu_coredump(gt, engine_mask);
+	dump = __i915_gpu_coredump(gt, engine_mask, dump_flags);
 	mutex_unlock(&capture_mutex);
 
 	return dump;
@@ -1994,11 +2091,11 @@ void i915_error_state_store(struct i915_gpu_coredump *error)
  * to pick up.
  */
 void i915_capture_error_state(struct intel_gt *gt,
-			      intel_engine_mask_t engine_mask)
+			      intel_engine_mask_t engine_mask, u32 dump_flags)
 {
 	struct i915_gpu_coredump *error;
 
-	error = i915_gpu_coredump(gt, engine_mask);
+	error = i915_gpu_coredump(gt, engine_mask, dump_flags);
 	if (IS_ERR(error)) {
 		cmpxchg(&gt->i915->gpu_error.first_error, NULL, error);
 		return;
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h
index 5aedf5129814..d20a1779ea51 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.h
+++ b/drivers/gpu/drm/i915/i915_gpu_error.h
@@ -17,6 +17,7 @@
 #include "gt/intel_engine.h"
 #include "gt/intel_gt_types.h"
 #include "gt/uc/intel_uc_fw.h"
+#include "gt/uc/intel_guc_capture.h"
 
 #include "intel_device_info.h"
 
@@ -53,6 +54,8 @@ struct i915_request_coredump {
 	struct i915_sched_attr sched_attr;
 };
 
+struct __guc_capture_parsed_output;
+
 struct intel_engine_coredump {
 	const struct intel_engine_cs *engine;
 
@@ -84,6 +87,10 @@ struct intel_engine_coredump {
 	u32 rc_psmi; /* sleep state */
 	struct intel_instdone instdone;
 
+	/* GuC matched capture-lists info */
+	struct intel_guc_state_capture *capture;
+	struct __guc_capture_parsed_output *guc_capture_node;
+
 	struct i915_gem_context_coredump {
 		char comm[TASK_COMM_LEN];
 
@@ -124,7 +131,6 @@ struct intel_gt_coredump {
 	u32 pgtbl_er;
 	u32 ier;
 	u32 gtier[6], ngtier;
-	u32 derrmr;
 	u32 forcewake;
 	u32 error; /* gen6+ */
 	u32 err_int; /* gen7 */
@@ -137,9 +143,12 @@ struct intel_gt_coredump {
 	u32 gfx_mode;
 	u32 gtt_cache;
 	u32 aux_err; /* gen12 */
-	u32 sfc_done[GEN12_SFC_DONE_MAX]; /* gen12 */
 	u32 gam_done; /* gen12 */
 
+	/* Display related */
+	u32 derrmr;
+	u32 sfc_done[GEN12_SFC_DONE_MAX]; /* gen12 */
+
 	u32 nfence;
 	u64 fence[I915_MAX_NUM_FENCES];
 
@@ -149,6 +158,7 @@ struct intel_gt_coredump {
 		struct intel_uc_fw guc_fw;
 		struct intel_uc_fw huc_fw;
 		struct i915_vma_coredump *guc_log;
+		bool is_guc_capture;
 	} *uc;
 
 	struct intel_gt_coredump *next;
@@ -210,24 +220,27 @@ struct drm_i915_error_state_buf {
 	int err;
 };
 
+#define CORE_DUMP_FLAG_NONE           0x0
+#define CORE_DUMP_FLAG_IS_GUC_CAPTURE BIT(0)
+
 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
 
 __printf(2, 3)
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
 
 struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt,
-					    intel_engine_mask_t engine_mask);
+					    intel_engine_mask_t engine_mask, u32 dump_flags);
 void i915_capture_error_state(struct intel_gt *gt,
-			      intel_engine_mask_t engine_mask);
+			      intel_engine_mask_t engine_mask, u32 dump_flags);
 
 struct i915_gpu_coredump *
 i915_gpu_coredump_alloc(struct drm_i915_private *i915, gfp_t gfp);
 
 struct intel_gt_coredump *
-intel_gt_coredump_alloc(struct intel_gt *gt, gfp_t gfp);
+intel_gt_coredump_alloc(struct intel_gt *gt, gfp_t gfp, u32 dump_flags);
 
 struct intel_engine_coredump *
-intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp);
+intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp, u32 dump_flags);
 
 struct intel_engine_capture_vma *
 intel_engine_coredump_add_request(struct intel_engine_coredump *ee,
@@ -271,7 +284,7 @@ void i915_disable_error_state(struct drm_i915_private *i915, int err);
 #else
 
 static inline void
-i915_capture_error_state(struct intel_gt *gt, intel_engine_mask_t engine_mask)
+i915_capture_error_state(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags)
 {
 }
 
@@ -282,13 +295,13 @@ i915_gpu_coredump_alloc(struct drm_i915_private *i915, gfp_t gfp)
 }
 
 static inline struct intel_gt_coredump *
-intel_gt_coredump_alloc(struct intel_gt *gt, gfp_t gfp)
+intel_gt_coredump_alloc(struct intel_gt *gt, gfp_t gfp, u32 dump_flags)
 {
 	return NULL;
 }
 
 static inline struct intel_engine_coredump *
-intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp)
+intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp, u32 dump_flags)
 {
 	return NULL;
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 09/10] drm/i915/guc: Follow legacy register names
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (8 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-02-03 19:09   ` Matthew Brost
  -1 siblings, 1 reply; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Before we print the GuC provided register dumps, modify the
register tables to use string names as per the legacy error
capture execlist codes.

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 70 +++++++++----------
 1 file changed, 35 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 2f5dc413dddc..506496058daf 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -22,7 +22,7 @@
  *       from the engine-mmio-base
  */
 #define COMMON_BASE_GLOBAL() \
-	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}
+	{FORCEWAKE_MT,             0,      0, "FORCEWAKE"}
 
 #define COMMON_GEN9BASE_GLOBAL() \
 	{GEN8_FAULT_TLB_DATA0,     0,      0, "GEN8_FAULT_TLB_DATA0"}, \
@@ -34,43 +34,43 @@
 #define COMMON_GEN12BASE_GLOBAL() \
 	{GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0"}, \
 	{GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1"}, \
-	{GEN12_AUX_ERR_DBG,        0,      0, "GEN12_AUX_ERR_DBG"}, \
-	{GEN12_GAM_DONE,           0,      0, "GEN12_GAM_DONE"}, \
-	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
+	{GEN12_AUX_ERR_DBG,        0,      0, "AUX_ERR_DBG"}, \
+	{GEN12_GAM_DONE,           0,      0, "GAM_DONE"}, \
+	{GEN12_RING_FAULT_REG,     0,      0, "FAULT_REG"}
 
 #define COMMON_BASE_ENGINE_INSTANCE() \
-	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
-	{RING_ESR(0),              0,      0, "RING_ESR"}, \
-	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \
-	{RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UP32"}, \
-	{RING_IPEIR(0),            0,      0, "RING_IPEIR"}, \
-	{RING_IPEHR(0),            0,      0, "RING_IPEHR"}, \
-	{RING_INSTPS(0),           0,      0, "RING_INSTPS"}, \
+	{RING_PSMI_CTL(0),         0,      0, "RC PSMI"}, \
+	{RING_ESR(0),              0,      0, "ESR"}, \
+	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LDW"}, \
+	{RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UDW"}, \
+	{RING_IPEIR(0),            0,      0, "IPEIR"}, \
+	{RING_IPEHR(0),            0,      0, "IPEHR"}, \
+	{RING_INSTPS(0),           0,      0, "INSTPS"}, \
 	{RING_BBADDR(0),           0,      0, "RING_BBADDR_LOW32"}, \
 	{RING_BBADDR_UDW(0),       0,      0, "RING_BBADDR_UP32"}, \
-	{RING_BBSTATE(0),          0,      0, "RING_BBSTATE"}, \
+	{RING_BBSTATE(0),          0,      0, "BB_STATE"}, \
 	{CCID(0),                  0,      0, "CCID"}, \
-	{RING_ACTHD(0),            0,      0, "RING_ACTHD_LOW32"}, \
-	{RING_ACTHD_UDW(0),        0,      0, "RING_ACTHD_UP32"}, \
-	{RING_INSTPM(0),           0,      0, "RING_INSTPM"}, \
+	{RING_ACTHD(0),            0,      0, "ACTHD_LDW"}, \
+	{RING_ACTHD_UDW(0),        0,      0, "ACTHD_UDW"}, \
+	{RING_INSTPM(0),           0,      0, "INSTPM"}, \
+	{RING_INSTDONE(0),         0,      0, "INSTDONE"}, \
 	{RING_NOPID(0),            0,      0, "RING_NOPID"}, \
-	{RING_START(0),            0,      0, "RING_START"}, \
-	{RING_HEAD(0),             0,      0, "RING_HEAD"}, \
-	{RING_TAIL(0),             0,      0, "RING_TAIL"}, \
-	{RING_CTL(0),              0,      0, "RING_CTL"}, \
-	{RING_MI_MODE(0),          0,      0, "RING_MI_MODE"}, \
+	{RING_START(0),            0,      0, "START"}, \
+	{RING_HEAD(0),             0,      0, "HEAD"}, \
+	{RING_TAIL(0),             0,      0, "TAIL"}, \
+	{RING_CTL(0),              0,      0, "CTL"}, \
+	{RING_MI_MODE(0),          0,      0, "MODE"}, \
 	{RING_CONTEXT_CONTROL(0),  0,      0, "RING_CONTEXT_CONTROL"}, \
-	{RING_INSTDONE(0),         0,      0, "RING_INSTDONE"}, \
-	{RING_HWS_PGA(0),          0,      0, "RING_HWS_PGA"}, \
-	{RING_MODE_GEN7(0),        0,      0, "RING_MODE_GEN7"}, \
-	{GEN8_RING_PDP_LDW(0, 0),  0,      0, "GEN8_RING_PDP0_LDW"}, \
-	{GEN8_RING_PDP_UDW(0, 0),  0,      0, "GEN8_RING_PDP0_UDW"}, \
-	{GEN8_RING_PDP_LDW(0, 1),  0,      0, "GEN8_RING_PDP1_LDW"}, \
-	{GEN8_RING_PDP_UDW(0, 1),  0,      0, "GEN8_RING_PDP1_UDW"}, \
-	{GEN8_RING_PDP_LDW(0, 2),  0,      0, "GEN8_RING_PDP2_LDW"}, \
-	{GEN8_RING_PDP_UDW(0, 2),  0,      0, "GEN8_RING_PDP2_UDW"}, \
-	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "GEN8_RING_PDP3_LDW"}, \
-	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "GEN8_RING_PDP3_UDW"}
+	{RING_HWS_PGA(0),          0,      0, "HWS"}, \
+	{RING_MODE_GEN7(0),        0,      0, "GFX_MODE"}, \
+	{GEN8_RING_PDP_LDW(0, 0),  0,      0, "PDP0_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 0),  0,      0, "PDP0_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 1),  0,      0, "PDP1_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 1),  0,      0, "PDP1_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 2),  0,      0, "PDP2_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 2),  0,      0, "PDP2_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "PDP3_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "PDP3_UDW"}
 
 #define COMMON_BASE_HAS_EU() \
 	{EIR,                      0,      0, "EIR"}
@@ -83,10 +83,10 @@
 	{GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2"}
 
 #define COMMON_GEN12BASE_VEC() \
-	{GEN12_SFC_DONE(0),        0,      0, "GEN12_SFC_DONE0"}, \
-	{GEN12_SFC_DONE(1),        0,      0, "GEN12_SFC_DONE1"}, \
-	{GEN12_SFC_DONE(2),        0,      0, "GEN12_SFC_DONE2"}, \
-	{GEN12_SFC_DONE(3),        0,      0, "GEN12_SFC_DONE3"}
+	{GEN12_SFC_DONE(0),        0,      0, "SFC_DONE[0]"}, \
+	{GEN12_SFC_DONE(1),        0,      0, "SFC_DONE[1]"}, \
+	{GEN12_SFC_DONE(2),        0,      0, "SFC_DONE[2]"}, \
+	{GEN12_SFC_DONE(3),        0,      0, "SFC_DONE[3]"}
 
 /* XE_LPD - Global */
 static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [Intel-gfx] [PATCH v5 10/10] drm/i915/guc: Print the GuC error capture output register list.
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (9 preceding siblings ...)
  (?)
@ 2022-01-26 10:48 ` Alan Previn
  2022-02-07 21:43   ` Umesh Nerlige Ramappa
  -1 siblings, 1 reply; 52+ messages in thread
From: Alan Previn @ 2022-01-26 10:48 UTC (permalink / raw)
  To: intel-gfx; +Cc: Alan Previn

Print the GuC captured error state register list (string names
and values) when gpu_coredump_state printout is invoked via
the i915 debugfs for flushing the gpu error-state that was
captured prior.

Since GuC could have reported multiple engine register dumps
in a single notification event, parse the captured data
(appearing as a stream of structures) to identify each dump as
a different 'engine-capture-group-output'.

Finally, for each 'engine-capture-group-output' that is found,
verify if the engine register dump corresponds to the
engine_coredump content that was previously populated by the
i915_gpu_coredump function. That function would have copied
the context's vma's including the bacth buffer during the
G2H-context-reset notification that occurred earlier. Perform
this verification check by comparing guc_id, lrca and engine-
instance obtained from the 'engine-capture-group-output' vs a
copy of that same info taken during i915_gpu_coredump. If
they match, then print those vma's as well (such as the batch
buffers).

Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
---
 drivers/gpu/drm/i915/gt/intel_engine_cs.c     |   4 +-
 .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 169 ++++++++++++++++++
 .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   2 +-
 drivers/gpu/drm/i915/i915_debugfs.c           |   1 +
 drivers/gpu/drm/i915/i915_gpu_error.c         |  16 +-
 drivers/gpu/drm/i915/i915_gpu_error.h         |   5 +
 6 files changed, 185 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index 4317ae5e525b..47c0c32d9b86 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -1628,9 +1628,7 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine,
 		drm_printf(m, "\tIPEHR: 0x%08x\n", ENGINE_READ(engine, IPEHR));
 	}
 
-	if (intel_engine_uses_guc(engine)) {
-		/* nothing to print yet */
-	} else if (HAS_EXECLISTS(dev_priv)) {
+	if (HAS_EXECLISTS(dev_priv) && !intel_engine_uses_guc(engine)) {
 		struct i915_request * const *port, *rq;
 		const u32 *hws =
 			&engine->status_page.addr[I915_HWS_CSB_BUF0_INDEX];
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 506496058daf..5cb24098747e 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -739,6 +739,15 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
  *                                       intel_engine_coredump struct (if the context and
  *                                       engine of the event notification matches a node
  *                                       in the link list)
+ *
+ * User Sysfs / Debugfs
+ * --------------------
+ *      --> i915_gpu_coredump_copy_to_buffer->
+ *                   L--> err_print_to_sgl --> err_print_gt
+ *                        L--> error_print_guc_captures
+ *                             L--> intel_guc_capture_print_node prints the
+ *                                  register lists values of the attached node
+ *                                  on the error-engine-dump being reported.
  */
 
 static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
@@ -1216,12 +1225,172 @@ static void __guc_capture_store_snapshot_work(struct intel_guc *guc)
 
 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
 
+static const char *
+guc_capture_reg_to_str(const struct intel_guc *guc, u32 owner, u32 type,
+		       u32 class, u32 id, u32 offset, u32 *is_ext)
+{
+	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
+	struct __guc_mmio_reg_descr_group *match;
+	int num_regs, j;
+
+	*is_ext = 0;
+	if (!reglists)
+		return NULL;
+
+	match = guc_capture_get_one_list(reglists, owner, type, id);
+
+	if (match) {
+		for (num_regs = match->num_regs, j = 0; j < num_regs; ++j) {
+			if (offset == match->list[j].reg.reg)
+				return match->list[j].regname;
+		}
+	}
+	if (match->ext) {
+		for (num_regs = match->num_ext, j = 0; j < num_regs; ++j) {
+			if (offset == match->ext[j].reg.reg) {
+				*is_ext = 1;
+				return match->ext[j].regname;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+#ifdef CONFIG_DRM_I915_DEBUG_GUC
+#define guc_capt_err_print(a, b, ...) \
+	do { \
+		drm_warn(a, __VA_ARGS__); \
+		if (b) \
+			i915_error_printf(b, __VA_ARGS__); \
+	} while (0)
+#else
+#define guc_capt_err_print(a, b, ...) \
+	do { \
+		if (b) \
+			i915_error_printf(b, __VA_ARGS__); \
+	} while (0)
+#endif
+
+static struct intel_engine_cs *
+guc_capture_lookup_engine(struct intel_guc *guc, u8 guc_class, u8 instance)
+{
+	struct intel_gt *gt = guc_to_gt(guc);
+	u8 engine_class = guc_class_to_engine_class(guc_class);
+
+	/* Class index is checked in class converter */
+	GEM_BUG_ON(instance > MAX_ENGINE_INSTANCE);
+
+	return gt->engine_class[engine_class][instance];
+}
+
+#define GCAP_PRINT_INTEL_ENG_INFO(i915, ebuf, eng) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Name: %s command stream\n", \
+		      (eng)->name); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-LogicalMask: 0x%08x\n", \
+		      (eng)->logical_mask); \
+	} while (0)
+
+#define GCAP_PRINT_GUC_INST_INFO(i915, ebuf, node) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Engine-Inst-Id: 0x%08x\n", \
+		      (node)->eng_inst); \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Context-Id: 0x%08x\n", (node)->guc_id); \
+		PRINT(&(i915)->drm, (ebuf), "    LRCA: 0x%08x\n", (node)->lrca); \
+	} while (0)
+
+#define PRINT guc_capt_err_print
+
 int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
 					const struct intel_engine_coredump *ee)
 {
+	struct intel_guc_state_capture *cap;
+	struct intel_guc *guc;
+	struct drm_i915_private *i915;
+	struct __guc_capture_parsed_output *node;
+	struct guc_mmio_reg *regs;
+	const char *grptypestr[GUC_STATE_CAPTURE_GROUP_TYPE_MAX] = {"full-capture",
+								    "partial-capture"};
+	const char *datatypestr[GUC_CAPTURE_LIST_TYPE_MAX] = {"Global", "Engine-Class",
+							      "Engine-Instance"};
+	struct intel_engine_cs *eng;
+	int numregs, i, j;
+	u32 is_ext;
+	const char *str;
+	char noname[16];
+
+	if (!ebuf || !ee)
+		return -EINVAL;
+	cap = ee->capture;
+	if (!cap->priv || !ee->engine)
+		return -ENODEV;
+
+	guc = container_of(cap, struct intel_guc, capture);
+	i915 = (container_of(guc, struct intel_gt, uc.guc))->i915;
+	PRINT(&i915->drm, ebuf, "global --- GuC Error Capture on %s command stream:\n",
+	      ee->engine->name);
+
+	node = ee->guc_capture_node;
+	if (!node) {
+		PRINT(&i915->drm, ebuf, "  No matching ee-node\n");
+		return 0;
+	}
+
+	PRINT(&i915->drm, ebuf, "Coverage:  %s\n", grptypestr[node->is_partial]);
+
+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
+		PRINT(&i915->drm, ebuf, "  RegListType: %s\n",
+		      datatypestr[i % GUC_CAPTURE_LIST_TYPE_MAX]);
+		PRINT(&i915->drm, ebuf, "    Owner-Id: %d\n", node->reginfo[i].vfid);
+
+		switch (i) {
+		case GUC_CAPTURE_LIST_TYPE_GLOBAL:
+		default:
+			break;
+		case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
+			PRINT(&i915->drm, ebuf, "    GuC-Eng-Class: %d\n", node->eng_class);
+			PRINT(&i915->drm, ebuf, "    i915-Eng-Class: %d\n",
+			      guc_class_to_engine_class(node->eng_class));
+			break;
+		case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
+			eng = guc_capture_lookup_engine(guc, node->eng_class, node->eng_inst);
+			if (eng)
+				GCAP_PRINT_INTEL_ENG_INFO(i915, ebuf, eng);
+			else
+				PRINT(&i915->drm, ebuf, "    i915-Eng-Lookup Fail!\n");
+			GCAP_PRINT_GUC_INST_INFO(i915, ebuf, node);
+			break;
+		}
+
+		numregs = node->reginfo[i].num;
+		PRINT(&i915->drm, ebuf, "    NumRegs: %d\n", numregs);
+		j = 0;
+		while (numregs--) {
+			regs = node->reginfo[i].regs;
+			str = guc_capture_reg_to_str(guc, GUC_CAPTURE_LIST_INDEX_PF, i,
+						     node->eng_class, 0, regs[j].offset, &is_ext);
+			if (!str) {
+				snprintf(noname, sizeof(noname), "REG-0x%08x", regs[j].offset);
+				PRINT(&i915->drm, ebuf, "      %s", noname);
+			} else {
+				PRINT(&i915->drm, ebuf, "      %s", str);
+			}
+			if (is_ext)
+				PRINT(&i915->drm, ebuf, "[%ld][%ld]",
+				      FIELD_GET(GUC_REGSET_STEERING_GROUP, regs[j].flags),
+				      FIELD_GET(GUC_REGSET_STEERING_INSTANCE, regs[j].flags));
+			PRINT(&i915->drm, ebuf, ":  0x%08x\n", regs[j].value);
+			++j;
+		}
+	}
 	return 0;
 }
 
+#undef PRINT
+
 #endif //CONFIG_DRM_I915_DEBUG_GUC
 
 void intel_guc_capture_free_node(struct intel_engine_coredump *ee)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
index 9a2037638e64..3ed33f14ac7d 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
@@ -11,8 +11,8 @@
 struct drm_i915_error_state_buf;
 struct guc_ads;
 struct guc_gt_system_info;
-struct intel_context;
 struct intel_engine_coredump;
+struct intel_context;
 struct intel_gt;
 struct intel_guc;
 
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index d2af0d1f3a3e..35faba20d406 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -295,6 +295,7 @@ static int i915_gpu_info_open(struct inode *inode, struct file *file)
 	gpu = NULL;
 	with_intel_runtime_pm(&i915->runtime_pm, wakeref)
 		gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES, CORE_DUMP_FLAG_NONE);
+
 	if (IS_ERR(gpu))
 		return PTR_ERR(gpu);
 
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index d8c82589d86e..67d39226155e 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -526,8 +526,8 @@ __find_vma(struct i915_vma_coredump *vma, const char *name)
 	return NULL;
 }
 
-static struct i915_vma_coredump *
-find_batch(const struct intel_engine_coredump *ee)
+struct i915_vma_coredump *
+intel_gpu_error_find_batch(const struct intel_engine_coredump *ee)
 {
 	return __find_vma(ee->vma, "batch");
 }
@@ -555,7 +555,7 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
 
 	error_print_instdone(m, ee);
 
-	batch = find_batch(ee);
+	batch = intel_gpu_error_find_batch(ee);
 	if (batch) {
 		u64 start = batch->gtt_offset;
 		u64 end = start + batch->gtt_size;
@@ -606,9 +606,9 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
 	va_end(args);
 }
 
-static void print_error_vma(struct drm_i915_error_state_buf *m,
-			    const struct intel_engine_cs *engine,
-			    const struct i915_vma_coredump *vma)
+void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m,
+			       const struct intel_engine_cs *engine,
+			       const struct i915_vma_coredump *vma)
 {
 	char out[ASCII85_BUFSZ];
 	struct page *page;
@@ -677,7 +677,7 @@ static void err_print_uc(struct drm_i915_error_state_buf *m,
 
 	intel_uc_fw_dump(&error_uc->guc_fw, &p);
 	intel_uc_fw_dump(&error_uc->huc_fw, &p);
-	print_error_vma(m, NULL, error_uc->guc_log);
+	intel_gpu_error_print_vma(m, NULL, error_uc->guc_log);
 }
 
 static void err_free_sgl(struct scatterlist *sgl)
@@ -797,7 +797,7 @@ static void err_print_gt_engines(struct drm_i915_error_state_buf *m,
 		error_print_context(m, "  Active context: ", &ee->context);
 
 		for (vma = ee->vma; vma; vma = vma->next)
-			print_error_vma(m, ee->engine, vma);
+			intel_gpu_error_print_vma(m, ee->engine, vma);
 	}
 
 }
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h
index d20a1779ea51..5f52dda67ef8 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.h
+++ b/drivers/gpu/drm/i915/i915_gpu_error.h
@@ -227,6 +227,11 @@ struct drm_i915_error_state_buf {
 
 __printf(2, 3)
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
+void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m,
+			       const struct intel_engine_cs *engine,
+			       const struct i915_vma_coredump *vma);
+struct i915_vma_coredump *
+intel_gpu_error_find_batch(const struct intel_engine_coredump *ee);
 
 struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt,
 					    intel_engine_mask_t engine_mask, u32 dump_flags);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists Alan Previn
@ 2022-01-26 18:09   ` Jani Nikula
  2022-01-26 18:15   ` Jani Nikula
  2022-01-26 22:46   ` Lucas De Marchi
  2 siblings, 0 replies; 52+ messages in thread
From: Jani Nikula @ 2022-01-26 18:09 UTC (permalink / raw)
  To: Alan Previn, intel-gfx; +Cc: Alan Previn

On Wed, 26 Jan 2022, Alan Previn <alan.previn.teres.alexis@intel.com> wrote:
> Update GuC ADS size allocation to include space for
> the lists of error state capture register descriptors.
>
> Also, populate the lists of registers we want GuC to report back to
> Host on engine reset events. This list should include global,
> engine-class and engine-instance registers for every engine-class
> type on the current hardware.
>
> NOTE: Start with a sample table of register lists to layout the
> framework before adding real registers in subsequent patch.
>
> Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |  36 ++
>  drivers/gpu/drm/i915/gt/uc/intel_guc.c        |  13 +-
>  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |  11 +-
>  drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c    |  36 +-
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 450 ++++++++++++++++++
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |  20 +
>  drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |  17 +
>  8 files changed, 555 insertions(+), 29 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
>  create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>  create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index a26e6736bebb..236bcd6cd8ea 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -183,6 +183,7 @@ i915-y += gt/uc/intel_uc.o \
>  	  gt/uc/intel_uc_fw.o \
>  	  gt/uc/intel_guc.o \
>  	  gt/uc/intel_guc_ads.o \
> +	  gt/uc/intel_guc_capture.o \
>  	  gt/uc/intel_guc_ct.o \
>  	  gt/uc/intel_guc_debugfs.o \
>  	  gt/uc/intel_guc_fw.o \
> diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
> new file mode 100644
> index 000000000000..15b8c02b8a76
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021-2021 Intel Corporation
> + */
> +
> +#ifndef _INTEL_GUC_CAPTURE_FWIF_H
> +#define _INTEL_GUC_CAPTURE_FWIF_H
> +
> +#include <linux/types.h>
> +#include "intel_guc_fwif.h"
> +
> +struct intel_guc;
> +
> +struct __guc_mmio_reg_descr {
> +	i915_reg_t reg;
> +	u32 flags;
> +	u32 mask;
> +	const char *regname;
> +};
> +
> +struct __guc_mmio_reg_descr_group {
> +	struct __guc_mmio_reg_descr *list;
> +	u32 num_regs;
> +	u32 owner; /* see enum guc_capture_owner */
> +	u32 type; /* see enum guc_capture_type */
> +	u32 engine; /* as per MAX_ENGINE_CLASS */
> +};
> +
> +struct __guc_state_capture_priv {
> +	struct __guc_mmio_reg_descr_group *reglists;
> +	u16 num_instance_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
> +	u16 num_class_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
> +	u16 num_global_regs[GUC_CAPTURE_LIST_INDEX_MAX];
> +};
> +
> +#endif /* _INTEL_GUC_CAPTURE_FWIF_H */
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
> index ba2a67f9e500..d035a3ba8700 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
> @@ -8,8 +8,9 @@
>  #include "gt/intel_gt_irq.h"
>  #include "gt/intel_gt_pm_irq.h"
>  #include "intel_guc.h"
> -#include "intel_guc_slpc.h"
>  #include "intel_guc_ads.h"
> +#include "intel_guc_capture.h"
> +#include "intel_guc_slpc.h"
>  #include "intel_guc_submission.h"
>  #include "i915_drv.h"
>  #include "i915_irq.h"
> @@ -361,9 +362,14 @@ int intel_guc_init(struct intel_guc *guc)
>  	if (ret)
>  		goto err_fw;
>  
> -	ret = intel_guc_ads_create(guc);
> +	ret = intel_guc_capture_init(guc);
>  	if (ret)
>  		goto err_log;
> +
> +	ret = intel_guc_ads_create(guc);
> +	if (ret)
> +		goto err_capture;
> +
>  	GEM_BUG_ON(!guc->ads_vma);
>  
>  	ret = intel_guc_ct_init(&guc->ct);
> @@ -402,6 +408,8 @@ int intel_guc_init(struct intel_guc *guc)
>  	intel_guc_ct_fini(&guc->ct);
>  err_ads:
>  	intel_guc_ads_destroy(guc);
> +err_capture:
> +	intel_guc_capture_destroy(guc);
>  err_log:
>  	intel_guc_log_destroy(&guc->log);
>  err_fw:
> @@ -429,6 +437,7 @@ void intel_guc_fini(struct intel_guc *guc)
>  	intel_guc_ct_fini(&guc->ct);
>  
>  	intel_guc_ads_destroy(guc);
> +	intel_guc_capture_destroy(guc);
>  	intel_guc_log_destroy(&guc->log);
>  	intel_uc_fw_fini(&guc->fw);
>  }
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> index 697d9d66acef..4e819853ec2e 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> @@ -9,18 +9,19 @@
>  #include <linux/xarray.h>
>  #include <linux/delay.h>
>  
> -#include "intel_uncore.h"
> +#include "intel_guc_ct.h"
>  #include "intel_guc_fw.h"
>  #include "intel_guc_fwif.h"
> -#include "intel_guc_ct.h"
>  #include "intel_guc_log.h"
>  #include "intel_guc_reg.h"
>  #include "intel_guc_slpc_types.h"
>  #include "intel_uc_fw.h"
> +#include "intel_uncore.h"
>  #include "i915_utils.h"
>  #include "i915_vma.h"
>  
>  struct __guc_ads_blob;
> +struct __guc_state_capture_priv;
>  
>  /**
>   * struct intel_guc - Top level structure of GuC.
> @@ -37,6 +38,10 @@ struct intel_guc {
>  	struct intel_guc_ct ct;
>  	/** @slpc: sub-structure containing SLPC related data and objects */
>  	struct intel_guc_slpc slpc;
> +	/** @capture: the error-state-capture module's data and objects */
> +	struct intel_guc_state_capture {
> +		struct __guc_state_capture_priv *priv;
> +	} capture;
>  
>  	/** @sched_engine: Global engine used to submit requests to GuC */
>  	struct i915_sched_engine *sched_engine;
> @@ -152,6 +157,8 @@ struct intel_guc {
>  	u32 ads_regset_size;
>  	/** @ads_golden_ctxt_size: size of the golden contexts in the ADS */
>  	u32 ads_golden_ctxt_size;
> +	/** @ads_capture_size: size of register lists in the ADS used for error capture */
> +	u32 ads_capture_size;
>  	/** @ads_engine_usage_size: size of engine usage in the ADS */
>  	u32 ads_engine_usage_size;
>  
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
> index 668bf4ac9b0c..4597ba0a4177 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
> @@ -10,6 +10,7 @@
>  #include "gt/intel_lrc.h"
>  #include "gt/shmem_utils.h"
>  #include "intel_guc_ads.h"
> +#include "intel_guc_capture.h"
>  #include "intel_guc_fwif.h"
>  #include "intel_uc.h"
>  #include "i915_drv.h"
> @@ -72,8 +73,7 @@ static u32 guc_ads_golden_ctxt_size(struct intel_guc *guc)
>  
>  static u32 guc_ads_capture_size(struct intel_guc *guc)
>  {
> -	/* FIXME: Allocate a proper capture list */
> -	return PAGE_ALIGN(PAGE_SIZE);
> +	return PAGE_ALIGN(guc->ads_capture_size);
>  }
>  
>  static u32 guc_ads_private_data_size(struct intel_guc *guc)
> @@ -520,26 +520,6 @@ static void guc_init_golden_context(struct intel_guc *guc)
>  	GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
>  }
>  
> -static void guc_capture_list_init(struct intel_guc *guc, struct __guc_ads_blob *blob)
> -{
> -	int i, j;
> -	u32 addr_ggtt, offset;
> -
> -	offset = guc_ads_capture_offset(guc);
> -	addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
> -
> -	/* FIXME: Populate a proper capture list */
> -
> -	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
> -		for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
> -			blob->ads.capture_instance[i][j] = addr_ggtt;
> -			blob->ads.capture_class[i][j] = addr_ggtt;
> -		}
> -
> -		blob->ads.capture_global[i] = addr_ggtt;
> -	}
> -}
> -
>  static void __guc_ads_init(struct intel_guc *guc)
>  {
>  	struct intel_gt *gt = guc_to_gt(guc);
> @@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
>  
>  	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
>  
> -	/* Capture list for hang debug */
> -	guc_capture_list_init(guc, blob);
> -
> +	/* Lists for error capture debug */
> +	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
> +				     guc_ads_capture_offset(guc), &blob->system_info);
>  	/* ADS */
>  	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
>  	blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
> @@ -615,6 +595,12 @@ int intel_guc_ads_create(struct intel_guc *guc)
>  		return ret;
>  	guc->ads_golden_ctxt_size = ret;
>  
> +	/* Likewise the capture lists: */
> +	ret = intel_guc_capture_prep_lists(guc, NULL, 0, 0, NULL);
> +	if (ret < 0)
> +		return ret;
> +	guc->ads_capture_size = ret;
> +
>  	/* Now the total size can be determined: */
>  	size = guc_ads_blob_size(guc);
>  
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> new file mode 100644
> index 000000000000..06873d617b8b
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> @@ -0,0 +1,450 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021-2021 Intel Corporation
> + */
> +
> +#include <linux/types.h>
> +
> +#include <drm/drm_print.h>
> +
> +#include "gt/intel_engine_regs.h"
> +#include "gt/intel_gt.h"
> +#include "guc_capture_fwif.h"
> +#include "intel_guc_fwif.h"
> +#include "i915_drv.h"
> +#include "i915_memcpy.h"
> +
> +/*
> + * Define all device tables of GuC error capture register lists
> + * NOTE: For engine-registers, GuC only needs the register offsets
> + *       from the engine-mmio-base
> + */
> +/* XE_LPD - Global */
> +static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
> +	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
> +};
> +
> +/* XE_LPD - Render / Compute Per-Class */
> +static struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
> +	{EIR,                      0,      0, "EIR"}
> +};
> +
> +/* XE_LPD - Render / Compute Per-Engine-Instance */
> +static struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
> +	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> +	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +};
> +
> +/* XE_LPD - Media Decode/Encode Per-Class */
> +static struct __guc_mmio_reg_descr xe_lpd_vd_class_regs[] = {
> +};
> +
> +/* XE_LPD - Media Decode/Encode Per-Engine-Instance */
> +static struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
> +	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> +	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +};
> +
> +/* XE_LPD - Video Enhancement Per-Class */
> +static struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
> +};
> +
> +/* XE_LPD - Video Enhancement Per-Engine-Instance */
> +static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
> +	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> +	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +};
> +
> +#define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
> +#define TO_GCAP_DEF_TYPE(x) (GUC_CAPTURE_LIST_TYPE_##x)
> +#define MAKE_REGLIST(regslist, regsowner, regstype, class) \
> +	{ \
> +		.list = regslist, \
> +		.num_regs = ARRAY_SIZE(regslist), \
> +		.owner = TO_GCAP_DEF_OWNER(regsowner), \
> +		.type = TO_GCAP_DEF_TYPE(regstype), \
> +		.engine = class, \
> +	}
> +
> +/* List of lists */
> +static struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
> +	MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
> +	MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
> +	MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
> +	MAKE_REGLIST(xe_lpd_vd_class_regs, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
> +	MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
> +	MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
> +	MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
> +	{}
> +};
> +
> +static struct __guc_mmio_reg_descr_group *
> +guc_capture_get_device_reglist(struct intel_guc *guc)
> +{
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +
> +	if (IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915) ||
> +	    IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) {
> +		/*
> +		 * For certain engine classes, there are slice and subslice
> +		 * level registers requiring steering. We allocate and populate
> +		 * these at init time based on hw config add it as an extension
> +		 * list at the end of the pre-populated render list.
> +		 */
> +		return xe_lpd_lists;
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct __guc_mmio_reg_descr_group *
> +guc_capture_get_one_list(struct __guc_mmio_reg_descr_group *reglists, u32 owner, u32 type, u32 id)
> +{
> +	int i;
> +
> +	if (!reglists)
> +		return NULL;
> +
> +	for (i = 0; reglists[i].list; i++) {
> +		if (reglists[i].owner == owner && reglists[i].type == type &&
> +		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
> +		return &reglists[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +static const char *
> +guc_capture_stringify_owner(u32 owner)
> +{
> +	switch (owner) {
> +	case GUC_CAPTURE_LIST_INDEX_PF:
> +		return "PF";
> +	case GUC_CAPTURE_LIST_INDEX_VF:
> +		return "VF";
> +	default:
> +		return "unknown";
> +	}
> +
> +	return "";
> +}
> +
> +static const char *
> +guc_capture_stringify_type(u32 type)
> +{
> +	switch (type) {
> +	case GUC_CAPTURE_LIST_TYPE_GLOBAL:
> +		return "Global";
> +	case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
> +		return "Class";
> +	case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
> +		return "Instance";
> +	default:
> +		return "unknown";
> +	}
> +
> +	return "";
> +}
> +
> +static const char *
> +guc_capture_stringify_engclass(u32 class)
> +{
> +	switch (class) {
> +	case GUC_RENDER_CLASS:
> +		return "Render";
> +	case GUC_VIDEO_CLASS:
> +		return "Video";
> +	case GUC_VIDEOENHANCE_CLASS:
> +		return "VideoEnhance";
> +	case GUC_BLITTER_CLASS:
> +		return "Blitter";
> +	case GUC_RESERVED_CLASS:
> +		return "Reserved";
> +	default:
> +		return "unknown";
> +	}
> +
> +	return "";
> +}
> +
> +static void
> +guc_capture_warn_with_list_info(struct drm_i915_private *i915, char *msg,
> +				u32 owner, u32 type, u32 classid)
> +{
> +	if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
> +		drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers.\n", msg,
> +			guc_capture_stringify_owner(owner), guc_capture_stringify_type(type));
> +	else
> +		drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers on %s-Engine\n", msg,
> +			guc_capture_stringify_owner(owner), guc_capture_stringify_type(type),
> +			guc_capture_stringify_engclass(classid));
> +}
> +
> +static int
> +guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
> +		      struct guc_mmio_reg *ptr, u16 num_entries)
> +{
> +	u32 j = 0;
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
> +	struct __guc_mmio_reg_descr_group *match;
> +
> +	if (!reglists)
> +		return -ENODEV;
> +
> +	match = guc_capture_get_one_list(reglists, owner, type, classid);
> +	if (match) {
> +		for (j = 0; j < num_entries && j < match->num_regs; ++j) {
> +			ptr[j].offset = match->list[j].reg.reg;
> +			ptr[j].value = 0xDEADF00D;
> +			ptr[j].flags = match->list[j].flags;
> +			ptr[j].mask = match->list[j].mask;
> +		}
> +		return 0;
> +	}
> +
> +	guc_capture_warn_with_list_info(i915, "Missing register list init", owner, type,
> +					classid);
> +
> +	return -ENODATA;
> +}
> +
> +static int
> +guc_capture_fill_reglist(struct intel_guc *guc, struct guc_ads *ads,
> +			 u32 owner, int type, int classid, u16 numregs,
> +			 u8 **p_virt, u32 *p_ggtt, u32 null_ggtt)
> +{
> +	struct guc_debug_capture_list *listnode;
> +	u32 *p_capturelist_ggtt;
> +	int size = 0;
> +
> +	/*
> +	 * For enabled capture lists, we not only need to call capture module to help
> +	 * populate the list-descriptor into the correct ads capture structures, but
> +	 * we also need to increment the virtual pointers and ggtt offsets so that
> +	 * caller has the subsequent gfx memory location.
> +	 */
> +	size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
> +			  (numregs * sizeof(struct guc_mmio_reg)));
> +	/* if caller hasn't allocated ADS blob, return size and counts, we're done */
> +	if (!ads)
> +		return size;
> +
> +	/*
> +	 * If caller allocated ADS blob, populate the capture register descriptors into
> +	 * the designated ADS location based on list-owner, list-type and engine-classid
> +	 */
> +	if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
> +		p_capturelist_ggtt = &ads->capture_global[owner];
> +	else if (type == GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS)
> +		p_capturelist_ggtt = &ads->capture_class[owner][classid];
> +	else /*GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE*/
> +		p_capturelist_ggtt = &ads->capture_instance[owner][classid];
> +
> +	if (!numregs) {
> +		*p_capturelist_ggtt = null_ggtt;
> +	} else {
> +		/* get ptr and populate header info: */
> +		*p_capturelist_ggtt = *p_ggtt;
> +		listnode = (struct guc_debug_capture_list *)*p_virt;
> +		*p_ggtt += sizeof(struct guc_debug_capture_list);
> +		*p_virt += sizeof(struct guc_debug_capture_list);
> +		listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, numregs);
> +
> +		/* get ptr and populate register descriptor list: */
> +		guc_capture_list_init(guc, owner, type, classid,
> +				      (struct guc_mmio_reg *)*p_virt,
> +				      numregs);
> +
> +		/* increment ptrs for that header: */
> +		*p_ggtt += size - sizeof(struct guc_debug_capture_list);
> +		*p_virt += size - sizeof(struct guc_debug_capture_list);
> +	}
> +
> +	return size;
> +}
> +
> +static int
> +guc_capture_list_count(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
> +		       u16 *num_entries)
> +{
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
> +	struct __guc_mmio_reg_descr_group *match;
> +
> +	if (!reglists)
> +		return -ENODEV;
> +
> +	match = guc_capture_get_one_list(reglists, owner, type, classid);
> +	if (!match) {
> +		guc_capture_warn_with_list_info(i915, "Missing register list size",
> +						owner, type, classid);
> +		return -ENODATA;
> +	}
> +
> +	*num_entries = match->num_regs;
> +	return 0;
> +}
> +
> +static void
> +guc_capture_fill_engine_enable_masks(struct intel_gt *gt,
> +				     struct guc_gt_system_info *info)
> +{
> +	info->engine_enabled_masks[GUC_RENDER_CLASS] = 1;
> +	info->engine_enabled_masks[GUC_BLITTER_CLASS] = 1;
> +	info->engine_enabled_masks[GUC_VIDEO_CLASS] = VDBOX_MASK(gt);
> +	info->engine_enabled_masks[GUC_VIDEOENHANCE_CLASS] = VEBOX_MASK(gt);
> +}
> +
> +int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
> +				 u32 capture_offset, struct guc_gt_system_info *sysinfo)
> +{
> +	struct intel_gt *gt = guc_to_gt(guc);
> +	struct guc_gt_system_info *info, local_info;
> +	struct guc_debug_capture_list *listnode;
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +	struct __guc_state_capture_priv *gc = guc->capture.priv;
> +	int i, j, size;
> +	u32 ggtt, null_ggtt, alloc_size = 0;
> +	u16 tmpnumreg = 0;
> +	u8 *ptr = NULL;
> +
> +	GEM_BUG_ON(!gc);
> +
> +	if (blob) {
> +		ptr = ((u8 *)blob) + capture_offset;
> +		ggtt = blob_ggtt + capture_offset;
> +		GEM_BUG_ON(!sysinfo);
> +		info = sysinfo;
> +	} else {
> +		memset(&local_info, 0, sizeof(local_info));
> +		info = &local_info;
> +		guc_capture_fill_engine_enable_masks(gt, info);
> +	}
> +
> +	/* first, set aside the first page for a capture_list with zero descriptors */
> +	alloc_size = PAGE_SIZE;
> +	if (blob) {
> +		listnode = (struct guc_debug_capture_list *)ptr;
> +		listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, 0);
> +		null_ggtt = ggtt;
> +		ggtt += PAGE_SIZE;
> +		ptr +=  PAGE_SIZE;
> +	}
> +
> +#define COUNT_REGS guc_capture_list_count
> +#define FILL_REGS guc_capture_fill_reglist
> +#define TYPE_GLOBAL GUC_CAPTURE_LIST_TYPE_GLOBAL
> +#define TYPE_CLASS GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS
> +#define TYPE_INSTANCE GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE
> +#define OWNER2STR guc_capture_stringify_owner
> +#define ENGCLS2STR guc_capture_stringify_engclass
> +#define TYPE2STR guc_capture_stringify_type

What is this? Please don't do this.

BR,
Jani.


> +
> +	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
> +		for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
> +			if (!info->engine_enabled_masks[j]) {
> +				if (gc->num_class_regs[i][j])
> +					drm_warn(&i915->drm, "GuC-Cap %s's %s class-"
> +						 "list enable mismatch was=%d now off\n",
> +						 OWNER2STR(i), ENGCLS2STR(j),
> +						 gc->num_class_regs[i][j]);
> +				if (gc->num_instance_regs[i][j])
> +					drm_warn(&i915->drm, "GuC-Cap %s's %s inst-"
> +						 "list enable mismatch was=%d now off!\n",
> +						 OWNER2STR(i), ENGCLS2STR(j),
> +						 gc->num_instance_regs[i][j]);
> +				gc->num_class_regs[i][j] = 0;
> +				gc->num_instance_regs[i][j] = 0;
> +				if (blob) {
> +					blob->capture_class[i][j] = null_ggtt;
> +					blob->capture_instance[i][j] = null_ggtt;
> +				}
> +			} else {
> +				if (!COUNT_REGS(guc, i, TYPE_CLASS, j, &tmpnumreg)) {
> +					if (blob && tmpnumreg > gc->num_class_regs[i][j]) {
> +						drm_warn(&i915->drm, "GuC-Cap %s's %s-%s-list "
> +							 "count overflow cap from %d to %d",
> +							 OWNER2STR(i), ENGCLS2STR(j),
> +							 TYPE2STR(TYPE_CLASS),
> +							 gc->num_class_regs[i][j], tmpnumreg);
> +						tmpnumreg = gc->num_class_regs[i][j];
> +					}
> +					size = FILL_REGS(guc, blob, i, TYPE_CLASS, j,
> +							 tmpnumreg, &ptr, &ggtt, null_ggtt);
> +					alloc_size += size;
> +					gc->num_class_regs[i][j] = tmpnumreg;
> +				} else {
> +					gc->num_class_regs[i][j] = 0;
> +					if (blob)
> +						blob->capture_class[i][j] = null_ggtt;
> +				}
> +				if (!COUNT_REGS(guc, i, TYPE_INSTANCE, j, &tmpnumreg)) {
> +					if (blob && tmpnumreg > gc->num_instance_regs[i][j]) {
> +						drm_warn(&i915->drm, "GuC-Cap %s's %s-%s-list "
> +							 "count overflow cap from %d to %d",
> +							 OWNER2STR(i), ENGCLS2STR(j),
> +							 TYPE2STR(TYPE_INSTANCE),
> +							 gc->num_instance_regs[i][j], tmpnumreg);
> +						tmpnumreg = gc->num_instance_regs[i][j];
> +					}
> +					size = FILL_REGS(guc, blob, i, TYPE_INSTANCE, j,
> +							 tmpnumreg, &ptr, &ggtt, null_ggtt);
> +					alloc_size += size;
> +					gc->num_instance_regs[i][j] = tmpnumreg;
> +				} else {
> +					gc->num_instance_regs[i][j] = 0;
> +					if (blob)
> +						blob->capture_instance[i][j] = null_ggtt;
> +				}
> +			}
> +		}
> +		if (!COUNT_REGS(guc, i, TYPE_GLOBAL, 0, &tmpnumreg)) {
> +			if (blob && tmpnumreg > gc->num_global_regs[i]) {
> +				drm_warn(&i915->drm, "GuC-Cap %s's %s-list count increased from %d to %d",
> +					 OWNER2STR(i), TYPE2STR(TYPE_GLOBAL),
> +					 gc->num_global_regs[i], tmpnumreg);
> +				tmpnumreg = gc->num_global_regs[i];
> +			}
> +			size = FILL_REGS(guc, blob, i, TYPE_GLOBAL, 0, tmpnumreg,
> +					 &ptr, &ggtt, null_ggtt);
> +			alloc_size += size;
> +			gc->num_global_regs[i] = tmpnumreg;
> +		} else {
> +			gc->num_global_regs[i] = 0;
> +			if (blob)
> +				blob->capture_global[i] = null_ggtt;
> +		}
> +	}
> +
> +#undef COUNT_REGS
> +#undef FILL_REGS
> +#undef TYPE_GLOBAL
> +#undef TYPE_CLASS
> +#undef TYPE_INSTANCE
> +#undef OWNER2STR
> +#undef ENGCLS2STR
> +#undef TYPE2STR
> +
> +	if (guc->ads_capture_size && guc->ads_capture_size != PAGE_ALIGN(alloc_size))
> +		drm_warn(&i915->drm, "GuC->ADS->Capture alloc size changed from %d to %d\n",
> +			 guc->ads_capture_size, PAGE_ALIGN(alloc_size));
> +
> +	return PAGE_ALIGN(alloc_size);
> +}
> +
> +void intel_guc_capture_destroy(struct intel_guc *guc)
> +{
> +	kfree(guc->capture.priv);
> +	guc->capture.priv = NULL;
> +}
> +
> +int intel_guc_capture_init(struct intel_guc *guc)
> +{
> +	guc->capture.priv = kzalloc(sizeof(*guc->capture.priv), GFP_KERNEL);
> +	if (!guc->capture.priv)
> +		return -ENOMEM;
> +	guc->capture.priv->reglists = guc_capture_get_device_reglist(guc);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
> new file mode 100644
> index 000000000000..6b5594ca529d
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021-2021 Intel Corporation
> + */
> +
> +#ifndef _INTEL_GUC_CAPTURE_H
> +#define _INTEL_GUC_CAPTURE_H
> +
> +#include <linux/types.h>
> +
> +struct intel_guc;
> +struct guc_ads;
> +struct guc_gt_system_info;
> +
> +int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
> +				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
> +void intel_guc_capture_destroy(struct intel_guc *guc);
> +int intel_guc_capture_init(struct intel_guc *guc);
> +
> +#endif /* _INTEL_GUC_CAPTURE_H */
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> index 6a4612a852e2..92bfe25a5e85 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> @@ -297,6 +297,23 @@ enum {
>  	GUC_CAPTURE_LIST_INDEX_MAX = 2,
>  };
>  
> +/*Register-types of GuC capture register lists */
> +enum guc_capture_type {
> +	GUC_CAPTURE_LIST_TYPE_GLOBAL = 0,
> +	GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
> +	GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
> +	GUC_CAPTURE_LIST_TYPE_MAX,
> +};
> +
> +struct guc_debug_capture_list_header {
> +	u32 info;
> +		#define GUC_CAPTURELISTHDR_NUMDESCR GENMASK(15, 0)
> +} __packed;
> +
> +struct guc_debug_capture_list {
> +	struct guc_debug_capture_list_header header;
> +} __packed;
> +
>  /* GuC Additional Data Struct */
>  struct guc_ads {
>  	struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS];

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 02/10] drm/i915/guc: Add XE_LP registers for GuC error state capture.
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 02/10] drm/i915/guc: Add XE_LP registers for GuC error state capture Alan Previn
@ 2022-01-26 18:13   ` Jani Nikula
  2022-01-26 21:46     ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Jani Nikula @ 2022-01-26 18:13 UTC (permalink / raw)
  To: Alan Previn, intel-gfx; +Cc: Alan Previn

On Wed, 26 Jan 2022, Alan Previn <alan.previn.teres.alexis@intel.com> wrote:
> Add device specific tables and register lists to cover different engines
> class types for GuC error state capture for XE_LP products.
>
> Also, add runtime allocation and freeing of extended register lists
> for registers that need steering identifiers that depend on
> the detected HW config.
>
> Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> ---
>  drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |   2 +
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 207 +++++++++++++++---
>  drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |   4 +-
>  3 files changed, 180 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
> index 15b8c02b8a76..a2f97d04ff18 100644
> --- a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
> +++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
> @@ -24,6 +24,8 @@ struct __guc_mmio_reg_descr_group {
>  	u32 owner; /* see enum guc_capture_owner */
>  	u32 type; /* see enum guc_capture_type */
>  	u32 engine; /* as per MAX_ENGINE_CLASS */
> +	int num_ext;
> +	struct __guc_mmio_reg_descr *ext;
>  };
>  
>  struct __guc_state_capture_priv {
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> index 06873d617b8b..b6882074fc8d 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> @@ -19,40 +19,101 @@
>   * NOTE: For engine-registers, GuC only needs the register offsets
>   *       from the engine-mmio-base
>   */
> +#define COMMON_GEN12BASE_GLOBAL() \
> +	{GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0"}, \
> +	{GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1"}, \
> +	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}, \
> +	{GEN12_AUX_ERR_DBG,        0,      0, "GEN12_AUX_ERR_DBG"}, \
> +	{GEN12_GAM_DONE,           0,      0, "GEN12_GAM_DONE"}, \
> +	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
> +
> +#define COMMON_GEN12BASE_ENGINE_INSTANCE() \
> +	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
> +	{RING_ESR(0),              0,      0, "RING_ESR"}, \
> +	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \
> +	{RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UP32"}, \
> +	{RING_IPEIR(0),            0,      0, "RING_IPEIR"}, \
> +	{RING_IPEHR(0),            0,      0, "RING_IPEHR"}, \
> +	{RING_INSTPS(0),           0,      0, "RING_INSTPS"}, \
> +	{RING_BBADDR(0),           0,      0, "RING_BBADDR_LOW32"}, \
> +	{RING_BBADDR_UDW(0),       0,      0, "RING_BBADDR_UP32"}, \
> +	{RING_BBSTATE(0),          0,      0, "RING_BBSTATE"}, \
> +	{CCID(0),                  0,      0, "CCID"}, \
> +	{RING_ACTHD(0),            0,      0, "RING_ACTHD_LOW32"}, \
> +	{RING_ACTHD_UDW(0),        0,      0, "RING_ACTHD_UP32"}, \
> +	{RING_INSTPM(0),           0,      0, "RING_INSTPM"}, \
> +	{RING_NOPID(0),            0,      0, "RING_NOPID"}, \
> +	{RING_START(0),            0,      0, "RING_START"}, \
> +	{RING_HEAD(0),             0,      0, "RING_HEAD"}, \
> +	{RING_TAIL(0),             0,      0, "RING_TAIL"}, \
> +	{RING_CTL(0),              0,      0, "RING_CTL"}, \
> +	{RING_MI_MODE(0),          0,      0, "RING_MI_MODE"}, \
> +	{RING_CONTEXT_CONTROL(0),  0,      0, "RING_CONTEXT_CONTROL"}, \
> +	{RING_INSTDONE(0),         0,      0, "RING_INSTDONE"}, \
> +	{RING_HWS_PGA(0),          0,      0, "RING_HWS_PGA"}, \
> +	{RING_MODE_GEN7(0),        0,      0, "RING_MODE_GEN7"}, \
> +	{GEN8_RING_PDP_LDW(0, 0),  0,      0, "GEN8_RING_PDP0_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 0),  0,      0, "GEN8_RING_PDP0_UDW"}, \
> +	{GEN8_RING_PDP_LDW(0, 1),  0,      0, "GEN8_RING_PDP1_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 1),  0,      0, "GEN8_RING_PDP1_UDW"}, \
> +	{GEN8_RING_PDP_LDW(0, 2),  0,      0, "GEN8_RING_PDP2_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 2),  0,      0, "GEN8_RING_PDP2_UDW"}, \
> +	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "GEN8_RING_PDP3_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "GEN8_RING_PDP3_UDW"}
> +
> +#define COMMON_GEN12BASE_HAS_EU() \
> +	{EIR,                      0,      0, "EIR"}
> +
> +#define COMMON_GEN12BASE_RENDER() \
> +	{GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE"}, \
> +	{GEN12_SC_INSTDONE_EXTRA,  0,      0, "GEN12_SC_INSTDONE_EXTRA"}, \
> +	{GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2"}
> +
> +#define COMMON_GEN12BASE_VEC() \
> +	{GEN12_SFC_DONE(0),        0,      0, "GEN12_SFC_DONE0"}, \
> +	{GEN12_SFC_DONE(1),        0,      0, "GEN12_SFC_DONE1"}, \
> +	{GEN12_SFC_DONE(2),        0,      0, "GEN12_SFC_DONE2"}, \
> +	{GEN12_SFC_DONE(3),        0,      0, "GEN12_SFC_DONE3"}
> +
>  /* XE_LPD - Global */
>  static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
> -	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
> +	COMMON_GEN12BASE_GLOBAL(),
>  };
>  
>  /* XE_LPD - Render / Compute Per-Class */
>  static struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
> -	{EIR,                      0,      0, "EIR"}
> +	COMMON_GEN12BASE_HAS_EU(),
> +	COMMON_GEN12BASE_RENDER(),
>  };
>  
>  /* XE_LPD - Render / Compute Per-Engine-Instance */
>  static struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
> -	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> -	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> -};
> -
> -/* XE_LPD - Media Decode/Encode Per-Class */
> -static struct __guc_mmio_reg_descr xe_lpd_vd_class_regs[] = {
> +	COMMON_GEN12BASE_ENGINE_INSTANCE(),
>  };
>  
>  /* XE_LPD - Media Decode/Encode Per-Engine-Instance */
>  static struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
> -	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> -	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +	COMMON_GEN12BASE_ENGINE_INSTANCE(),
>  };
>  
>  /* XE_LPD - Video Enhancement Per-Class */
>  static struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
> +	COMMON_GEN12BASE_VEC(),
>  };
>  
>  /* XE_LPD - Video Enhancement Per-Engine-Instance */
>  static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
> -	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> -	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +	COMMON_GEN12BASE_ENGINE_INSTANCE(),
> +};
> +
> +/* XE_LPD - Blitter Per-Engine-Instance */
> +static struct __guc_mmio_reg_descr xe_lpd_blt_inst_regs[] = {
> +	COMMON_GEN12BASE_ENGINE_INSTANCE(),
> +};
> +
> +/* XE_LPD - Blitter Per-Class */
> +/* XE_LPD - Media Decode/Encode Per-Class */
> +static struct __guc_mmio_reg_descr empty_regs_list[] = {
>  };
>  
>  #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
> @@ -64,6 +125,8 @@ static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
>  		.owner = TO_GCAP_DEF_OWNER(regsowner), \
>  		.type = TO_GCAP_DEF_TYPE(regstype), \
>  		.engine = class, \
> +		.num_ext = 0, \
> +		.ext = NULL, \
>  	}
>  
>  /* List of lists */
> @@ -71,13 +134,96 @@ static struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
>  	MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
>  	MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
>  	MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
> -	MAKE_REGLIST(xe_lpd_vd_class_regs, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
> +	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
>  	MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
>  	MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
>  	MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
> +	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
> +	MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
>  	{}
>  };
>  
> +static struct __guc_mmio_reg_descr_group *
> +guc_capture_get_one_list(struct __guc_mmio_reg_descr_group *reglists, u32 owner, u32 type, u32 id)
> +{
> +	int i;
> +
> +	if (!reglists)
> +		return NULL;
> +
> +	for (i = 0; reglists[i].list; i++) {
> +		if (reglists[i].owner == owner && reglists[i].type == type &&
> +		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
> +		return &reglists[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +static void guc_capture_clear_ext_regs(struct __guc_mmio_reg_descr_group *lists)
> +{
> +	while (lists->list) {
> +		kfree(lists->ext);
> +		lists->ext = NULL;
> +		++lists;
> +	}
> +}
> +
> +struct __ext_steer_reg {
> +	const char *name;
> +	i915_reg_t reg;
> +};
> +
> +static struct __ext_steer_reg xelpd_extregs[] = {
> +	{"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE},
> +	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
> +};

Either this needs to be const or, if it needs to be mutable, moved to
device specific data.

Ditto for all such things all over the place.

BR,
Jani.

> +
> +static void
> +guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
> +				     struct __guc_mmio_reg_descr_group *lists)
> +{
> +	struct intel_gt *gt = guc_to_gt(guc);
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +	struct sseu_dev_info *sseu;
> +	int slice, subslice, i, num_tot_regs = 0;
> +	struct __guc_mmio_reg_descr_group *list;
> +	struct __guc_mmio_reg_descr *extarray;
> +	int num_steer_regs = ARRAY_SIZE(xelpd_extregs);
> +
> +	/* In XE_LP we only care about render-class steering registers during error-capture */
> +	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
> +					GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, GUC_RENDER_CLASS);
> +	if (!list)
> +		return;
> +
> +	if (list->ext)
> +		return; /* already populated */
> +
> +	sseu = &gt->info.sseu;
> +	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
> +		num_tot_regs += num_steer_regs;
> +	}
> +	if (!num_tot_regs)
> +		return;
> +
> +	list->ext = kcalloc(num_tot_regs, sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL);
> +	if (!list->ext)
> +		return;
> +
> +	extarray = list->ext;
> +	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
> +		for (i = 0; i < num_steer_regs; i++) {
> +			extarray->reg = xelpd_extregs[i].reg;
> +			extarray->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice);
> +			extarray->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice);
> +			extarray->regname = xelpd_extregs[i].name;
> +			++extarray;
> +		}
> +	}
> +	list->num_ext = num_tot_regs;
> +}
> +
>  static struct __guc_mmio_reg_descr_group *
>  guc_capture_get_device_reglist(struct intel_guc *guc)
>  {
> @@ -91,29 +237,13 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
>  		 * these at init time based on hw config add it as an extension
>  		 * list at the end of the pre-populated render list.
>  		 */
> +		guc_capture_alloc_steered_list_xelpd(guc, xe_lpd_lists);
>  		return xe_lpd_lists;
>  	}
>  
>  	return NULL;
>  }
>  
> -static struct __guc_mmio_reg_descr_group *
> -guc_capture_get_one_list(struct __guc_mmio_reg_descr_group *reglists, u32 owner, u32 type, u32 id)
> -{
> -	int i;
> -
> -	if (!reglists)
> -		return NULL;
> -
> -	for (i = 0; reglists[i].list; i++) {
> -		if (reglists[i].owner == owner && reglists[i].type == type &&
> -		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
> -		return &reglists[i];
> -	}
> -
> -	return NULL;
> -}
> -
>  static const char *
>  guc_capture_stringify_owner(u32 owner)
>  {
> @@ -184,7 +314,7 @@ static int
>  guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
>  		      struct guc_mmio_reg *ptr, u16 num_entries)
>  {
> -	u32 j = 0;
> +	u32 j = 0, k = 0;
>  	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
>  	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
>  	struct __guc_mmio_reg_descr_group *match;
> @@ -200,6 +330,18 @@ guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
>  			ptr[j].flags = match->list[j].flags;
>  			ptr[j].mask = match->list[j].mask;
>  		}
> +		if (match->ext) {
> +			for (j = match->num_regs, k = 0; j < num_entries &&
> +			     j < (match->num_regs + match->num_ext); ++j, ++k) {
> +				ptr[j].offset = match->ext[k].reg.reg;
> +				ptr[j].value = 0xDEADF00D;
> +				ptr[j].flags = match->ext[k].flags;
> +				ptr[j].mask = match->ext[k].mask;
> +			}
> +		}
> +		if (j < num_entries)
> +			drm_dbg(&i915->drm, "GuC-capture: Init reglist short %d out %d.\n",
> +				(int)j, (int)num_entries);
>  		return 0;
>  	}
>  
> @@ -282,7 +424,7 @@ guc_capture_list_count(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
>  		return -ENODATA;
>  	}
>  
> -	*num_entries = match->num_regs;
> +	*num_entries = match->num_regs + match->num_ext;
>  	return 0;
>  }
>  
> @@ -435,6 +577,7 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
>  
>  void intel_guc_capture_destroy(struct intel_guc *guc)
>  {
> +	guc_capture_clear_ext_regs(guc->capture.priv->reglists);
>  	kfree(guc->capture.priv);
>  	guc->capture.priv = NULL;
>  }
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> index 92bfe25a5e85..50fcd987f2a2 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> @@ -271,10 +271,12 @@ struct guc_mmio_reg {
>  	u32 offset;
>  	u32 value;
>  	u32 flags;
> -	u32 mask;
>  #define GUC_REGSET_MASKED		BIT(0)
>  #define GUC_REGSET_MASKED_WITH_VALUE	BIT(2)
>  #define GUC_REGSET_RESTORE_ONLY		BIT(3)
> +#define GUC_REGSET_STEERING_GROUP       GENMASK(15, 12)
> +#define GUC_REGSET_STEERING_INSTANCE    GENMASK(23, 20)
> +	u32 mask;
>  } __packed;
>  
>  /* GuC register sets */

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists Alan Previn
  2022-01-26 18:09   ` Jani Nikula
@ 2022-01-26 18:15   ` Jani Nikula
  2022-01-26 22:46   ` Lucas De Marchi
  2 siblings, 0 replies; 52+ messages in thread
From: Jani Nikula @ 2022-01-26 18:15 UTC (permalink / raw)
  To: Alan Previn, intel-gfx; +Cc: Alan Previn

On Wed, 26 Jan 2022, Alan Previn <alan.previn.teres.alexis@intel.com> wrote:
> Update GuC ADS size allocation to include space for
> the lists of error state capture register descriptors.
>
> Also, populate the lists of registers we want GuC to report back to
> Host on engine reset events. This list should include global,
> engine-class and engine-instance registers for every engine-class
> type on the current hardware.
>
> NOTE: Start with a sample table of register lists to layout the
> framework before adding real registers in subsequent patch.
>
> Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |  36 ++
>  drivers/gpu/drm/i915/gt/uc/intel_guc.c        |  13 +-
>  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |  11 +-
>  drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c    |  36 +-
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 450 ++++++++++++++++++
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |  20 +
>  drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |  17 +
>  8 files changed, 555 insertions(+), 29 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
>  create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>  create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index a26e6736bebb..236bcd6cd8ea 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -183,6 +183,7 @@ i915-y += gt/uc/intel_uc.o \
>  	  gt/uc/intel_uc_fw.o \
>  	  gt/uc/intel_guc.o \
>  	  gt/uc/intel_guc_ads.o \
> +	  gt/uc/intel_guc_capture.o \
>  	  gt/uc/intel_guc_ct.o \
>  	  gt/uc/intel_guc_debugfs.o \
>  	  gt/uc/intel_guc_fw.o \
> diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
> new file mode 100644
> index 000000000000..15b8c02b8a76
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021-2021 Intel Corporation
> + */
> +
> +#ifndef _INTEL_GUC_CAPTURE_FWIF_H
> +#define _INTEL_GUC_CAPTURE_FWIF_H
> +
> +#include <linux/types.h>
> +#include "intel_guc_fwif.h"
> +
> +struct intel_guc;
> +
> +struct __guc_mmio_reg_descr {
> +	i915_reg_t reg;
> +	u32 flags;
> +	u32 mask;
> +	const char *regname;
> +};
> +
> +struct __guc_mmio_reg_descr_group {
> +	struct __guc_mmio_reg_descr *list;
> +	u32 num_regs;
> +	u32 owner; /* see enum guc_capture_owner */
> +	u32 type; /* see enum guc_capture_type */
> +	u32 engine; /* as per MAX_ENGINE_CLASS */
> +};
> +
> +struct __guc_state_capture_priv {
> +	struct __guc_mmio_reg_descr_group *reglists;
> +	u16 num_instance_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
> +	u16 num_class_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
> +	u16 num_global_regs[GUC_CAPTURE_LIST_INDEX_MAX];
> +};
> +
> +#endif /* _INTEL_GUC_CAPTURE_FWIF_H */
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
> index ba2a67f9e500..d035a3ba8700 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
> @@ -8,8 +8,9 @@
>  #include "gt/intel_gt_irq.h"
>  #include "gt/intel_gt_pm_irq.h"
>  #include "intel_guc.h"
> -#include "intel_guc_slpc.h"
>  #include "intel_guc_ads.h"
> +#include "intel_guc_capture.h"
> +#include "intel_guc_slpc.h"
>  #include "intel_guc_submission.h"
>  #include "i915_drv.h"
>  #include "i915_irq.h"
> @@ -361,9 +362,14 @@ int intel_guc_init(struct intel_guc *guc)
>  	if (ret)
>  		goto err_fw;
>  
> -	ret = intel_guc_ads_create(guc);
> +	ret = intel_guc_capture_init(guc);
>  	if (ret)
>  		goto err_log;
> +
> +	ret = intel_guc_ads_create(guc);
> +	if (ret)
> +		goto err_capture;
> +
>  	GEM_BUG_ON(!guc->ads_vma);
>  
>  	ret = intel_guc_ct_init(&guc->ct);
> @@ -402,6 +408,8 @@ int intel_guc_init(struct intel_guc *guc)
>  	intel_guc_ct_fini(&guc->ct);
>  err_ads:
>  	intel_guc_ads_destroy(guc);
> +err_capture:
> +	intel_guc_capture_destroy(guc);
>  err_log:
>  	intel_guc_log_destroy(&guc->log);
>  err_fw:
> @@ -429,6 +437,7 @@ void intel_guc_fini(struct intel_guc *guc)
>  	intel_guc_ct_fini(&guc->ct);
>  
>  	intel_guc_ads_destroy(guc);
> +	intel_guc_capture_destroy(guc);
>  	intel_guc_log_destroy(&guc->log);
>  	intel_uc_fw_fini(&guc->fw);
>  }
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> index 697d9d66acef..4e819853ec2e 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> @@ -9,18 +9,19 @@
>  #include <linux/xarray.h>
>  #include <linux/delay.h>
>  
> -#include "intel_uncore.h"
> +#include "intel_guc_ct.h"
>  #include "intel_guc_fw.h"
>  #include "intel_guc_fwif.h"
> -#include "intel_guc_ct.h"
>  #include "intel_guc_log.h"
>  #include "intel_guc_reg.h"
>  #include "intel_guc_slpc_types.h"
>  #include "intel_uc_fw.h"
> +#include "intel_uncore.h"
>  #include "i915_utils.h"
>  #include "i915_vma.h"
>  
>  struct __guc_ads_blob;
> +struct __guc_state_capture_priv;
>  
>  /**
>   * struct intel_guc - Top level structure of GuC.
> @@ -37,6 +38,10 @@ struct intel_guc {
>  	struct intel_guc_ct ct;
>  	/** @slpc: sub-structure containing SLPC related data and objects */
>  	struct intel_guc_slpc slpc;
> +	/** @capture: the error-state-capture module's data and objects */
> +	struct intel_guc_state_capture {
> +		struct __guc_state_capture_priv *priv;
> +	} capture;
>  
>  	/** @sched_engine: Global engine used to submit requests to GuC */
>  	struct i915_sched_engine *sched_engine;
> @@ -152,6 +157,8 @@ struct intel_guc {
>  	u32 ads_regset_size;
>  	/** @ads_golden_ctxt_size: size of the golden contexts in the ADS */
>  	u32 ads_golden_ctxt_size;
> +	/** @ads_capture_size: size of register lists in the ADS used for error capture */
> +	u32 ads_capture_size;
>  	/** @ads_engine_usage_size: size of engine usage in the ADS */
>  	u32 ads_engine_usage_size;
>  
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
> index 668bf4ac9b0c..4597ba0a4177 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
> @@ -10,6 +10,7 @@
>  #include "gt/intel_lrc.h"
>  #include "gt/shmem_utils.h"
>  #include "intel_guc_ads.h"
> +#include "intel_guc_capture.h"
>  #include "intel_guc_fwif.h"
>  #include "intel_uc.h"
>  #include "i915_drv.h"
> @@ -72,8 +73,7 @@ static u32 guc_ads_golden_ctxt_size(struct intel_guc *guc)
>  
>  static u32 guc_ads_capture_size(struct intel_guc *guc)
>  {
> -	/* FIXME: Allocate a proper capture list */
> -	return PAGE_ALIGN(PAGE_SIZE);
> +	return PAGE_ALIGN(guc->ads_capture_size);
>  }
>  
>  static u32 guc_ads_private_data_size(struct intel_guc *guc)
> @@ -520,26 +520,6 @@ static void guc_init_golden_context(struct intel_guc *guc)
>  	GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
>  }
>  
> -static void guc_capture_list_init(struct intel_guc *guc, struct __guc_ads_blob *blob)
> -{
> -	int i, j;
> -	u32 addr_ggtt, offset;
> -
> -	offset = guc_ads_capture_offset(guc);
> -	addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
> -
> -	/* FIXME: Populate a proper capture list */
> -
> -	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
> -		for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
> -			blob->ads.capture_instance[i][j] = addr_ggtt;
> -			blob->ads.capture_class[i][j] = addr_ggtt;
> -		}
> -
> -		blob->ads.capture_global[i] = addr_ggtt;
> -	}
> -}
> -
>  static void __guc_ads_init(struct intel_guc *guc)
>  {
>  	struct intel_gt *gt = guc_to_gt(guc);
> @@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
>  
>  	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
>  
> -	/* Capture list for hang debug */
> -	guc_capture_list_init(guc, blob);
> -
> +	/* Lists for error capture debug */
> +	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
> +				     guc_ads_capture_offset(guc), &blob->system_info);
>  	/* ADS */
>  	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
>  	blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
> @@ -615,6 +595,12 @@ int intel_guc_ads_create(struct intel_guc *guc)
>  		return ret;
>  	guc->ads_golden_ctxt_size = ret;
>  
> +	/* Likewise the capture lists: */
> +	ret = intel_guc_capture_prep_lists(guc, NULL, 0, 0, NULL);
> +	if (ret < 0)
> +		return ret;
> +	guc->ads_capture_size = ret;
> +
>  	/* Now the total size can be determined: */
>  	size = guc_ads_blob_size(guc);
>  
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> new file mode 100644
> index 000000000000..06873d617b8b
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> @@ -0,0 +1,450 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021-2021 Intel Corporation
> + */
> +
> +#include <linux/types.h>
> +
> +#include <drm/drm_print.h>
> +
> +#include "gt/intel_engine_regs.h"
> +#include "gt/intel_gt.h"
> +#include "guc_capture_fwif.h"
> +#include "intel_guc_fwif.h"
> +#include "i915_drv.h"
> +#include "i915_memcpy.h"
> +
> +/*
> + * Define all device tables of GuC error capture register lists
> + * NOTE: For engine-registers, GuC only needs the register offsets
> + *       from the engine-mmio-base
> + */
> +/* XE_LPD - Global */
> +static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
> +	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
> +};
> +
> +/* XE_LPD - Render / Compute Per-Class */
> +static struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
> +	{EIR,                      0,      0, "EIR"}
> +};
> +
> +/* XE_LPD - Render / Compute Per-Engine-Instance */
> +static struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
> +	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> +	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +};
> +
> +/* XE_LPD - Media Decode/Encode Per-Class */
> +static struct __guc_mmio_reg_descr xe_lpd_vd_class_regs[] = {
> +};
> +
> +/* XE_LPD - Media Decode/Encode Per-Engine-Instance */
> +static struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
> +	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> +	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +};
> +
> +/* XE_LPD - Video Enhancement Per-Class */
> +static struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
> +};
> +
> +/* XE_LPD - Video Enhancement Per-Engine-Instance */
> +static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
> +	{RING_HEAD(0),             0,      0, "RING_HEAD"},
> +	{RING_TAIL(0),             0,      0, "RING_TAIL"},
> +};
> +
> +#define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
> +#define TO_GCAP_DEF_TYPE(x) (GUC_CAPTURE_LIST_TYPE_##x)
> +#define MAKE_REGLIST(regslist, regsowner, regstype, class) \
> +	{ \
> +		.list = regslist, \
> +		.num_regs = ARRAY_SIZE(regslist), \
> +		.owner = TO_GCAP_DEF_OWNER(regsowner), \
> +		.type = TO_GCAP_DEF_TYPE(regstype), \
> +		.engine = class, \
> +	}
> +
> +/* List of lists */
> +static struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
> +	MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
> +	MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
> +	MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
> +	MAKE_REGLIST(xe_lpd_vd_class_regs, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
> +	MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
> +	MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
> +	MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
> +	{}
> +};
> +

I replied to one patch already, but I'll repeat it here: all of the
above structs need to be const or moved to allocated device specific
data.

BR,
Jani.

> +static struct __guc_mmio_reg_descr_group *
> +guc_capture_get_device_reglist(struct intel_guc *guc)
> +{
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +
> +	if (IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915) ||
> +	    IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) {
> +		/*
> +		 * For certain engine classes, there are slice and subslice
> +		 * level registers requiring steering. We allocate and populate
> +		 * these at init time based on hw config add it as an extension
> +		 * list at the end of the pre-populated render list.
> +		 */
> +		return xe_lpd_lists;
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct __guc_mmio_reg_descr_group *
> +guc_capture_get_one_list(struct __guc_mmio_reg_descr_group *reglists, u32 owner, u32 type, u32 id)
> +{
> +	int i;
> +
> +	if (!reglists)
> +		return NULL;
> +
> +	for (i = 0; reglists[i].list; i++) {
> +		if (reglists[i].owner == owner && reglists[i].type == type &&
> +		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
> +		return &reglists[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +static const char *
> +guc_capture_stringify_owner(u32 owner)
> +{
> +	switch (owner) {
> +	case GUC_CAPTURE_LIST_INDEX_PF:
> +		return "PF";
> +	case GUC_CAPTURE_LIST_INDEX_VF:
> +		return "VF";
> +	default:
> +		return "unknown";
> +	}
> +
> +	return "";
> +}
> +
> +static const char *
> +guc_capture_stringify_type(u32 type)
> +{
> +	switch (type) {
> +	case GUC_CAPTURE_LIST_TYPE_GLOBAL:
> +		return "Global";
> +	case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
> +		return "Class";
> +	case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
> +		return "Instance";
> +	default:
> +		return "unknown";
> +	}
> +
> +	return "";
> +}
> +
> +static const char *
> +guc_capture_stringify_engclass(u32 class)
> +{
> +	switch (class) {
> +	case GUC_RENDER_CLASS:
> +		return "Render";
> +	case GUC_VIDEO_CLASS:
> +		return "Video";
> +	case GUC_VIDEOENHANCE_CLASS:
> +		return "VideoEnhance";
> +	case GUC_BLITTER_CLASS:
> +		return "Blitter";
> +	case GUC_RESERVED_CLASS:
> +		return "Reserved";
> +	default:
> +		return "unknown";
> +	}
> +
> +	return "";
> +}
> +
> +static void
> +guc_capture_warn_with_list_info(struct drm_i915_private *i915, char *msg,
> +				u32 owner, u32 type, u32 classid)
> +{
> +	if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
> +		drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers.\n", msg,
> +			guc_capture_stringify_owner(owner), guc_capture_stringify_type(type));
> +	else
> +		drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers on %s-Engine\n", msg,
> +			guc_capture_stringify_owner(owner), guc_capture_stringify_type(type),
> +			guc_capture_stringify_engclass(classid));
> +}
> +
> +static int
> +guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
> +		      struct guc_mmio_reg *ptr, u16 num_entries)
> +{
> +	u32 j = 0;
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
> +	struct __guc_mmio_reg_descr_group *match;
> +
> +	if (!reglists)
> +		return -ENODEV;
> +
> +	match = guc_capture_get_one_list(reglists, owner, type, classid);
> +	if (match) {
> +		for (j = 0; j < num_entries && j < match->num_regs; ++j) {
> +			ptr[j].offset = match->list[j].reg.reg;
> +			ptr[j].value = 0xDEADF00D;
> +			ptr[j].flags = match->list[j].flags;
> +			ptr[j].mask = match->list[j].mask;
> +		}
> +		return 0;
> +	}
> +
> +	guc_capture_warn_with_list_info(i915, "Missing register list init", owner, type,
> +					classid);
> +
> +	return -ENODATA;
> +}
> +
> +static int
> +guc_capture_fill_reglist(struct intel_guc *guc, struct guc_ads *ads,
> +			 u32 owner, int type, int classid, u16 numregs,
> +			 u8 **p_virt, u32 *p_ggtt, u32 null_ggtt)
> +{
> +	struct guc_debug_capture_list *listnode;
> +	u32 *p_capturelist_ggtt;
> +	int size = 0;
> +
> +	/*
> +	 * For enabled capture lists, we not only need to call capture module to help
> +	 * populate the list-descriptor into the correct ads capture structures, but
> +	 * we also need to increment the virtual pointers and ggtt offsets so that
> +	 * caller has the subsequent gfx memory location.
> +	 */
> +	size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
> +			  (numregs * sizeof(struct guc_mmio_reg)));
> +	/* if caller hasn't allocated ADS blob, return size and counts, we're done */
> +	if (!ads)
> +		return size;
> +
> +	/*
> +	 * If caller allocated ADS blob, populate the capture register descriptors into
> +	 * the designated ADS location based on list-owner, list-type and engine-classid
> +	 */
> +	if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
> +		p_capturelist_ggtt = &ads->capture_global[owner];
> +	else if (type == GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS)
> +		p_capturelist_ggtt = &ads->capture_class[owner][classid];
> +	else /*GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE*/
> +		p_capturelist_ggtt = &ads->capture_instance[owner][classid];
> +
> +	if (!numregs) {
> +		*p_capturelist_ggtt = null_ggtt;
> +	} else {
> +		/* get ptr and populate header info: */
> +		*p_capturelist_ggtt = *p_ggtt;
> +		listnode = (struct guc_debug_capture_list *)*p_virt;
> +		*p_ggtt += sizeof(struct guc_debug_capture_list);
> +		*p_virt += sizeof(struct guc_debug_capture_list);
> +		listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, numregs);
> +
> +		/* get ptr and populate register descriptor list: */
> +		guc_capture_list_init(guc, owner, type, classid,
> +				      (struct guc_mmio_reg *)*p_virt,
> +				      numregs);
> +
> +		/* increment ptrs for that header: */
> +		*p_ggtt += size - sizeof(struct guc_debug_capture_list);
> +		*p_virt += size - sizeof(struct guc_debug_capture_list);
> +	}
> +
> +	return size;
> +}
> +
> +static int
> +guc_capture_list_count(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
> +		       u16 *num_entries)
> +{
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
> +	struct __guc_mmio_reg_descr_group *match;
> +
> +	if (!reglists)
> +		return -ENODEV;
> +
> +	match = guc_capture_get_one_list(reglists, owner, type, classid);
> +	if (!match) {
> +		guc_capture_warn_with_list_info(i915, "Missing register list size",
> +						owner, type, classid);
> +		return -ENODATA;
> +	}
> +
> +	*num_entries = match->num_regs;
> +	return 0;
> +}
> +
> +static void
> +guc_capture_fill_engine_enable_masks(struct intel_gt *gt,
> +				     struct guc_gt_system_info *info)
> +{
> +	info->engine_enabled_masks[GUC_RENDER_CLASS] = 1;
> +	info->engine_enabled_masks[GUC_BLITTER_CLASS] = 1;
> +	info->engine_enabled_masks[GUC_VIDEO_CLASS] = VDBOX_MASK(gt);
> +	info->engine_enabled_masks[GUC_VIDEOENHANCE_CLASS] = VEBOX_MASK(gt);
> +}
> +
> +int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
> +				 u32 capture_offset, struct guc_gt_system_info *sysinfo)
> +{
> +	struct intel_gt *gt = guc_to_gt(guc);
> +	struct guc_gt_system_info *info, local_info;
> +	struct guc_debug_capture_list *listnode;
> +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> +	struct __guc_state_capture_priv *gc = guc->capture.priv;
> +	int i, j, size;
> +	u32 ggtt, null_ggtt, alloc_size = 0;
> +	u16 tmpnumreg = 0;
> +	u8 *ptr = NULL;
> +
> +	GEM_BUG_ON(!gc);
> +
> +	if (blob) {
> +		ptr = ((u8 *)blob) + capture_offset;
> +		ggtt = blob_ggtt + capture_offset;
> +		GEM_BUG_ON(!sysinfo);
> +		info = sysinfo;
> +	} else {
> +		memset(&local_info, 0, sizeof(local_info));
> +		info = &local_info;
> +		guc_capture_fill_engine_enable_masks(gt, info);
> +	}
> +
> +	/* first, set aside the first page for a capture_list with zero descriptors */
> +	alloc_size = PAGE_SIZE;
> +	if (blob) {
> +		listnode = (struct guc_debug_capture_list *)ptr;
> +		listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, 0);
> +		null_ggtt = ggtt;
> +		ggtt += PAGE_SIZE;
> +		ptr +=  PAGE_SIZE;
> +	}
> +
> +#define COUNT_REGS guc_capture_list_count
> +#define FILL_REGS guc_capture_fill_reglist
> +#define TYPE_GLOBAL GUC_CAPTURE_LIST_TYPE_GLOBAL
> +#define TYPE_CLASS GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS
> +#define TYPE_INSTANCE GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE
> +#define OWNER2STR guc_capture_stringify_owner
> +#define ENGCLS2STR guc_capture_stringify_engclass
> +#define TYPE2STR guc_capture_stringify_type
> +
> +	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
> +		for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
> +			if (!info->engine_enabled_masks[j]) {
> +				if (gc->num_class_regs[i][j])
> +					drm_warn(&i915->drm, "GuC-Cap %s's %s class-"
> +						 "list enable mismatch was=%d now off\n",
> +						 OWNER2STR(i), ENGCLS2STR(j),
> +						 gc->num_class_regs[i][j]);
> +				if (gc->num_instance_regs[i][j])
> +					drm_warn(&i915->drm, "GuC-Cap %s's %s inst-"
> +						 "list enable mismatch was=%d now off!\n",
> +						 OWNER2STR(i), ENGCLS2STR(j),
> +						 gc->num_instance_regs[i][j]);
> +				gc->num_class_regs[i][j] = 0;
> +				gc->num_instance_regs[i][j] = 0;
> +				if (blob) {
> +					blob->capture_class[i][j] = null_ggtt;
> +					blob->capture_instance[i][j] = null_ggtt;
> +				}
> +			} else {
> +				if (!COUNT_REGS(guc, i, TYPE_CLASS, j, &tmpnumreg)) {
> +					if (blob && tmpnumreg > gc->num_class_regs[i][j]) {
> +						drm_warn(&i915->drm, "GuC-Cap %s's %s-%s-list "
> +							 "count overflow cap from %d to %d",
> +							 OWNER2STR(i), ENGCLS2STR(j),
> +							 TYPE2STR(TYPE_CLASS),
> +							 gc->num_class_regs[i][j], tmpnumreg);
> +						tmpnumreg = gc->num_class_regs[i][j];
> +					}
> +					size = FILL_REGS(guc, blob, i, TYPE_CLASS, j,
> +							 tmpnumreg, &ptr, &ggtt, null_ggtt);
> +					alloc_size += size;
> +					gc->num_class_regs[i][j] = tmpnumreg;
> +				} else {
> +					gc->num_class_regs[i][j] = 0;
> +					if (blob)
> +						blob->capture_class[i][j] = null_ggtt;
> +				}
> +				if (!COUNT_REGS(guc, i, TYPE_INSTANCE, j, &tmpnumreg)) {
> +					if (blob && tmpnumreg > gc->num_instance_regs[i][j]) {
> +						drm_warn(&i915->drm, "GuC-Cap %s's %s-%s-list "
> +							 "count overflow cap from %d to %d",
> +							 OWNER2STR(i), ENGCLS2STR(j),
> +							 TYPE2STR(TYPE_INSTANCE),
> +							 gc->num_instance_regs[i][j], tmpnumreg);
> +						tmpnumreg = gc->num_instance_regs[i][j];
> +					}
> +					size = FILL_REGS(guc, blob, i, TYPE_INSTANCE, j,
> +							 tmpnumreg, &ptr, &ggtt, null_ggtt);
> +					alloc_size += size;
> +					gc->num_instance_regs[i][j] = tmpnumreg;
> +				} else {
> +					gc->num_instance_regs[i][j] = 0;
> +					if (blob)
> +						blob->capture_instance[i][j] = null_ggtt;
> +				}
> +			}
> +		}
> +		if (!COUNT_REGS(guc, i, TYPE_GLOBAL, 0, &tmpnumreg)) {
> +			if (blob && tmpnumreg > gc->num_global_regs[i]) {
> +				drm_warn(&i915->drm, "GuC-Cap %s's %s-list count increased from %d to %d",
> +					 OWNER2STR(i), TYPE2STR(TYPE_GLOBAL),
> +					 gc->num_global_regs[i], tmpnumreg);
> +				tmpnumreg = gc->num_global_regs[i];
> +			}
> +			size = FILL_REGS(guc, blob, i, TYPE_GLOBAL, 0, tmpnumreg,
> +					 &ptr, &ggtt, null_ggtt);
> +			alloc_size += size;
> +			gc->num_global_regs[i] = tmpnumreg;
> +		} else {
> +			gc->num_global_regs[i] = 0;
> +			if (blob)
> +				blob->capture_global[i] = null_ggtt;
> +		}
> +	}
> +
> +#undef COUNT_REGS
> +#undef FILL_REGS
> +#undef TYPE_GLOBAL
> +#undef TYPE_CLASS
> +#undef TYPE_INSTANCE
> +#undef OWNER2STR
> +#undef ENGCLS2STR
> +#undef TYPE2STR
> +
> +	if (guc->ads_capture_size && guc->ads_capture_size != PAGE_ALIGN(alloc_size))
> +		drm_warn(&i915->drm, "GuC->ADS->Capture alloc size changed from %d to %d\n",
> +			 guc->ads_capture_size, PAGE_ALIGN(alloc_size));
> +
> +	return PAGE_ALIGN(alloc_size);
> +}
> +
> +void intel_guc_capture_destroy(struct intel_guc *guc)
> +{
> +	kfree(guc->capture.priv);
> +	guc->capture.priv = NULL;
> +}
> +
> +int intel_guc_capture_init(struct intel_guc *guc)
> +{
> +	guc->capture.priv = kzalloc(sizeof(*guc->capture.priv), GFP_KERNEL);
> +	if (!guc->capture.priv)
> +		return -ENOMEM;
> +	guc->capture.priv->reglists = guc_capture_get_device_reglist(guc);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
> new file mode 100644
> index 000000000000..6b5594ca529d
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021-2021 Intel Corporation
> + */
> +
> +#ifndef _INTEL_GUC_CAPTURE_H
> +#define _INTEL_GUC_CAPTURE_H
> +
> +#include <linux/types.h>
> +
> +struct intel_guc;
> +struct guc_ads;
> +struct guc_gt_system_info;
> +
> +int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
> +				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
> +void intel_guc_capture_destroy(struct intel_guc *guc);
> +int intel_guc_capture_init(struct intel_guc *guc);
> +
> +#endif /* _INTEL_GUC_CAPTURE_H */
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> index 6a4612a852e2..92bfe25a5e85 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> @@ -297,6 +297,23 @@ enum {
>  	GUC_CAPTURE_LIST_INDEX_MAX = 2,
>  };
>  
> +/*Register-types of GuC capture register lists */
> +enum guc_capture_type {
> +	GUC_CAPTURE_LIST_TYPE_GLOBAL = 0,
> +	GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
> +	GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
> +	GUC_CAPTURE_LIST_TYPE_MAX,
> +};
> +
> +struct guc_debug_capture_list_header {
> +	u32 info;
> +		#define GUC_CAPTURELISTHDR_NUMDESCR GENMASK(15, 0)
> +} __packed;
> +
> +struct guc_debug_capture_list {
> +	struct guc_debug_capture_list_header header;
> +} __packed;
> +
>  /* GuC Additional Data Struct */
>  struct guc_ads {
>  	struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS];

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for Add GuC Error Capture Support (rev5)
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (10 preceding siblings ...)
  (?)
@ 2022-01-26 18:51 ` Patchwork
  -1 siblings, 0 replies; 52+ messages in thread
From: Patchwork @ 2022-01-26 18:51 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

== Series Details ==

Series: Add GuC Error Capture Support (rev5)
URL   : https://patchwork.freedesktop.org/series/97187/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
233b325e5a87 drm/i915/guc: Update GuC ADS size for error capture lists
-:32: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#32: 
new file mode 100644

-:307: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'regslist' - possible side-effects?
#307: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:60:
+#define MAKE_REGLIST(regslist, regsowner, regstype, class) \
+	{ \
+		.list = regslist, \
+		.num_regs = ARRAY_SIZE(regslist), \
+		.owner = TO_GCAP_DEF_OWNER(regsowner), \
+		.type = TO_GCAP_DEF_TYPE(regstype), \
+		.engine = class, \
+	}

-:356: WARNING:SUSPECT_CODE_INDENT: suspect code indent for conditional statements (16, 16)
#356: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:109:
+		if (reglists[i].owner == owner && reglists[i].type == type &&
[...]
+		return &reglists[i];

total: 0 errors, 2 warnings, 1 checks, 681 lines checked
34501e7d2c33 drm/i915/guc: Add XE_LP registers for GuC error state capture.
-:37: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#37: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:22:
+#define COMMON_GEN12BASE_GLOBAL() \
+	{GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0"}, \
+	{GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1"}, \
+	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}, \
+	{GEN12_AUX_ERR_DBG,        0,      0, "GEN12_AUX_ERR_DBG"}, \
+	{GEN12_GAM_DONE,           0,      0, "GEN12_GAM_DONE"}, \
+	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}

-:45: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#45: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:30:
+#define COMMON_GEN12BASE_ENGINE_INSTANCE() \
+	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
+	{RING_ESR(0),              0,      0, "RING_ESR"}, \
+	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \
+	{RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UP32"}, \
+	{RING_IPEIR(0),            0,      0, "RING_IPEIR"}, \
+	{RING_IPEHR(0),            0,      0, "RING_IPEHR"}, \
+	{RING_INSTPS(0),           0,      0, "RING_INSTPS"}, \
+	{RING_BBADDR(0),           0,      0, "RING_BBADDR_LOW32"}, \
+	{RING_BBADDR_UDW(0),       0,      0, "RING_BBADDR_UP32"}, \
+	{RING_BBSTATE(0),          0,      0, "RING_BBSTATE"}, \
+	{CCID(0),                  0,      0, "CCID"}, \
+	{RING_ACTHD(0),            0,      0, "RING_ACTHD_LOW32"}, \
+	{RING_ACTHD_UDW(0),        0,      0, "RING_ACTHD_UP32"}, \
+	{RING_INSTPM(0),           0,      0, "RING_INSTPM"}, \
+	{RING_NOPID(0),            0,      0, "RING_NOPID"}, \
+	{RING_START(0),            0,      0, "RING_START"}, \
+	{RING_HEAD(0),             0,      0, "RING_HEAD"}, \
+	{RING_TAIL(0),             0,      0, "RING_TAIL"}, \
+	{RING_CTL(0),              0,      0, "RING_CTL"}, \
+	{RING_MI_MODE(0),          0,      0, "RING_MI_MODE"}, \
+	{RING_CONTEXT_CONTROL(0),  0,      0, "RING_CONTEXT_CONTROL"}, \
+	{RING_INSTDONE(0),         0,      0, "RING_INSTDONE"}, \
+	{RING_HWS_PGA(0),          0,      0, "RING_HWS_PGA"}, \
+	{RING_MODE_GEN7(0),        0,      0, "RING_MODE_GEN7"}, \
+	{GEN8_RING_PDP_LDW(0, 0),  0,      0, "GEN8_RING_PDP0_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 0),  0,      0, "GEN8_RING_PDP0_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 1),  0,      0, "GEN8_RING_PDP1_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 1),  0,      0, "GEN8_RING_PDP1_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 2),  0,      0, "GEN8_RING_PDP2_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 2),  0,      0, "GEN8_RING_PDP2_UDW"}, \
+	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "GEN8_RING_PDP3_LDW"}, \
+	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "GEN8_RING_PDP3_UDW"}

-:82: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#82: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:67:
+#define COMMON_GEN12BASE_RENDER() \
+	{GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE"}, \
+	{GEN12_SC_INSTDONE_EXTRA,  0,      0, "GEN12_SC_INSTDONE_EXTRA"}, \
+	{GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2"}

-:87: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#87: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:72:
+#define COMMON_GEN12BASE_VEC() \
+	{GEN12_SFC_DONE(0),        0,      0, "GEN12_SFC_DONE0"}, \
+	{GEN12_SFC_DONE(1),        0,      0, "GEN12_SFC_DONE1"}, \
+	{GEN12_SFC_DONE(2),        0,      0, "GEN12_SFC_DONE2"}, \
+	{GEN12_SFC_DONE(3),        0,      0, "GEN12_SFC_DONE3"}

-:179: WARNING:SUSPECT_CODE_INDENT: suspect code indent for conditional statements (16, 16)
#179: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:155:
+		if (reglists[i].owner == owner && reglists[i].type == type &&
[...]
+		return &reglists[i];

total: 4 errors, 1 warnings, 0 checks, 310 lines checked
e267d6f56a70 drm/i915/guc: Add DG2 registers for GuC error state capture.
-:79: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'ext' - possible side-effects?
#79: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:231:
+#define POPULATE_NEXT_EXTREG(ext, list, idx, slicenum, subslicenum) \
+	{ \
+		(ext)->reg = list[idx].reg; \
+		(ext)->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slicenum); \
+		(ext)->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslicenum); \
+		(ext)->regname = xelpd_extregs[i].name; \
+		++(ext); \
+	}

total: 0 errors, 0 warnings, 1 checks, 100 lines checked
5f79985dd3d6 drm/i915/guc: Add Gen9 registers for GuC error state capture.
-:22: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#22: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:25:
+#define COMMON_GEN9BASE_GLOBAL() \
+	{GEN8_FAULT_TLB_DATA0,     0,      0, "GEN8_FAULT_TLB_DATA0"}, \
+	{GEN8_FAULT_TLB_DATA1,     0,      0, "GEN8_FAULT_TLB_DATA1"}, \
+	{ERROR_GEN6,               0,      0, "ERROR_GEN6"}, \
+	{DONE_REG,                 0,      0, "DONE_REG"}, \
+	{HSW_GTT_CACHE_EN,         0,      0, "HSW_GTT_CACHE_EN"}

-:38: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#38: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:39:
+#define COMMON_BASE_ENGINE_INSTANCE() \
 	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
 	{RING_ESR(0),              0,      0, "RING_ESR"}, \
 	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \

total: 2 errors, 0 warnings, 0 checks, 138 lines checked
82ae5e0bde63 drm/i915/guc: Add GuC's error state capture output structures.
a31eff00312f drm/i915/guc: Update GuC's log-buffer-state access for error capture.
-:191: CHECK:MULTIPLE_ASSIGNMENTS: multiple assignments should be avoided
#191: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_log.c:218:
+	log_buf_state = src_data = log->buf_addr;

total: 0 errors, 0 warnings, 1 checks, 436 lines checked
41c83070d184 drm/i915/guc: Extract GuC error capture lists on G2H notification.
-:318: WARNING:NEEDLESS_IF: kfree(NULL) is safe and this check is probably not required
#318: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:868:
+				if (n->reginfo[i].regs)
+					kfree(n->reginfo[i].regs);

-:346: WARNING:NEEDLESS_IF: kfree(NULL) is safe and this check is probably not required
#346: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:896:
+				if (found->reginfo[i].regs)
+					kfree(found->reginfo[i].regs);

-:406: WARNING:NEEDLESS_IF: kfree(NULL) is safe and this check is probably not required
#406: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:956:
+		if (new->reginfo[i].regs)
+			kfree(new->reginfo[i].regs);

-:495: CHECK:BRACES: Blank lines aren't necessary after an open brace '{'
#495: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1045:
+	while (numlists--) {
+

-:588: WARNING:NEEDLESS_IF: kfree(NULL) is safe and this check is probably not required
#588: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1138:
+		if (node)
+			kfree(node);

total: 0 errors, 4 warnings, 1 checks, 741 lines checked
f91d07f2eeea drm/i915/guc: Plumb GuC-capture into gpu_coredump
-:103: WARNING:NEEDLESS_IF: kfree(NULL) is safe and this check is probably not required
#103: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1237:
+		if (ee->guc_capture_node->reginfo[i].regs)
+			kfree(ee->guc_capture_node->reginfo[i].regs);

total: 0 errors, 1 warnings, 0 checks, 689 lines checked
5d218e0455a0 drm/i915/guc: Follow legacy register names
63ae1e872f0e drm/i915/guc: Print the GuC error capture output register list.
-:103: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'b' - possible side-effects?
#103: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1261:
+#define guc_capt_err_print(a, b, ...) \
+	do { \
+		drm_warn(a, __VA_ARGS__); \
+		if (b) \
+			i915_error_printf(b, __VA_ARGS__); \
+	} while (0)

-:110: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'b' - possible side-effects?
#110: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1268:
+#define guc_capt_err_print(a, b, ...) \
+	do { \
+		if (b) \
+			i915_error_printf(b, __VA_ARGS__); \
+	} while (0)

-:129: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'i915' - possible side-effects?
#129: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1287:
+#define GCAP_PRINT_INTEL_ENG_INFO(i915, ebuf, eng) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Name: %s command stream\n", \
+		      (eng)->name); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-LogicalMask: 0x%08x\n", \
+		      (eng)->logical_mask); \
+	} while (0)

-:129: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'ebuf' - possible side-effects?
#129: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1287:
+#define GCAP_PRINT_INTEL_ENG_INFO(i915, ebuf, eng) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Name: %s command stream\n", \
+		      (eng)->name); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-LogicalMask: 0x%08x\n", \
+		      (eng)->logical_mask); \
+	} while (0)

-:129: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'eng' - possible side-effects?
#129: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1287:
+#define GCAP_PRINT_INTEL_ENG_INFO(i915, ebuf, eng) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Name: %s command stream\n", \
+		      (eng)->name); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \
+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-LogicalMask: 0x%08x\n", \
+		      (eng)->logical_mask); \
+	} while (0)

-:139: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'i915' - possible side-effects?
#139: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1297:
+#define GCAP_PRINT_GUC_INST_INFO(i915, ebuf, node) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Engine-Inst-Id: 0x%08x\n", \
+		      (node)->eng_inst); \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Context-Id: 0x%08x\n", (node)->guc_id); \
+		PRINT(&(i915)->drm, (ebuf), "    LRCA: 0x%08x\n", (node)->lrca); \
+	} while (0)

-:139: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'ebuf' - possible side-effects?
#139: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1297:
+#define GCAP_PRINT_GUC_INST_INFO(i915, ebuf, node) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Engine-Inst-Id: 0x%08x\n", \
+		      (node)->eng_inst); \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Context-Id: 0x%08x\n", (node)->guc_id); \
+		PRINT(&(i915)->drm, (ebuf), "    LRCA: 0x%08x\n", (node)->lrca); \
+	} while (0)

-:139: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'node' - possible side-effects?
#139: FILE: drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c:1297:
+#define GCAP_PRINT_GUC_INST_INFO(i915, ebuf, node) \
+	do { \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Engine-Inst-Id: 0x%08x\n", \
+		      (node)->eng_inst); \
+		PRINT(&(i915)->drm, (ebuf), "    GuC-Context-Id: 0x%08x\n", (node)->guc_id); \
+		PRINT(&(i915)->drm, (ebuf), "    LRCA: 0x%08x\n", (node)->lrca); \
+	} while (0)

total: 0 errors, 0 warnings, 8 checks, 270 lines checked



^ permalink raw reply	[flat|nested] 52+ messages in thread

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for Add GuC Error Capture Support (rev5)
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (11 preceding siblings ...)
  (?)
@ 2022-01-26 18:52 ` Patchwork
  -1 siblings, 0 replies; 52+ messages in thread
From: Patchwork @ 2022-01-26 18:52 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

== Series Details ==

Series: Add GuC Error Capture Support (rev5)
URL   : https://patchwork.freedesktop.org/series/97187/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.



^ permalink raw reply	[flat|nested] 52+ messages in thread

* [Intel-gfx] ✗ Fi.CI.BAT: failure for Add GuC Error Capture Support (rev5)
  2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
                   ` (12 preceding siblings ...)
  (?)
@ 2022-01-26 19:25 ` Patchwork
  -1 siblings, 0 replies; 52+ messages in thread
From: Patchwork @ 2022-01-26 19:25 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 11631 bytes --]

== Series Details ==

Series: Add GuC Error Capture Support (rev5)
URL   : https://patchwork.freedesktop.org/series/97187/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_11145 -> Patchwork_22112
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with Patchwork_22112 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_22112, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/index.html

Participating hosts (46 -> 43)
------------------------------

  Additional (1): fi-icl-u2 
  Missing    (4): fi-ctg-p8600 fi-bsw-cyan fi-bdw-samus fi-hsw-4200u 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in Patchwork_22112:

### IGT changes ###

#### Possible regressions ####

  * igt@i915_selftest@live@gt_engines:
    - bat-dg1-6:          [PASS][1] -> [DMESG-FAIL][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/bat-dg1-6/igt@i915_selftest@live@gt_engines.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/bat-dg1-6/igt@i915_selftest@live@gt_engines.html
    - fi-rkl-guc:         [PASS][3] -> [DMESG-FAIL][4]
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/fi-rkl-guc/igt@i915_selftest@live@gt_engines.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-rkl-guc/igt@i915_selftest@live@gt_engines.html
    - bat-dg1-5:          [PASS][5] -> [DMESG-FAIL][6]
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/bat-dg1-5/igt@i915_selftest@live@gt_engines.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/bat-dg1-5/igt@i915_selftest@live@gt_engines.html

  * igt@i915_selftest@live@workarounds:
    - bat-dg1-5:          [PASS][7] -> [DMESG-WARN][8]
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/bat-dg1-5/igt@i915_selftest@live@workarounds.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/bat-dg1-5/igt@i915_selftest@live@workarounds.html
    - bat-dg1-6:          [PASS][9] -> [DMESG-WARN][10]
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/bat-dg1-6/igt@i915_selftest@live@workarounds.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/bat-dg1-6/igt@i915_selftest@live@workarounds.html
    - fi-rkl-guc:         [PASS][11] -> [DMESG-WARN][12]
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/fi-rkl-guc/igt@i915_selftest@live@workarounds.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-rkl-guc/igt@i915_selftest@live@workarounds.html

  
Known issues
------------

  Here are the changes found in Patchwork_22112 that come from known issues:

### CI changes ###

#### Possible fixes ####

  * boot:
    - fi-ilk-650:         [FAIL][13] -> [PASS][14]
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/fi-ilk-650/boot.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-ilk-650/boot.html

  

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_cs_nop@fork-gfx0:
    - fi-icl-u2:          NOTRUN -> [SKIP][15] ([fdo#109315]) +17 similar issues
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-icl-u2/igt@amdgpu/amd_cs_nop@fork-gfx0.html

  * igt@amdgpu/amd_cs_nop@nop-compute0:
    - fi-ilk-650:         NOTRUN -> [SKIP][16] ([fdo#109271]) +39 similar issues
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-ilk-650/igt@amdgpu/amd_cs_nop@nop-compute0.html

  * igt@gem_huc_copy@huc-copy:
    - fi-skl-6600u:       NOTRUN -> [SKIP][17] ([fdo#109271] / [i915#2190])
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@gem_huc_copy@huc-copy.html
    - fi-icl-u2:          NOTRUN -> [SKIP][18] ([i915#2190])
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-icl-u2/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@parallel-random-engines:
    - fi-icl-u2:          NOTRUN -> [SKIP][19] ([i915#4613]) +3 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-icl-u2/igt@gem_lmem_swapping@parallel-random-engines.html

  * igt@gem_lmem_swapping@verify-random:
    - fi-skl-6600u:       NOTRUN -> [SKIP][20] ([fdo#109271] / [i915#4613]) +3 similar issues
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@gem_lmem_swapping@verify-random.html

  * igt@i915_selftest@live:
    - fi-skl-6600u:       NOTRUN -> [FAIL][21] ([i915#4547])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@i915_selftest@live.html

  * igt@i915_selftest@live@hangcheck:
    - fi-hsw-4770:        [PASS][22] -> [INCOMPLETE][23] ([i915#3303])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/fi-hsw-4770/igt@i915_selftest@live@hangcheck.html
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-hsw-4770/igt@i915_selftest@live@hangcheck.html

  * igt@kms_chamelium@dp-hpd-fast:
    - fi-ilk-650:         NOTRUN -> [SKIP][24] ([fdo#109271] / [fdo#111827]) +8 similar issues
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-ilk-650/igt@kms_chamelium@dp-hpd-fast.html

  * igt@kms_chamelium@hdmi-hpd-fast:
    - fi-icl-u2:          NOTRUN -> [SKIP][25] ([fdo#111827]) +8 similar issues
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-icl-u2/igt@kms_chamelium@hdmi-hpd-fast.html

  * igt@kms_chamelium@vga-edid-read:
    - fi-skl-6600u:       NOTRUN -> [SKIP][26] ([fdo#109271] / [fdo#111827]) +8 similar issues
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@kms_chamelium@vga-edid-read.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy:
    - fi-icl-u2:          NOTRUN -> [SKIP][27] ([fdo#109278]) +2 similar issues
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-icl-u2/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy.html
    - fi-skl-6600u:       NOTRUN -> [SKIP][28] ([fdo#109271]) +3 similar issues
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy.html

  * igt@kms_force_connector_basic@force-load-detect:
    - fi-icl-u2:          NOTRUN -> [SKIP][29] ([fdo#109285])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-icl-u2/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-d:
    - fi-skl-6600u:       NOTRUN -> [SKIP][30] ([fdo#109271] / [i915#533])
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-d.html

  * igt@prime_vgem@basic-userptr:
    - fi-icl-u2:          NOTRUN -> [SKIP][31] ([i915#3301])
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-icl-u2/igt@prime_vgem@basic-userptr.html

  * igt@runner@aborted:
    - bat-dg1-5:          NOTRUN -> [FAIL][32] ([i915#4312])
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/bat-dg1-5/igt@runner@aborted.html
    - fi-bdw-5557u:       NOTRUN -> [FAIL][33] ([i915#2426] / [i915#4312])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-bdw-5557u/igt@runner@aborted.html
    - fi-hsw-4770:        NOTRUN -> [FAIL][34] ([fdo#109271] / [i915#1436] / [i915#4312])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-hsw-4770/igt@runner@aborted.html
    - fi-rkl-guc:         NOTRUN -> [FAIL][35] ([i915#2426] / [i915#4312])
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-rkl-guc/igt@runner@aborted.html
    - bat-dg1-6:          NOTRUN -> [FAIL][36] ([i915#4312])
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/bat-dg1-6/igt@runner@aborted.html

  
#### Possible fixes ####

  * igt@gem_flink_basic@bad-flink:
    - fi-skl-6600u:       [FAIL][37] ([i915#4547]) -> [PASS][38]
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/fi-skl-6600u/igt@gem_flink_basic@bad-flink.html
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@gem_flink_basic@bad-flink.html

  * igt@kms_frontbuffer_tracking@basic:
    - fi-cml-u2:          [DMESG-WARN][39] ([i915#4269]) -> [PASS][40]
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/fi-cml-u2/igt@kms_frontbuffer_tracking@basic.html
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-cml-u2/igt@kms_frontbuffer_tracking@basic.html

  
#### Warnings ####

  * igt@runner@aborted:
    - fi-skl-6600u:       [FAIL][41] ([i915#4312]) -> [FAIL][42] ([i915#1436] / [i915#4312])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11145/fi-skl-6600u/igt@runner@aborted.html
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/fi-skl-6600u/igt@runner@aborted.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [i915#1436]: https://gitlab.freedesktop.org/drm/intel/issues/1436
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2426]: https://gitlab.freedesktop.org/drm/intel/issues/2426
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#3303]: https://gitlab.freedesktop.org/drm/intel/issues/3303
  [i915#4269]: https://gitlab.freedesktop.org/drm/intel/issues/4269
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4547]: https://gitlab.freedesktop.org/drm/intel/issues/4547
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4898]: https://gitlab.freedesktop.org/drm/intel/issues/4898
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533
  [i915#541]: https://gitlab.freedesktop.org/drm/intel/issues/541


Build changes
-------------

  * Linux: CI_DRM_11145 -> Patchwork_22112

  CI-20190529: 20190529
  CI_DRM_11145: 348109d01999f0feea85e8f336dc804b782ab870 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_6335: 2b30115edd692b60d16cb10375730a87f51f0e37 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  Patchwork_22112: 63ae1e872f0e68f9874d5b9ec0478789043ed6af @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

63ae1e872f0e drm/i915/guc: Print the GuC error capture output register list.
5d218e0455a0 drm/i915/guc: Follow legacy register names
f91d07f2eeea drm/i915/guc: Plumb GuC-capture into gpu_coredump
41c83070d184 drm/i915/guc: Extract GuC error capture lists on G2H notification.
a31eff00312f drm/i915/guc: Update GuC's log-buffer-state access for error capture.
82ae5e0bde63 drm/i915/guc: Add GuC's error state capture output structures.
5f79985dd3d6 drm/i915/guc: Add Gen9 registers for GuC error state capture.
e267d6f56a70 drm/i915/guc: Add DG2 registers for GuC error state capture.
34501e7d2c33 drm/i915/guc: Add XE_LP registers for GuC error state capture.
233b325e5a87 drm/i915/guc: Update GuC ADS size for error capture lists

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22112/index.html

[-- Attachment #2: Type: text/html, Size: 14200 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 02/10] drm/i915/guc: Add XE_LP registers for GuC error state capture.
  2022-01-26 18:13   ` Jani Nikula
@ 2022-01-26 21:46     ` Teres Alexis, Alan Previn
  2022-01-27  9:30       ` Jani Nikula
  0 siblings, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-01-26 21:46 UTC (permalink / raw)
  To: intel-gfx, jani.nikula


Thanks Jani for taking the time to review... 

1. apologies on the const issue, this is my bad, i think it was
one of the comments from earlier rev not sure how i missed it.
Will fix this on next rev.

2. I do have a question below on the const for one of specific types
of tables. Need your thoughts

...alan


On Wed, 2022-01-26 at 20:13 +0200, Jani Nikula wrote:
> On Wed, 26 Jan 2022, Alan Previn <alan.previn.teres.alexis@intel.com> wrote:
> > Add device specific tables and register lists to cover different engines
> > class types for GuC error state capture for XE_LP products.
> > 
...

> > +static struct __ext_steer_reg xelpd_extregs[] = {
> > +	{"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE},
> > +	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
> > +};
> 
> Either this needs to be const or, if it needs to be mutable, moved to
> device specific data.
> 
> Ditto for all such things all over the place.
> 
> BR,
> Jani.


I had a question though... the list of registers like the one above as well
as below shall be made const... however, the table-of-lists (see farther down), contains a pointer to "extended_regs"
that shall be allocated at startup - is it okay for that list to remain non-const
since the others with actual register offsets remain const?

Alan: will add const for this and above tables:
	static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
		COMMON_BASE_GLOBAL(),
		COMMON_GEN9BASE_GLOBAL(),
		COMMON_GEN12BASE_GLOBAL(),
	};

Is this okay to not be const?:
	static struct __guc_mmio_reg_descr_group default_lists[] = {
		MAKE_REGLIST(default_global_regs, PF, GLOBAL, 0),
		MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
		MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
		MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
		MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
		MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
		{}
	};



^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists Alan Previn
  2022-01-26 18:09   ` Jani Nikula
  2022-01-26 18:15   ` Jani Nikula
@ 2022-01-26 22:46   ` Lucas De Marchi
  2022-02-03 19:03     ` Matthew Brost
  2 siblings, 1 reply; 52+ messages in thread
From: Lucas De Marchi @ 2022-01-26 22:46 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

On Wed, Jan 26, 2022 at 02:48:13AM -0800, Alan Previn wrote:
>Update GuC ADS size allocation to include space for
>the lists of error state capture register descriptors.
>
>Also, populate the lists of registers we want GuC to report back to
>Host on engine reset events. This list should include global,
>engine-class and engine-instance registers for every engine-class
>type on the current hardware.
>
>NOTE: Start with a sample table of register lists to layout the
>framework before adding real registers in subsequent patch.
>
>Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>---

...

> static void __guc_ads_init(struct intel_guc *guc)
> {
> 	struct intel_gt *gt = guc_to_gt(guc);
>@@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
>
> 	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
>
>-	/* Capture list for hang debug */
>-	guc_capture_list_init(guc, blob);
>-
>+	/* Lists for error capture debug */
>+	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,

no, please don't cast/export struct guc_ads like this. We can't really
dereference it since it may be in IO memory.

See https://patchwork.freedesktop.org/series/99378/ with the huge
refactor in this file to make it conform to the rules of accessing IO
memory.

Maybe this list could be appended in the same reglist buffer and we just
copy it once to its final location, like we are doing with the reglist?

Lucas De Marchi

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture Alan Previn
@ 2022-01-27  4:26   ` Teres Alexis, Alan Previn
  2022-02-04 18:19   ` Matthew Brost
  1 sibling, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-01-27  4:26 UTC (permalink / raw)
  To: intel-gfx

As per the rev 5 CI results between this patch and patch7, i have introduced a lockdep splat bug, i shall fix that in
the next rev.

...alan

On Wed, 2022-01-26 at 02:48 -0800, Alan Previn wrote:
> GuC log buffer regions for debug-log-events, crash-dumps and
> error-state-capture are all a single bo allocation that includes
> the guc_log_buffer_state structures.
> 
> Since the error-capture region is accessed with high priority at non-
> deterministic times (as part of gpu coredump) while the debug-log-event
> region is populated and accessed with different priorities, timings and
> consumers, let's split out separate locks for buffer-state accesses
> of each region.
> 
> Also, ensure a global mapping is made up front for the entire bo
> throughout GuC operation so that dynamic mapping and unmapping isn't
> required for error capture log access if relay-logging isn't running.
> 
> Additionally, while here, make some readibility improvements:
> 1. change previous function names with "capture_logs" to
>    "copy_debug_logs" to help make the distinction clearer.
> 2. Update the guc log region mapping comments to order them
>    according to the enum definition as per the GuC interface.
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 02/10] drm/i915/guc: Add XE_LP registers for GuC error state capture.
  2022-01-26 21:46     ` Teres Alexis, Alan Previn
@ 2022-01-27  9:30       ` Jani Nikula
  2022-01-28 16:54         ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Jani Nikula @ 2022-01-27  9:30 UTC (permalink / raw)
  To: Teres Alexis, Alan Previn, intel-gfx

On Wed, 26 Jan 2022, "Teres Alexis, Alan Previn" <alan.previn.teres.alexis@intel.com> wrote:
> Thanks Jani for taking the time to review... 
>
> 1. apologies on the const issue, this is my bad, i think it was
> one of the comments from earlier rev not sure how i missed it.
> Will fix this on next rev.
>
> 2. I do have a question below on the const for one of specific types
> of tables. Need your thoughts
>
> ...alan
>
>
> On Wed, 2022-01-26 at 20:13 +0200, Jani Nikula wrote:
>> On Wed, 26 Jan 2022, Alan Previn <alan.previn.teres.alexis@intel.com> wrote:
>> > Add device specific tables and register lists to cover different engines
>> > class types for GuC error state capture for XE_LP products.
>> > 
> ...
>
>> > +static struct __ext_steer_reg xelpd_extregs[] = {
>> > +	{"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE},
>> > +	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
>> > +};
>> 
>> Either this needs to be const or, if it needs to be mutable, moved to
>> device specific data.
>> 
>> Ditto for all such things all over the place.
>> 
>> BR,
>> Jani.
>
>
> I had a question though... the list of registers like the one above as well
> as below shall be made const... however, the table-of-lists (see farther down), contains a pointer to "extended_regs"
> that shall be allocated at startup - is it okay for that list to remain non-const
> since the others with actual register offsets remain const?

A static mutable array like this is module or driver specific. Your
allocation is device specific.

Sure, you have a check in there with /* already populated */ comment on
the module specific data to avoid allocating it multiple times.

Now, consider probing two devices with different properties. The latter
one will use the stuff you allocated for the first device. It will get
really tricky really quickly.

Pretty much the rule is no static (or global) non-const data for
anything. We do have to make some exceptions, but every one of them adds
to the burden of checking if they're going to be a problem, maybe later
on if not right now. So it's not so much about being const per se, it's
about ensuring we don't screw up with device specific data.


BR,
Jani.


>
> Alan: will add const for this and above tables:
> 	static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
> 		COMMON_BASE_GLOBAL(),
> 		COMMON_GEN9BASE_GLOBAL(),
> 		COMMON_GEN12BASE_GLOBAL(),
> 	};
>
> Is this okay to not be const?:
> 	static struct __guc_mmio_reg_descr_group default_lists[] = {
> 		MAKE_REGLIST(default_global_regs, PF, GLOBAL, 0),
> 		MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
> 		MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
> 		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
> 		MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
> 		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
> 		MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
> 		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
> 		MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
> 		{}
> 	};
>
>

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 02/10] drm/i915/guc: Add XE_LP registers for GuC error state capture.
  2022-01-27  9:30       ` Jani Nikula
@ 2022-01-28 16:54         ` Teres Alexis, Alan Previn
  0 siblings, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-01-28 16:54 UTC (permalink / raw)
  To: intel-gfx, jani.nikula

Facepalming myself - yes you're right - that's an easy fix...
move the device specific ext-list into the guc_capture_priv structure
which is allocated per gt. 

Thanks Jani. 

...alan

On Thu, 2022-01-27 at 11:30 +0200, Jani Nikula wrote:
> On Wed, 26 Jan 2022, "Teres Alexis, Alan Previn" <alan.previn.teres.alexis@intel.com> wrote:
> > Thanks Jani for taking the time to review... 
> > 
> > 1. apologies on the const issue, this is my bad, i think it was
> > one of the comments from earlier rev not sure how i missed it.
> > Will fix this on next rev.
> > 
> > 2. I do have a question below on the const for one of specific types
> > of tables. Need your thoughts
> > 
> > ...alan
> > 
> > 
> > On Wed, 2022-01-26 at 20:13 +0200, Jani Nikula wrote:
> > > On Wed, 26 Jan 2022, Alan Previn <alan.previn.teres.alexis@intel.com> wrote:
> > > > Add device specific tables and register lists to cover different engines
> > > > class types for GuC error state capture for XE_LP products.
> > > > 
> > ...
> > 
> > > > +static struct __ext_steer_reg xelpd_extregs[] = {
> > > > +	{"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE},
> > > > +	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
> > > > +};
> > > 
> > > Either this needs to be const or, if it needs to be mutable, moved to
> > > device specific data.
> > > 
> > > Ditto for all such things all over the place.
> > > 
> > > BR,
> > > Jani.
> > 
> > I had a question though... the list of registers like the one above as well
> > as below shall be made const... however, the table-of-lists (see farther down), contains a pointer to "extended_regs"
> > that shall be allocated at startup - is it okay for that list to remain non-const
> > since the others with actual register offsets remain const?
> 
> A static mutable array like this is module or driver specific. Your
> allocation is device specific.
> 
> Sure, you have a check in there with /* already populated */ comment on
> the module specific data to avoid allocating it multiple times.
> 
> Now, consider probing two devices with different properties. The latter
> one will use the stuff you allocated for the first device. It will get
> really tricky really quickly.
> 
> Pretty much the rule is no static (or global) non-const data for
> anything. We do have to make some exceptions, but every one of them adds
> to the burden of checking if they're going to be a problem, maybe later
> on if not right now. So it's not so much about being const per se, it's
> about ensuring we don't screw up with device specific data.
> 
> 
> BR,
> Jani.
> 
> 
> > Alan: will add const for this and above tables:
> > 	static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
> > 		COMMON_BASE_GLOBAL(),
> > 		COMMON_GEN9BASE_GLOBAL(),
> > 		COMMON_GEN12BASE_GLOBAL(),
> > 	};
> > 
> > Is this okay to not be const?:
> > 	static struct __guc_mmio_reg_descr_group default_lists[] = {
> > 		MAKE_REGLIST(default_global_regs, PF, GLOBAL, 0),
> > 		MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
> > 		MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
> > 		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
> > 		MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
> > 		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
> > 		MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
> > 		MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
> > 		MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
> > 		{}
> > 	};
> > 
> > 
> 
> -- 
> Jani Nikula, Intel Open Source Graphics Center


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-01-26 22:46   ` Lucas De Marchi
@ 2022-02-03 19:03     ` Matthew Brost
  2022-02-03 20:04       ` Lucas De Marchi
  0 siblings, 1 reply; 52+ messages in thread
From: Matthew Brost @ 2022-02-03 19:03 UTC (permalink / raw)
  To: Lucas De Marchi; +Cc: intel-gfx, Alan Previn

On Wed, Jan 26, 2022 at 02:46:19PM -0800, Lucas De Marchi wrote:
> On Wed, Jan 26, 2022 at 02:48:13AM -0800, Alan Previn wrote:
> > Update GuC ADS size allocation to include space for
> > the lists of error state capture register descriptors.
> > 
> > Also, populate the lists of registers we want GuC to report back to
> > Host on engine reset events. This list should include global,
> > engine-class and engine-instance registers for every engine-class
> > type on the current hardware.
> > 
> > NOTE: Start with a sample table of register lists to layout the
> > framework before adding real registers in subsequent patch.
> > 
> > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > ---
> 
> ...
> 
> > static void __guc_ads_init(struct intel_guc *guc)
> > {
> > 	struct intel_gt *gt = guc_to_gt(guc);
> > @@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
> > 
> > 	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
> > 
> > -	/* Capture list for hang debug */
> > -	guc_capture_list_init(guc, blob);
> > -
> > +	/* Lists for error capture debug */
> > +	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
> 
> no, please don't cast/export struct guc_ads like this. We can't really
> dereference it since it may be in IO memory.
> 
> See https://patchwork.freedesktop.org/series/99378/ with the huge
> refactor in this file to make it conform to the rules of accessing IO
> memory.
> 
> Maybe this list could be appended in the same reglist buffer and we just
> copy it once to its final location, like we are doing with the reglist?
> 

Agree with Lucas here, let's create the capture list on probe and store
it somewhere in the device data. On ADS population this more or less
turns into a memcpy (or after Lucas's series a dma-buf-map call). And on
fini, just free to stored data. The create capture list IMO is fine to
be done in an external file and return the data to the ADS code but
let's make sure everyone is on board with that. Maybe ping Lucas
directly about this?

Specific patch Lucas's is referencing:
https://patchwork.freedesktop.org/patch/471051/?series=99378&rev=1

Matt

> Lucas De Marchi

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 09/10] drm/i915/guc: Follow legacy register names
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 09/10] drm/i915/guc: Follow legacy register names Alan Previn
@ 2022-02-03 19:09   ` Matthew Brost
  2022-02-04 18:53     ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Matthew Brost @ 2022-02-03 19:09 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

On Wed, Jan 26, 2022 at 02:48:21AM -0800, Alan Previn wrote:
> Before we print the GuC provided register dumps, modify the
> register tables to use string names as per the legacy error
> capture execlist codes.
> 
> Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>

I'd just squash this to the patches early in the series where these are
initially defined.

Matt 

> ---
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 70 +++++++++----------
>  1 file changed, 35 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> index 2f5dc413dddc..506496058daf 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> @@ -22,7 +22,7 @@
>   *       from the engine-mmio-base
>   */
>  #define COMMON_BASE_GLOBAL() \
> -	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}
> +	{FORCEWAKE_MT,             0,      0, "FORCEWAKE"}
>  
>  #define COMMON_GEN9BASE_GLOBAL() \
>  	{GEN8_FAULT_TLB_DATA0,     0,      0, "GEN8_FAULT_TLB_DATA0"}, \
> @@ -34,43 +34,43 @@
>  #define COMMON_GEN12BASE_GLOBAL() \
>  	{GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0"}, \
>  	{GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1"}, \
> -	{GEN12_AUX_ERR_DBG,        0,      0, "GEN12_AUX_ERR_DBG"}, \
> -	{GEN12_GAM_DONE,           0,      0, "GEN12_GAM_DONE"}, \
> -	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
> +	{GEN12_AUX_ERR_DBG,        0,      0, "AUX_ERR_DBG"}, \
> +	{GEN12_GAM_DONE,           0,      0, "GAM_DONE"}, \
> +	{GEN12_RING_FAULT_REG,     0,      0, "FAULT_REG"}
>  
>  #define COMMON_BASE_ENGINE_INSTANCE() \
> -	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
> -	{RING_ESR(0),              0,      0, "RING_ESR"}, \
> -	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \
> -	{RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UP32"}, \
> -	{RING_IPEIR(0),            0,      0, "RING_IPEIR"}, \
> -	{RING_IPEHR(0),            0,      0, "RING_IPEHR"}, \
> -	{RING_INSTPS(0),           0,      0, "RING_INSTPS"}, \
> +	{RING_PSMI_CTL(0),         0,      0, "RC PSMI"}, \
> +	{RING_ESR(0),              0,      0, "ESR"}, \
> +	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LDW"}, \
> +	{RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UDW"}, \
> +	{RING_IPEIR(0),            0,      0, "IPEIR"}, \
> +	{RING_IPEHR(0),            0,      0, "IPEHR"}, \
> +	{RING_INSTPS(0),           0,      0, "INSTPS"}, \
>  	{RING_BBADDR(0),           0,      0, "RING_BBADDR_LOW32"}, \
>  	{RING_BBADDR_UDW(0),       0,      0, "RING_BBADDR_UP32"}, \
> -	{RING_BBSTATE(0),          0,      0, "RING_BBSTATE"}, \
> +	{RING_BBSTATE(0),          0,      0, "BB_STATE"}, \
>  	{CCID(0),                  0,      0, "CCID"}, \
> -	{RING_ACTHD(0),            0,      0, "RING_ACTHD_LOW32"}, \
> -	{RING_ACTHD_UDW(0),        0,      0, "RING_ACTHD_UP32"}, \
> -	{RING_INSTPM(0),           0,      0, "RING_INSTPM"}, \
> +	{RING_ACTHD(0),            0,      0, "ACTHD_LDW"}, \
> +	{RING_ACTHD_UDW(0),        0,      0, "ACTHD_UDW"}, \
> +	{RING_INSTPM(0),           0,      0, "INSTPM"}, \
> +	{RING_INSTDONE(0),         0,      0, "INSTDONE"}, \
>  	{RING_NOPID(0),            0,      0, "RING_NOPID"}, \
> -	{RING_START(0),            0,      0, "RING_START"}, \
> -	{RING_HEAD(0),             0,      0, "RING_HEAD"}, \
> -	{RING_TAIL(0),             0,      0, "RING_TAIL"}, \
> -	{RING_CTL(0),              0,      0, "RING_CTL"}, \
> -	{RING_MI_MODE(0),          0,      0, "RING_MI_MODE"}, \
> +	{RING_START(0),            0,      0, "START"}, \
> +	{RING_HEAD(0),             0,      0, "HEAD"}, \
> +	{RING_TAIL(0),             0,      0, "TAIL"}, \
> +	{RING_CTL(0),              0,      0, "CTL"}, \
> +	{RING_MI_MODE(0),          0,      0, "MODE"}, \
>  	{RING_CONTEXT_CONTROL(0),  0,      0, "RING_CONTEXT_CONTROL"}, \
> -	{RING_INSTDONE(0),         0,      0, "RING_INSTDONE"}, \
> -	{RING_HWS_PGA(0),          0,      0, "RING_HWS_PGA"}, \
> -	{RING_MODE_GEN7(0),        0,      0, "RING_MODE_GEN7"}, \
> -	{GEN8_RING_PDP_LDW(0, 0),  0,      0, "GEN8_RING_PDP0_LDW"}, \
> -	{GEN8_RING_PDP_UDW(0, 0),  0,      0, "GEN8_RING_PDP0_UDW"}, \
> -	{GEN8_RING_PDP_LDW(0, 1),  0,      0, "GEN8_RING_PDP1_LDW"}, \
> -	{GEN8_RING_PDP_UDW(0, 1),  0,      0, "GEN8_RING_PDP1_UDW"}, \
> -	{GEN8_RING_PDP_LDW(0, 2),  0,      0, "GEN8_RING_PDP2_LDW"}, \
> -	{GEN8_RING_PDP_UDW(0, 2),  0,      0, "GEN8_RING_PDP2_UDW"}, \
> -	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "GEN8_RING_PDP3_LDW"}, \
> -	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "GEN8_RING_PDP3_UDW"}
> +	{RING_HWS_PGA(0),          0,      0, "HWS"}, \
> +	{RING_MODE_GEN7(0),        0,      0, "GFX_MODE"}, \
> +	{GEN8_RING_PDP_LDW(0, 0),  0,      0, "PDP0_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 0),  0,      0, "PDP0_UDW"}, \
> +	{GEN8_RING_PDP_LDW(0, 1),  0,      0, "PDP1_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 1),  0,      0, "PDP1_UDW"}, \
> +	{GEN8_RING_PDP_LDW(0, 2),  0,      0, "PDP2_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 2),  0,      0, "PDP2_UDW"}, \
> +	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "PDP3_LDW"}, \
> +	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "PDP3_UDW"}
>  
>  #define COMMON_BASE_HAS_EU() \
>  	{EIR,                      0,      0, "EIR"}
> @@ -83,10 +83,10 @@
>  	{GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2"}
>  
>  #define COMMON_GEN12BASE_VEC() \
> -	{GEN12_SFC_DONE(0),        0,      0, "GEN12_SFC_DONE0"}, \
> -	{GEN12_SFC_DONE(1),        0,      0, "GEN12_SFC_DONE1"}, \
> -	{GEN12_SFC_DONE(2),        0,      0, "GEN12_SFC_DONE2"}, \
> -	{GEN12_SFC_DONE(3),        0,      0, "GEN12_SFC_DONE3"}
> +	{GEN12_SFC_DONE(0),        0,      0, "SFC_DONE[0]"}, \
> +	{GEN12_SFC_DONE(1),        0,      0, "SFC_DONE[1]"}, \
> +	{GEN12_SFC_DONE(2),        0,      0, "SFC_DONE[2]"}, \
> +	{GEN12_SFC_DONE(3),        0,      0, "SFC_DONE[3]"}
>  
>  /* XE_LPD - Global */
>  static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-02-03 19:03     ` Matthew Brost
@ 2022-02-03 20:04       ` Lucas De Marchi
  2022-02-03 20:37         ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Lucas De Marchi @ 2022-02-03 20:04 UTC (permalink / raw)
  To: Matthew Brost; +Cc: intel-gfx, Alan Previn

On Thu, Feb 03, 2022 at 11:03:24AM -0800, Matthew Brost wrote:
>On Wed, Jan 26, 2022 at 02:46:19PM -0800, Lucas De Marchi wrote:
>> On Wed, Jan 26, 2022 at 02:48:13AM -0800, Alan Previn wrote:
>> > Update GuC ADS size allocation to include space for
>> > the lists of error state capture register descriptors.
>> >
>> > Also, populate the lists of registers we want GuC to report back to
>> > Host on engine reset events. This list should include global,
>> > engine-class and engine-instance registers for every engine-class
>> > type on the current hardware.
>> >
>> > NOTE: Start with a sample table of register lists to layout the
>> > framework before adding real registers in subsequent patch.
>> >
>> > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>> > ---
>>
>> ...
>>
>> > static void __guc_ads_init(struct intel_guc *guc)
>> > {
>> > 	struct intel_gt *gt = guc_to_gt(guc);
>> > @@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
>> >
>> > 	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
>> >
>> > -	/* Capture list for hang debug */
>> > -	guc_capture_list_init(guc, blob);
>> > -
>> > +	/* Lists for error capture debug */
>> > +	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
>>
>> no, please don't cast/export struct guc_ads like this. We can't really
>> dereference it since it may be in IO memory.
>>
>> See https://patchwork.freedesktop.org/series/99378/ with the huge
>> refactor in this file to make it conform to the rules of accessing IO
>> memory.
>>
>> Maybe this list could be appended in the same reglist buffer and we just
>> copy it once to its final location, like we are doing with the reglist?
>>
>
>Agree with Lucas here, let's create the capture list on probe and store
>it somewhere in the device data. On ADS population this more or less
>turns into a memcpy (or after Lucas's series a dma-buf-map call). And on
>fini, just free to stored data. The create capture list IMO is fine to
>be done in an external file and return the data to the ADS code but
>let's make sure everyone is on board with that. Maybe ping Lucas
>directly about this?

yeah, sounds good to me. My worry is exporting ADS struct layout to
other compilation units. Asking for the entire ads blob
(or what would be dma_buf_map in my patches, or iosys_map in the new
version I will send soon) could quickly spread too much knowledge about it to
the rest of the driver.

I think we should at most export the speficic offset inside the buffer
another compilation unit can fill out. In that case with the
iosys_buf API we would return a shallow copy of our guc->ads_map +
offset.

And the other alternative would be as you suggested: save the list in a
temporary buffer and when needed call intel_guc_ads() to populate that
into ads in the right place.

The integration with iosys-map I can figure out if my patch series lands
after this one, or I can help rebasing this otherwise. But IMO we
should not pass the plain blob pointer around regardless of iosys-map.


thanks
Lucas De Marchi

>
>Specific patch Lucas's is referencing:
>https://patchwork.freedesktop.org/patch/471051/?series=99378&rev=1
>
>Matt
>
>> Lucas De Marchi

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-02-03 20:04       ` Lucas De Marchi
@ 2022-02-03 20:37         ` Teres Alexis, Alan Previn
  2022-02-03 20:40           ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-03 20:37 UTC (permalink / raw)
  To: Brost, Matthew, Harrison, John C, De Marchi, Lucas; +Cc: intel-gfx

I can refactor my code to enforce an owner module to only return the size and an interim
buffer pointer (kzalloc, not io mem) and have ADS memcpy from that pointer into the ADS
substructure pointer.. 

But I hope we can make it a rule that its okay for an external owner-module to 
know and define the layout of the 2nd level substructure layout. This would allow
future new ADS substructure to have separate owner-modules handle the definition
of the substructure layout

something like this:

guc_ads_top_fwif.h

ADS owns top level ADS
{
    u32 ptr1;// substruct_foo1
    u32 ptr2;// substruct_foo2
    u32 ptr3;// substruct_foo3
	...
}

guc_capture_private.h

substruct_foo



So putting aside the fact that already have ADS containing the knowledge for
golden context,  register-save-restore, and others, but moving forward i am hoping
we can avoid piling on more and more unrelated low level knowledge inside of ADS.

The the error capture substructure layout has awareness of per PF-vs-VF, global vs
engine-class vs engine-instance and other fuse-specific awareness. So i am hoping
we can allow other moules to own the definition and parsing of the substructure
layout.

...alan


On Thu, 2022-02-03 at 12:04 -0800, Lucas De Marchi wrote:
> On Thu, Feb 03, 2022 at 11:03:24AM -0800, Matthew Brost wrote:
> > On Wed, Jan 26, 2022 at 02:46:19PM -0800, Lucas De Marchi wrote:
> > > On Wed, Jan 26, 2022 at 02:48:13AM -0800, Alan Previn wrote:
> > > > Update GuC ADS size allocation to include space for
> > > > the lists of error state capture register descriptors.
> > > > 
> > > > Also, populate the lists of registers we want GuC to report back to
> > > > Host on engine reset events. This list should include global,
> > > > engine-class and engine-instance registers for every engine-class
> > > > type on the current hardware.
> > > > 
> > > > NOTE: Start with a sample table of register lists to layout the
> > > > framework before adding real registers in subsequent patch.
> > > > 
> > > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > > > ---
> > > 
> > > ...
> > > 
> > > > static void __guc_ads_init(struct intel_guc *guc)
> > > > {
> > > > 	struct intel_gt *gt = guc_to_gt(guc);
> > > > @@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
> > > > 
> > > > 	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
> > > > 
> > > > -	/* Capture list for hang debug */
> > > > -	guc_capture_list_init(guc, blob);
> > > > -
> > > > +	/* Lists for error capture debug */
> > > > +	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
> > > 
> > > no, please don't cast/export struct guc_ads like this. We can't really
> > > dereference it since it may be in IO memory.
> > > 
> > > See https://patchwork.freedesktop.org/series/99378/ with the huge
> > > refactor in this file to make it conform to the rules of accessing IO
> > > memory.
> > > 
> > > Maybe this list could be appended in the same reglist buffer and we just
> > > copy it once to its final location, like we are doing with the reglist?
> > > 
> > 
> > Agree with Lucas here, let's create the capture list on probe and store
> > it somewhere in the device data. On ADS population this more or less
> > turns into a memcpy (or after Lucas's series a dma-buf-map call). And on
> > fini, just free to stored data. The create capture list IMO is fine to
> > be done in an external file and return the data to the ADS code but
> > let's make sure everyone is on board with that. Maybe ping Lucas
> > directly about this?
> 
> yeah, sounds good to me. My worry is exporting ADS struct layout to
> other compilation units. Asking for the entire ads blob
> (or what would be dma_buf_map in my patches, or iosys_map in the new
> version I will send soon) could quickly spread too much knowledge about it to
> the rest of the driver.
> 
I'm in partial disagreement with above. Based on above statement, are we enforcing
that we must always continue to only have ADS know the 2nd level blobl structure layout?
Doesn't that also force that intelligence of knowing its substructure contents to
always be in ADS only? So ADS C file continues to grow larger and larger with completely
orthogonal domain specific knowledge? (golden context: engine info,
error-capture: debug registers, etc..).
I believe ADS should really let the substructure headers be accessible to external
modules to deal with the parsing, size determination and preparing its contents.

NOTE: see my next comment specifically regarding the pointer access.

> I think we should at most export the speficic offset inside the buffer
> another compilation unit can fill out. In that case with the
> iosys_buf API we would return a shallow copy of our guc->ads_map +
> offset.
> 
> And the other alternative would be as you suggested: save the list in a
> temporary buffer and when needed call intel_guc_ads() to populate that
> into ads in the right place.
> 

Alan: The first part of above is already what is happening in my series today,
we have a seperate register list  in the intel_guc_capture module
that also determines (based on device and fusing) which registers
to include or exclude. There is are static global lists and
per-gt-allocated lists (based on fuse masks). The latter
is not in current rev but already commented as planned change.

So in response to the original review comment, I can change this
patch so that the ADS gets a regular heap-kzalloc-allocated pointer and
size from the error-capture module and ADS do the copying into the
io-mem ptr but i want to ensure the layout of the error-capture 
lists are not private to ADS only.

Are we okay with that?

> The integration with iosys-map I can figure out if my patch series lands
> after this one, or I can help rebasing this otherwise. But IMO we
> should not pass the plain blob pointer around regardless of iosys-map.
> 
> 
> thanks
> Lucas De Marchi
> 
> > Specific patch Lucas's is referencing:
> > https://patchwork.freedesktop.org/patch/471051/?series=99378&rev=1
> > 
> > Matt
> > 
> > > Lucas De Marchi


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-02-03 20:37         ` Teres Alexis, Alan Previn
@ 2022-02-03 20:40           ` Teres Alexis, Alan Previn
  2022-02-03 21:40             ` Lucas De Marchi
  0 siblings, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-03 20:40 UTC (permalink / raw)
  To: Brost, Matthew, Harrison, John C, De Marchi, Lucas; +Cc: intel-gfx

Apologies, please ignore last reply (wrestling with my VNC). Proper reply:

On Thu, 2022-02-03 at 12:39 -0800, Alan Previn Teres Alexis wrote:
> 
> 
> On Thu, 2022-02-03 at 12:04 -0800, Lucas De Marchi wrote:
> > On Thu, Feb 03, 2022 at 11:03:24AM -0800, Matthew Brost wrote:
> > > On Wed, Jan 26, 2022 at 02:46:19PM -0800, Lucas De Marchi wrote:
> > > > On Wed, Jan 26, 2022 at 02:48:13AM -0800, Alan Previn wrote:
> > > > > Update GuC ADS size allocation to include space for
> > > > > the lists of error state capture register descriptors.
> > > > > 
> > > > > Also, populate the lists of registers we want GuC to report back to
> > > > > Host on engine reset events. This list should include global,
> > > > > engine-class and engine-instance registers for every engine-class
> > > > > type on the current hardware.
> > > > > 
> > > > > NOTE: Start with a sample table of register lists to layout the
> > > > > framework before adding real registers in subsequent patch.
> > > > > 
> > > > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > > > > ---
> > > > 
> > > > ...
> > > > 
> > > > > static void __guc_ads_init(struct intel_guc *guc)
> > > > > {
> > > > > 	struct intel_gt *gt = guc_to_gt(guc);
> > > > > @@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
> > > > > 
> > > > > 	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
> > > > > 
> > > > > -	/* Capture list for hang debug */
> > > > > -	guc_capture_list_init(guc, blob);
> > > > > -
> > > > > +	/* Lists for error capture debug */
> > > > > +	intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
> > > > 
> > > > no, please don't cast/export struct guc_ads like this. We can't really
> > > > dereference it since it may be in IO memory.
> > > > 
> > > > See https://patchwork.freedesktop.org/series/99378/ with the huge
> > > > refactor in this file to make it conform to the rules of accessing IO
> > > > memory.
> > > > 
> > > > Maybe this list could be appended in the same reglist buffer and we just
> > > > copy it once to its final location, like we are doing with the reglist?
> > > > 
> > > 
> > > Agree with Lucas here, let's create the capture list on probe and store
> > > it somewhere in the device data. On ADS population this more or less
> > > turns into a memcpy (or after Lucas's series a dma-buf-map call). And on
> > > fini, just free to stored data. The create capture list IMO is fine to
> > > be done in an external file and return the data to the ADS code but
> > > let's make sure everyone is on board with that. Maybe ping Lucas
> > > directly about this?
> > 
> > yeah, sounds good to me. My worry is exporting ADS struct layout to
> > other compilation units. Asking for the entire ads blob
> > (or what would be dma_buf_map in my patches, or iosys_map in the new
> > version I will send soon) could quickly spread too much knowledge about it to
> > the rest of the driver.
> > 
> 

I'm in partial disagreement with above. Based on above statement, are we enforcing
that we must always continue to only have ADS know the 2nd level blobl structure layout?
Doesn't that also force that intelligence of knowing its substructure contents to
always be in ADS only? So ADS C file continues to grow larger and larger with completely
orthogonal domain specific knowledge? (golden context: engine info,
error-capture: debug registers, etc..).
I believe ADS should really let the substructure headers be accessible to external
modules to deal with the parsing, size determination and preparing its contents.

NOTE: see my next comment specifically regarding the pointer access.


> I think we should at most export the speficic offset inside the buffer
> 
> > another compilation unit can fill out. In that case with the
> > iosys_buf API we would return a shallow copy of our guc->ads_map +
> > offset.
> > 
> > And the other alternative would be as you suggested: save the list in a
> > temporary buffer and when needed call intel_guc_ads() to populate that
> > into ads in the right place.
> > 
> 
Alan: The first part of above is already what is happening in my series today,
we have a seperate register list  in the intel_guc_capture module
that also determines (based on device and fusing) which registers
to include or exclude. There is are static global lists and
per-gt-allocated lists (based on fuse masks). The latter
is not in current rev but already commented as planned change.

So in response to the original review comment, I can change this
patch so that the ADS gets a regular heap-kzalloc-allocated pointer and
size from the error-capture module and ADS do the copying into the
io-mem ptr but i want to ensure the layout of the error-capture 
lists are not private to ADS only.

Are we okay with that?


> 
> > The integration with iosys-map I can figure out if my patch series lands
> > after this one, or I can help rebasing this otherwise. But IMO we
> > should not pass the plain blob pointer around regardless of iosys-map.
> > 
> > 
> > thanks
> > Lucas De Marchi
> > 
> > > Specific patch Lucas's is referencing:
> > > https://patchwork.freedesktop.org/patch/471051/?series=99378&rev=1
> > > 
> > > Matt
> > > 
> > > > Lucas De Marchi


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-02-03 20:40           ` Teres Alexis, Alan Previn
@ 2022-02-03 21:40             ` Lucas De Marchi
  2022-02-03 21:58               ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Lucas De Marchi @ 2022-02-03 21:40 UTC (permalink / raw)
  To: Teres Alexis, Alan Previn; +Cc: intel-gfx

On Thu, Feb 03, 2022 at 12:40:54PM -0800, Teres Alexis, Alan Previn wrote:
>Apologies, please ignore last reply (wrestling with my VNC). Proper reply:
>
>On Thu, 2022-02-03 at 12:39 -0800, Alan Previn Teres Alexis wrote:
>>
>>
>> On Thu, 2022-02-03 at 12:04 -0800, Lucas De Marchi wrote:
>> > On Thu, Feb 03, 2022 at 11:03:24AM -0800, Matthew Brost wrote:
>> > > On Wed, Jan 26, 2022 at 02:46:19PM -0800, Lucas De Marchi wrote:
>> > > > On Wed, Jan 26, 2022 at 02:48:13AM -0800, Alan Previn wrote:
>> > > > > Update GuC ADS size allocation to include space for
>> > > > > the lists of error state capture register descriptors.
>> > > > >
>> > > > > Also, populate the lists of registers we want GuC to report back to
>> > > > > Host on engine reset events. This list should include global,
>> > > > > engine-class and engine-instance registers for every engine-class
>> > > > > type on the current hardware.
>> > > > >
>> > > > > NOTE: Start with a sample table of register lists to layout the
>> > > > > framework before adding real registers in subsequent patch.
>> > > > >
>> > > > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>> > > > > ---
>> > > >
>> > > > ...
>> > > >
>> > > > > static void __guc_ads_init(struct intel_guc *guc)
>> > > > > {
>> > > > >       struct intel_gt *gt = guc_to_gt(guc);
>> > > > > @@ -573,9 +553,9 @@ static void __guc_ads_init(struct intel_guc *guc)
>> > > > >
>> > > > >       base = intel_guc_ggtt_offset(guc, guc->ads_vma);
>> > > > >
>> > > > > -     /* Capture list for hang debug */
>> > > > > -     guc_capture_list_init(guc, blob);
>> > > > > -
>> > > > > +     /* Lists for error capture debug */
>> > > > > +     intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
>> > > >
>> > > > no, please don't cast/export struct guc_ads like this. We can't really
>> > > > dereference it since it may be in IO memory.
>> > > >
>> > > > See https://patchwork.freedesktop.org/series/99378/ with the huge
>> > > > refactor in this file to make it conform to the rules of accessing IO
>> > > > memory.
>> > > >
>> > > > Maybe this list could be appended in the same reglist buffer and we just
>> > > > copy it once to its final location, like we are doing with the reglist?
>> > > >
>> > >
>> > > Agree with Lucas here, let's create the capture list on probe and store
>> > > it somewhere in the device data. On ADS population this more or less
>> > > turns into a memcpy (or after Lucas's series a dma-buf-map call). And on
>> > > fini, just free to stored data. The create capture list IMO is fine to
>> > > be done in an external file and return the data to the ADS code but
>> > > let's make sure everyone is on board with that. Maybe ping Lucas
>> > > directly about this?
>> >
>> > yeah, sounds good to me. My worry is exporting ADS struct layout to
>> > other compilation units. Asking for the entire ads blob
>> > (or what would be dma_buf_map in my patches, or iosys_map in the new
>> > version I will send soon) could quickly spread too much knowledge about it to
>> > the rest of the driver.
>> >
>>
>
>I'm in partial disagreement with above. Based on above statement, are we enforcing
>that we must always continue to only have ADS know the 2nd level blobl structure layout?

no

>Doesn't that also force that intelligence of knowing its substructure contents to
>always be in ADS only? So ADS C file continues to grow larger and larger with completely
>orthogonal domain specific knowledge? (golden context: engine info,
>error-capture: debug registers, etc..).

no, see below

>I believe ADS should really let the substructure headers be accessible to external
>modules to deal with the parsing, size determination and preparing its contents.
>
>NOTE: see my next comment specifically regarding the pointer access.
>
>
>> I think we should at most export the speficic offset inside the buffer
>>
>> > another compilation unit can fill out. In that case with the
>> > iosys_buf API we would return a shallow copy of our guc->ads_map +
>> > offset.
>> >
>> > And the other alternative would be as you suggested: save the list in a
>> > temporary buffer and when needed call intel_guc_ads() to populate that
>> > into ads in the right place.
>> >
>>
>Alan: The first part of above is already what is happening in my series today,
>we have a seperate register list  in the intel_guc_capture module

no, what you have in this patch I commented on is:

>> > > > > +     /* Lists for error capture debug */
>> > > > > +     intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,

you are passing the complete ads blob outside. I'd even try to avoid passing 
the second level struct depending on the case, but that would be
much more acceptable.



>that also determines (based on device and fusing) which registers
>to include or exclude. There is are static global lists and
>per-gt-allocated lists (based on fuse masks). The latter
>is not in current rev but already commented as planned change.
>
>So in response to the original review comment, I can change this
>patch so that the ADS gets a regular heap-kzalloc-allocated pointer and
>size from the error-capture module and ADS do the copying into the
>io-mem ptr but i want to ensure the layout of the error-capture
>lists are not private to ADS only.
>
>Are we okay with that?

I think that is fine.  Either of these 2 solutions would actually be
fine with me. Note that in my patch series I use both depending on the
case. The reglist uses a temporary buffer allocated on gt init, while
all the remaining read/write go directlry to the ads_map. There is even the
intel_guc_engine_usage_record_map() that exports the second level struct
and intel_guc_submission.c reads that out (see
https://patchwork.freedesktop.org/patch/471052/?series=99378&rev=1)
When doing the patch I was tempted to change that with something like

	intel_guc_ads_get_engine_usage_record(engine, &last_switch, &ctx_id, &total)

but decided that it would not be future-proof.

Lucas De Marchi

>
>
>>
>> > The integration with iosys-map I can figure out if my patch series lands
>> > after this one, or I can help rebasing this otherwise. But IMO we
>> > should not pass the plain blob pointer around regardless of iosys-map.
>> >
>> >
>> > thanks
>> > Lucas De Marchi
>> >
>> > > Specific patch Lucas's is referencing:
>> > > https://patchwork.freedesktop.org/patch/471051/?series=99378&rev=1
>> > >
>> > > Matt
>> > >
>> > > > Lucas De Marchi
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists
  2022-02-03 21:40             ` Lucas De Marchi
@ 2022-02-03 21:58               ` Teres Alexis, Alan Previn
  0 siblings, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-03 21:58 UTC (permalink / raw)
  To: De Marchi, Lucas; +Cc: intel-gfx

So we are coming to an agreement... I will go with the option
of ADS calling intel_guc_capture and asking it for the temp buf ptr and
size and let ADS do the actual copying. I will have to see how straight
forward the copying will be (if u see RFC-rev1 of this series, the ADS
does the full population and calls intel_guc_capture just for the external
(not io-mem) register list pointer. But a lot of code that got injected
into ADS as it traversed through individual error capture substructure
members.


One last comment on below:

> > Alan: The first part of above is already what is happening in my series today,
> > we have a seperate register list  in the intel_guc_capture module
> 
> no, what you have in this patch I commented on is:
> 
> > > > > > > +     /* Lists for error capture debug */
> > > > > > > +     intel_guc_capture_prep_lists(guc, (struct guc_ads *)blob, base,
> 
> you are passing the complete ads blob outside. I'd even try to avoid passing 
> the second level struct depending on the case, but that would be
> much more acceptable.

I'm sorry I wasnt clear, what i meant is just the part about having an interim
buffer for the error capture register list outside of ADS blob io-memory.
That already exists in all rev's of this series but in rev 3 onwards, as u pointed out
above, the external buffer ptr was not passed to ADS and i was taking the blob ptr from ADS.
Rev-1-RFC probably is closer to what we want.


...alan


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture Alan Previn
  2022-01-27  4:26   ` Teres Alexis, Alan Previn
@ 2022-02-04 18:19   ` Matthew Brost
  2022-02-08 19:38     ` Teres Alexis, Alan Previn
  1 sibling, 1 reply; 52+ messages in thread
From: Matthew Brost @ 2022-02-04 18:19 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> GuC log buffer regions for debug-log-events, crash-dumps and
> error-state-capture are all a single bo allocation that includes
> the guc_log_buffer_state structures.
> 
> Since the error-capture region is accessed with high priority at non-
> deterministic times (as part of gpu coredump) while the debug-log-event
> region is populated and accessed with different priorities, timings and
> consumers, let's split out separate locks for buffer-state accesses
> of each region.
> 
> Also, ensure a global mapping is made up front for the entire bo
> throughout GuC operation so that dynamic mapping and unmapping isn't
> required for error capture log access if relay-logging isn't running.
> 
> Additionally, while here, make some readibility improvements:
> 1. change previous function names with "capture_logs" to
>    "copy_debug_logs" to help make the distinction clearer.
> 2. Update the guc log region mapping comments to order them
>    according to the enum definition as per the GuC interface.
> 
> Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> ---
>  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
>  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
>  drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
>  drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
>  5 files changed, 141 insertions(+), 60 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> index 4e819853ec2e..be1ad7fa2bf8 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> @@ -34,6 +34,8 @@ struct intel_guc {
>  	struct intel_uc_fw fw;
>  	/** @log: sub-structure containing GuC log related data and objects */
>  	struct intel_guc_log log;
> +	/** @log_state: states and locks for each subregion of GuC's log buffer */
> +	struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];

Why move this? This still probably should be sub-structure of
intel_guc_log. Most of the access is from functions that pass in
intel_guc_log, then retrieve the GuC object, only to access this new
intel_guc_log_stats object. That layering seems wrong, if the argument
to a function is intel_guc_log it should really try to access members
within that object or below. Obv some exceptions exist but here it seems
clear to me this is in the wrong place.

Another nit, I'd personally break this out into multiple patches.

e.g. 1 to rename relay log functions, 1 introducing intel_guc_log_stats
+ lock, and 1 adding intel_guc_capture_output_min_size_est. Maybe I'm
missing another patch or two in there.

Not a blocker but it does make reviews easier.

Matt

>  	/** @ct: the command transport communication channel */
>  	struct intel_guc_ct ct;
>  	/** @slpc: sub-structure containing SLPC related data and objects */
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> index 70d2ee841289..e7f99d051636 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> @@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
>  	return PAGE_ALIGN(alloc_size);
>  }
>  
> +#define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3
> +int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
> +{
> +	struct intel_gt *gt = guc_to_gt(guc);
> +	struct intel_engine_cs *engine;
> +	enum intel_engine_id id;
> +	int worst_min_size = 0, num_regs = 0;
> +	u16 tmp = 0;
> +
> +	/*
> +	 * If every single engine-instance suffered a failure in quick succession but
> +	 * were all unrelated, then a burst of multiple error-capture events would dump
> +	 * registers for every one engine instance, one at a time. In this case, GuC
> +	 * would even dump the global-registers repeatedly.
> +	 *
> +	 * For each engine instance, there would be 1 x guc_state_capture_group_t output
> +	 * followed by 3 x guc_state_capture_t lists. The latter is how the register
> +	 * dumps are split across different register types (where the '3' are global vs class
> +	 * vs instance). Finally, let's multiply the whole thing by 3x (just so we are
> +	 * not limited to just 1 round of data in a worst case full register dump log)
> +	 *
> +	 * NOTE: intel_guc_log that allocates the log buffer would round this size up to
> +	 * a power of two.
> +	 */
> +
> +	for_each_engine(engine, gt, id) {
> +		worst_min_size += sizeof(struct guc_state_capture_group_header_t) +
> +				  (3 * sizeof(struct guc_state_capture_header_t));
> +
> +		if (!guc_capture_list_count(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp))
> +			num_regs += tmp;
> +
> +		if (!guc_capture_list_count(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
> +					    engine->class, &tmp)) {
> +			num_regs += tmp;
> +		}
> +		if (!guc_capture_list_count(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
> +					    engine->class, &tmp)) {
> +			num_regs += tmp;
> +		}
> +	}
> +
> +	worst_min_size += (num_regs * sizeof(struct guc_mmio_reg));
> +
> +	return (worst_min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER);
> +}
> +
>  void intel_guc_capture_destroy(struct intel_guc *guc)
>  {
>  	guc_capture_clear_ext_regs(guc->capture.priv->reglists);
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
> index 6b5594ca529d..4d3e5221128c 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
> @@ -14,6 +14,7 @@ struct guc_gt_system_info;
>  
>  int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
>  				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
> +int intel_guc_capture_output_min_size_est(struct intel_guc *guc);
>  void intel_guc_capture_destroy(struct intel_guc *guc);
>  int intel_guc_capture_init(struct intel_guc *guc);
>  
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
> index b53f61f3101f..d6b1a3c0fb15 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
> @@ -6,12 +6,13 @@
>  #include <linux/debugfs.h>
>  
>  #include "gt/intel_gt.h"
> +#include "intel_guc_capture.h"
> +#include "intel_guc_log.h"
>  #include "i915_drv.h"
>  #include "i915_irq.h"
>  #include "i915_memcpy.h"
> -#include "intel_guc_log.h"
>  
> -static void guc_log_capture_logs(struct intel_guc_log *log);
> +static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log);
>  
>  /**
>   * DOC: GuC firmware log
> @@ -136,7 +137,7 @@ static void guc_move_to_next_buf(struct intel_guc_log *log)
>  	smp_wmb();
>  
>  	/* All data has been written, so now move the offset of sub buffer. */
> -	relay_reserve(log->relay.channel, log->vma->obj->base.size);
> +	relay_reserve(log->relay.channel, log->vma->obj->base.size - CAPTURE_BUFFER_SIZE);
>  
>  	/* Switch to the next sub buffer */
>  	relay_flush(log->relay.channel);
> @@ -156,25 +157,25 @@ static void *guc_get_write_buffer(struct intel_guc_log *log)
>  	return relay_reserve(log->relay.channel, 0);
>  }
>  
> -static bool guc_check_log_buf_overflow(struct intel_guc_log *log,
> -				       enum guc_log_buffer_type type,
> +static bool guc_check_log_buf_overflow(struct intel_guc *guc,
> +				       struct intel_guc_log_stats *log_state,
>  				       unsigned int full_cnt)
>  {
> -	unsigned int prev_full_cnt = log->stats[type].sampled_overflow;
> +	unsigned int prev_full_cnt = log_state->sampled_overflow;
>  	bool overflow = false;
>  
>  	if (full_cnt != prev_full_cnt) {
>  		overflow = true;
>  
> -		log->stats[type].overflow = full_cnt;
> -		log->stats[type].sampled_overflow += full_cnt - prev_full_cnt;
> +		log_state->overflow = full_cnt;
> +		log_state->sampled_overflow += full_cnt - prev_full_cnt;
>  
>  		if (full_cnt < prev_full_cnt) {
>  			/* buffer_full_cnt is a 4 bit counter */
> -			log->stats[type].sampled_overflow += 16;
> +			log_state->sampled_overflow += 16;
>  		}
>  
> -		dev_notice_ratelimited(guc_to_gt(log_to_guc(log))->i915->drm.dev,
> +		dev_notice_ratelimited(guc_to_gt(guc)->i915->drm.dev,
>  				       "GuC log buffer overflow\n");
>  	}
>  
> @@ -197,8 +198,10 @@ static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
>  	return 0;
>  }
>  
> -static void guc_read_update_log_buffer(struct intel_guc_log *log)
> +static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
>  {
> +	struct intel_guc *guc = log_to_guc(log);
> +	struct intel_guc_log_stats *logstate;
>  	unsigned int buffer_size, read_offset, write_offset, bytes_to_copy, full_cnt;
>  	struct guc_log_buffer_state *log_buf_state, *log_buf_snapshot_state;
>  	struct guc_log_buffer_state log_buf_state_local;
> @@ -212,7 +215,7 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
>  		goto out_unlock;
>  
>  	/* Get the pointer to shared GuC log buffer */
> -	log_buf_state = src_data = log->relay.buf_addr;
> +	log_buf_state = src_data = log->buf_addr;
>  
>  	/* Get the pointer to local buffer to store the logs */
>  	log_buf_snapshot_state = dst_data = guc_get_write_buffer(log);
> @@ -222,7 +225,7 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
>  		 * Used rate limited to avoid deluge of messages, logs might be
>  		 * getting consumed by User at a slow rate.
>  		 */
> -		DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n");
> +		DRM_ERROR_RATELIMITED("no sub-buffer to copy general logs\n");
>  		log->relay.full_count++;
>  
>  		goto out_unlock;
> @@ -232,12 +235,16 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
>  	src_data += PAGE_SIZE;
>  	dst_data += PAGE_SIZE;
>  
> -	for (type = GUC_DEBUG_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) {
> +	/* For relay logging, we exclude error state capture */
> +	for (type = GUC_DEBUG_LOG_BUFFER; type <= GUC_CRASH_DUMP_LOG_BUFFER; type++) {
>  		/*
> +		 * Get a lock to the buffer_state we want to read and update.
>  		 * Make a copy of the state structure, inside GuC log buffer
>  		 * (which is uncached mapped), on the stack to avoid reading
>  		 * from it multiple times.
>  		 */
> +		logstate = &guc->log_state[type];
> +		mutex_lock(&logstate->lock);
>  		memcpy(&log_buf_state_local, log_buf_state,
>  		       sizeof(struct guc_log_buffer_state));
>  		buffer_size = guc_get_log_buffer_size(type);
> @@ -246,13 +253,14 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
>  		full_cnt = log_buf_state_local.buffer_full_cnt;
>  
>  		/* Bookkeeping stuff */
> -		log->stats[type].flush += log_buf_state_local.flush_to_file;
> -		new_overflow = guc_check_log_buf_overflow(log, type, full_cnt);
> +		logstate->flush += log_buf_state_local.flush_to_file;
> +		new_overflow = guc_check_log_buf_overflow(guc, logstate, full_cnt);
>  
>  		/* Update the state of shared log buffer */
>  		log_buf_state->read_ptr = write_offset;
>  		log_buf_state->flush_to_file = 0;
>  		log_buf_state++;
> +		mutex_unlock(&logstate->lock);
>  
>  		/* First copy the state structure in snapshot buffer */
>  		memcpy(log_buf_snapshot_state, &log_buf_state_local,
> @@ -300,49 +308,49 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log)
>  	mutex_unlock(&log->relay.lock);
>  }
>  
> -static void capture_logs_work(struct work_struct *work)
> +static void copy_debug_logs_work(struct work_struct *work)
>  {
>  	struct intel_guc_log *log =
>  		container_of(work, struct intel_guc_log, relay.flush_work);
>  
> -	guc_log_capture_logs(log);
> +	guc_log_copy_debuglogs_for_relay(log);
>  }
>  
> -static int guc_log_map(struct intel_guc_log *log)
> +static int guc_log_relay_map(struct intel_guc_log *log)
>  {
> -	void *vaddr;
> -
>  	lockdep_assert_held(&log->relay.lock);
>  
> -	if (!log->vma)
> +	if (!log->vma || !log->buf_addr)
>  		return -ENODEV;
>  
>  	/*
> -	 * Create a WC (Uncached for read) vmalloc mapping of log
> -	 * buffer pages, so that we can directly get the data
> -	 * (up-to-date) from memory.
> +	 * WC vmalloc mapping of log buffer pages was done at
> +	 * GuC Init time, but lets keep a ref for book-keeping
>  	 */
> -	vaddr = i915_gem_object_pin_map_unlocked(log->vma->obj, I915_MAP_WC);
> -	if (IS_ERR(vaddr))
> -		return PTR_ERR(vaddr);
> -
> -	log->relay.buf_addr = vaddr;
> +	i915_gem_object_get(log->vma->obj);
> +	log->relay.buf_in_use = true;
>  
>  	return 0;
>  }
>  
> -static void guc_log_unmap(struct intel_guc_log *log)
> +static void guc_log_relay_unmap(struct intel_guc_log *log)
>  {
>  	lockdep_assert_held(&log->relay.lock);
>  
> -	i915_gem_object_unpin_map(log->vma->obj);
> -	log->relay.buf_addr = NULL;
> +	i915_gem_object_put(log->vma->obj);
> +	log->relay.buf_in_use = false;
>  }
>  
>  void intel_guc_log_init_early(struct intel_guc_log *log)
>  {
> +	struct intel_guc *guc = log_to_guc(log);
> +	int n;
> +
> +	for (n = GUC_DEBUG_LOG_BUFFER; n < GUC_MAX_LOG_BUFFER; n++)
> +		mutex_init(&guc->log_state[n].lock);
> +
>  	mutex_init(&log->relay.lock);
> -	INIT_WORK(&log->relay.flush_work, capture_logs_work);
> +	INIT_WORK(&log->relay.flush_work, copy_debug_logs_work);
>  	log->relay.started = false;
>  }
>  
> @@ -357,8 +365,11 @@ static int guc_log_relay_create(struct intel_guc_log *log)
>  	lockdep_assert_held(&log->relay.lock);
>  	GEM_BUG_ON(!log->vma);
>  
> -	 /* Keep the size of sub buffers same as shared log buffer */
> -	subbuf_size = log->vma->size;
> +	 /*
> +	  * Keep the size of sub buffers same as shared log buffer
> +	  * but GuC log-events excludes the error-state-capture logs
> +	  */
> +	subbuf_size = log->vma->size - CAPTURE_BUFFER_SIZE;
>  
>  	/*
>  	 * Store up to 8 snapshots, which is large enough to buffer sufficient
> @@ -393,13 +404,13 @@ static void guc_log_relay_destroy(struct intel_guc_log *log)
>  	log->relay.channel = NULL;
>  }
>  
> -static void guc_log_capture_logs(struct intel_guc_log *log)
> +static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
>  {
>  	struct intel_guc *guc = log_to_guc(log);
>  	struct drm_i915_private *dev_priv = guc_to_gt(guc)->i915;
>  	intel_wakeref_t wakeref;
>  
> -	guc_read_update_log_buffer(log);
> +	_guc_log_copy_debuglogs_for_relay(log);
>  
>  	/*
>  	 * Generally device is expected to be active only at this
> @@ -439,6 +450,7 @@ int intel_guc_log_create(struct intel_guc_log *log)
>  {
>  	struct intel_guc *guc = log_to_guc(log);
>  	struct i915_vma *vma;
> +	void *vaddr;
>  	u32 guc_log_size;
>  	int ret;
>  
> @@ -446,25 +458,29 @@ int intel_guc_log_create(struct intel_guc_log *log)
>  
>  	/*
>  	 *  GuC Log buffer Layout
> +	 * (this ordering must follow "enum guc_log_buffer_type" definition)
>  	 *
>  	 *  +===============================+ 00B
> -	 *  |    Crash dump state header    |
> -	 *  +-------------------------------+ 32B
>  	 *  |      Debug state header       |
> +	 *  +-------------------------------+ 32B
> +	 *  |    Crash dump state header    |
>  	 *  +-------------------------------+ 64B
>  	 *  |     Capture state header      |
>  	 *  +-------------------------------+ 96B
>  	 *  |                               |
>  	 *  +===============================+ PAGE_SIZE (4KB)
> -	 *  |        Crash Dump logs        |
> -	 *  +===============================+ + CRASH_SIZE
>  	 *  |          Debug logs           |
>  	 *  +===============================+ + DEBUG_SIZE
> +	 *  |        Crash Dump logs        |
> +	 *  +===============================+ + CRASH_SIZE
>  	 *  |         Capture logs          |
>  	 *  +===============================+ + CAPTURE_SIZE
>  	 */
> -	guc_log_size = PAGE_SIZE + CRASH_BUFFER_SIZE + DEBUG_BUFFER_SIZE +
> -		       CAPTURE_BUFFER_SIZE;
> +	if (intel_guc_capture_output_min_size_est(guc) > CAPTURE_BUFFER_SIZE)
> +		DRM_WARN("GuC log buffer for state_capture maybe too small. %d < %d\n",
> +			 CAPTURE_BUFFER_SIZE, intel_guc_capture_output_min_size_est(guc));
> +
> +	guc_log_size = PAGE_SIZE + CRASH_BUFFER_SIZE + DEBUG_BUFFER_SIZE + CAPTURE_BUFFER_SIZE;
>  
>  	vma = intel_guc_allocate_vma(guc, guc_log_size);
>  	if (IS_ERR(vma)) {
> @@ -473,6 +489,17 @@ int intel_guc_log_create(struct intel_guc_log *log)
>  	}
>  
>  	log->vma = vma;
> +	/*
> +	 * Create a WC (Uncached for read) vmalloc mapping up front immediate access to
> +	 * data from memory during  critical events such as error capture
> +	 */
> +	vaddr = i915_gem_object_pin_map_unlocked(log->vma->obj, I915_MAP_WC);
> +	if (IS_ERR(vaddr)) {
> +		ret = PTR_ERR(vaddr);
> +		i915_vma_unpin_and_release(&log->vma, 0);
> +		goto err;
> +	}
> +	log->buf_addr = vaddr;
>  
>  	log->level = __get_default_log_level(log);
>  	DRM_DEBUG_DRIVER("guc_log_level=%d (%s, verbose:%s, verbosity:%d)\n",
> @@ -483,13 +510,14 @@ int intel_guc_log_create(struct intel_guc_log *log)
>  	return 0;
>  
>  err:
> -	DRM_ERROR("Failed to allocate GuC log buffer. %d\n", ret);
> +	DRM_ERROR("Failed to allocate or map GuC log buffer. %d\n", ret);
>  	return ret;
>  }
>  
>  void intel_guc_log_destroy(struct intel_guc_log *log)
>  {
> -	i915_vma_unpin_and_release(&log->vma, 0);
> +	log->buf_addr = NULL;
> +	i915_vma_unpin_and_release(&log->vma, I915_VMA_RELEASE_MAP);
>  }
>  
>  int intel_guc_log_set_level(struct intel_guc_log *log, u32 level)
> @@ -534,7 +562,7 @@ int intel_guc_log_set_level(struct intel_guc_log *log, u32 level)
>  
>  bool intel_guc_log_relay_created(const struct intel_guc_log *log)
>  {
> -	return log->relay.buf_addr;
> +	return log->buf_addr;
>  }
>  
>  int intel_guc_log_relay_open(struct intel_guc_log *log)
> @@ -565,7 +593,7 @@ int intel_guc_log_relay_open(struct intel_guc_log *log)
>  	if (ret)
>  		goto out_unlock;
>  
> -	ret = guc_log_map(log);
> +	ret = guc_log_relay_map(log);
>  	if (ret)
>  		goto out_relay;
>  
> @@ -615,8 +643,8 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log)
>  	with_intel_runtime_pm(guc_to_gt(guc)->uncore->rpm, wakeref)
>  		guc_action_flush_log(guc);
>  
> -	/* GuC would have updated log buffer by now, so capture it */
> -	guc_log_capture_logs(log);
> +	/* GuC would have updated log buffer by now, so copy it */
> +	guc_log_copy_debuglogs_for_relay(log);
>  }
>  
>  /*
> @@ -645,7 +673,7 @@ void intel_guc_log_relay_close(struct intel_guc_log *log)
>  
>  	mutex_lock(&log->relay.lock);
>  	GEM_BUG_ON(!intel_guc_log_relay_created(log));
> -	guc_log_unmap(log);
> +	guc_log_relay_unmap(log);
>  	guc_log_relay_destroy(log);
>  	mutex_unlock(&log->relay.lock);
>  }
> @@ -682,6 +710,7 @@ stringify_guc_log_type(enum guc_log_buffer_type type)
>   */
>  void intel_guc_log_info(struct intel_guc_log *log, struct drm_printer *p)
>  {
> +	struct intel_guc *guc = log_to_guc(log);
>  	enum guc_log_buffer_type type;
>  
>  	if (!intel_guc_log_relay_created(log)) {
> @@ -696,8 +725,8 @@ void intel_guc_log_info(struct intel_guc_log *log, struct drm_printer *p)
>  	for (type = GUC_DEBUG_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) {
>  		drm_printf(p, "\t%s:\tflush count %10u, overflow count %10u\n",
>  			   stringify_guc_log_type(type),
> -			   log->stats[type].flush,
> -			   log->stats[type].sampled_overflow);
> +			   guc->log_state[type].flush,
> +			   guc->log_state[type].sampled_overflow);
>  	}
>  }
>  
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
> index d7e1b6471fed..b6e8e9ee37b7 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
> @@ -46,23 +46,25 @@ struct intel_guc;
>  #define GUC_VERBOSITY_TO_LOG_LEVEL(x)	((x) + 2)
>  #define GUC_LOG_LEVEL_MAX GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)
>  
> +struct intel_guc_log_stats {
> +	struct mutex lock; /* protects below and guc_log_buffer_state's read-ptr */
> +	u32 sampled_overflow;
> +	u32 overflow;
> +	u32 flush;
> +};
> +
>  struct intel_guc_log {
>  	u32 level;
>  	struct i915_vma *vma;
> +	void *buf_addr;
>  	struct {
> -		void *buf_addr;
> +		bool buf_in_use;
>  		bool started;
>  		struct work_struct flush_work;
>  		struct rchan *channel;
>  		struct mutex lock;
>  		u32 full_count;
>  	} relay;
> -	/* logging related stats */
> -	struct {
> -		u32 sampled_overflow;
> -		u32 overflow;
> -		u32 flush;
> -	} stats[GUC_MAX_LOG_BUFFER];
>  };
>  
>  void intel_guc_log_init_early(struct intel_guc_log *log);
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 09/10] drm/i915/guc: Follow legacy register names
  2022-02-03 19:09   ` Matthew Brost
@ 2022-02-04 18:53     ` Teres Alexis, Alan Previn
  0 siblings, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-04 18:53 UTC (permalink / raw)
  To: Brost, Matthew; +Cc: intel-gfx

Squash will be much easier if i also squash all the prior register table additions together
Should i do that? Squash XeLP + DG2 + Gen9 and this together?

On Thu, 2022-02-03 at 11:09 -0800, Matthew Brost wrote:
> On Wed, Jan 26, 2022 at 02:48:21AM -0800, Alan Previn wrote:
> > Before we print the GuC provided register dumps, modify the
> > register tables to use string names as per the legacy error
> > capture execlist codes.
> > 
> > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> 
> I'd just squash this to the patches early in the series where these are
> initially defined.
> 
> Matt 
> 
> > ---
> >  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 70 +++++++++----------
> >  1 file changed, 35 insertions(+), 35 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > index 2f5dc413dddc..506496058daf 100644
> > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > @@ -22,7 +22,7 @@
> >   *       from the engine-mmio-base
> >   */
> >  #define COMMON_BASE_GLOBAL() \
> > -	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}
> > +	{FORCEWAKE_MT,             0,      0, "FORCEWAKE"}
> >  
> >  #define COMMON_GEN9BASE_GLOBAL() \
> >  	{GEN8_FAULT_TLB_DATA0,     0,      0, "GEN8_FAULT_TLB_DATA0"}, \
> > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 03/10] drm/i915/guc: Add DG2 registers for GuC error state capture.
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 03/10] drm/i915/guc: Add DG2 " Alan Previn
@ 2022-02-05  1:28   ` Umesh Nerlige Ramappa
  2022-02-10  5:17     ` Teres Alexis, Alan Previn
  2022-02-11 19:24     ` Teres Alexis, Alan Previn
  0 siblings, 2 replies; 52+ messages in thread
From: Umesh Nerlige Ramappa @ 2022-02-05  1:28 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

On Wed, Jan 26, 2022 at 02:48:15AM -0800, Alan Previn wrote:
>Add additional DG2 registers for GuC error state capture.
>
>Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>---
> .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 64 ++++++++++++++-----
> 1 file changed, 49 insertions(+), 15 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>index b6882074fc8d..19719daffed4 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>@@ -179,19 +179,23 @@ static struct __ext_steer_reg xelpd_extregs[] = {
> 	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
> };
>
>+static struct __ext_steer_reg xehpg_extregs[] = {
>+	{"XEHPG_INSTDONE_GEOM_SVG", XEHPG_INSTDONE_GEOM_SVG}
>+};
>+
> static void
>-guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
>-				     struct __guc_mmio_reg_descr_group *lists)
>+guc_capture_alloc_steered_list_xe_lpd_hpg(struct intel_guc *guc,
>+					  struct __guc_mmio_reg_descr_group *lists,
>+					  u32 ipver)

IMO having 2 separate functions would be easier to read and maintain. No 
ipver logic inside here.

> {
> 	struct intel_gt *gt = guc_to_gt(guc);
> 	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> 	struct sseu_dev_info *sseu;
>-	int slice, subslice, i, num_tot_regs = 0;
>+	int slice, subslice, i, iter, num_steer_regs, num_tot_regs = 0;
> 	struct __guc_mmio_reg_descr_group *list;
> 	struct __guc_mmio_reg_descr *extarray;
>-	int num_steer_regs = ARRAY_SIZE(xelpd_extregs);
>
>-	/* In XE_LP we only care about render-class steering registers during error-capture */
>+	/* In XE_LP / HPG we only have render-class steering registers during error-capture */
> 	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
> 					GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, GUC_RENDER_CLASS);
> 	if (!list)
>@@ -200,10 +204,21 @@ guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
> 	if (list->ext)
> 		return; /* already populated */

nit:
if (!list || list->ext)
	return;
>
>+	num_steer_regs = ARRAY_SIZE(xelpd_extregs);
>+	if (ipver >= IP_VER(12, 55))

What does this actually mean? 12 55 has both lpd and hpg regs?

You could (if possible) use has_lpd_regs/has_hpg_regs in i915_pci.c to 
simplify the platform specific logic.

>+		num_steer_regs += ARRAY_SIZE(xehpg_extregs);
>+
> 	sseu = &gt->info.sseu;
>-	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
>-		num_tot_regs += num_steer_regs;
>+	if (ipver >= IP_VER(12, 50)) {
>+		for_each_instdone_gslice_dss_xehp(i915, sseu, iter, slice, subslice) {
>+			num_tot_regs += num_steer_regs;
>+		}
>+	} else {
>+		for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
>+			num_tot_regs += num_steer_regs;
>+		}
> 	}
>+
> 	if (!num_tot_regs)
> 		return;
>
>@@ -212,15 +227,31 @@ guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
> 		return;
>
> 	extarray = list->ext;

nit: I would mostly use extarray everywhere and assign it to list->ext 
at the end of the function.

>-	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
>-		for (i = 0; i < num_steer_regs; i++) {
>-			extarray->reg = xelpd_extregs[i].reg;
>-			extarray->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice);
>-			extarray->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice);

could use helpers

extarray->flags |= __steering_flags(slice, subslice);


>-			extarray->regname = xelpd_extregs[i].name;
>-			++extarray;
>+
>+#define POPULATE_NEXT_EXTREG(ext, list, idx, slicenum, subslicenum) \
>+	{ \
>+		(ext)->reg = list[idx].reg; \
>+		(ext)->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slicenum); \
>+		(ext)->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslicenum); \
>+		(ext)->regname = xelpd_extregs[i].name; \
>+		++(ext); \
>+	}

I prefer having an inline for the above assignments and move the ++(ext_ 
into the for loop itself.

>+	if (ipver >= IP_VER(12, 50)) {
>+		for_each_instdone_gslice_dss_xehp(i915, sseu, iter, slice, subslice) {
>+			for (i = 0; i < ARRAY_SIZE(xelpd_extregs); i++)
>+				POPULATE_NEXT_EXTREG(extarray, xelpd_extregs, i, slice, subslice)
>+			for (i = 0; i < ARRAY_SIZE(xehpg_extregs) && ipver >= IP_VER(12, 55);
>+			     i++)
>+				POPULATE_NEXT_EXTREG(extarray, xehpg_extregs, i, slice, subslice)
>+		}
>+	} else {
>+		for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
>+			for (i = 0; i < num_steer_regs; i++)
>+				POPULATE_NEXT_EXTREG(extarray, xelpd_extregs, i, slice, subslice)
> 		}
> 	}
>+#undef POPULATE_NEXT_EXTREG
>+
> 	list->num_ext = num_tot_regs;
> }
>
>@@ -237,7 +268,10 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
> 		 * these at init time based on hw config add it as an extension
> 		 * list at the end of the pre-populated render list.
> 		 */
>-		guc_capture_alloc_steered_list_xelpd(guc, xe_lpd_lists);
>+		guc_capture_alloc_steered_list_xe_lpd_hpg(guc, xe_lpd_lists, IP_VER(12, 0));

Ideally, I would just think about having seperate 

guc_capture_alloc_steered_list_xe_lpd and
guc_capture_alloc_steered_list_xe_hpg

Maybe there could just be one check for say IP_VER(12, 50) at the top 
level and you can call the respective function.


>+		return xe_lpd_lists;
>+	} else if (IS_DG2(i915)) {
>+		guc_capture_alloc_steered_list_xe_lpd_hpg(guc, xe_lpd_lists, IP_VER(12, 55));
> 		return xe_lpd_lists;

xe_lpd_lists is returned in both if/else, so can be moved out of the 
conditions. Also now you could just rename it to xe_lists.

Regards,
Umesh

> 	}
>
>-- 
>2.25.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 04/10] drm/i915/guc: Add Gen9 registers for GuC error state capture.
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 04/10] drm/i915/guc: Add Gen9 " Alan Previn
@ 2022-02-07 19:14   ` Umesh Nerlige Ramappa
  0 siblings, 0 replies; 52+ messages in thread
From: Umesh Nerlige Ramappa @ 2022-02-07 19:14 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

lgtm,

Reviewed-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>

Umesh

On Wed, Jan 26, 2022 at 02:48:16AM -0800, Alan Previn wrote:
>Abstract out a Gen9 register list as the default for all other
>platforms we don't yet formally support GuC submission on.
>
>Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>---
> .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 74 +++++++++++++++----
> 1 file changed, 58 insertions(+), 16 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>index 19719daffed4..70d2ee841289 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>@@ -19,15 +19,24 @@
>  * NOTE: For engine-registers, GuC only needs the register offsets
>  *       from the engine-mmio-base
>  */
>+#define COMMON_BASE_GLOBAL() \
>+	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}
>+
>+#define COMMON_GEN9BASE_GLOBAL() \
>+	{GEN8_FAULT_TLB_DATA0,     0,      0, "GEN8_FAULT_TLB_DATA0"}, \
>+	{GEN8_FAULT_TLB_DATA1,     0,      0, "GEN8_FAULT_TLB_DATA1"}, \
>+	{ERROR_GEN6,               0,      0, "ERROR_GEN6"}, \
>+	{DONE_REG,                 0,      0, "DONE_REG"}, \
>+	{HSW_GTT_CACHE_EN,         0,      0, "HSW_GTT_CACHE_EN"}
>+
> #define COMMON_GEN12BASE_GLOBAL() \
> 	{GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0"}, \
> 	{GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1"}, \
>-	{FORCEWAKE_MT,             0,      0, "FORCEWAKE_MT"}, \
> 	{GEN12_AUX_ERR_DBG,        0,      0, "GEN12_AUX_ERR_DBG"}, \
> 	{GEN12_GAM_DONE,           0,      0, "GEN12_GAM_DONE"}, \
> 	{GEN12_RING_FAULT_REG,     0,      0, "GEN12_RING_FAULT_REG"}
>
>-#define COMMON_GEN12BASE_ENGINE_INSTANCE() \
>+#define COMMON_BASE_ENGINE_INSTANCE() \
> 	{RING_PSMI_CTL(0),         0,      0, "RING_PSMI_CTL"}, \
> 	{RING_ESR(0),              0,      0, "RING_ESR"}, \
> 	{RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LOW32"}, \
>@@ -61,11 +70,13 @@
> 	{GEN8_RING_PDP_LDW(0, 3),  0,      0, "GEN8_RING_PDP3_LDW"}, \
> 	{GEN8_RING_PDP_UDW(0, 3),  0,      0, "GEN8_RING_PDP3_UDW"}
>
>-#define COMMON_GEN12BASE_HAS_EU() \
>+#define COMMON_BASE_HAS_EU() \
> 	{EIR,                      0,      0, "EIR"}
>
>+#define COMMON_BASE_RENDER() \
>+	{GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE"}
>+
> #define COMMON_GEN12BASE_RENDER() \
>-	{GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE"}, \
> 	{GEN12_SC_INSTDONE_EXTRA,  0,      0, "GEN12_SC_INSTDONE_EXTRA"}, \
> 	{GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2"}
>
>@@ -77,23 +88,26 @@
>
> /* XE_LPD - Global */
> static struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
>+	COMMON_BASE_GLOBAL(),
>+	COMMON_GEN9BASE_GLOBAL(),
> 	COMMON_GEN12BASE_GLOBAL(),
> };
>
> /* XE_LPD - Render / Compute Per-Class */
> static struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
>-	COMMON_GEN12BASE_HAS_EU(),
>+	COMMON_BASE_HAS_EU(),
>+	COMMON_BASE_RENDER(),
> 	COMMON_GEN12BASE_RENDER(),
> };
>
>-/* XE_LPD - Render / Compute Per-Engine-Instance */
>+/* GEN9/XE_LPD - Render / Compute Per-Engine-Instance */
> static struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
>-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
>+	COMMON_BASE_ENGINE_INSTANCE(),
> };
>
>-/* XE_LPD - Media Decode/Encode Per-Engine-Instance */
>+/* GEN9/XE_LPD - Media Decode/Encode Per-Engine-Instance */
> static struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
>-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
>+	COMMON_BASE_ENGINE_INSTANCE(),
> };
>
> /* XE_LPD - Video Enhancement Per-Class */
>@@ -101,18 +115,33 @@ static struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
> 	COMMON_GEN12BASE_VEC(),
> };
>
>-/* XE_LPD - Video Enhancement Per-Engine-Instance */
>+/* GEN9/XE_LPD - Video Enhancement Per-Engine-Instance */
> static struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
>-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
>+	COMMON_BASE_ENGINE_INSTANCE(),
> };
>
>-/* XE_LPD - Blitter Per-Engine-Instance */
>+/* GEN9/XE_LPD - Blitter Per-Engine-Instance */
> static struct __guc_mmio_reg_descr xe_lpd_blt_inst_regs[] = {
>-	COMMON_GEN12BASE_ENGINE_INSTANCE(),
>+	COMMON_BASE_ENGINE_INSTANCE(),
>+};
>+
>+/* GEN9 - Global */
>+static struct __guc_mmio_reg_descr default_global_regs[] = {
>+	COMMON_BASE_GLOBAL(),
>+	COMMON_GEN9BASE_GLOBAL(),
> };
>
>-/* XE_LPD - Blitter Per-Class */
>-/* XE_LPD - Media Decode/Encode Per-Class */
>+static struct __guc_mmio_reg_descr default_rc_class_regs[] = {
>+	COMMON_BASE_HAS_EU(),
>+	COMMON_BASE_RENDER(),
>+};
>+
>+/*
>+ * Empty lists:
>+ * GEN9/XE_LPD - Blitter-Class
>+ * GEN9/XE_LPD - Media Class
>+ * GEN9 - VEC Class
>+ */
> static struct __guc_mmio_reg_descr empty_regs_list[] = {
> };
>
>@@ -130,6 +159,18 @@ static struct __guc_mmio_reg_descr empty_regs_list[] = {
> 	}
>
> /* List of lists */
>+static struct __guc_mmio_reg_descr_group default_lists[] = {
>+	MAKE_REGLIST(default_global_regs, PF, GLOBAL, 0),
>+	MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
>+	MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
>+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
>+	MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
>+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
>+	MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
>+	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_BLITTER_CLASS),
>+	MAKE_REGLIST(xe_lpd_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_BLITTER_CLASS),
>+	{}
>+};
> static struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
> 	MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
> 	MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
>@@ -275,7 +316,8 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
> 		return xe_lpd_lists;
> 	}
>
>-	return NULL;
>+	/* if GuC submission is enabled on a non-POR platform, just use a common baseline */
>+	return default_lists;
> }
>
> static const char *
>-- 
>2.25.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 10/10] drm/i915/guc: Print the GuC error capture output register list.
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 10/10] drm/i915/guc: Print the GuC error capture output register list Alan Previn
@ 2022-02-07 21:43   ` Umesh Nerlige Ramappa
  0 siblings, 0 replies; 52+ messages in thread
From: Umesh Nerlige Ramappa @ 2022-02-07 21:43 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

On Wed, Jan 26, 2022 at 02:48:22AM -0800, Alan Previn wrote:
>Print the GuC captured error state register list (string names
>and values) when gpu_coredump_state printout is invoked via
>the i915 debugfs for flushing the gpu error-state that was
>captured prior.
>
>Since GuC could have reported multiple engine register dumps
>in a single notification event, parse the captured data
>(appearing as a stream of structures) to identify each dump as
>a different 'engine-capture-group-output'.
>
>Finally, for each 'engine-capture-group-output' that is found,
>verify if the engine register dump corresponds to the
>engine_coredump content that was previously populated by the
>i915_gpu_coredump function. That function would have copied
>the context's vma's including the bacth buffer during the
>G2H-context-reset notification that occurred earlier. Perform
>this verification check by comparing guc_id, lrca and engine-
>instance obtained from the 'engine-capture-group-output' vs a
>copy of that same info taken during i915_gpu_coredump. If
>they match, then print those vma's as well (such as the batch
>buffers).
>
>Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>---
> drivers/gpu/drm/i915/gt/intel_engine_cs.c     |   4 +-
> .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 169 ++++++++++++++++++
> .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   2 +-
> drivers/gpu/drm/i915/i915_debugfs.c           |   1 +
> drivers/gpu/drm/i915/i915_gpu_error.c         |  16 +-
> drivers/gpu/drm/i915/i915_gpu_error.h         |   5 +
> 6 files changed, 185 insertions(+), 12 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
>index 4317ae5e525b..47c0c32d9b86 100644
>--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
>+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
>@@ -1628,9 +1628,7 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine,
> 		drm_printf(m, "\tIPEHR: 0x%08x\n", ENGINE_READ(engine, IPEHR));
> 	}
>
>-	if (intel_engine_uses_guc(engine)) {
>-		/* nothing to print yet */
>-	} else if (HAS_EXECLISTS(dev_priv)) {
>+	if (HAS_EXECLISTS(dev_priv) && !intel_engine_uses_guc(engine)) {
> 		struct i915_request * const *port, *rq;
> 		const u32 *hws =
> 			&engine->status_page.addr[I915_HWS_CSB_BUF0_INDEX];
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>index 506496058daf..5cb24098747e 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>@@ -739,6 +739,15 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
>  *                                       intel_engine_coredump struct (if the context and
>  *                                       engine of the event notification matches a node
>  *                                       in the link list)
>+ *
>+ * User Sysfs / Debugfs
>+ * --------------------
>+ *      --> i915_gpu_coredump_copy_to_buffer->
>+ *                   L--> err_print_to_sgl --> err_print_gt
>+ *                        L--> error_print_guc_captures
>+ *                             L--> intel_guc_capture_print_node prints the
>+ *                                  register lists values of the attached node
>+ *                                  on the error-engine-dump being reported.
>  */
>
> static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
>@@ -1216,12 +1225,172 @@ static void __guc_capture_store_snapshot_work(struct intel_guc *guc)
>
> #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
>
>+static const char *
>+guc_capture_reg_to_str(const struct intel_guc *guc, u32 owner, u32 type,
>+		       u32 class, u32 id, u32 offset, u32 *is_ext)
>+{
>+	struct __guc_mmio_reg_descr_group *reglists = guc->capture.priv->reglists;
>+	struct __guc_mmio_reg_descr_group *match;
>+	int num_regs, j;
>+
>+	*is_ext = 0;
>+	if (!reglists)
>+		return NULL;
>+
>+	match = guc_capture_get_one_list(reglists, owner, type, id);
>+
>+	if (match) {
>+		for (num_regs = match->num_regs, j = 0; j < num_regs; ++j) {
>+			if (offset == match->list[j].reg.reg)
>+				return match->list[j].regname;
>+		}
>+	}
>+	if (match->ext) {
>+		for (num_regs = match->num_ext, j = 0; j < num_regs; ++j) {
>+			if (offset == match->ext[j].reg.reg) {
>+				*is_ext = 1;
>+				return match->ext[j].regname;
>+			}
>+		}
>+	}
>+
>+	return NULL;
>+}
>+
>+#ifdef CONFIG_DRM_I915_DEBUG_GUC
>+#define guc_capt_err_print(a, b, ...) \
>+	do { \
>+		drm_warn(a, __VA_ARGS__); \
>+		if (b) \
>+			i915_error_printf(b, __VA_ARGS__); \
>+	} while (0)
>+#else
>+#define guc_capt_err_print(a, b, ...) \
>+	do { \
>+		if (b) \
>+			i915_error_printf(b, __VA_ARGS__); \
>+	} while (0)
>+#endif
>+
>+static struct intel_engine_cs *
>+guc_capture_lookup_engine(struct intel_guc *guc, u8 guc_class, u8 instance)
>+{
>+	struct intel_gt *gt = guc_to_gt(guc);
>+	u8 engine_class = guc_class_to_engine_class(guc_class);
>+
>+	/* Class index is checked in class converter */
>+	GEM_BUG_ON(instance > MAX_ENGINE_INSTANCE);
>+
>+	return gt->engine_class[engine_class][instance];
>+}

Same as intel_guc_submission.c -> guc_lookup_engine. We should export 
that and reuse here.

>+
>+#define GCAP_PRINT_INTEL_ENG_INFO(i915, ebuf, eng) \
>+	do { \
>+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Name: %s command stream\n", \
>+		      (eng)->name); \
>+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \
>+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \
>+		PRINT(&(i915)->drm, (ebuf), "    i915-Eng-LogicalMask: 0x%08x\n", \
>+		      (eng)->logical_mask); \
>+	} while (0)
>+
>+#define GCAP_PRINT_GUC_INST_INFO(i915, ebuf, node) \
>+	do { \
>+		PRINT(&(i915)->drm, (ebuf), "    GuC-Engine-Inst-Id: 0x%08x\n", \
>+		      (node)->eng_inst); \
>+		PRINT(&(i915)->drm, (ebuf), "    GuC-Context-Id: 0x%08x\n", (node)->guc_id); \
>+		PRINT(&(i915)->drm, (ebuf), "    LRCA: 0x%08x\n", (node)->lrca); \
>+	} while (0)
>+
>+#define PRINT guc_capt_err_print

Instead of an alias, I would just use guc_capt_err_print or a shorter 
unique name like of your choice (like __err_print) since this is only 
used in this file.

>+
> int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
> 					const struct intel_engine_coredump *ee)
> {
>+	struct intel_guc_state_capture *cap;
>+	struct intel_guc *guc;
>+	struct drm_i915_private *i915;
>+	struct __guc_capture_parsed_output *node;
>+	struct guc_mmio_reg *regs;
>+	const char *grptypestr[GUC_STATE_CAPTURE_GROUP_TYPE_MAX] = {"full-capture",
>+								    "partial-capture"};

const char *grptypestr[GUC_STATE_CAPTURE_GROUP_TYPE_MAX] = {
	"full-capture",
	"partial-capture",
};

Also str is implied, you could just use grp_type or grp_name as the 
name. Avoid having to use name of the type in the variable.

>+	const char *datatypestr[GUC_CAPTURE_LIST_TYPE_MAX] = {"Global", "Engine-Class",
>+							      "Engine-Instance"};

same here ^

>+	struct intel_engine_cs *eng;
>+	int numregs, i, j;
>+	u32 is_ext;
>+	const char *str;
>+	char noname[16];

general convention for the above is longest line to shortest line 
length.

>+
>+	if (!ebuf || !ee)
>+		return -EINVAL;
>+	cap = ee->capture;
>+	if (!cap->priv || !ee->engine)
>+		return -ENODEV;
>+
>+	guc = container_of(cap, struct intel_guc, capture);

If using this ^ in many places, consider adding a helper 
__err_cap_to_guc().

>+	i915 = (container_of(guc, struct intel_gt, uc.guc))->i915;
>+	PRINT(&i915->drm, ebuf, "global --- GuC Error Capture on %s 
>command stream:\n",
>+	      ee->engine->name);

You could just pass ebuf to the print and use ebuf->i915 in the MACRO.  
That way you don't need i915 in this function.

>+
>+	node = ee->guc_capture_node;
>+	if (!node) {
>+		PRINT(&i915->drm, ebuf, "  No matching ee-node\n");
>+		return 0;
>+	}
>+
>+	PRINT(&i915->drm, ebuf, "Coverage:  %s\n", grptypestr[node->is_partial]);
>+
>+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+		PRINT(&i915->drm, ebuf, "  RegListType: %s\n",
>+		      datatypestr[i % GUC_CAPTURE_LIST_TYPE_MAX]);
>+		PRINT(&i915->drm, ebuf, "    Owner-Id: %d\n", node->reginfo[i].vfid);
>+
>+		switch (i) {
>+		case GUC_CAPTURE_LIST_TYPE_GLOBAL:
>+		default:
>+			break;
>+		case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
>+			PRINT(&i915->drm, ebuf, "    GuC-Eng-Class: %d\n", node->eng_class);
>+			PRINT(&i915->drm, ebuf, "    i915-Eng-Class: %d\n",
>+			      guc_class_to_engine_class(node->eng_class));
>+			break;
>+		case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
>+			eng = guc_capture_lookup_engine(guc, node->eng_class, node->eng_inst);
>+			if (eng)
>+				GCAP_PRINT_INTEL_ENG_INFO(i915, ebuf, eng);
>+			else
>+				PRINT(&i915->drm, ebuf, "    i915-Eng-Lookup Fail!\n");
>+			GCAP_PRINT_GUC_INST_INFO(i915, ebuf, node);
>+			break;
>+		}

nit: Consider a helper function for the above switch.

>+
>+		numregs = node->reginfo[i].num;
>+		PRINT(&i915->drm, ebuf, "    NumRegs: %d\n", numregs);
>+		j = 0;
>+		while (numregs--) {
>+			regs = node->reginfo[i].regs;
>+			str = guc_capture_reg_to_str(guc, GUC_CAPTURE_LIST_INDEX_PF, i,
>+						     node->eng_class, 0, regs[j].offset, &is_ext);
>+			if (!str) {
>+				snprintf(noname, sizeof(noname), "REG-0x%08x", regs[j].offset);
>+				PRINT(&i915->drm, ebuf, "      %s", noname);

Above 2 lines are same as
PRINT(&i915->drm, ebuf, "      REG-0x%08x", regs[j].offset);

You can drop noname and then drop the braces around if/else too
>+			} else {
>+				PRINT(&i915->drm, ebuf, "      %s", str);
>+			}

>+			if (is_ext)
>+				PRINT(&i915->drm, ebuf, "[%ld][%ld]",
>+				      FIELD_GET(GUC_REGSET_STEERING_GROUP, regs[j].flags),
>+				      FIELD_GET(GUC_REGSET_STEERING_INSTANCE, regs[j].flags));
>+			PRINT(&i915->drm, ebuf, ":  0x%08x\n", regs[j].value);
>+			++j;
>+		}
>+	}
> 	return 0;
> }
>
>+#undef PRINT
>+
> #endif //CONFIG_DRM_I915_DEBUG_GUC
>
> void intel_guc_capture_free_node(struct intel_engine_coredump *ee)
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>index 9a2037638e64..3ed33f14ac7d 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>@@ -11,8 +11,8 @@
> struct drm_i915_error_state_buf;
> struct guc_ads;
> struct guc_gt_system_info;
>-struct intel_context;
> struct intel_engine_coredump;
>+struct intel_context;
> struct intel_gt;
> struct intel_guc;

Moved lines ^, assuming not intentional.

Regards,
Umesh

>
>diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>index d2af0d1f3a3e..35faba20d406 100644
>--- a/drivers/gpu/drm/i915/i915_debugfs.c
>+++ b/drivers/gpu/drm/i915/i915_debugfs.c
>@@ -295,6 +295,7 @@ static int i915_gpu_info_open(struct inode *inode, struct file *file)
> 	gpu = NULL;
> 	with_intel_runtime_pm(&i915->runtime_pm, wakeref)
> 		gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES, CORE_DUMP_FLAG_NONE);
>+
> 	if (IS_ERR(gpu))
> 		return PTR_ERR(gpu);
>
>diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
>index d8c82589d86e..67d39226155e 100644
>--- a/drivers/gpu/drm/i915/i915_gpu_error.c
>+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
>@@ -526,8 +526,8 @@ __find_vma(struct i915_vma_coredump *vma, const char *name)
> 	return NULL;
> }
>
>-static struct i915_vma_coredump *
>-find_batch(const struct intel_engine_coredump *ee)
>+struct i915_vma_coredump *
>+intel_gpu_error_find_batch(const struct intel_engine_coredump *ee)
> {
> 	return __find_vma(ee->vma, "batch");
> }
>@@ -555,7 +555,7 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
>
> 	error_print_instdone(m, ee);
>
>-	batch = find_batch(ee);
>+	batch = intel_gpu_error_find_batch(ee);
> 	if (batch) {
> 		u64 start = batch->gtt_offset;
> 		u64 end = start + batch->gtt_size;
>@@ -606,9 +606,9 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
> 	va_end(args);
> }
>
>-static void print_error_vma(struct drm_i915_error_state_buf *m,
>-			    const struct intel_engine_cs *engine,
>-			    const struct i915_vma_coredump *vma)
>+void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m,
>+			       const struct intel_engine_cs *engine,
>+			       const struct i915_vma_coredump *vma)
> {
> 	char out[ASCII85_BUFSZ];
> 	struct page *page;
>@@ -677,7 +677,7 @@ static void err_print_uc(struct drm_i915_error_state_buf *m,
>
> 	intel_uc_fw_dump(&error_uc->guc_fw, &p);
> 	intel_uc_fw_dump(&error_uc->huc_fw, &p);
>-	print_error_vma(m, NULL, error_uc->guc_log);
>+	intel_gpu_error_print_vma(m, NULL, error_uc->guc_log);
> }
>
> static void err_free_sgl(struct scatterlist *sgl)
>@@ -797,7 +797,7 @@ static void err_print_gt_engines(struct drm_i915_error_state_buf *m,
> 		error_print_context(m, "  Active context: ", &ee->context);
>
> 		for (vma = ee->vma; vma; vma = vma->next)
>-			print_error_vma(m, ee->engine, vma);
>+			intel_gpu_error_print_vma(m, ee->engine, vma);
> 	}
>
> }
>diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h
>index d20a1779ea51..5f52dda67ef8 100644
>--- a/drivers/gpu/drm/i915/i915_gpu_error.h
>+++ b/drivers/gpu/drm/i915/i915_gpu_error.h
>@@ -227,6 +227,11 @@ struct drm_i915_error_state_buf {
>
> __printf(2, 3)
> void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
>+void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m,
>+			       const struct intel_engine_cs *engine,
>+			       const struct i915_vma_coredump *vma);
>+struct i915_vma_coredump *
>+intel_gpu_error_find_batch(const struct intel_engine_coredump *ee);
>
> struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt,
> 					    intel_engine_mask_t engine_mask, u32 dump_flags);
>-- 
>2.25.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-04 18:19   ` Matthew Brost
@ 2022-02-08 19:38     ` Teres Alexis, Alan Previn
  2022-02-08 22:18       ` Matthew Brost
  0 siblings, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-08 19:38 UTC (permalink / raw)
  To: Brost, Matthew; +Cc: intel-gfx

Hi Matt, thank you for taking the time to review the codes.
Answering your question inline below.


On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > GuC log buffer regions for debug-log-events, crash-dumps and
> > error-state-capture are all a single bo allocation that includes
> > the guc_log_buffer_state structures.
> > 
> > Since the error-capture region is accessed with high priority at non-
> > deterministic times (as part of gpu coredump) while the debug-log-event
> > region is populated and accessed with different priorities, timings and
> > consumers, let's split out separate locks for buffer-state accesses
> > of each region.
> > 
> > Also, ensure a global mapping is made up front for the entire bo
> > throughout GuC operation so that dynamic mapping and unmapping isn't
> > required for error capture log access if relay-logging isn't running.
> > 
> > Additionally, while here, make some readibility improvements:
> > 1. change previous function names with "capture_logs" to
> >    "copy_debug_logs" to help make the distinction clearer.
> > 2. Update the guc log region mapping comments to order them
> >    according to the enum definition as per the GuC interface.
> > 
> > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > ---
> >  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
> >  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
> >  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
> >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
> >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
> >  5 files changed, 141 insertions(+), 60 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > index 4e819853ec2e..be1ad7fa2bf8 100644
> > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > @@ -34,6 +34,8 @@ struct intel_guc {
> >  	struct intel_uc_fw fw;
> >  	/** @log: sub-structure containing GuC log related data and objects */
> >  	struct intel_guc_log log;
> > +	/** @log_state: states and locks for each subregion of GuC's log buffer */
> > +	struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];
> 
> Why move this? This still probably should be sub-structure of
> intel_guc_log. Most of the access is from functions that pass in
> intel_guc_log, then retrieve the GuC object, only to access this new
> intel_guc_log_stats object. That layering seems wrong, if the argument
> to a function is intel_guc_log it should really try to access members
> within that object or below. Obv some exceptions exist but here it seems
> clear to me this is in the wrong place.
> 
So the reasoning i had was because because intel_guc_log module only managed
guc-relay-logging and guc-log-dumping for log-events but allocates the buffer
for 3 separate subregion/usages (i.e. log-events, crash-dump and error-capture).
That said, I did not want intel_guc_capture and relay-logging (or log-dumping)
to have to contend with the same lock because these two subregions are completely
independant of each other in terms of when they are being accessed and why.

However, after the redesign of rev5 (this rev), I now believe the intel_guc_capture
module does not require a lock because its only ever accessing its log
subregion in response to the ctb handler functions that run out of the same queue.
As we know intel_guc_capture reacts to G2H-error-capture-notification and G2H-context-reset
(that trickles into i915_gpu_coredump). At the point of i915_error_state dump,
intel_guc_capture module does not access the buffer - it merely dumps the already-parsed
and engine-dump-node (that was detached from error-capture's internal linked-list
and attached to the gpu_coredump structure in the second G2H above).

And of course, intel_guc_log only ever accesses the log-events subregion
and never the error-capture regions.

That said, i could revert the lock structure to the original and not have
intel_guc_capture using locks. What do you think?

...alan

> Another nit, I'd personally break this out into multiple patches.
> 
> e.g. 1 to rename relay log functions, 1 introducing intel_guc_log_stats
> + lock, and 1 adding intel_guc_capture_output_min_size_est. Maybe I'm
> missing another patch or two in there.
> 
> Not a blocker but it does make reviews easier.
> 
Will do.

> Matt
> 
> >  	/** @ct: the command transport communication channel */
> >  	struct intel_guc_ct ct;
> >  	/** @slpc: sub-structure containing SLPC related data and objects */
> > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > index 70d2ee841289..e7f99d051636 100644
> > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > @@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
> >  	return PAGE_ALIGN(alloc_size);
> >  }
> >  
> > 2.25.1
> > 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-08 19:38     ` Teres Alexis, Alan Previn
@ 2022-02-08 22:18       ` Matthew Brost
  2022-02-08 22:55         ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Matthew Brost @ 2022-02-08 22:18 UTC (permalink / raw)
  To: Teres Alexis, Alan Previn; +Cc: intel-gfx

On Tue, Feb 08, 2022 at 11:38:13AM -0800, Teres Alexis, Alan Previn wrote:
> Hi Matt, thank you for taking the time to review the codes.
> Answering your question inline below.
> 
> 
> On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> > On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > > GuC log buffer regions for debug-log-events, crash-dumps and
> > > error-state-capture are all a single bo allocation that includes
> > > the guc_log_buffer_state structures.
> > >
> > > Since the error-capture region is accessed with high priority at non-
> > > deterministic times (as part of gpu coredump) while the debug-log-event
> > > region is populated and accessed with different priorities, timings and
> > > consumers, let's split out separate locks for buffer-state accesses
> > > of each region.
> > >
> > > Also, ensure a global mapping is made up front for the entire bo
> > > throughout GuC operation so that dynamic mapping and unmapping isn't
> > > required for error capture log access if relay-logging isn't running.
> > >
> > > Additionally, while here, make some readibility improvements:
> > > 1. change previous function names with "capture_logs" to
> > >    "copy_debug_logs" to help make the distinction clearer.
> > > 2. Update the guc log region mapping comments to order them
> > >    according to the enum definition as per the GuC interface.
> > >
> > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
> > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
> > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
> > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
> > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
> > >  5 files changed, 141 insertions(+), 60 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > index 4e819853ec2e..be1ad7fa2bf8 100644
> > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > @@ -34,6 +34,8 @@ struct intel_guc {
> > >     struct intel_uc_fw fw;
> > >     /** @log: sub-structure containing GuC log related data and objects */
> > >     struct intel_guc_log log;
> > > +   /** @log_state: states and locks for each subregion of GuC's log buffer */
> > > +   struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];
> >
> > Why move this? This still probably should be sub-structure of
> > intel_guc_log. Most of the access is from functions that pass in
> > intel_guc_log, then retrieve the GuC object, only to access this new
> > intel_guc_log_stats object. That layering seems wrong, if the argument
> > to a function is intel_guc_log it should really try to access members
> > within that object or below. Obv some exceptions exist but here it seems
> > clear to me this is in the wrong place.
> >
> So the reasoning i had was because because intel_guc_log module only managed
> guc-relay-logging and guc-log-dumping for log-events but allocates the buffer
> for 3 separate subregion/usages (i.e. log-events, crash-dump and error-capture).
> That said, I did not want intel_guc_capture and relay-logging (or log-dumping)
> to have to contend with the same lock because these two subregions are completely
> independant of each other in terms of when they are being accessed and why.
> 

All that is fine, I just think the 'struct intel_guc_log_stats' should
be sub-substure of struct intel_guc_log.

> However, after the redesign of rev5 (this rev), I now believe the intel_guc_capture
> module does not require a lock because its only ever accessing its log
> subregion in response to the ctb handler functions that run out of the same queue.
> As we know intel_guc_capture reacts to G2H-error-capture-notification and G2H-context-reset
> (that trickles into i915_gpu_coredump). At the point of i915_error_state dump,
> intel_guc_capture module does not access the buffer - it merely dumps the already-parsed
> and engine-dump-node (that was detached from error-capture's internal linked-list
> and attached to the gpu_coredump structure in the second G2H above).
> 
> And of course, intel_guc_log only ever accesses the log-events subregion
> and never the error-capture regions.
> 
> That said, i could revert the lock structure to the original and not have
> intel_guc_capture using locks. What do you think?
> 

Again my comment has nothing to do with locking, it is where the
structure lives.

Matt

> ...alan
> 
> > Another nit, I'd personally break this out into multiple patches.
> >
> > e.g. 1 to rename relay log functions, 1 introducing intel_guc_log_stats
> > + lock, and 1 adding intel_guc_capture_output_min_size_est. Maybe I'm
> > missing another patch or two in there.
> >
> > Not a blocker but it does make reviews easier.
> >
> Will do.
> 
> > Matt
> >
> > >     /** @ct: the command transport communication channel */
> > >     struct intel_guc_ct ct;
> > >     /** @slpc: sub-structure containing SLPC related data and objects */
> > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > index 70d2ee841289..e7f99d051636 100644
> > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > @@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
> > >     return PAGE_ALIGN(alloc_size);
> > >  }
> > >
> > > 2.25.1
> > >
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-08 22:18       ` Matthew Brost
@ 2022-02-08 22:55         ` Teres Alexis, Alan Previn
  2022-02-09  3:34           ` Matthew Brost
  0 siblings, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-08 22:55 UTC (permalink / raw)
  To: Brost, Matthew; +Cc: intel-gfx


On Tue, 2022-02-08 at 14:18 -0800, Matthew Brost wrote:
> On Tue, Feb 08, 2022 at 11:38:13AM -0800, Teres Alexis, Alan Previn wrote:
> > Hi Matt, thank you for taking the time to review the codes.
> > Answering your question inline below.
> > 
> > 
> > On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> > > On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > > > GuC log buffer regions for debug-log-events, crash-dumps and
> > > > error-state-capture are all a single bo allocation that includes
> > > > the guc_log_buffer_state structures.
> > > > 
> > > > Since the error-capture region is accessed with high priority at non-
> > > > deterministic times (as part of gpu coredump) while the debug-log-event
> > > > region is populated and accessed with different priorities, timings and
> > > > consumers, let's split out separate locks for buffer-state accesses
> > > > of each region.
> > > > 
> > > > Also, ensure a global mapping is made up front for the entire bo
> > > > throughout GuC operation so that dynamic mapping and unmapping isn't
> > > > required for error capture log access if relay-logging isn't running.
> > > > 
> > > > Additionally, while here, make some readibility improvements:
> > > > 1. change previous function names with "capture_logs" to
> > > >    "copy_debug_logs" to help make the distinction clearer.
> > > > 2. Update the guc log region mapping comments to order them
> > > >    according to the enum definition as per the GuC interface.
> > > > 
> > > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > > > ---
> > > >  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
> > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
> > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
> > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
> > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
> > > >  5 files changed, 141 insertions(+), 60 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > index 4e819853ec2e..be1ad7fa2bf8 100644
> > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > @@ -34,6 +34,8 @@ struct intel_guc {
> > > >     struct intel_uc_fw fw;
> > > >     /** @log: sub-structure containing GuC log related data and objects */
> > > >     struct intel_guc_log log;
> > > > +   /** @log_state: states and locks for each subregion of GuC's log buffer */
> > > > +   struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];
> > > 
> > > Why move this? This still probably should be sub-structure of
> > > intel_guc_log. Most of the access is from functions that pass in
> > > intel_guc_log, then retrieve the GuC object, only to access this new
> > > intel_guc_log_stats object. That layering seems wrong, if the argument
> > > to a function is intel_guc_log it should really try to access members
> > > within that object or below. Obv some exceptions exist but here it seems
> > > clear to me this is in the wrong place.
> > > 
> > So the reasoning i had was because because intel_guc_log module only managed
> > guc-relay-logging and guc-log-dumping for log-events but allocates the buffer
> > for 3 separate subregion/usages (i.e. log-events, crash-dump and error-capture).
> > That said, I did not want intel_guc_capture and relay-logging (or log-dumping)
> > to have to contend with the same lock because these two subregions are completely
> > independant of each other in terms of when they are being accessed and why.
> > 
> 
> All that is fine, I just think the 'struct intel_guc_log_stats' should
> be sub-substure of struct intel_guc_log.
> 
> > However, after the redesign of rev5 (this rev), I now believe the intel_guc_capture
> > module does not require a lock because its only ever accessing its log
> > subregion in response to the ctb handler functions that run out of the same queue.
> > As we know intel_guc_capture reacts to G2H-error-capture-notification and G2H-context-reset
> > (that trickles into i915_gpu_coredump). At the point of i915_error_state dump,
> > intel_guc_capture module does not access the buffer - it merely dumps the already-parsed
> > and engine-dump-node (that was detached from error-capture's internal linked-list
> > and attached to the gpu_coredump structure in the second G2H above).
> > 
> > And of course, intel_guc_log only ever accesses the log-events subregion
> > and never the error-capture regions.
> > 
> > That said, i could revert the lock structure to the original and not have
> > intel_guc_capture using locks. What do you think?
> > 
> 
> Again my comment has nothing to do with locking, it is where the
> structure lives.
> 
> 
IMHO, based on my understanding of the codes and the GuC interface,
i see intel_guc_log and intel_guc_capture as 2 subsystems at equal level
under the intel_guc framework. Both these subsystems have completely independent
functions with completely separate input streams with completely separate
content and usage. They do happen to share the same bo but have independent
regions. That said, I believe the stats array-structure and even the vma
ptr should go into the parent - i.e. intel_guc, the parent of both intel_guc_log and
intel_guc_capture. Alernatively, each subsystem that has its own stats structure.

However, without the need for the locks, i guess i dont need to change anything
other than have intel_guc_log skip over the capture region and let intel_guc_capture
deal with its region independantly without sharing any member variable
from intel_guc_log.

I am admittedly new to the GuC infrastructure so please do let me know if I am mistaken
and if intel_guc_capture is supposed to be a subsystem of intel_guc_log.

> Matt
> 
> > ...alan
> > 
> > > Another nit, I'd personally break this out into multiple patches.
> > > 
> > > e.g. 1 to rename relay log functions, 1 introducing intel_guc_log_stats
> > > + lock, and 1 adding intel_guc_capture_output_min_size_est. Maybe I'm
> > > missing another patch or two in there.
> > > 
> > > Not a blocker but it does make reviews easier.
> > > 
> > Will do.
> > 
> > > Matt
> > > 
> > > >     /** @ct: the command transport communication channel */
> > > >     struct intel_guc_ct ct;
> > > >     /** @slpc: sub-structure containing SLPC related data and objects */
> > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > index 70d2ee841289..e7f99d051636 100644
> > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > @@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
> > > >     return PAGE_ALIGN(alloc_size);
> > > >  }
> > > > 
> > > > 2.25.1
> > > > 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-08 22:55         ` Teres Alexis, Alan Previn
@ 2022-02-09  3:34           ` Matthew Brost
  2022-02-09  3:41             ` Matthew Brost
  2022-02-09  3:51             ` Teres Alexis, Alan Previn
  0 siblings, 2 replies; 52+ messages in thread
From: Matthew Brost @ 2022-02-09  3:34 UTC (permalink / raw)
  To: Teres Alexis, Alan Previn; +Cc: intel-gfx

On Tue, Feb 08, 2022 at 02:55:07PM -0800, Teres Alexis, Alan Previn wrote:
> 
> On Tue, 2022-02-08 at 14:18 -0800, Matthew Brost wrote:
> > On Tue, Feb 08, 2022 at 11:38:13AM -0800, Teres Alexis, Alan Previn wrote:
> > > Hi Matt, thank you for taking the time to review the codes.
> > > Answering your question inline below.
> > >
> > >
> > > On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> > > > On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > > > > GuC log buffer regions for debug-log-events, crash-dumps and
> > > > > error-state-capture are all a single bo allocation that includes
> > > > > the guc_log_buffer_state structures.
> > > > >
> > > > > Since the error-capture region is accessed with high priority at non-
> > > > > deterministic times (as part of gpu coredump) while the debug-log-event
> > > > > region is populated and accessed with different priorities, timings and
> > > > > consumers, let's split out separate locks for buffer-state accesses
> > > > > of each region.
> > > > >
> > > > > Also, ensure a global mapping is made up front for the entire bo
> > > > > throughout GuC operation so that dynamic mapping and unmapping isn't
> > > > > required for error capture log access if relay-logging isn't running.
> > > > >
> > > > > Additionally, while here, make some readibility improvements:
> > > > > 1. change previous function names with "capture_logs" to
> > > > >    "copy_debug_logs" to help make the distinction clearer.
> > > > > 2. Update the guc log region mapping comments to order them
> > > > >    according to the enum definition as per the GuC interface.
> > > > >
> > > > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > > > > ---
> > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
> > > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
> > > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
> > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
> > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
> > > > >  5 files changed, 141 insertions(+), 60 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > index 4e819853ec2e..be1ad7fa2bf8 100644
> > > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > @@ -34,6 +34,8 @@ struct intel_guc {
> > > > >     struct intel_uc_fw fw;
> > > > >     /** @log: sub-structure containing GuC log related data and objects */
> > > > >     struct intel_guc_log log;
> > > > > +   /** @log_state: states and locks for each subregion of GuC's log buffer */
> > > > > +   struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];
> > > >
> > > > Why move this? This still probably should be sub-structure of
> > > > intel_guc_log. Most of the access is from functions that pass in
> > > > intel_guc_log, then retrieve the GuC object, only to access this new
> > > > intel_guc_log_stats object. That layering seems wrong, if the argument
> > > > to a function is intel_guc_log it should really try to access members
> > > > within that object or below. Obv some exceptions exist but here it seems
> > > > clear to me this is in the wrong place.
> > > >
> > > So the reasoning i had was because because intel_guc_log module only managed
> > > guc-relay-logging and guc-log-dumping for log-events but allocates the buffer
> > > for 3 separate subregion/usages (i.e. log-events, crash-dump and error-capture).
> > > That said, I did not want intel_guc_capture and relay-logging (or log-dumping)
> > > to have to contend with the same lock because these two subregions are completely
> > > independant of each other in terms of when they are being accessed and why.
> > >
> >
> > All that is fine, I just think the 'struct intel_guc_log_stats' should
> > be sub-substure of struct intel_guc_log.
> >
> > > However, after the redesign of rev5 (this rev), I now believe the intel_guc_capture
> > > module does not require a lock because its only ever accessing its log
> > > subregion in response to the ctb handler functions that run out of the same queue.
> > > As we know intel_guc_capture reacts to G2H-error-capture-notification and G2H-context-reset
> > > (that trickles into i915_gpu_coredump). At the point of i915_error_state dump,
> > > intel_guc_capture module does not access the buffer - it merely dumps the already-parsed
> > > and engine-dump-node (that was detached from error-capture's internal linked-list
> > > and attached to the gpu_coredump structure in the second G2H above).
> > >
> > > And of course, intel_guc_log only ever accesses the log-events subregion
> > > and never the error-capture regions.
> > >
> > > That said, i could revert the lock structure to the original and not have
> > > intel_guc_capture using locks. What do you think?
> > >
> >
> > Again my comment has nothing to do with locking, it is where the
> > structure lives.
> >
> >
> IMHO, based on my understanding of the codes and the GuC interface,
> i see intel_guc_log and intel_guc_capture as 2 subsystems at equal level
> under the intel_guc framework. Both these subsystems have completely independent
> functions with completely separate input streams with completely separate
> content and usage. They do happen to share the same bo but have independent
> regions. That said, I believe the stats array-structure and even the vma
> ptr should go into the parent - i.e. intel_guc, the parent of both intel_guc_log and
> intel_guc_capture. Alernatively, each subsystem that has its own stats structure.
> 
> However, without the need for the locks, i guess i dont need to change anything
> other than have intel_guc_log skip over the capture region and let intel_guc_capture
> deal with its region independantly without sharing any member variable
> from intel_guc_log.
> 
> I am admittedly new to the GuC infrastructure so please do let me know if I am mistaken
> and if intel_guc_capture is supposed to be a subsystem of intel_guc_log.
> 

If the object lives at the GuC level, operate on it at the GuC level.

e.g.
intel_guc_log_init_early calls mutex init on guc->log_state - that is
wrong and breaks the layering. intel_guc_log_init_early should only
operate on guc_log or below objects, not above it.

The key here is consisteny, if the GuC level owns the object it should
be initialized there + passed into the lower levels if possible. The
lower levels should avoid reaching back to GuC level for objects
whenever possible.

You could have 2 intel_guc_log_stats objects below the guc_log object
and 1 intel_guc_log_stats object for capture at the GuC level. That's
likely the right approach here.

I know this is kinda a nit but actually important to have a well
structured / layered driver. The i915 isn't a great example of this but
we should avoid making this worse.

Matt

> > Matt
> >
> > > ...alan
> > >
> > > > Another nit, I'd personally break this out into multiple patches.
> > > >
> > > > e.g. 1 to rename relay log functions, 1 introducing intel_guc_log_stats
> > > > + lock, and 1 adding intel_guc_capture_output_min_size_est. Maybe I'm
> > > > missing another patch or two in there.
> > > >
> > > > Not a blocker but it does make reviews easier.
> > > >
> > > Will do.
> > >
> > > > Matt
> > > >
> > > > >     /** @ct: the command transport communication channel */
> > > > >     struct intel_guc_ct ct;
> > > > >     /** @slpc: sub-structure containing SLPC related data and objects */
> > > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > index 70d2ee841289..e7f99d051636 100644
> > > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > @@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
> > > > >     return PAGE_ALIGN(alloc_size);
> > > > >  }
> > > > >
> > > > > 2.25.1
> > > > >
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-09  3:34           ` Matthew Brost
@ 2022-02-09  3:41             ` Matthew Brost
  2022-02-09  3:51             ` Teres Alexis, Alan Previn
  1 sibling, 0 replies; 52+ messages in thread
From: Matthew Brost @ 2022-02-09  3:41 UTC (permalink / raw)
  To: Teres Alexis, Alan Previn; +Cc: intel-gfx

On Tue, Feb 08, 2022 at 07:34:37PM -0800, Matthew Brost wrote:
> On Tue, Feb 08, 2022 at 02:55:07PM -0800, Teres Alexis, Alan Previn wrote:
> > 
> > On Tue, 2022-02-08 at 14:18 -0800, Matthew Brost wrote:
> > > On Tue, Feb 08, 2022 at 11:38:13AM -0800, Teres Alexis, Alan Previn wrote:
> > > > Hi Matt, thank you for taking the time to review the codes.
> > > > Answering your question inline below.
> > > >
> > > >
> > > > On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> > > > > On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > > > > > GuC log buffer regions for debug-log-events, crash-dumps and
> > > > > > error-state-capture are all a single bo allocation that includes
> > > > > > the guc_log_buffer_state structures.
> > > > > >
> > > > > > Since the error-capture region is accessed with high priority at non-
> > > > > > deterministic times (as part of gpu coredump) while the debug-log-event
> > > > > > region is populated and accessed with different priorities, timings and
> > > > > > consumers, let's split out separate locks for buffer-state accesses
> > > > > > of each region.
> > > > > >
> > > > > > Also, ensure a global mapping is made up front for the entire bo
> > > > > > throughout GuC operation so that dynamic mapping and unmapping isn't
> > > > > > required for error capture log access if relay-logging isn't running.
> > > > > >
> > > > > > Additionally, while here, make some readibility improvements:
> > > > > > 1. change previous function names with "capture_logs" to
> > > > > >    "copy_debug_logs" to help make the distinction clearer.
> > > > > > 2. Update the guc log region mapping comments to order them
> > > > > >    according to the enum definition as per the GuC interface.
> > > > > >
> > > > > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
> > > > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
> > > > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
> > > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
> > > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
> > > > > >  5 files changed, 141 insertions(+), 60 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > > index 4e819853ec2e..be1ad7fa2bf8 100644
> > > > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > > @@ -34,6 +34,8 @@ struct intel_guc {
> > > > > >     struct intel_uc_fw fw;
> > > > > >     /** @log: sub-structure containing GuC log related data and objects */
> > > > > >     struct intel_guc_log log;
> > > > > > +   /** @log_state: states and locks for each subregion of GuC's log buffer */
> > > > > > +   struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];
> > > > >
> > > > > Why move this? This still probably should be sub-structure of
> > > > > intel_guc_log. Most of the access is from functions that pass in
> > > > > intel_guc_log, then retrieve the GuC object, only to access this new
> > > > > intel_guc_log_stats object. That layering seems wrong, if the argument
> > > > > to a function is intel_guc_log it should really try to access members
> > > > > within that object or below. Obv some exceptions exist but here it seems
> > > > > clear to me this is in the wrong place.
> > > > >
> > > > So the reasoning i had was because because intel_guc_log module only managed
> > > > guc-relay-logging and guc-log-dumping for log-events but allocates the buffer
> > > > for 3 separate subregion/usages (i.e. log-events, crash-dump and error-capture).
> > > > That said, I did not want intel_guc_capture and relay-logging (or log-dumping)
> > > > to have to contend with the same lock because these two subregions are completely
> > > > independant of each other in terms of when they are being accessed and why.
> > > >
> > >
> > > All that is fine, I just think the 'struct intel_guc_log_stats' should
> > > be sub-substure of struct intel_guc_log.
> > >
> > > > However, after the redesign of rev5 (this rev), I now believe the intel_guc_capture
> > > > module does not require a lock because its only ever accessing its log
> > > > subregion in response to the ctb handler functions that run out of the same queue.
> > > > As we know intel_guc_capture reacts to G2H-error-capture-notification and G2H-context-reset
> > > > (that trickles into i915_gpu_coredump). At the point of i915_error_state dump,
> > > > intel_guc_capture module does not access the buffer - it merely dumps the already-parsed
> > > > and engine-dump-node (that was detached from error-capture's internal linked-list
> > > > and attached to the gpu_coredump structure in the second G2H above).
> > > >
> > > > And of course, intel_guc_log only ever accesses the log-events subregion
> > > > and never the error-capture regions.
> > > >
> > > > That said, i could revert the lock structure to the original and not have
> > > > intel_guc_capture using locks. What do you think?
> > > >
> > >
> > > Again my comment has nothing to do with locking, it is where the
> > > structure lives.
> > >
> > >
> > IMHO, based on my understanding of the codes and the GuC interface,
> > i see intel_guc_log and intel_guc_capture as 2 subsystems at equal level
> > under the intel_guc framework. Both these subsystems have completely independent
> > functions with completely separate input streams with completely separate
> > content and usage. They do happen to share the same bo but have independent
> > regions. That said, I believe the stats array-structure and even the vma
> > ptr should go into the parent - i.e. intel_guc, the parent of both intel_guc_log and
> > intel_guc_capture. Alernatively, each subsystem that has its own stats structure.
> > 
> > However, without the need for the locks, i guess i dont need to change anything
> > other than have intel_guc_log skip over the capture region and let intel_guc_capture
> > deal with its region independantly without sharing any member variable
> > from intel_guc_log.
> > 
> > I am admittedly new to the GuC infrastructure so please do let me know if I am mistaken
> > and if intel_guc_capture is supposed to be a subsystem of intel_guc_log.
> > 
> 
> If the object lives at the GuC level, operate on it at the GuC level.
> 
> e.g.
> intel_guc_log_init_early calls mutex init on guc->log_state - that is
> wrong and breaks the layering. intel_guc_log_init_early should only
> operate on guc_log or below objects, not above it.
> 
> The key here is consisteny, if the GuC level owns the object it should
> be initialized there + passed into the lower levels if possible. The
> lower levels should avoid reaching back to GuC level for objects
> whenever possible.
> 

Let me clarifiy this even more, reaching back to get an object to pass
to another fucntion - ok, reaching back to read something - meh,
reaching back to modify something - no.

Matt 

> You could have 2 intel_guc_log_stats objects below the guc_log object
> and 1 intel_guc_log_stats object for capture at the GuC level. That's
> likely the right approach here.
> 
> I know this is kinda a nit but actually important to have a well
> structured / layered driver. The i915 isn't a great example of this but
> we should avoid making this worse.
> 
> Matt
> 
> > > Matt
> > >
> > > > ...alan
> > > >
> > > > > Another nit, I'd personally break this out into multiple patches.
> > > > >
> > > > > e.g. 1 to rename relay log functions, 1 introducing intel_guc_log_stats
> > > > > + lock, and 1 adding intel_guc_capture_output_min_size_est. Maybe I'm
> > > > > missing another patch or two in there.
> > > > >
> > > > > Not a blocker but it does make reviews easier.
> > > > >
> > > > Will do.
> > > >
> > > > > Matt
> > > > >
> > > > > >     /** @ct: the command transport communication channel */
> > > > > >     struct intel_guc_ct ct;
> > > > > >     /** @slpc: sub-structure containing SLPC related data and objects */
> > > > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > > index 70d2ee841289..e7f99d051636 100644
> > > > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > > @@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
> > > > > >     return PAGE_ALIGN(alloc_size);
> > > > > >  }
> > > > > >
> > > > > > 2.25.1
> > > > > >
> > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-09  3:34           ` Matthew Brost
  2022-02-09  3:41             ` Matthew Brost
@ 2022-02-09  3:51             ` Teres Alexis, Alan Previn
  2022-02-14 19:20               ` Teres Alexis, Alan Previn
  1 sibling, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-09  3:51 UTC (permalink / raw)
  To: Brost, Matthew; +Cc: intel-gfx


On Tue, 2022-02-08 at 19:34 -0800, Matthew Brost wrote:
> On Tue, Feb 08, 2022 at 02:55:07PM -0800, Teres Alexis, Alan Previn wrote:
> > On Tue, 2022-02-08 at 14:18 -0800, Matthew Brost wrote:
> > > On Tue, Feb 08, 2022 at 11:38:13AM -0800, Teres Alexis, Alan Previn wrote:
> > > > Hi Matt, thank you for taking the time to review the codes.
> > > > Answering your question inline below.
> > > > 
> > > > 
> > > > On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> > > > > On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > > > > > GuC log buffer regions for debug-log-events, crash-dumps and
> > > > > > error-state-capture are all a single bo allocation that includes
> > > > > > the guc_log_buffer_state structures.
> > > > > > 
> > > > > > Since the error-capture region is accessed with high priority at non-
> > > > > > deterministic times (as part of gpu coredump) while the debug-log-event
> > > > > > region is populated and accessed with different priorities, timings and
> > > > > > consumers, let's split out separate locks for buffer-state accesses
> > > > > > of each region.
> > > > > > 
> > > > > > Also, ensure a global mapping is made up front for the entire bo
> > > > > > throughout GuC operation so that dynamic mapping and unmapping isn't
> > > > > > required for error capture log access if relay-logging isn't running.
> > > > > > 
> > > > > > Additionally, while here, make some readibility improvements:
> > > > > > 1. change previous function names with "capture_logs" to
> > > > > >    "copy_debug_logs" to help make the distinction clearer.
> > > > > > 2. Update the guc log region mapping comments to order them
> > > > > >    according to the enum definition as per the GuC interface.
> > > > > > 
> > > > > > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |   2 +
> > > > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  47 ++++++
> > > > > >  .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
> > > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    | 135 +++++++++++-------
> > > > > >  drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |  16 ++-
> > > > > >  5 files changed, 141 insertions(+), 60 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > > index 4e819853ec2e..be1ad7fa2bf8 100644
> > > > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
> > > > > > @@ -34,6 +34,8 @@ struct intel_guc {
> > > > > >     struct intel_uc_fw fw;
> > > > > >     /** @log: sub-structure containing GuC log related data and objects */
> > > > > >     struct intel_guc_log log;
> > > > > > +   /** @log_state: states and locks for each subregion of GuC's log buffer */
> > > > > > +   struct intel_guc_log_stats log_state[GUC_MAX_LOG_BUFFER];
> > > > > 
> > > > > Why move this? This still probably should be sub-structure of
> > > > > intel_guc_log. Most of the access is from functions that pass in
> > > > > intel_guc_log, then retrieve the GuC object, only to access this new
> > > > > intel_guc_log_stats object. That layering seems wrong, if the argument
> > > > > to a function is intel_guc_log it should really try to access members
> > > > > within that object or below. Obv some exceptions exist but here it seems
> > > > > clear to me this is in the wrong place.
> > > > > 
> > > > So the reasoning i had was because because intel_guc_log module only managed
> > > > guc-relay-logging and guc-log-dumping for log-events but allocates the buffer
> > > > for 3 separate subregion/usages (i.e. log-events, crash-dump and error-capture).
> > > > That said, I did not want intel_guc_capture and relay-logging (or log-dumping)
> > > > to have to contend with the same lock because these two subregions are completely
> > > > independant of each other in terms of when they are being accessed and why.
> > > > 
> > > 
> > > All that is fine, I just think the 'struct intel_guc_log_stats' should
> > > be sub-substure of struct intel_guc_log.
> > > 
> > > > However, after the redesign of rev5 (this rev), I now believe the intel_guc_capture
> > > > module does not require a lock because its only ever accessing its log
> > > > subregion in response to the ctb handler functions that run out of the same queue.
> > > > As we know intel_guc_capture reacts to G2H-error-capture-notification and G2H-context-reset
> > > > (that trickles into i915_gpu_coredump). At the point of i915_error_state dump,
> > > > intel_guc_capture module does not access the buffer - it merely dumps the already-parsed
> > > > and engine-dump-node (that was detached from error-capture's internal linked-list
> > > > and attached to the gpu_coredump structure in the second G2H above).
> > > > 
> > > > And of course, intel_guc_log only ever accesses the log-events subregion
> > > > and never the error-capture regions.
> > > > 
> > > > That said, i could revert the lock structure to the original and not have
> > > > intel_guc_capture using locks. What do you think?
> > > > 
> > > 
> > > Again my comment has nothing to do with locking, it is where the
> > > structure lives.
> > > 
> > > 
> > IMHO, based on my understanding of the codes and the GuC interface,
> > i see intel_guc_log and intel_guc_capture as 2 subsystems at equal level
> > under the intel_guc framework. Both these subsystems have completely independent
> > functions with completely separate input streams with completely separate
> > content and usage. They do happen to share the same bo but have independent
> > regions. That said, I believe the stats array-structure and even the vma
> > ptr should go into the parent - i.e. intel_guc, the parent of both intel_guc_log and
> > intel_guc_capture. Alernatively, each subsystem that has its own stats structure.
> > 
> > However, without the need for the locks, i guess i dont need to change anything
> > other than have intel_guc_log skip over the capture region and let intel_guc_capture
> > deal with its region independantly without sharing any member variable
> > from intel_guc_log.
> > 
> > I am admittedly new to the GuC infrastructure so please do let me know if I am mistaken
> > and if intel_guc_capture is supposed to be a subsystem of intel_guc_log.
> > 
> 
> If the object lives at the GuC level, operate on it at the GuC level.
> 
> e.g.
> intel_guc_log_init_early calls mutex init on guc->log_state - that is
> wrong and breaks the layering. intel_guc_log_init_early should only
> operate on guc_log or below objects, not above it.
> 
> The key here is consisteny, if the GuC level owns the object it should
> be initialized there + passed into the lower levels if possible. The
> lower levels should avoid reaching back to GuC level for objects
> whenever possible.
> 
> You could have 2 intel_guc_log_stats objects below the guc_log object
> and 1 intel_guc_log_stats object for capture at the GuC level. That's
> likely the right approach here.

Thanks Matt - I'm in agreement... I was concerned about too much of
change - but you're right, I should be focusing on the design consistency.
Above sounds like the correct design (these stats and locks should belong
to their sole user).

...alan

> 
> I know this is kinda a nit but actually important to have a well
> structured / layered driver. The i915 isn't a great example of this but
> we should avoid making this worse.
> 
> Matt
> 
> > > Matt
> > > 
> > > > ...alan
> > > > 
> > > > > Another nit, I'd personally break this out into multiple patches.
> > > > > 
> > > > > e.g. 1 to rename relay log functions, 1 introducing intel_guc_log_stats
> > > > > + lock, and 1 adding intel_guc_capture_output_min_size_est. Maybe I'm
> > > > > missing another patch or two in there.
> > > > > 
> > > > > Not a blocker but it does make reviews easier.
> > > > > 
> > > > Will do.
> > > > 
> > > > > Matt
> > > > > 
> > > > > >     /** @ct: the command transport communication channel */
> > > > > >     struct intel_guc_ct ct;
> > > > > >     /** @slpc: sub-structure containing SLPC related data and objects */
> > > > > > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > > index 70d2ee841289..e7f99d051636 100644
> > > > > > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > > > > > @@ -651,6 +651,53 @@ int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u3
> > > > > >     return PAGE_ALIGN(alloc_size);
> > > > > >  }
> > > > > > 
> > > > > > 2.25.1
> > > > > > 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 03/10] drm/i915/guc: Add DG2 registers for GuC error state capture.
  2022-02-05  1:28   ` Umesh Nerlige Ramappa
@ 2022-02-10  5:17     ` Teres Alexis, Alan Previn
  2022-02-11 19:24     ` Teres Alexis, Alan Previn
  1 sibling, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-10  5:17 UTC (permalink / raw)
  To: Nerlige Ramappa, Umesh; +Cc: intel-gfx

Apologies for the delayed response. I totally agree with the
lpd vs hpg function separation. Thats what i initially implemented
but when cross-referencing my logic with the execlist i realized
DG2 steering registers for all Gens were in the same function so
I thought of keeping it consistent but i rather go with your
proposal.

I'll replace the macro with a static function but won't inline
it (i think there is a rule against that? let the compiler handle).

I'll fix the rest as per your review comment.
Thank you for reviewing :)


On Fri, 2022-02-04 at 17:28 -0800, Umesh Nerlige Ramappa wrote:
> On Wed, Jan 26, 2022 at 02:48:15AM -0800, Alan Previn wrote:
> > Add additional DG2 registers for GuC error state capture.
> > 
> > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > ---
> > .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 64 ++++++++++++++-----
> > 1 file changed, 49 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > index b6882074fc8d..19719daffed4 100644
> > --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
> > @@ -179,19 +179,23 @@ static struct __ext_steer_reg xelpd_extregs[] = {
> > 	{"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
> > };
> > 
> > +static struct __ext_steer_reg xehpg_extregs[] = {
> > +	{"XEHPG_INSTDONE_GEOM_SVG", XEHPG_INSTDONE_GEOM_SVG}
> > +};
> > +
> > static void
> > -guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
> > -				     struct __guc_mmio_reg_descr_group *lists)
> > +guc_capture_alloc_steered_list_xe_lpd_hpg(struct intel_guc *guc,
> > +					  struct __guc_mmio_reg_descr_group *lists,
> > +					  u32 ipver)
> 
> IMO having 2 separate functions would be easier to read and maintain. No 
> ipver logic inside here.
> 
> > {
> > 	struct intel_gt *gt = guc_to_gt(guc);
> > 	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> > 	struct sseu_dev_info *sseu;
> > -	int slice, subslice, i, num_tot_regs = 0;
> > +	int slice, subslice, i, iter, num_steer_regs, num_tot_regs = 0;
> > 	struct __guc_mmio_reg_descr_group *list;
> > 	struct __guc_mmio_reg_descr *extarray;
> > -	int num_steer_regs = ARRAY_SIZE(xelpd_extregs);
> > 
> > -	/* In XE_LP we only care about render-class steering registers during error-capture */
> > +	/* In XE_LP / HPG we only have render-class steering registers during error-capture */
> > 	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
> > 					GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, GUC_RENDER_CLASS);
> > 	if (!list)
> > @@ -200,10 +204,21 @@ guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
> > 	if (list->ext)
> > 		return; /* already populated */
> 
> nit:
> if (!list || list->ext)
> 	return;
> > +	num_steer_regs = ARRAY_SIZE(xelpd_extregs);
> > +	if (ipver >= IP_VER(12, 55))
> 
> What does this actually mean? 12 55 has both lpd and hpg regs?
> 
> You could (if possible) use has_lpd_regs/has_hpg_regs in i915_pci.c to 
> simplify the platform specific logic.
> 
> > +		num_steer_regs += ARRAY_SIZE(xehpg_extregs);
> > +
> > 	sseu = &gt->info.sseu;
> > -	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
> > -		num_tot_regs += num_steer_regs;
> > +	if (ipver >= IP_VER(12, 50)) {
> > +		for_each_instdone_gslice_dss_xehp(i915, sseu, iter, slice, subslice) {
> > +			num_tot_regs += num_steer_regs;
> > +		}
> > +	} else {
> > +		for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
> > +			num_tot_regs += num_steer_regs;
> > +		}
> > 	}
> > +
> > 	if (!num_tot_regs)
> > 		return;
> > 
> > @@ -212,15 +227,31 @@ guc_capture_alloc_steered_list_xelpd(struct intel_guc *guc,
> > 		return;
> > 
> > 	extarray = list->ext;
> 
> nit: I would mostly use extarray everywhere and assign it to list->ext 
> at the end of the function.
> 
> > -	for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
> > -		for (i = 0; i < num_steer_regs; i++) {
> > -			extarray->reg = xelpd_extregs[i].reg;
> > -			extarray->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice);
> > -			extarray->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice);
> 
> could use helpers
> 
> extarray->flags |= __steering_flags(slice, subslice);
> 
> 
> > -			extarray->regname = xelpd_extregs[i].name;
> > -			++extarray;
> > +
> > +#define POPULATE_NEXT_EXTREG(ext, list, idx, slicenum, subslicenum) \
> > +	{ \
> > +		(ext)->reg = list[idx].reg; \
> > +		(ext)->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slicenum); \
> > +		(ext)->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslicenum); \
> > +		(ext)->regname = xelpd_extregs[i].name; \
> > +		++(ext); \
> > +	}
> 
> I prefer having an inline for the above assignments and move the ++(ext_ 
> into the for loop itself.
> 
> > +	if (ipver >= IP_VER(12, 50)) {
> > +		for_each_instdone_gslice_dss_xehp(i915, sseu, iter, slice, subslice) {
> > +			for (i = 0; i < ARRAY_SIZE(xelpd_extregs); i++)
> > +				POPULATE_NEXT_EXTREG(extarray, xelpd_extregs, i, slice, subslice)
> > +			for (i = 0; i < ARRAY_SIZE(xehpg_extregs) && ipver >= IP_VER(12, 55);
> > +			     i++)
> > +				POPULATE_NEXT_EXTREG(extarray, xehpg_extregs, i, slice, subslice)
> > +		}
> > +	} else {
> > +		for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
> > +			for (i = 0; i < num_steer_regs; i++)
> > +				POPULATE_NEXT_EXTREG(extarray, xelpd_extregs, i, slice, subslice)
> > 		}
> > 	}
> > +#undef POPULATE_NEXT_EXTREG
> > +
> > 	list->num_ext = num_tot_regs;
> > }
> > 
> > @@ -237,7 +268,10 @@ guc_capture_get_device_reglist(struct intel_guc *guc)
> > 		 * these at init time based on hw config add it as an extension
> > 		 * list at the end of the pre-populated render list.
> > 		 */
> > -		guc_capture_alloc_steered_list_xelpd(guc, xe_lpd_lists);
> > +		guc_capture_alloc_steered_list_xe_lpd_hpg(guc, xe_lpd_lists, IP_VER(12, 0));
> 
> Ideally, I would just think about having seperate 
> 
> guc_capture_alloc_steered_list_xe_lpd and
> guc_capture_alloc_steered_list_xe_hpg
> 
> Maybe there could just be one check for say IP_VER(12, 50) at the top 
> level and you can call the respective function.
> 
> 
> > +		return xe_lpd_lists;
> > +	} else if (IS_DG2(i915)) {
> > +		guc_capture_alloc_steered_list_xe_lpd_hpg(guc, xe_lpd_lists, IP_VER(12, 55));
> > 		return xe_lpd_lists;
> 
> xe_lpd_lists is returned in both if/else, so can be moved out of the 
> conditions. Also now you could just rename it to xe_lists.
> 
> Regards,
> Umesh
> 
> > 	}
> > 
> > -- 
> > 2.25.1
> > 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 07/10] drm/i915/guc: Extract GuC error capture lists on G2H notification.
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 07/10] drm/i915/guc: Extract GuC error capture lists on G2H notification Alan Previn
@ 2022-02-11  1:36   ` Umesh Nerlige Ramappa
  2022-02-13 19:47     ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Umesh Nerlige Ramappa @ 2022-02-11  1:36 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

On Wed, Jan 26, 2022 at 02:48:19AM -0800, Alan Previn wrote:
>- Upon the G2H Notify-Err-Capture event, parse through the
>  GuC Log Buffer (error-capture-region) and dynamically allocate
>  capture-nodes, A single node represents a single "engine-
>  instance-capture-dump" and contains at least 3 register lists:
>  global, engine-class and engine-instance. An internal link
>  list is maintained to store one or more nodes.
>- The G2G error-capture notification event happens before the
>  corresponding G2H context-reset that triggers the
>  i915_gpu_coredump (where we want to avoid memory allocation
>  moving forward).
>- Because the link-list node allocations happen before the call
>  to i915_gpu_codedump, duplicate global and engine-class register
>  lists for each engine-instance register dump if we find
>  dependent-engine resets in a engine-capture-group.
>- Later when i915_gpu_coredump calls into capture_engine, (in
>  the subsequent patch) we dettach the matching node (guc-id,
>  LRCA, etc) from the link list above and attach it to
>  i915_gpu_coredump's intel_engine_coredump structure when have
>  matching LRCA/guc-id/engine-instance.
>- Finally, when we reset GuC submission lets also parse
>  all outstanding capture data here too.
>
>Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>---
> .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h  |   7 +
> drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |  52 +-
> .../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 517 +++++++++++++++++-
> .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |   1 +
> drivers/gpu/drm/i915/gt/uc/intel_guc_log.c    |  26 +-
> drivers/gpu/drm/i915/gt/uc/intel_guc_log.h    |   4 +
> .../gpu/drm/i915/gt/uc/intel_guc_submission.c |  14 +-
> 7 files changed, 608 insertions(+), 13 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
>index 7afdadc7656f..82a69f54cddb 100644
>--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
>+++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
>@@ -173,4 +173,11 @@ enum intel_guc_sleep_state_status {
> #define GUC_LOG_CONTROL_VERBOSITY_MASK	(0xF << GUC_LOG_CONTROL_VERBOSITY_SHIFT)
> #define GUC_LOG_CONTROL_DEFAULT_LOGGING	(1 << 8)
>
>+enum intel_guc_state_capture_event_status {
>+	INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_SUCCESS = 0x0,
>+	INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE = 0x1,
>+};
>+
>+#define INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK      0x1

MASK is not needed. See below

>+
> #endif /* _ABI_GUC_ACTIONS_ABI_H */
>diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
>index 495cdb0228c6..14c497f12621 100644
>--- a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
>+++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
>@@ -29,7 +29,8 @@ struct __guc_mmio_reg_descr_group {
> };
>
> struct guc_state_capture_header_t {
>-	u32 reserved1;
>+	u32 owner;
>+		#define CAP_HDR_CAPTURE_VFID GENMASK(7, 0)

I would start #define at first column (no indents) like other code in 
the driver/kernel. Likewise at other places.

> 	u32 info;
> 		#define CAP_HDR_CAPTURE_TYPE GENMASK(3, 0) /* see enum guc_capture_type */
> 		#define CAP_HDR_ENGINE_CLASS GENMASK(7, 4) /* see GUC_MAX_ENGINE_CLASSES */
>@@ -52,7 +53,8 @@ enum guc_capture_group_types {
> };
>
> struct guc_state_capture_group_header_t {
>-	u32 reserved1;
>+	u32 owner;
>+		#define CAP_GRP_HDR_CAPTURE_VFID GENMASK(7, 0)
> 	u32 info;
> 		#define CAP_GRP_HDR_NUM_CAPTURES GENMASK(7, 0)
> 		#define CAP_GRP_HDR_CAPTURE_TYPE GENMASK(15, 8) /* guc_capture_group_types */
>@@ -63,11 +65,57 @@ struct guc_state_capture_group_t {
> 	struct guc_state_capture_t capture_entries[0];
> } __packed;
>
>+struct __guc_capture_parsed_output {
>+	/*
>+	 * a single set of 3 capture lists: a global-list
>+	 * an engine-class-list and an engine-instance list.
>+	 * outlist in __guc_capture_parsed_output will keep
>+	 * a linked list of these nodes that will eventually
>+	 * be detached from outlist and attached into to
>+	 * i915_gpu_codedump in response to a context reset
>+	 */
>+	struct list_head link;
>+	bool is_partial;
>+	u32 eng_class;
>+	u32 eng_inst;
>+	u32 guc_id;
>+	u32 lrca;
>+	struct gcap_reg_list_info {
>+		u32 vfid;
>+		u32 num;

s/num/num_regs/ ?

>+		struct guc_mmio_reg *regs;
>+	} reginfo[GUC_CAPTURE_LIST_TYPE_MAX];
>+	#define GCAP_PARSED_REGLIST_INDEX_GLOBAL   BIT(GUC_CAPTURE_LIST_TYPE_GLOBAL)
>+	#define GCAP_PARSED_REGLIST_INDEX_ENGCLASS BIT(GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS)
>+	#define GCAP_PARSED_REGLIST_INDEX_ENGINST  BIT(GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE)
>+};
>+
>+#define MAX_NODE_LINKLIST_THRESHOLD     24
>+	/* The maximum number of allocated __guc_capture_parsed_output nodes
>+	 * that we shall keep in outlist. If we receive an error-capture
>+	 * notification and need to allocate another node but have hit this
>+	 * threshold, we shall free the oldest entry and add a new one (FIFO).
>+	 */

needs kernel comment style for multi-line comment (blank line to start 
with).

>+
>+struct __guc_capture_bufstate {
>+	unsigned int size;
>+	void *data;
>+	unsigned int rd;
>+	unsigned int wr;

s/unsigned int/u32/

>+};
>+
> struct __guc_state_capture_priv {
> 	struct __guc_mmio_reg_descr_group *reglists;
> 	u16 num_instance_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
> 	u16 num_class_regs[GUC_CAPTURE_LIST_INDEX_MAX][GUC_MAX_ENGINE_CLASSES];
> 	u16 num_global_regs[GUC_CAPTURE_LIST_INDEX_MAX];
>+	/* An interim linked list of parsed GuC error-capture-output before
>+	 * reporting with formatting. Each node in this linked list shall
>+	 * contain a single engine-capture including global, engine-class and
>+	 * engine-instance register dumps as per guc_capture_parsed_output_node
>+	 */

kernel comment style ^ same as above

>+	struct list_head outlist;
>+	int listcount; /* see MAX_NODE_LINKLIST_THRESHOLD */
> };
>
> #endif /* _INTEL_GUC_CAPTURE_FWIF_H */
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>index e7f99d051636..0b6d743712a6 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>@@ -12,6 +12,8 @@
> #include "guc_capture_fwif.h"
> #include "intel_guc_fwif.h"
> #include "i915_drv.h"
>+#include "i915_gpu_error.h"
>+#include "i915_irq.h"
> #include "i915_memcpy.h"
>
> /*
>@@ -660,6 +662,9 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
> 	int worst_min_size = 0, num_regs = 0;
> 	u16 tmp = 0;
>
>+	if (!guc->capture.priv)
>+		return -ENODEV;
>+
> 	/*
> 	 * If every single engine-instance suffered a failure in quick succession but
> 	 * were all unrelated, then a burst of multiple error-capture events would dump
>@@ -698,8 +703,518 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
> 	return (worst_min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER);
> }
>
>+/*
>+ * KMD Init time flows:
>+ * --------------------
>+ *     --> alloc A: GuC input capture regs lists (registered via ADS)
>+ *                  List acquired via intel_guc_capture_list_count + intel_guc_capture_list_init
>+ *                  Size = global-reg-list + (class-reg-list) + (num-instances x instance-reg-list)
>+ *                  Device tables carry: 1x global, 1x per-class, 1x per-instance)
>+ *                  Caller needs to call per-class and per-instance multiplie times
>+ *
>+ *     --> alloc B: GuC output capture buf (registered via guc_init_params(log_param))
>+ *                  Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small)
>+ *                  Note2: 'x 3' to hold multiple capture groups
>+ *
>+ *
>+ * GUC Runtime notify capture:
>+ * --------------------------
>+ *     --> G2H STATE_CAPTURE_NOTIFICATION
>+ *                   L--> intel_guc_capture_store_snapshot
>+ *                           L--> Loop through B (head..tail) and for each engine instance
>+ *                                register we find:
>+ *      --> alloc C: A capture-output-node structure that includes misc capture info along
>+ *                   with 3 register list dumps (global, engine-class and engine-
>+ *                   instance). This node id added to a linked list stored in
>+ *                   guc->capture->priv for matchup and printout when triggered by
>+ *                   i915_gpu_coredump and err_print_gt (via error capture sysfs) later.
>+ */
>+
>+static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
>+{
>+	if (buf->rd == buf->wr)
>+		return 0;
>+	if (buf->wr > buf->rd)
>+		return (buf->wr - buf->rd);
>+	return (buf->size - buf->rd) + buf->wr;
>+}

Is this a circular buffer shared between GuC and kmd? Since the size is 
a power of 2, the above function is simply:

static u32 guc_capture_buf_count(struct __guc_capture_bufstate *buf)
{
	return (buf->wr - buf->rd) & (buf->size - 1);
}

>+
>+static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf)
>+{
>+	if (buf->rd > buf->wr)
>+		return (buf->size - buf->rd);
>+	return (buf->wr - buf->rd);
>+}
>+
>+static int
>+guc_capture_log_remove_dw(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
>+			  u32 *dw)
>+{
>+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
>+	int tries = 2;
>+	int avail = 0;
>+	u32 *src_data;
>+
>+	if (!guc_capture_buf_cnt(buf))
>+		return 0;
>+
>+	while (tries--) {
>+		avail = guc_capture_buf_cnt_to_end(buf);

Shouldn't this be avail = guc_capture_buf_cnt(buf)?

>+		if (avail >= sizeof(u32)) {
>+			src_data = (u32 *)(buf->data + buf->rd);
>+			*dw = *src_data;
>+			buf->rd += 4;
>+			return 4;
>+		}
>+		if (avail)
>+			drm_warn(&i915->drm, "GuC-Cap-Logs not dword aligned, skipping.\n");

this can be a debug message rather than a warn.

>+		buf->rd = 0;
>+	}
>+
>+	return 0;
>+}
>+
>+static bool
>+guc_capture_data_extracted(struct __guc_capture_bufstate *b,
>+			   int s, void *p)

s/s/size/
s/p/dest/

>+{
>+	if (guc_capture_buf_cnt_to_end(b) >= s) {
>+		memcpy(p, (b->data + b->rd), s);
>+		b->rd += s;
>+		return true;
>+	}
>+	return false;
>+}
>+
>+static int
>+guc_capture_log_get_group_hdr(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
>+			      struct guc_state_capture_group_header_t *ghdr)
>+{
>+	int read = 0;
>+	int fullsize = sizeof(struct guc_state_capture_group_header_t);
>+
>+	if (fullsize > guc_capture_buf_cnt(buf))
>+		return -1;
>+
>+	if (guc_capture_data_extracted(buf, fullsize, (void *)ghdr))
>+		return 0;
>+
>+	read += guc_capture_log_remove_dw(guc, buf, &ghdr->owner);
>+	read += guc_capture_log_remove_dw(guc, buf, &ghdr->info);
>+	if (read != fullsize)
>+		return -1;
>+
>+	return 0;
>+}
>+
>+static int
>+guc_capture_log_get_data_hdr(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
>+			     struct guc_state_capture_header_t *hdr)
>+{
>+	int read = 0;
>+	int fullsize = sizeof(struct guc_state_capture_header_t);
>+
>+	if (fullsize > guc_capture_buf_cnt(buf))
>+		return -1;
>+
>+	if (guc_capture_data_extracted(buf, fullsize, (void *)hdr))
>+		return 0;
>+
>+	read += guc_capture_log_remove_dw(guc, buf, &hdr->owner);
>+	read += guc_capture_log_remove_dw(guc, buf, &hdr->info);
>+	read += guc_capture_log_remove_dw(guc, buf, &hdr->lrca);
>+	read += guc_capture_log_remove_dw(guc, buf, &hdr->guc_id);
>+	read += guc_capture_log_remove_dw(guc, buf, &hdr->num_mmios);
>+	if (read != fullsize)
>+		return -1;
>+
>+	return 0;
>+}
>+
>+static int
>+guc_capture_log_get_register(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
>+			     struct guc_mmio_reg *reg)
>+{
>+	int read = 0;
>+	int fullsize = sizeof(struct guc_mmio_reg);
>+
>+	if (fullsize > guc_capture_buf_cnt(buf))
>+		return -1;
>+
>+	if (guc_capture_data_extracted(buf, fullsize, (void *)reg))
>+		return 0;
>+
>+	read += guc_capture_log_remove_dw(guc, buf, &reg->offset);
>+	read += guc_capture_log_remove_dw(guc, buf, &reg->value);
>+	read += guc_capture_log_remove_dw(guc, buf, &reg->flags);
>+	read += guc_capture_log_remove_dw(guc, buf, &reg->mask);
>+	if (read != fullsize)
>+		return -1;
>+
>+	return 0;
>+}
>+
>+static void
>+guc_capture_del_all_nodes(struct intel_guc *guc)
>+{
>+	int i;
>+
>+	if (!list_empty(&guc->capture.priv->outlist)) {
>+		struct __guc_capture_parsed_output *n, *ntmp;
>+
>+		list_for_each_entry_safe(n, ntmp, &guc->capture.priv->outlist, link) {
>+			for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+				if (n->reginfo[i].regs)
>+					kfree(n->reginfo[i].regs);
>+			}
>+			list_del(&n->link);
>+			kfree(n);
>+		}
>+	}
>+	guc->capture.priv->listcount = 0;
>+}
>+
>+static void
>+guc_capture_del_node(struct intel_guc *guc, struct __guc_capture_parsed_output *node)
>+{
>+	int i;
>+	struct __guc_capture_parsed_output *found = NULL;
>+
>+	if (!list_empty(&guc->capture.priv->outlist)) {
>+		struct __guc_capture_parsed_output *n, *ntmp;
>+
>+		if (node) {
>+			found = node;
>+		} else {
>+			/* traverse down and get the oldest entry */
>+			list_for_each_entry_safe(n, ntmp, &guc->capture.priv->outlist, link)
>+				found = n;
>+		}
>+		if (found) {
>+			for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+				if (found->reginfo[i].regs)
>+					kfree(found->reginfo[i].regs);
>+			}
>+			list_del(&found->link);
>+			kfree(found);
>+			--guc->capture.priv->listcount;
>+		}
>+	}
>+}
>+
>+static void
>+guc_capture_add_node_to_list(struct intel_guc *guc, struct __guc_capture_parsed_output *node)
>+{
>+	GEM_BUG_ON(guc->capture.priv->listcount > MAX_NODE_LINKLIST_THRESHOLD);
>+
>+	if (guc->capture.priv->listcount == MAX_NODE_LINKLIST_THRESHOLD) {
>+		/* discard oldest node */
>+		guc_capture_del_node(guc, NULL);
>+	}
>+
>+	++guc->capture.priv->listcount;
>+	list_add_tail(&node->link, &guc->capture.priv->outlist);
>+}
>+
>+static struct __guc_capture_parsed_output *
>+guc_capture_create_node(struct intel_guc *guc, struct __guc_capture_parsed_output *ori,
>+			u32 keep_reglist_mask)
>+{
>+	struct __guc_capture_parsed_output *new;
>+	int i;
>+
>+	new = kzalloc(sizeof(*new), GFP_KERNEL);
>+	if (!new)
>+		return NULL;
>+	INIT_LIST_HEAD(&new->link);
>+	if (!ori)
>+		return new;
>+	memcpy(new, ori, sizeof(*new));
>+
>+	/* reallocate individual reg-list pointers */
>+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+		new->reginfo[i].regs = NULL;
>+		new->reginfo[i].num = 0;
>+	}
>+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+		if (keep_reglist_mask & BIT(i)) {
>+			new->reginfo[i].regs = kcalloc(ori->reginfo[i].num,
>+						       sizeof(struct guc_mmio_reg), GFP_KERNEL);
>+			if (!new->reginfo[i].regs)
>+				goto bail_clone;
>+			memcpy(new->reginfo[i].regs, ori->reginfo[i].regs, ori->reginfo[i].num *
>+			       sizeof(struct guc_mmio_reg));
>+			new->reginfo[i].num = ori->reginfo[i].num;
>+		}
>+	}
>+
>+	return new;
>+
>+bail_clone:
>+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+		if (new->reginfo[i].regs)
>+			kfree(new->reginfo[i].regs);
>+	}
>+	kfree(new);
>+	return NULL;
>+}
>+
>+static int
>+guc_capture_extract_reglists(struct intel_guc *guc, struct __guc_capture_bufstate *buf)
>+{
>+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
>+	struct guc_state_capture_group_header_t ghdr = {0};
>+	struct guc_state_capture_header_t hdr = {0};
>+	struct __guc_capture_parsed_output *node = NULL;
>+	struct guc_mmio_reg *regs = NULL;
>+	int i, numlists, numreg, ret = 0;
>+	bool is_partial = false;
>+	enum guc_capture_type datatype;
>+
>+	i = guc_capture_buf_cnt(buf);
>+	if (!i)
>+		return -ENODATA;
>+	if (i % sizeof(u32)) {
>+		drm_warn(&i915->drm, "GuC Capture new entries unaligned\n");
>+		ret = -EIO;
>+		goto bailout;
>+	}
>+
>+	/* first get the capture group header */
>+	if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) {
>+		ret = -EIO;
>+		goto bailout;
>+	}
>+	/*
>+	 * we would typically expect a layout as below where n would be expected to be
>+	 * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine
>+	 * instances being reset together.
>+	 * ____________________________________________
>+	 * | Capture Group                            |
>+	 * | ________________________________________ |
>+	 * | | Capture Group Header:                | |
>+	 * | |  - num_captures = 5                  | |
>+	 * | |______________________________________| |
>+	 * | ________________________________________ |
>+	 * | | Capture1:                            | |
>+	 * | |  Hdr: GLOBAL, numregs=a              | |
>+	 * | | ____________________________________ | |
>+	 * | | | Reglist                          | | |
>+	 * | | | - reg1, reg2, ... rega           | | |
>+	 * | | |__________________________________| | |
>+	 * | |______________________________________| |
>+	 * | ________________________________________ |
>+	 * | | Capture2:                            | |
>+	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=b| |
>+	 * | | ____________________________________ | |
>+	 * | | | Reglist                          | | |
>+	 * | | | - reg1, reg2, ... regb           | | |
>+	 * | | |__________________________________| | |
>+	 * | |______________________________________| |
>+	 * | ________________________________________ |
>+	 * | | Capture3:                            | |
>+	 * | |  Hdr: INSTANCE=RCS, numregs=c        | |
>+	 * | | ____________________________________ | |
>+	 * | | | Reglist                          | | |
>+	 * | | | - reg1, reg2, ... regc           | | |
>+	 * | | |__________________________________| | |
>+	 * | |______________________________________| |
>+	 * | ________________________________________ |
>+	 * | | Capture4:                            | |
>+	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=d| |
>+	 * | | ____________________________________ | |
>+	 * | | | Reglist                          | | |
>+	 * | | | - reg1, reg2, ... regd           | | |
>+	 * | | |__________________________________| | |
>+	 * | |______________________________________| |
>+	 * | ________________________________________ |
>+	 * | | Capture5:                            | |
>+	 * | |  Hdr: INSTANCE=CCS0, numregs=e       | |
>+	 * | | ____________________________________ | |
>+	 * | | | Reglist                          | | |
>+	 * | | | - reg1, reg2, ... rege           | | |
>+	 * | | |__________________________________| | |
>+	 * | |______________________________________| |
>+	 * |__________________________________________|
>+	 */
>+	is_partial = FIELD_GET(CAP_GRP_HDR_CAPTURE_TYPE, ghdr.info);
>+	if (is_partial)
>+		drm_warn(&i915->drm, "GuC Capture group is partial\n");

I don't see a whole lot of value in warning of a partial capture group 
here. If you could print this information during log dump or if this is 
shared with the user in any way, that should be enough.

>+	numlists = FIELD_GET(CAP_GRP_HDR_NUM_CAPTURES, ghdr.info);
>+	while (numlists--) {
>+
>+		numreg = 0;
>+		regs = NULL;

The above 2 initializations are not needed as both are being initialized 
below.

>+		if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) {
>+			ret = -EIO;
>+			break;
>+		}
>+
>+		datatype = FIELD_GET(CAP_HDR_CAPTURE_TYPE, hdr.info);
>+		if (node) {
>+			/* Based on the current capture type and what we have so far,
>+			 * decide if we should add the current node into the internal
>+			 * linked list for match-up when i915_gpu_coredump calls later
>+			 * (and alloc a blank node for the next set of reglists)
>+			 * or continue with the same node or clone the current node
>+			 * but only retain the global or class registers (such as the
>+			 * case of dependent engine resets).
>+			 */
>+			if (datatype == GUC_CAPTURE_LIST_TYPE_GLOBAL) {
>+				guc_capture_add_node_to_list(guc, node);
>+				node = NULL;
>+			} else if (datatype == GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS &&
>+				   node->reginfo[GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS].regs) {
>+				/* Add to list, clone node and duplicate global list */
>+				guc_capture_add_node_to_list(guc, node);
>+				node = guc_capture_create_node(guc, node,
>+							       GCAP_PARSED_REGLIST_INDEX_GLOBAL);
>+			} else if (datatype == GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE &&
>+				   node->reginfo[GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE].regs) {
>+				/* Add to list, clone node and duplicate global + class lists */
>+				guc_capture_add_node_to_list(guc, node);
>+				node = guc_capture_create_node(guc, node,
>+							       (GCAP_PARSED_REGLIST_INDEX_GLOBAL |
>+							       GCAP_PARSED_REGLIST_INDEX_ENGCLASS));
>+			}
>+		}
>+
>+		if (!node) {
>+			node = guc_capture_create_node(guc, NULL, 0);
>+			if (!node) {
>+				ret = -ENOMEM;
>+				break;
>+			}
>+			if (datatype != GUC_CAPTURE_LIST_TYPE_GLOBAL)
>+				drm_dbg(&i915->drm, "GuC Capture missing global dump: %08x!\n",
>+					datatype);
>+		}
>+		node->is_partial = is_partial;
>+		switch (datatype) {
>+		case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
>+			node->eng_inst = FIELD_GET(CAP_HDR_ENGINE_INSTANCE, hdr.info);
>+			node->lrca = hdr.lrca;
>+			node->guc_id = hdr.guc_id;
>+			node->eng_class = FIELD_GET(CAP_HDR_ENGINE_CLASS, hdr.info);
>+			break;
>+		case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
>+			node->eng_class = FIELD_GET(CAP_HDR_ENGINE_CLASS, hdr.info);
>+			break;
>+		default:
>+			break;
>+		}
>+		regs = NULL;
>+		numreg = FIELD_GET(CAP_HDR_NUM_MMIOS, hdr.num_mmios);
>+		if (numreg) {
>+			regs = kcalloc(numreg, sizeof(*regs), GFP_KERNEL);
>+			if (!regs) {
>+				ret = -ENOMEM;
>+				break;
>+			}
>+		}
>+		node->reginfo[datatype].num = numreg;
>+		node->reginfo[datatype].regs = regs;
>+		node->reginfo[datatype].vfid = FIELD_GET(CAP_HDR_CAPTURE_VFID, hdr.info);
>+		i = 0;
>+		while (numreg--) {
>+			if (guc_capture_log_get_register(guc, buf, &regs[i++])) {
>+				ret = -EIO;
>+				break;
>+			}
>+		}
>+	}
>+
>+bailout:
>+	if (node) {
>+		/* If we have data, add to linked list for match-up when i915_gpu_coredump calls */
>+		for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+			if (node->reginfo[i].regs) {
>+				guc_capture_add_node_to_list(guc, node);
>+				node = NULL;
>+				break;
>+			}
>+		}
>+		if (node)
>+			kfree(node);
>+	}
>+	return ret;
>+}
>+
>+static void __guc_capture_store_snapshot_work(struct intel_guc *guc)
>+{
>+	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
>+	unsigned int buffer_size, read_offset, write_offset, full_count;
>+	struct guc_log_buffer_state *log_buf_state;
>+	struct guc_log_buffer_state log_buf_state_local;
>+	void *src_data = NULL;
>+	bool new_overflow;
>+	struct __guc_capture_bufstate buf;
>+	int ret;
>+
>+	/* Lock to get the pointer to GuC capture-log-buffer-state */
>+	mutex_lock(&guc->log_state[GUC_CAPTURE_LOG_BUFFER].lock);
>+	log_buf_state = guc->log.buf_addr +
>+			(sizeof(struct guc_log_buffer_state) * GUC_CAPTURE_LOG_BUFFER);
>+	src_data = guc->log.buf_addr + intel_guc_get_log_buffer_offset(GUC_CAPTURE_LOG_BUFFER);
>+
>+	/*
>+	 * Make a copy of the state structure, inside GuC log buffer
>+	 * (which is uncached mapped), on the stack to avoid reading
>+	 * from it multiple times.
>+	 */
>+	memcpy(&log_buf_state_local, log_buf_state, sizeof(struct guc_log_buffer_state));
>+	buffer_size = intel_guc_get_log_buffer_size(GUC_CAPTURE_LOG_BUFFER);
>+	read_offset = log_buf_state_local.read_ptr;
>+	write_offset = log_buf_state_local.sampled_write_ptr;
>+	full_count = log_buf_state_local.buffer_full_cnt;
>+
>+	/* Bookkeeping stuff */
>+	guc->log_state[GUC_CAPTURE_LOG_BUFFER].flush += log_buf_state_local.flush_to_file;
>+	new_overflow = intel_guc_check_log_buf_overflow(guc,
>+							&guc->log_state[GUC_CAPTURE_LOG_BUFFER],
>+							full_count);

I am not sure how the overflow logic works here and whether it is 
applicable to the error capture buffer. Is the guc log buffer one big 
buffer where the error capture is just a portion of that buffer? If so, 
is the wrap around applicable to just the errorcapture buffer or to the 
whole buffer?

Also what is the wrap_offset field in struct guc_log_buffer_state?

>+
>+	/* Now copy the actual logs. */
>+	if (unlikely(new_overflow)) {
>+		/* copy the whole buffer in case of overflow */
>+		read_offset = 0;
>+		write_offset = buffer_size;
>+	} else if (unlikely((read_offset > buffer_size) ||
>+			(write_offset > buffer_size))) {
>+		drm_err(&i915->drm, "invalid GuC log capture buffer state!\n");
>+		/* copy whole buffer as offsets are unreliable */
>+		read_offset = 0;
>+		write_offset = buffer_size;
>+	}
>+
>+	buf.size = buffer_size;
>+	buf.rd = read_offset;
>+	buf.wr = write_offset;
>+	buf.data = src_data;
>+	/*  */
>+	do {
>+		ret = guc_capture_extract_reglists(guc, &buf);
>+	} while (ret >= 0);
>+
>+	/* Update the state of shared log buffer */
>+	log_buf_state->read_ptr = write_offset;
>+	log_buf_state->flush_to_file = 0;
>+
>+	mutex_unlock(&guc->log_state[GUC_CAPTURE_LOG_BUFFER].lock);
>+}
>+
>+void intel_guc_capture_store_snapshot(struct intel_guc *guc)
>+{
>+	if (guc->capture.priv)
>+		__guc_capture_store_snapshot_work(guc);
>+}
>+
> void intel_guc_capture_destroy(struct intel_guc *guc)
> {
>+	if (!guc->capture.priv)
>+		return;
>+
>+	guc_capture_del_all_nodes(guc);
> 	guc_capture_clear_ext_regs(guc->capture.priv->reglists);
> 	kfree(guc->capture.priv);
> 	guc->capture.priv = NULL;
>@@ -710,7 +1225,7 @@ int intel_guc_capture_init(struct intel_guc *guc)
> 	guc->capture.priv = kzalloc(sizeof(*guc->capture.priv), GFP_KERNEL);
> 	if (!guc->capture.priv)
> 		return -ENOMEM;
>+	INIT_LIST_HEAD(&guc->capture.priv->outlist);
> 	guc->capture.priv->reglists = guc_capture_get_device_reglist(guc);
>-
> 	return 0;
> }
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>index 4d3e5221128c..c240a4cc046b 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.h
>@@ -14,6 +14,7 @@ struct guc_gt_system_info;
>
> int intel_guc_capture_prep_lists(struct intel_guc *guc, struct guc_ads *blob, u32 blob_ggtt,
> 				 u32 capture_offset, struct guc_gt_system_info *sysinfo);
>+void intel_guc_capture_store_snapshot(struct intel_guc *guc);
> int intel_guc_capture_output_min_size_est(struct intel_guc *guc);
> void intel_guc_capture_destroy(struct intel_guc *guc);
> int intel_guc_capture_init(struct intel_guc *guc);
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
>index d6b1a3c0fb15..194b17e8c2ae 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
>@@ -157,9 +157,9 @@ static void *guc_get_write_buffer(struct intel_guc_log *log)
> 	return relay_reserve(log->relay.channel, 0);
> }
>
>-static bool guc_check_log_buf_overflow(struct intel_guc *guc,
>-				       struct intel_guc_log_stats *log_state,
>-				       unsigned int full_cnt)
>+bool intel_guc_check_log_buf_overflow(struct intel_guc *guc,
>+				      struct intel_guc_log_stats *log_state,
>+				      unsigned int full_cnt)
> {
> 	unsigned int prev_full_cnt = log_state->sampled_overflow;
> 	bool overflow = false;
>@@ -182,7 +182,7 @@ static bool guc_check_log_buf_overflow(struct intel_guc *guc,
> 	return overflow;
> }
>
>-static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
>+unsigned int intel_guc_get_log_buffer_size(enum guc_log_buffer_type type)
> {
> 	switch (type) {
> 	case GUC_DEBUG_LOG_BUFFER:
>@@ -198,6 +198,20 @@ static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type)
> 	return 0;
> }
>
>+size_t intel_guc_get_log_buffer_offset(enum guc_log_buffer_type type)
>+{
>+	enum guc_log_buffer_type i;
>+	size_t offset = PAGE_SIZE;/* for the log_buffer_states */
>+
>+	for (i = GUC_DEBUG_LOG_BUFFER; i < GUC_MAX_LOG_BUFFER; i++) {
>+		if (i == type)
>+			break;
>+		offset += intel_guc_get_log_buffer_size(i);
>+	}
>+
>+	return offset;
>+}
>+
> static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
> {
> 	struct intel_guc *guc = log_to_guc(log);
>@@ -247,14 +261,14 @@ static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
> 		mutex_lock(&logstate->lock);
> 		memcpy(&log_buf_state_local, log_buf_state,
> 		       sizeof(struct guc_log_buffer_state));
>-		buffer_size = guc_get_log_buffer_size(type);
>+		buffer_size = intel_guc_get_log_buffer_size(type);
> 		read_offset = log_buf_state_local.read_ptr;
> 		write_offset = log_buf_state_local.sampled_write_ptr;
> 		full_cnt = log_buf_state_local.buffer_full_cnt;
>
> 		/* Bookkeeping stuff */
> 		logstate->flush += log_buf_state_local.flush_to_file;
>-		new_overflow = guc_check_log_buf_overflow(guc, logstate, full_cnt);
>+		new_overflow = intel_guc_check_log_buf_overflow(guc, logstate, full_cnt);
>
> 		/* Update the state of shared log buffer */
> 		log_buf_state->read_ptr = write_offset;
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
>index b6e8e9ee37b7..f16de816447d 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.h
>@@ -68,6 +68,10 @@ struct intel_guc_log {
> };
>
> void intel_guc_log_init_early(struct intel_guc_log *log);
>+bool intel_guc_check_log_buf_overflow(struct intel_guc *guc, struct intel_guc_log_stats *state,
>+				      unsigned int full_cnt);
>+unsigned int intel_guc_get_log_buffer_size(enum guc_log_buffer_type type);
>+size_t intel_guc_get_log_buffer_offset(enum guc_log_buffer_type type);
> int intel_guc_log_create(struct intel_guc_log *log);
> void intel_guc_log_destroy(struct intel_guc_log *log);
>
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
>index db9615dcb0ec..c19d6d682394 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
>@@ -24,6 +24,7 @@
> #include "gt/intel_ring.h"
>
> #include "intel_guc_ads.h"
>+#include "intel_guc_capture.h"
> #include "intel_guc_submission.h"
>
> #include "i915_drv.h"
>@@ -1444,6 +1445,8 @@ void intel_guc_submission_reset_prepare(struct intel_guc *guc)
> 	flush_work(&guc->ct.requests.worker);
>
> 	scrub_guc_desc_for_outstanding_g2h(guc);
>+
>+	intel_guc_capture_store_snapshot(guc);
> }
>
> static struct intel_engine_cs *
>@@ -4016,17 +4019,20 @@ int intel_guc_context_reset_process_msg(struct intel_guc *guc,
> int intel_guc_error_capture_process_msg(struct intel_guc *guc,
> 					const u32 *msg, u32 len)
> {
>-	int status;
>+	u32 status;
>
> 	if (unlikely(len != 1)) {
> 		drm_dbg(&guc_to_gt(guc)->i915->drm, "Invalid length %u", len);
> 		return -EPROTO;
> 	}
>
>-	status = msg[0];
>-	drm_info(&guc_to_gt(guc)->i915->drm, "Got error capture: status = %d", status);
>+	status = msg[0] & INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK;

The interface is clearly defining valid values as 0 or 1, so we can drop 
the mask here and return/log an error if msg[0] is invalid.

>+	if (status == INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE)
>+		drm_warn(&guc_to_gt(guc)->i915->drm, "G2H-Error capture no space");
>+	else
>+		drm_info(&guc_to_gt(guc)->i915->drm, "G2H-Received error capture");

Considering you return an error for an invalid value above, you may drop 
the else part.

Regards,
Umesh

>
>-	/* FIXME: Do something with the capture */
>+	intel_guc_capture_store_snapshot(guc);
>
> 	return 0;
> }
>-- 
>2.25.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 08/10] drm/i915/guc: Plumb GuC-capture into gpu_coredump
  2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 08/10] drm/i915/guc: Plumb GuC-capture into gpu_coredump Alan Previn
@ 2022-02-11  2:11   ` Umesh Nerlige Ramappa
  2022-02-12  0:31     ` Teres Alexis, Alan Previn
  2022-02-12  0:38     ` Teres Alexis, Alan Previn
  0 siblings, 2 replies; 52+ messages in thread
From: Umesh Nerlige Ramappa @ 2022-02-11  2:11 UTC (permalink / raw)
  To: Alan Previn; +Cc: intel-gfx

On Wed, Jan 26, 2022 at 02:48:20AM -0800, Alan Previn wrote:
>Add a flags parameter through all of the coredump creation
>functions. Add a bitmask flag to indicate if the top
>level gpu_coredump event is triggered in response to
>a GuC context reset notification.
>
>Using that flag, ensure all coredump functions that
>read or print mmio-register values related to work submission
>or command-streamer engines are skipped and replaced with
>a calls guc-capture module equivalent functions to retrieve
>or print the register dump.
>
>While here, split out display related register reading
>and printing into its own function that is called agnostic
>to whether GuC had triggered the reset.
>
>For now, introduce an empty printing function that can
>filled in on a subsequent patch just to handle formatting.
>
>Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
>---
> .../drm/i915/gt/intel_execlists_submission.c  |   4 +-
> drivers/gpu/drm/i915/gt/intel_reset.c         |   2 +-
> .../gpu/drm/i915/gt/uc/intel_guc_capture.c    |  78 ++++++
> .../gpu/drm/i915/gt/uc/intel_guc_capture.h    |  11 +-
> .../gpu/drm/i915/gt/uc/intel_guc_submission.c |   2 +-
> drivers/gpu/drm/i915/i915_debugfs.c           |   2 +-
> drivers/gpu/drm/i915/i915_gpu_error.c         | 263 ++++++++++++------
> drivers/gpu/drm/i915/i915_gpu_error.h         |  31 ++-
> 8 files changed, 295 insertions(+), 98 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
>index 960a9aaf4f3a..c8bb43863461 100644
>--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
>+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
>@@ -2230,11 +2230,11 @@ static struct execlists_capture *capture_regs(struct intel_engine_cs *engine)
> 	if (!cap->error)
> 		goto err_cap;
>
>-	cap->error->gt = intel_gt_coredump_alloc(engine->gt, gfp);
>+	cap->error->gt = intel_gt_coredump_alloc(engine->gt, gfp, CORE_DUMP_FLAG_NONE);
> 	if (!cap->error->gt)
> 		goto err_gpu;
>
>-	cap->error->gt->engine = intel_engine_coredump_alloc(engine, gfp);
>+	cap->error->gt->engine = intel_engine_coredump_alloc(engine, gfp, CORE_DUMP_FLAG_NONE);
> 	if (!cap->error->gt->engine)
> 		goto err_gt;
>
>diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
>index 6f2821cca409..c1dc3f8b1108 100644
>--- a/drivers/gpu/drm/i915/gt/intel_reset.c
>+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
>@@ -1305,7 +1305,7 @@ void intel_gt_handle_error(struct intel_gt *gt,
> 	engine_mask &= gt->info.engine_mask;
>
> 	if (flags & I915_ERROR_CAPTURE) {
>-		i915_capture_error_state(gt, engine_mask);
>+		i915_capture_error_state(gt, engine_mask, CORE_DUMP_FLAG_NONE);
> 		intel_gt_clear_error_registers(gt, engine_mask);
> 	}
>
>diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>index 0b6d743712a6..2f5dc413dddc 100644
>--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
>@@ -728,6 +728,17 @@ int intel_guc_capture_output_min_size_est(struct intel_guc *guc)
>  *                   instance). This node id added to a linked list stored in
>  *                   guc->capture->priv for matchup and printout when triggered by
>  *                   i915_gpu_coredump and err_print_gt (via error capture sysfs) later.
>+ *
>+ * GUC --> notify context reset:
>+ * -----------------------------
>+ *     --> G2H CONTEXT RESET
>+ *                   L--> guc_handle_context_reset --> i915_capture_error_state
>+ *                          L--> i915_gpu_coredump(..IS_GUC_CAPTURE) --> gt_record_engines
>+ *                               --> capture_engine(..IS_GUC_CAPTURE)
>+ *                                  L--> detach C from internal linked list and add into
>+ *                                       intel_engine_coredump struct (if the context and
>+ *                                       engine of the event notification matches a node
>+ *                                       in the link list)
>  */
>
> static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
>@@ -1203,6 +1214,73 @@ static void __guc_capture_store_snapshot_work(struct intel_guc *guc)
> 	mutex_unlock(&guc->log_state[GUC_CAPTURE_LOG_BUFFER].lock);
> }
>
>+#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
>+
>+int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
>+					const struct intel_engine_coredump *ee)
>+{
>+	return 0;

What goes here? Also return value is not used.

>+}
>+
>+#endif //CONFIG_DRM_I915_DEBUG_GUC
>+
>+void intel_guc_capture_free_node(struct intel_engine_coredump *ee)
>+{
>+	int i;
>+
>+	if (!ee)
>+		return;
>+	if (!ee->guc_capture_node)
>+		return;

if (!ee || !ee->guc_capture_node) ^

>+	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {
>+		if (ee->guc_capture_node->reginfo[i].regs)
>+			kfree(ee->guc_capture_node->reginfo[i].regs);
>+	}
>+	kfree(ee->guc_capture_node);
>+	ee->guc_capture_node = NULL;
>+}
>+
>+void intel_guc_capture_get_matching_node(struct intel_gt *gt,
>+					 struct intel_engine_coredump *ee,
>+					 struct intel_context *ce)
>+{
>+	struct intel_guc *guc;
>+	struct drm_i915_private *i915;
>+
>+	if (!gt || !ee || !ce)
>+		return;
>+
>+	i915 = gt->i915;
>+	guc = &gt->uc.guc;
>+	if (!guc->capture.priv)
>+		return;
>+
>+	GEM_BUG_ON(ee->guc_capture_node);
>+	/*
>+	 * Look for a matching GuC reported error capture node from
>+	 * the internal output link-list based on lrca, guc-id and engine
>+	 * identification.
>+	 */
>+	if (!list_empty(&guc->capture.priv->outlist)) {

You would just not execute anything in the loop below if empty, so no 
need to check for empty.

>+		struct __guc_capture_parsed_output *n, *ntmp;
>+
>+		list_for_each_entry_safe(n, ntmp, &guc->capture.priv->outlist, link) {
>+			if (n->eng_inst == GUC_ID_TO_ENGINE_INSTANCE(ee->engine->guc_id) &&
>+			    n->eng_class == GUC_ID_TO_ENGINE_CLASS(ee->engine->guc_id) &&
>+			    n->guc_id == ce->guc_id.id &&
>+			    (n->lrca & CTX_GTT_ADDRESS_MASK) ==
>+			    (ce->lrc.lrca & CTX_GTT_ADDRESS_MASK)) {
>+				list_del(&n->link);
>+				--guc->capture.priv->listcount;
>+				ee->guc_capture_node = n;
>+				ee->capture = &guc->capture;
>+				return;
>+			}
>+		}
>+	}
>+	drm_warn(&i915->drm, "GuC capture can't match ee to node\n");
>+}

lgtm. In general the implementation differences between submission 
backends (guc vs execlists) need to be vfuncs so we can avoid having to 
use the flags and conditions. Regardless, with the above comments 
addressed, this is:

Reviewed-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>

Umesh

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 03/10] drm/i915/guc: Add DG2 registers for GuC error state capture.
  2022-02-05  1:28   ` Umesh Nerlige Ramappa
  2022-02-10  5:17     ` Teres Alexis, Alan Previn
@ 2022-02-11 19:24     ` Teres Alexis, Alan Previn
  1 sibling, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-11 19:24 UTC (permalink / raw)
  To: Nerlige Ramappa, Umesh; +Cc: intel-gfx

On this specific question.

On Fri, 2022-02-04 at 17:28 -0800, Umesh Nerlige Ramappa wrote:
> On Wed, Jan 26, 2022 at 02:48:15AM -0800, Alan Previn wrote:
> > Add additional DG2 registers for GuC error state capture.
> > 
> > +	num_steer_regs = ARRAY_SIZE(xelpd_extregs);
> > +	if (ipver >= IP_VER(12, 55))
> 
> 
> What does this actually mean? 12 55 has both lpd and hpg regs?
Yes - at least for the current platforms we are addressing in
this function - but i will split them so these checks would be
removed from here 

> 
> You could (if possible) use has_lpd_regs/has_hpg_regs in i915_pci.c to 
> simplify the platform specific logic.
> 
I will check those if if we can be be used here.

> > 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 08/10] drm/i915/guc: Plumb GuC-capture into gpu_coredump
  2022-02-11  2:11   ` Umesh Nerlige Ramappa
@ 2022-02-12  0:31     ` Teres Alexis, Alan Previn
  2022-02-12  0:38     ` Teres Alexis, Alan Previn
  1 sibling, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-12  0:31 UTC (permalink / raw)
  To: Nerlige Ramappa, Umesh; +Cc: intel-gfx

Thanks Umesh for reviewing this for me and for the R-v-b.

Responding on one comment below

On Thu, 2022-02-10 at 18:11 -0800, Umesh Nerlige Ramappa wrote:
> On Wed, Jan 26, 2022 at 02:48:20AM -0800, Alan Previn wrote:
> > Add a flags parameter through all of the coredump creation
> > functions. Add a bitmask flag to indicate if the top
> > level gpu_coredump event is triggered in response to
> > a GuC context reset notification.
> > 
> > lgtm. In general the implementation differences between submission 
> backends (guc vs execlists) need to be vfuncs so we can avoid having to 
> use the flags and conditions. Regardless, with the above comments 
> addressed, this is:
> 

I do agree its much cleaner and consistent with other engine related
vfuncs that differentiate guc vs execlist however, in the case of the
gpu coredump operation, we can have cases where GuC submission is enabled
but the capture_engine function may have been triggered NOT by GuC.
Consider the following scenarios:
1. A context was reset by the GuC as per the context-level execution
   quanta + preemption timeout... OR... a context failure caught
   by HW and routed to GuC.
2. If the user had started i915 with modparam reset == 1 and hangcheck
   enabled, but the context was executed with an infinite execution
   quanta, then heartbeat could trigger a full GT reset and capture
   all engine states despite having GuC submission and in this case,
   we do want manual HW register dumps by i915 and not rely on GuC.

That said, for now, with the existing gpu_coredump framework that,
idea may not work.

> Reviewed-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
> 
> Umesh


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 08/10] drm/i915/guc: Plumb GuC-capture into gpu_coredump
  2022-02-11  2:11   ` Umesh Nerlige Ramappa
  2022-02-12  0:31     ` Teres Alexis, Alan Previn
@ 2022-02-12  0:38     ` Teres Alexis, Alan Previn
  1 sibling, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-12  0:38 UTC (permalink / raw)
  To: Nerlige Ramappa, Umesh; +Cc: intel-gfx


On Thu, 2022-02-10 at 18:11 -0800, Umesh Nerlige Ramappa wrote:
> On Wed, Jan 26, 2022 at 02:48:20AM -0800, Alan Previn wrote:
> > Add a flags parameter through all of the coredump creation
> > functions. Add a bitmask flag to indicate if the top
> > level gpu_coredump event is triggered in response to
> > a GuC context reset notification.
> > 
> > Using that flag, ensure all coredump functions that
> > read or print mmio-register values related to work submission
> > or command-streamer engines are skipped and replaced with
> > a calls guc-capture module equivalent functions to retrieve
> > or print the register dump.
> > 
> > While here, split out display related register reading
> > and printing into its own function that is called agnostic
> > to whether GuC had triggered the reset.
> > 
> > For now, introduce an empty printing function that can
> > filled in on a subsequent patch just to handle formatting.
> > 
> > Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com>
> > +#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
> > +
> > +int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
> > +					const struct intel_engine_coredump *ee)
> > +{
> > +	return 0;
> 
> What goes here? Also return value is not used.
> 
This was explained in the commit message, i wanted to keep all of the
plumbing touch points in this patch and handle just the straigt up
printing on a separate patch. 

thanks again.
> > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 07/10] drm/i915/guc: Extract GuC error capture lists on G2H notification.
  2022-02-11  1:36   ` Umesh Nerlige Ramappa
@ 2022-02-13 19:47     ` Teres Alexis, Alan Previn
  2022-02-17 19:21       ` Umesh Nerlige Ramappa
  0 siblings, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-13 19:47 UTC (permalink / raw)
  To: Nerlige Ramappa, Umesh; +Cc: intel-gfx

Thanks Umesh for reviewing the patch.
Am fixing all the rest but a couple of comments.
Responses to the latter and other questions below:

...alan

> > +enum intel_guc_state_capture_event_status {
> > +	INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_SUCCESS = 0x0,
> > +	INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE = 0x1,
> > +};
> > +
> > +#define INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK      0x1
> 
> MASK is not needed. See below

Alan: Oh wait, actually the mask for the capture status is 0x000000FF
(above is a typo). I'll fix above  mask and shall not change the 
code below because the upper 24 bits of the first dword of this msg 
is not defined.

...


> > +static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
> > +{
> > +	if (buf->rd == buf->wr)
> > +		return 0;
> > +	if (buf->wr > buf->rd)
> > +		return (buf->wr - buf->rd);
> > +	return (buf->size - buf->rd) + buf->wr;
> > +}
> 
> Is this a circular buffer shared between GuC and kmd? Since the size is 
> a power of 2, the above function is simply:
> 
Alan: not this is not a circular buffer, so I'll keep the above
version.
> static u32 guc_capture_buf_count(struct __guc_capture_bufstate *buf)
> {
> 	return (buf->wr - buf->rd) & (buf->size - 1);
> }
> 

...

> > +static int
> > +guc_capture_log_remove_dw(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
> > +			  u32 *dw)
> > +{
> > +	struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
> > +	int tries = 2;
> > +	int avail = 0;
> > +	u32 *src_data;
> > +
> > +	if (!guc_capture_buf_cnt(buf))
> > +		return 0;
> > +
> > +	while (tries--) {
> > +		avail = guc_capture_buf_cnt_to_end(buf);
> 
> Shouldn't this be avail = guc_capture_buf_cnt(buf)?
> 

Alan : The "guc_capture_log_get_[foo]" functions only call above
guc_capture_log_remove_dw when there isnt sufficient space to
copy out an entire structure from the space between the read pointer
and the end of the subregion (before the wrap-around). Those function
would populate the structure dword by dword by calling above func.
(NOTE the buffer and all error capture output structs are dword
aligned). Thats why above function tries twice and resets buf->rd = 0
if we find no space left at the end of the subregion (i.e. need to
wrap around) - which can only be done by calling
"guc_capture_buf_cnt_to_end".

...

> > +
> > +	/* Bookkeeping stuff */
> > +	guc->log_state[GUC_CAPTURE_LOG_BUFFER].flush += log_buf_state_local.flush_to_file;
> > +	new_overflow = intel_guc_check_log_buf_overflow(guc,
> > +							&guc->log_state[GUC_CAPTURE_LOG_BUFFER],
> > +							full_count);
> 
> I am not sure how the overflow logic works here and whether it is 
> applicable to the error capture buffer. Is the guc log buffer one big 
> buffer where the error capture is just a portion of that buffer? If so, 
> is the wrap around applicable to just the errorcapture buffer or to the 
> whole buffer?
> 
Alan: Yes, the guc log buffer is one big log buffer but there are 3 independent
subregions within that are populated with different content and are used
in different ways and timings. Each guc-log subregion (general-logs,
crash-dump and error-capture) has it's own read and write pointers.


> Also what is the wrap_offset field in struct guc_log_buffer_state?

Alan: This is the byte offset of a location in the subregion that is the 1st byte
after the last valid guc entry written by Guc firmware before a wraparound
was done. This would generate a tiny hole at the end of the subregion for better
cacheline alignment when flushing entries into the subregion. However,
the error-capture subregion is dword aligned and all of the output structures
used for error-capture are also dword aligned so this can never happen for the
error-capture subregion.


> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-09  3:51             ` Teres Alexis, Alan Previn
@ 2022-02-14 19:20               ` Teres Alexis, Alan Previn
  2022-02-15  1:22                 ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-14 19:20 UTC (permalink / raw)
  To: Brost, Matthew; +Cc: intel-gfx

Matt, just a final confirmation on below

> > > > > 
> > > > > On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> > > > > > On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > > > > > > 
> > If the object lives at the GuC level, operate on it at the GuC level.
> > 
> > e.g.
> > intel_guc_log_init_early calls mutex init on guc->log_state - that is
> > wrong and breaks the layering. intel_guc_log_init_early should only
> > operate on guc_log or below objects, not above it.
> > 
> > The key here is consisteny, if the GuC level owns the object it should
> > be initialized there + passed into the lower levels if possible. The
> > lower levels should avoid reaching back to GuC level for objects
> > whenever possible.
> > 
> > You could have 2 intel_guc_log_stats objects below the guc_log object
> > and 1 intel_guc_log_stats object for capture at the GuC level. That's
> > likely the right approach here.
> 
> Thanks Matt - I'm in agreement... I was concerned about too much of
> change - but you're right, I should be focusing on the design consistency.
> Above sounds like the correct design (these stats and locks should belong
> to their sole user).
> 
> ...alan
> 

So this means:
1. guc[upper] allocates the shared-logging-buffer
   - but would ask the lower level components for the sizes before
     buffering-up or capping-down to match interface spec.
2. guc-log and guc-error-capture requests guc for a vmap at their init.
3. guc-log and guc-error-capture owns independent log-stats and
   (and separate locks if needed).
4. when lower level components are done, they relinquish access to
   their region by requesting guc[upper] to unmap and free

A super clean separation like above could mean ripping apart enums
and other #defines to split them across guc_log and guc_error_capture
headers (such as region sizes).

I believe that separation complicates the understanding of the fw interface
for logging as we break that picture into independant files / components.
For now I want to keep guc[upper] aware of the individual sub-region
allocation requirements (no ripping apart of enums but moving them around)
but only keep the requesting of vmap and independant log-region-stats
within the lower level?

Are you okay with this?

side note: error-capture no longer need locks after the recent G2H triggered
linked-list extraction redesign.



^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture.
  2022-02-14 19:20               ` Teres Alexis, Alan Previn
@ 2022-02-15  1:22                 ` Teres Alexis, Alan Previn
  0 siblings, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-15  1:22 UTC (permalink / raw)
  To: Brost, Matthew; +Cc: intel-gfx

Looks like trying to move the vma up into guc-upper is impacting many other functions
in intel_guc_log and intel_guc_log_debugfs. I'll have to take it back (the level of
redesign i shall attempt with this series).

I'll just move the log_stats back into intel_guc_log and have intel_guc_capture
have its own stats structure - but keep the VMA allocation of this shared buffer in
intel_guc_log (like it was in the prior revs) and have intel_guc_capture "reach across"
into intel_guc_log to get the vma ptr (like it was in the prior revs).

...alan


On Mon, 2022-02-14 at 11:22 -0800, Alan Previn Teres Alexis wrote:
> Matt, just a final confirmation on below
> 
> > > > > > On Fri, 2022-02-04 at 10:19 -0800, Matthew Brost wrote:
> > > > > > > On Wed, Jan 26, 2022 at 02:48:18AM -0800, Alan Previn wrote:
> > > If the object lives at the GuC level, operate on it at the GuC level.
> > > 
> > > e.g.
> > > intel_guc_log_init_early calls mutex init on guc->log_state - that is
> > > wrong and breaks the layering. intel_guc_log_init_early should only
> > > operate on guc_log or below objects, not above it.
> > > 
> > > The key here is consisteny, if the GuC level owns the object it should
> > > be initialized there + passed into the lower levels if possible. The
> > > lower levels should avoid reaching back to GuC level for objects
> > > whenever possible.
> > > 
> > > You could have 2 intel_guc_log_stats objects below the guc_log object
> > > and 1 intel_guc_log_stats object for capture at the GuC level. That's
> > > likely the right approach here.
> > 
> > Thanks Matt - I'm in agreement... I was concerned about too much of
> > change - but you're right, I should be focusing on the design consistency.
> > Above sounds like the correct design (these stats and locks should belong
> > to their sole user).
> > 
> > ...alan
> > 
> 
> So this means:
> 1. guc[upper] allocates the shared-logging-buffer
>    - but would ask the lower level components for the sizes before
>      buffering-up or capping-down to match interface spec.
> 2. guc-log and guc-error-capture requests guc for a vmap at their init.
> 3. guc-log and guc-error-capture owns independent log-stats and
>    (and separate locks if needed).
> 4. when lower level components are done, they relinquish access to
>    their region by requesting guc[upper] to unmap and free
> 
> A super clean separation like above could mean ripping apart enums
> and other #defines to split them across guc_log and guc_error_capture
> headers (such as region sizes).
> 
> I believe that separation complicates the understanding of the fw interface
> for logging as we break that picture into independant files / components.
> For now I want to keep guc[upper] aware of the individual sub-region
> allocation requirements (no ripping apart of enums but moving them around)
> but only keep the requesting of vmap and independant log-region-stats
> within the lower level?
> 
> Are you okay with this?
> 
> side note: error-capture no longer need locks after the recent G2H triggered
> linked-list extraction redesign.
> 
> 


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 07/10] drm/i915/guc: Extract GuC error capture lists on G2H notification.
  2022-02-13 19:47     ` Teres Alexis, Alan Previn
@ 2022-02-17 19:21       ` Umesh Nerlige Ramappa
  2022-02-25  7:21         ` Teres Alexis, Alan Previn
  0 siblings, 1 reply; 52+ messages in thread
From: Umesh Nerlige Ramappa @ 2022-02-17 19:21 UTC (permalink / raw)
  To: Teres Alexis, Alan Previn; +Cc: intel-gfx

On Sun, Feb 13, 2022 at 11:47:00AM -0800, Teres Alexis, Alan Previn wrote:
>Thanks Umesh for reviewing the patch.
>Am fixing all the rest but a couple of comments.
>Responses to the latter and other questions below:
>
>...alan
>
>> > +enum intel_guc_state_capture_event_status {
>> > +   INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_SUCCESS = 0x0,
>> > +   INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE = 0x1,
>> > +};
>> > +
>> > +#define INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK      0x1
>>
>> MASK is not needed. See below
>
>Alan: Oh wait, actually the mask for the capture status is 0x000000FF
>(above is a typo). I'll fix above  mask and shall not change the
>code below because the upper 24 bits of the first dword of this msg
>is not defined.
>
>...
>
>
>> > +static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
>> > +{
>> > +   if (buf->rd == buf->wr)
>> > +           return 0;
>> > +   if (buf->wr > buf->rd)
>> > +           return (buf->wr - buf->rd);
>> > +   return (buf->size - buf->rd) + buf->wr;
>> > +}
>>
>> Is this a circular buffer shared between GuC and kmd? Since the size is
>> a power of 2, the above function is simply:
>>
>Alan: not this is not a circular buffer, so I'll keep the above
>version.
>> static u32 guc_capture_buf_count(struct __guc_capture_bufstate *buf)
>> {
>>       return (buf->wr - buf->rd) & (buf->size - 1);
>> }
>>
>
>...
>
>> > +static int
>> > +guc_capture_log_remove_dw(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
>> > +                     u32 *dw)
>> > +{
>> > +   struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
>> > +   int tries = 2;
>> > +   int avail = 0;
>> > +   u32 *src_data;
>> > +
>> > +   if (!guc_capture_buf_cnt(buf))
>> > +           return 0;
>> > +
>> > +   while (tries--) {
>> > +           avail = guc_capture_buf_cnt_to_end(buf);
>>
>> Shouldn't this be avail = guc_capture_buf_cnt(buf)?
>>
>
>Alan : The "guc_capture_log_get_[foo]" functions only call above
>guc_capture_log_remove_dw when there isnt sufficient space to
>copy out an entire structure from the space between the read pointer
>and the end of the subregion (before the wrap-around). Those function
>would populate the structure dword by dword by calling above func.
>(NOTE the buffer and all error capture output structs are dword
>aligned). Thats why above function tries twice and resets buf->rd = 0
>if we find no space left at the end of the subregion (i.e. need to
>wrap around) - which can only be done by calling
>"guc_capture_buf_cnt_to_end".
>
>...
>
>> > +
>> > +   /* Bookkeeping stuff */
>> > +   guc->log_state[GUC_CAPTURE_LOG_BUFFER].flush += log_buf_state_local.flush_to_file;
>> > +   new_overflow = intel_guc_check_log_buf_overflow(guc,
>> > +                                                   &guc->log_state[GUC_CAPTURE_LOG_BUFFER],
>> > +                                                   full_count);
>>
>> I am not sure how the overflow logic works here and whether it is
>> applicable to the error capture buffer. Is the guc log buffer one big
>> buffer where the error capture is just a portion of that buffer? If so,
>> is the wrap around applicable to just the errorcapture buffer or to the
>> whole buffer?
>>
>Alan: Yes, the guc log buffer is one big log buffer but there are 3 independent
>subregions within that are populated with different content and are used
>in different ways and timings. Each guc-log subregion (general-logs,
>crash-dump and error-capture) has it's own read and write pointers.

got it. I would also put this one detail in the commit message since 
it's not quickly inferred.

>
>
>> Also what is the wrap_offset field in struct guc_log_buffer_state?
>
>Alan: This is the byte offset of a location in the subregion that is the 1st byte
>after the last valid guc entry written by Guc firmware before a wraparound
>was done. This would generate a tiny hole at the end of the subregion for better
>cacheline alignment when flushing entries into the subregion. However,
>the error-capture subregion is dword aligned and all of the output structures
>used for error-capture are also dword aligned so this can never happen for the
>error-capture subregion.
>
Makes sense, thanks for clarifying.

Umesh
>
>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [Intel-gfx] [PATCH v5 07/10] drm/i915/guc: Extract GuC error capture lists on G2H notification.
  2022-02-17 19:21       ` Umesh Nerlige Ramappa
@ 2022-02-25  7:21         ` Teres Alexis, Alan Previn
  0 siblings, 0 replies; 52+ messages in thread
From: Teres Alexis, Alan Previn @ 2022-02-25  7:21 UTC (permalink / raw)
  To: intel-gfx

Folks, a brief update: over the last few weeks of internal reviews,
testing and debug, another redesign has been implemented for this
patch (the extraction of error capture information). When
experiencing back to back error capture notifications (as part of
multiple dependent engine resets), if a forced full GT reset comes
in at the same time (from either the heartbeat or the user forced
reset debugfs or the igt_core cleanup) GT reset code takes the reset
lock and later calls guc_submission_reset_prepare. This function
flushes the ct processing worker queue for handling G2H events.
intel_guc_capture gets called to extract new error capture data from
the guc-log buffer but is actually in the midst of a reset ..
this causes lockdep issues (the memory shrinker vs reset locks).
Checking for uc->reset_in_progress is racy. That said, the
extraction code (this patch) needs to be modified to never allocate
memory for the output 'engine-instance-capture' node. Redesign is
complete where a pool of blank nodes are allocated up front and
re-used through the life of the driver. That will be part of the
next rev.

..alan

On 2/17/2022 11:21 AM, Umesh Nerlige Ramappa wrote:
> On Sun, Feb 13, 2022 at 11:47:00AM -0800, Teres Alexis, Alan Previn 
> wrote:
>> Thanks Umesh for reviewing the patch.
>> Am fixing all the rest but a couple of comments.
>> Responses to the latter and other questions below:
>>
>> ...alan
>>
>>> > +enum intel_guc_state_capture_event_status {
>>> > +   INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_SUCCESS = 0x0,
>>> > +   INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE = 0x1,
>>> > +};
>>> > +
>>> > +#define INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK 0x1
>>>
>>> MASK is not needed. See below
>>
>> Alan: Oh wait, actually the mask for the capture status is 0x000000FF
>> (above is a typo). I'll fix above  mask and shall not change the
>> code below because the upper 24 bits of the first dword of this msg
>> is not defined.
>>
>> ...
>>
>>
>>> > +static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
>>> > +{
>>> > +   if (buf->rd == buf->wr)
>>> > +           return 0;
>>> > +   if (buf->wr > buf->rd)
>>> > +           return (buf->wr - buf->rd);
>>> > +   return (buf->size - buf->rd) + buf->wr;
>>> > +}
>>>
>>> Is this a circular buffer shared between GuC and kmd? Since the size is
>>> a power of 2, the above function is simply:
>>>
>> Alan: not this is not a circular buffer, so I'll keep the above
>> version.
>>> static u32 guc_capture_buf_count(struct __guc_capture_bufstate *buf)
>>> {
>>>       return (buf->wr - buf->rd) & (buf->size - 1);
>>> }
>>>
>>
>> ...
>>
>>> > +static int
>>> > +guc_capture_log_remove_dw(struct intel_guc *guc, struct 
>>> __guc_capture_bufstate *buf,
>>> > +                     u32 *dw)
>>> > +{
>>> > +   struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
>>> > +   int tries = 2;
>>> > +   int avail = 0;
>>> > +   u32 *src_data;
>>> > +
>>> > +   if (!guc_capture_buf_cnt(buf))
>>> > +           return 0;
>>> > +
>>> > +   while (tries--) {
>>> > +           avail = guc_capture_buf_cnt_to_end(buf);
>>>
>>> Shouldn't this be avail = guc_capture_buf_cnt(buf)?
>>>
>>
>> Alan : The "guc_capture_log_get_[foo]" functions only call above
>> guc_capture_log_remove_dw when there isnt sufficient space to
>> copy out an entire structure from the space between the read pointer
>> and the end of the subregion (before the wrap-around). Those function
>> would populate the structure dword by dword by calling above func.
>> (NOTE the buffer and all error capture output structs are dword
>> aligned). Thats why above function tries twice and resets buf->rd = 0
>> if we find no space left at the end of the subregion (i.e. need to
>> wrap around) - which can only be done by calling
>> "guc_capture_buf_cnt_to_end".
>>
>> ...
>>
>>> > +
>>> > +   /* Bookkeeping stuff */
>>> > +   guc->log_state[GUC_CAPTURE_LOG_BUFFER].flush += 
>>> log_buf_state_local.flush_to_file;
>>> > +   new_overflow = intel_guc_check_log_buf_overflow(guc,
>>> > + &guc->log_state[GUC_CAPTURE_LOG_BUFFER],
>>> > + full_count);
>>>
>>> I am not sure how the overflow logic works here and whether it is
>>> applicable to the error capture buffer. Is the guc log buffer one big
>>> buffer where the error capture is just a portion of that buffer? If so,
>>> is the wrap around applicable to just the errorcapture buffer or to the
>>> whole buffer?
>>>
>> Alan: Yes, the guc log buffer is one big log buffer but there are 3 
>> independent
>> subregions within that are populated with different content and are used
>> in different ways and timings. Each guc-log subregion (general-logs,
>> crash-dump and error-capture) has it's own read and write pointers.
>
> got it. I would also put this one detail in the commit message since 
> it's not quickly inferred.
>
>>
>>
>>> Also what is the wrap_offset field in struct guc_log_buffer_state?
>>
>> Alan: This is the byte offset of a location in the subregion that is 
>> the 1st byte
>> after the last valid guc entry written by Guc firmware before a 
>> wraparound
>> was done. This would generate a tiny hole at the end of the subregion 
>> for better
>> cacheline alignment when flushing entries into the subregion. However,
>> the error-capture subregion is dword aligned and all of the output 
>> structures
>> used for error-capture are also dword aligned so this can never 
>> happen for the
>> error-capture subregion.
>>
> Makes sense, thanks for clarifying.
>
> Umesh
>>
>>>
> .

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2022-02-25  7:21 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-26 10:48 [PATCH v5 00/10] Add GuC Error Capture Support Alan Previn
2022-01-26 10:48 ` [Intel-gfx] " Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 01/10] drm/i915/guc: Update GuC ADS size for error capture lists Alan Previn
2022-01-26 18:09   ` Jani Nikula
2022-01-26 18:15   ` Jani Nikula
2022-01-26 22:46   ` Lucas De Marchi
2022-02-03 19:03     ` Matthew Brost
2022-02-03 20:04       ` Lucas De Marchi
2022-02-03 20:37         ` Teres Alexis, Alan Previn
2022-02-03 20:40           ` Teres Alexis, Alan Previn
2022-02-03 21:40             ` Lucas De Marchi
2022-02-03 21:58               ` Teres Alexis, Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 02/10] drm/i915/guc: Add XE_LP registers for GuC error state capture Alan Previn
2022-01-26 18:13   ` Jani Nikula
2022-01-26 21:46     ` Teres Alexis, Alan Previn
2022-01-27  9:30       ` Jani Nikula
2022-01-28 16:54         ` Teres Alexis, Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 03/10] drm/i915/guc: Add DG2 " Alan Previn
2022-02-05  1:28   ` Umesh Nerlige Ramappa
2022-02-10  5:17     ` Teres Alexis, Alan Previn
2022-02-11 19:24     ` Teres Alexis, Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 04/10] drm/i915/guc: Add Gen9 " Alan Previn
2022-02-07 19:14   ` Umesh Nerlige Ramappa
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 05/10] drm/i915/guc: Add GuC's error state capture output structures Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 06/10] drm/i915/guc: Update GuC's log-buffer-state access for error capture Alan Previn
2022-01-27  4:26   ` Teres Alexis, Alan Previn
2022-02-04 18:19   ` Matthew Brost
2022-02-08 19:38     ` Teres Alexis, Alan Previn
2022-02-08 22:18       ` Matthew Brost
2022-02-08 22:55         ` Teres Alexis, Alan Previn
2022-02-09  3:34           ` Matthew Brost
2022-02-09  3:41             ` Matthew Brost
2022-02-09  3:51             ` Teres Alexis, Alan Previn
2022-02-14 19:20               ` Teres Alexis, Alan Previn
2022-02-15  1:22                 ` Teres Alexis, Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 07/10] drm/i915/guc: Extract GuC error capture lists on G2H notification Alan Previn
2022-02-11  1:36   ` Umesh Nerlige Ramappa
2022-02-13 19:47     ` Teres Alexis, Alan Previn
2022-02-17 19:21       ` Umesh Nerlige Ramappa
2022-02-25  7:21         ` Teres Alexis, Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 08/10] drm/i915/guc: Plumb GuC-capture into gpu_coredump Alan Previn
2022-02-11  2:11   ` Umesh Nerlige Ramappa
2022-02-12  0:31     ` Teres Alexis, Alan Previn
2022-02-12  0:38     ` Teres Alexis, Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 09/10] drm/i915/guc: Follow legacy register names Alan Previn
2022-02-03 19:09   ` Matthew Brost
2022-02-04 18:53     ` Teres Alexis, Alan Previn
2022-01-26 10:48 ` [Intel-gfx] [PATCH v5 10/10] drm/i915/guc: Print the GuC error capture output register list Alan Previn
2022-02-07 21:43   ` Umesh Nerlige Ramappa
2022-01-26 18:51 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for Add GuC Error Capture Support (rev5) Patchwork
2022-01-26 18:52 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2022-01-26 19:25 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.