linux/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c

// SPDX-License-Identifier: MIT
/*
 * Copyright © 2021-2022 Intel Corporation
 */

#include <linux/types.h>

#include <drm/drm_print.h>

#include "gt/intel_engine_regs.h"
#include "gt/intel_gt.h"
#include "gt/intel_gt_mcr.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_lrc.h"
#include "guc_capture_fwif.h"
#include "intel_guc_capture.h"
#include "intel_guc_fwif.h"
#include "intel_guc_print.h"
#include "i915_drv.h"
#include "i915_gpu_error.h"
#include "i915_irq.h"
#include "i915_memcpy.h"
#include "i915_reg.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
 */
#define COMMON_BASE_GLOBAL

#define COMMON_GEN8BASE_GLOBAL

#define GEN8_GLOBAL

#define COMMON_GEN12BASE_GLOBAL

#define COMMON_BASE_ENGINE_INSTANCE

#define COMMON_BASE_RENDER

#define COMMON_GEN12BASE_RENDER

#define COMMON_GEN12BASE_VEC

/* XE_LP Global */
static const struct __guc_mmio_reg_descr xe_lp_global_regs[] =;

/* XE_LP Render / Compute Per-Class */
static const struct __guc_mmio_reg_descr xe_lp_rc_class_regs[] =;

/* GEN8+ Render / Compute Per-Engine-Instance */
static const struct __guc_mmio_reg_descr gen8_rc_inst_regs[] =;

/* GEN8+ Media Decode/Encode Per-Engine-Instance */
static const struct __guc_mmio_reg_descr gen8_vd_inst_regs[] =;

/* XE_LP Video Enhancement Per-Class */
static const struct __guc_mmio_reg_descr xe_lp_vec_class_regs[] =;

/* GEN8+ Video Enhancement Per-Engine-Instance */
static const struct __guc_mmio_reg_descr gen8_vec_inst_regs[] =;

/* GEN8+ Blitter Per-Engine-Instance */
static const struct __guc_mmio_reg_descr gen8_blt_inst_regs[] =;

/* XE_LP - GSC Per-Engine-Instance */
static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] =;

/* GEN8 - Global */
static const struct __guc_mmio_reg_descr gen8_global_regs[] =;

static const struct __guc_mmio_reg_descr gen8_rc_class_regs[] =;

/*
 * Empty list to prevent warnings about unknown class/instance types
 * as not all class/instanace types have entries on all platforms.
 */
static const struct __guc_mmio_reg_descr empty_regs_list[] =;

#define TO_GCAP_DEF_OWNER(x)
#define TO_GCAP_DEF_TYPE(x)
#define MAKE_REGLIST(regslist, regsowner, regstype, class)

/* List of lists */
static const struct __guc_mmio_reg_descr_group gen8_lists[] =;

static const struct __guc_mmio_reg_descr_group xe_lp_lists[] =;

static const struct __guc_mmio_reg_descr_group *
guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
			 u32 owner, u32 type, u32 id)
{}

static struct __guc_mmio_reg_descr_group *
guc_capture_get_one_ext_list(struct __guc_mmio_reg_descr_group *reglists,
			     u32 owner, u32 type, u32 id)
{}

static void guc_capture_free_extlists(struct __guc_mmio_reg_descr_group *reglists)
{}

struct __ext_steer_reg {};

static const struct __ext_steer_reg gen8_extregs[] =;

static const struct __ext_steer_reg xehpg_extregs[] =;

static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
			   const struct __ext_steer_reg *extlist,
			   int slice_id, int subslice_id)
{}

static int
__alloc_ext_regs(struct __guc_mmio_reg_descr_group *newlist,
		 const struct __guc_mmio_reg_descr_group *rootlist, int num_regs)
{}

static void
guc_capture_alloc_steered_lists(struct intel_guc *guc,
				const struct __guc_mmio_reg_descr_group *lists)
{}

static const struct __guc_mmio_reg_descr_group *
guc_capture_get_device_reglist(struct intel_guc *guc)
{}

static const char *
__stringify_type(u32 type)
{}

static const char *
__stringify_engclass(u32 class)
{}

static int
guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
		      struct guc_mmio_reg *ptr, u16 num_entries)
{}

static int
guc_cap_list_num_regs(struct intel_guc_state_capture *gc, u32 owner, u32 type, u32 classid)
{}

static int
guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
			size_t *size, bool is_purpose_est)
{}

int
intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
			      size_t *size)
{}

static void guc_capture_create_prealloc_nodes(struct intel_guc *guc);

int
intel_guc_capture_getlist(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
			  void **outptr)
{}

int
intel_guc_capture_getnullheader(struct intel_guc *guc,
				void **outptr, size_t *size)
{}

static int
guc_capture_output_min_size_est(struct intel_guc *guc)
{}

/*
 * Add on a 3x multiplier to allow for multiple back-to-back captures occurring
 * before the i915 can read the data out and process it
 */
#define GUC_CAPTURE_OVERBUFFER_MULTIPLIER

static void check_guc_capture_size(struct intel_guc *guc)
{}

/*
 * KMD Init time flows:
 * --------------------
 *     --> alloc A: GuC input capture regs lists (registered to GuC via ADS).
 *                  intel_guc_ads acquires the register lists by calling
 *                  intel_guc_capture_list_size and intel_guc_capture_list_get 'n' times,
 *                  where n = 1 for global-reg-list +
 *                            num_engine_classes for class-reg-list +
 *                            num_engine_classes for instance-reg-list
 *                               (since all instances of the same engine-class type
 *                                have an identical engine-instance register-list).
 *                  ADS module also calls separately for PF vs VF.
 *
 *     --> 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_process
 *                           L--> Loop through B (head..tail) and for each engine instance's
 *                                err-state-captured register-list we find, we alloc 'C':
 *      --> 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 is created from a pre-allocated list of blank nodes in
 *                   guc->capture->cachelist and populated with the error-capture
 *                   data from GuC and then it's added into guc->capture->outlist linked
 *                   list. This list is used for matchup and printout by i915_gpu_coredump
 *                   and err_print_gt, (when user invokes the error capture sysfs).
 *
 * 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--> intel_guc_capture_get_matching_node is where
 *                                    detach C from internal linked list and add it into
 *                                    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.
 *                   L--> i915_reset_error_state ... -->__i915_gpu_coredump_free
 *                        L--> ... cleanup_gt -->
 *                             L--> intel_guc_capture_free_node returns the
 *                                  capture-output-node back to the internal
 *                                  cachelist for reuse.
 *
 */

static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
{}

static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf)
{}

/*
 * GuC's error-capture output is a ring buffer populated in a byte-stream fashion:
 *
 * The GuC Log buffer region for error-capture is managed like a ring buffer.
 * The GuC firmware dumps error capture logs into this ring in a byte-stream flow.
 * Additionally, as per the current and foreseeable future, all packed error-
 * capture output structures are dword aligned.
 *
 * That said, if the GuC firmware is in the midst of writing a structure that is larger
 * than one dword but the tail end of the err-capture buffer-region has lesser space left,
 * we would need to extract that structure one dword at a time straddled across the end,
 * onto the start of the ring.
 *
 * Below function, guc_capture_log_remove_dw is a helper for that. All callers of this
 * function would typically do a straight-up memcpy from the ring contents and will only
 * call this helper if their structure-extraction is straddling across the end of the
 * ring. GuC firmware does not add any padding. The reason for the no-padding is to ease
 * scalability for future expansion of output data types without requiring a redesign
 * of the flow controls.
 */
static int
guc_capture_log_remove_dw(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
			  u32 *dw)
{}

static bool
guc_capture_data_extracted(struct __guc_capture_bufstate *b,
			   int size, void *dest)
{}

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)
{}

static int
guc_capture_log_get_data_hdr(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
			     struct guc_state_capture_header_t *hdr)
{}

static int
guc_capture_log_get_register(struct intel_guc *guc, struct __guc_capture_bufstate *buf,
			     struct guc_mmio_reg *reg)
{}

static void
guc_capture_delete_one_node(struct intel_guc *guc, struct __guc_capture_parsed_output *node)
{}

static void
guc_capture_delete_prealloc_nodes(struct intel_guc *guc)
{}

static void
guc_capture_add_node_to_list(struct __guc_capture_parsed_output *node,
			     struct list_head *list)
{}

static void
guc_capture_add_node_to_outlist(struct intel_guc_state_capture *gc,
				struct __guc_capture_parsed_output *node)
{}

static void
guc_capture_add_node_to_cachelist(struct intel_guc_state_capture *gc,
				  struct __guc_capture_parsed_output *node)
{}

static void
guc_capture_init_node(struct intel_guc *guc, struct __guc_capture_parsed_output *node)
{}

static struct __guc_capture_parsed_output *
guc_capture_get_prealloc_node(struct intel_guc *guc)
{}

static struct __guc_capture_parsed_output *
guc_capture_alloc_one_node(struct intel_guc *guc)
{}

static struct __guc_capture_parsed_output *
guc_capture_clone_node(struct intel_guc *guc, struct __guc_capture_parsed_output *original,
		       u32 keep_reglist_mask)
{}

static void
__guc_capture_create_prealloc_nodes(struct intel_guc *guc)
{}

static int
guc_get_max_reglist_count(struct intel_guc *guc)
{}

static void
guc_capture_create_prealloc_nodes(struct intel_guc *guc)
{}

static int
guc_capture_extract_reglists(struct intel_guc *guc, struct __guc_capture_bufstate *buf)
{}

static int __guc_capture_flushlog_complete(struct intel_guc *guc)
{}

static void __guc_capture_process_output(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)
{}

#define GCAP_PRINT_INTEL_ENG_INFO(ebuf, eng)

#define GCAP_PRINT_GUC_INST_INFO(ebuf, node)

int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
					const struct intel_engine_coredump *ee)
{}

#endif //CONFIG_DRM_I915_CAPTURE_ERROR

static void guc_capture_find_ecode(struct intel_engine_coredump *ee)
{}

void intel_guc_capture_free_node(struct intel_engine_coredump *ee)
{}

bool intel_guc_capture_is_matching_engine(struct intel_gt *gt,
					  struct intel_context *ce,
					  struct intel_engine_cs *engine)
{}

void intel_guc_capture_get_matching_node(struct intel_gt *gt,
					 struct intel_engine_coredump *ee,
					 struct intel_context *ce)
{}

void intel_guc_capture_process(struct intel_guc *guc)
{}

static void
guc_capture_free_ads_cache(struct intel_guc_state_capture *gc)
{}

void intel_guc_capture_destroy(struct intel_guc *guc)
{}

int intel_guc_capture_init(struct intel_guc *guc)
{}